summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/aac/aac.c382
-rw-r--r--plugins/aac/aac_parser.c4
-rw-r--r--plugins/aac/aac_parser.h2
-rw-r--r--plugins/adplug/Makefile.am8
-rw-r--r--plugins/adplug/adplug-db.cpp62
-rw-r--r--plugins/adplug/libbinio/binfile.cpp28
-rw-r--r--plugins/adplug/libbinio/binfile.h4
-rw-r--r--plugins/adplug/plugin.c35
-rw-r--r--plugins/alsa/alsa.c370
-rw-r--r--plugins/ao/Makefile32
-rw-r--r--plugins/ao/Makefile.am27
-rw-r--r--plugins/ao/eng_ssf/m68kcpu.c2
-rw-r--r--plugins/ao/plugin.c97
-rw-r--r--plugins/artwork/Makefile.am4
-rw-r--r--plugins/artwork/albumartorg.c2
-rw-r--r--plugins/artwork/albumartorg.h2
-rw-r--r--plugins/artwork/artwork.c464
-rw-r--r--plugins/artwork/artwork.h3
-rw-r--r--plugins/artwork/escape.h2
-rw-r--r--plugins/artwork/lastfm.c2
-rw-r--r--plugins/artwork/lastfm.h2
-rw-r--r--plugins/cdda/cdda.c101
-rw-r--r--plugins/converter/Makefile32
-rw-r--r--plugins/converter/callbacks.c11
-rw-r--r--plugins/converter/callbacks.h124
-rw-r--r--plugins/converter/converter.c906
-rw-r--r--plugins/converter/converter.glade1839
-rw-r--r--plugins/converter/converter.gladep11
-rw-r--r--plugins/converter/converter.h150
-rw-r--r--plugins/converter/convgui.c1301
-rw-r--r--plugins/converter/interface.c890
-rw-r--r--plugins/converter/interface.h9
-rw-r--r--plugins/converter/support.c144
-rw-r--r--plugins/converter/support.h69
-rw-r--r--plugins/dca/Makefile.am3
-rw-r--r--plugins/dca/convert2s16.c218
-rw-r--r--plugins/dca/dcaplug.c162
-rw-r--r--plugins/dsp_libsrc/Makefile.am12
-rw-r--r--plugins/dsp_libsrc/src.c286
-rw-r--r--plugins/dsp_libsrc/src.h28
-rw-r--r--plugins/dumb/Makefile (renamed from plugins/dumb/Makefile.am)53
-rw-r--r--plugins/dumb/cdumb.c176
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadmod.c4
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadmod2.c4
-rw-r--r--plugins/dumb/dumb-kode54/src/it/readmod.c8
-rw-r--r--plugins/dumb/dumb-kode54/src/it/readmod2.c4
-rw-r--r--plugins/ffap/ffap.c143
-rw-r--r--plugins/ffmpeg/ChangeLog5
-rw-r--r--plugins/ffmpeg/ffmpeg.c228
-rw-r--r--plugins/flac/flac.c400
-rw-r--r--plugins/gme/Makefile.am7
-rw-r--r--plugins/gme/cgme.c248
-rw-r--r--plugins/gme/game-music-emu-0.5.5/gme/Sap_Apu.cpp2
-rw-r--r--plugins/gtkui/Makefile.am49
-rw-r--r--plugins/gtkui/actions.c2
-rw-r--r--plugins/gtkui/actions.h2
-rw-r--r--plugins/gtkui/callbacks.c250
-rw-r--r--plugins/gtkui/callbacks.h166
-rw-r--r--plugins/gtkui/coverart.c72
-rw-r--r--plugins/gtkui/coverart.h2
-rw-r--r--plugins/gtkui/ddbcellrenderertextmultiline.c51
-rw-r--r--plugins/gtkui/ddbcellrenderertextmultiline.h2
-rw-r--r--plugins/gtkui/ddbcellrenderertextmultiline.vala14
-rw-r--r--plugins/gtkui/ddbequalizer.c2
-rw-r--r--plugins/gtkui/ddbequalizer.h2
-rw-r--r--plugins/gtkui/ddblistview.c293
-rw-r--r--plugins/gtkui/ddblistview.h6
-rw-r--r--plugins/gtkui/ddbseekbar.c4
-rw-r--r--plugins/gtkui/ddbseekbar.h2
-rw-r--r--plugins/gtkui/ddbtabstrip.c94
-rw-r--r--plugins/gtkui/ddbtabstrip.h2
-rw-r--r--plugins/gtkui/ddbvolumebar.c2
-rw-r--r--plugins/gtkui/ddbvolumebar.h2
-rw-r--r--plugins/gtkui/deadbeef.glade3249
-rw-r--r--plugins/gtkui/deadbeef.gladep1
-rw-r--r--plugins/gtkui/drawing.h8
-rw-r--r--plugins/gtkui/dspconfig.c482
-rw-r--r--plugins/gtkui/dspconfig.h (renamed from plugins/supereq/supereq.h)18
-rw-r--r--plugins/gtkui/eq.c202
-rw-r--r--plugins/gtkui/eq.h6
-rw-r--r--plugins/gtkui/fileman.c51
-rw-r--r--plugins/gtkui/gdkdrawing.c52
-rw-r--r--plugins/gtkui/gtkui.c266
-rw-r--r--plugins/gtkui/gtkui.h24
-rw-r--r--plugins/gtkui/gtkui_api.h28
-rw-r--r--plugins/gtkui/interface.c1664
-rw-r--r--plugins/gtkui/interface.h7
-rw-r--r--plugins/gtkui/mainplaylist.c22
-rw-r--r--plugins/gtkui/mainplaylist.h2
-rw-r--r--plugins/gtkui/parser.c2
-rw-r--r--plugins/gtkui/parser.h2
-rw-r--r--plugins/gtkui/plcommon.c48
-rw-r--r--plugins/gtkui/plcommon.h2
-rw-r--r--plugins/gtkui/pluginconf.c360
-rw-r--r--plugins/gtkui/pluginconf.h28
-rw-r--r--plugins/gtkui/prefwin.c514
-rw-r--r--plugins/gtkui/progress.c46
-rw-r--r--plugins/gtkui/progress.h2
-rw-r--r--plugins/gtkui/search.c78
-rw-r--r--plugins/gtkui/search.h5
-rw-r--r--plugins/gtkui/support.h2
-rw-r--r--plugins/gtkui/tagwritersettings.c204
-rw-r--r--plugins/gtkui/tagwritersettings.h25
-rw-r--r--plugins/gtkui/timeline.c2
-rw-r--r--plugins/gtkui/timeline.h2
-rw-r--r--plugins/gtkui/trkproperties.c670
-rw-r--r--plugins/gtkui/trkproperties.h4
-rw-r--r--plugins/gtkui/wingeom.c101
-rw-r--r--plugins/gtkui/wingeom.h31
-rw-r--r--plugins/hotkeys/hotkeys.c51
-rw-r--r--plugins/hotkeys/hotkeys.h2
-rw-r--r--plugins/lastfm/lastfm.c48
-rw-r--r--plugins/m3u/Makefile.am11
-rw-r--r--plugins/m3u/m3u.c469
-rw-r--r--plugins/mms/mmsplug.c41
-rw-r--r--plugins/mpgmad/mpgmad.c534
-rw-r--r--plugins/musepack/Makefile.am2
-rw-r--r--plugins/musepack/mpc_decoder.c6
-rw-r--r--plugins/musepack/musepack.c190
-rw-r--r--plugins/notify/notify.c321
-rw-r--r--plugins/nullout/nullout.c73
-rw-r--r--plugins/oss/oss.c243
-rw-r--r--plugins/pulse/pulse.c231
-rw-r--r--plugins/shellexec/Makefile.am2
-rw-r--r--plugins/shellexec/shellexec.c25
-rw-r--r--plugins/shn/Makefile22
-rw-r--r--plugins/shn/Makefile.am10
-rw-r--r--plugins/shn/shn.c126
-rw-r--r--plugins/sid/Makefile.am6
-rw-r--r--plugins/sid/csid.cpp96
-rw-r--r--plugins/sid/csid.h4
-rw-r--r--plugins/sid/plugin.c39
-rw-r--r--plugins/sid/sidplay-libs/libsidplay/src/sidtune/SidTune.cpp13
-rw-r--r--plugins/sndfile/sndfile.c322
-rw-r--r--plugins/soundtouch/Makefile52
-rw-r--r--plugins/soundtouch/plugin.c308
-rw-r--r--plugins/soundtouch/soundtouch/COPYING.TXT458
-rw-r--r--plugins/soundtouch/soundtouch/README.html752
-rw-r--r--plugins/soundtouch/soundtouch/include/BPMDetect.h161
-rw-r--r--plugins/soundtouch/soundtouch/include/FIFOSampleBuffer.h174
-rw-r--r--plugins/soundtouch/soundtouch/include/FIFOSamplePipe.h221
-rw-r--r--plugins/soundtouch/soundtouch/include/STTypes.h149
-rw-r--r--plugins/soundtouch/soundtouch/include/SoundTouch.h252
-rw-r--r--plugins/soundtouch/soundtouch/include/soundtouch_config.h88
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/3dnow_win.cpp349
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/AAFilter.cpp184
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/AAFilter.h91
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/BPMDetect.cpp308
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/FIFOSampleBuffer.cpp262
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/FIRFilter.cpp269
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/FIRFilter.h164
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/PeakFinder.cpp239
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/PeakFinder.h93
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/RateTransposer.cpp628
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/RateTransposer.h159
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/SoundTouch.cpp480
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/TDStretch.cpp1045
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/TDStretch.h275
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/cpu_detect.h62
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/cpu_detect_x86_gcc.cpp135
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/cpu_detect_x86_win.cpp129
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/mmx_optimized.cpp320
-rw-r--r--plugins/soundtouch/soundtouch/source/SoundTouch/sse_optimized.cpp510
-rw-r--r--plugins/soundtouch/st.cpp112
-rw-r--r--plugins/soundtouch/st.h115
-rw-r--r--plugins/supereq/Equ.cpp602
-rw-r--r--plugins/supereq/Equ.h56
-rw-r--r--plugins/supereq/Fftsg_fl.cpp29
-rw-r--r--plugins/supereq/Makefile.am47
-rw-r--r--plugins/supereq/ff_rdft.c63
-rw-r--r--plugins/supereq/ffmpeg_fft/README9
-rw-r--r--plugins/supereq/ffmpeg_fft/config.h904
-rw-r--r--plugins/supereq/ffmpeg_fft/ffmpeg_fft.h95
-rw-r--r--plugins/supereq/ffmpeg_fft/libavcodec/arm/asm.S104
-rw-r--r--plugins/supereq/ffmpeg_fft/libavcodec/arm/fft_init_arm.c71
-rw-r--r--plugins/supereq/ffmpeg_fft/libavcodec/arm/fft_neon.S372
-rw-r--r--plugins/supereq/ffmpeg_fft/libavcodec/arm/rdft_neon.S151
-rw-r--r--plugins/supereq/ffmpeg_fft/libavcodec/arm/simple_idct_neon.S372
-rw-r--r--plugins/supereq/ffmpeg_fft/libavcodec/avfft.c142
-rw-r--r--plugins/supereq/ffmpeg_fft/libavcodec/avfft.h103
-rw-r--r--plugins/supereq/ffmpeg_fft/libavcodec/dct.c228
-rw-r--r--plugins/supereq/ffmpeg_fft/libavcodec/dct32.c262
-rw-r--r--plugins/supereq/ffmpeg_fft/libavcodec/dct32.h10
-rw-r--r--plugins/supereq/ffmpeg_fft/libavcodec/fft.c300
-rw-r--r--plugins/supereq/ffmpeg_fft/libavcodec/fft.h244
-rw-r--r--plugins/supereq/ffmpeg_fft/libavcodec/rdft.c137
-rw-r--r--plugins/supereq/ffmpeg_fft/libavutil/attributes.h122
-rw-r--r--plugins/supereq/ffmpeg_fft/libavutil/avconfig.h5
-rw-r--r--plugins/supereq/ffmpeg_fft/libavutil/avutil.h90
-rw-r--r--plugins/supereq/ffmpeg_fft/libavutil/common.h347
-rw-r--r--plugins/supereq/ffmpeg_fft/libavutil/intfloat_readwrite.c98
-rw-r--r--plugins/supereq/ffmpeg_fft/libavutil/intfloat_readwrite.h41
-rw-r--r--plugins/supereq/ffmpeg_fft/libavutil/mathematics.c181
-rw-r--r--plugins/supereq/ffmpeg_fft/libavutil/mathematics.h110
-rw-r--r--plugins/supereq/ffmpeg_fft/libavutil/mem.c176
-rw-r--r--plugins/supereq/ffmpeg_fft/libavutil/mem.h128
-rw-r--r--plugins/supereq/ffmpeg_fft/libavutil/rational.c131
-rw-r--r--plugins/supereq/ffmpeg_fft/libavutil/rational.h130
-rw-r--r--plugins/supereq/ffmpeg_fft/libffmpeg_fft.ver4
-rw-r--r--plugins/supereq/ffmpeg_fft/publik.h6
-rw-r--r--plugins/supereq/nsfft-1.00/README15
-rw-r--r--plugins/supereq/nsfft-1.00/dft/DFT.c327
-rw-r--r--plugins/supereq/nsfft-1.00/dft/DFT.h56
-rw-r--r--plugins/supereq/nsfft-1.00/dft/DFTUndiff.c1807
-rw-r--r--plugins/supereq/nsfft-1.00/dft/DFTUndiff.h114
l---------plugins/supereq/nsfft-1.00/dft/Makefile1
-rw-r--r--plugins/supereq/nsfft-1.00/dft/Makefile.altivec26
-rw-r--r--plugins/supereq/nsfft-1.00/dft/Makefile.neon26
-rw-r--r--plugins/supereq/nsfft-1.00/dft/Makefile.purec35
-rw-r--r--plugins/supereq/nsfft-1.00/dft/Makefile.x8629
-rw-r--r--plugins/supereq/nsfft-1.00/dft/Makefile.x86avx35
-rw-r--r--plugins/supereq/nsfft-1.00/dfttest/DFTExample.c88
-rw-r--r--plugins/supereq/nsfft-1.00/dfttest/DFTTestFFTW.c317
-rw-r--r--plugins/supereq/nsfft-1.00/dfttest/DFTTestNaive.c419
-rw-r--r--plugins/supereq/nsfft-1.00/dfttest/DFTTestOoura.c260
-rw-r--r--plugins/supereq/nsfft-1.00/dfttest/Makefile35
-rw-r--r--plugins/supereq/nsfft-1.00/dfttest/pi_fft.c.patch131
-rw-r--r--plugins/supereq/nsfft-1.00/doc/default.css34
-rw-r--r--plugins/supereq/nsfft-1.00/doc/index.xhtml2016
-rw-r--r--plugins/supereq/nsfft-1.00/doc/nsfft.pdfbin0 -> 78973 bytes
-rw-r--r--plugins/supereq/nsfft-1.00/ooura/Makefile11
-rw-r--r--plugins/supereq/nsfft-1.00/ooura/README2
-rw-r--r--plugins/supereq/nsfft-1.00/ooura/fftsg.c3314
-rw-r--r--plugins/supereq/nsfft-1.00/ooura/pi_fft.c1616
l---------plugins/supereq/nsfft-1.00/simd/Makefile1
-rw-r--r--plugins/supereq/nsfft-1.00/simd/Makefile.altivec26
-rw-r--r--plugins/supereq/nsfft-1.00/simd/Makefile.neon26
-rw-r--r--plugins/supereq/nsfft-1.00/simd/Makefile.purec35
-rw-r--r--plugins/supereq/nsfft-1.00/simd/Makefile.x8635
-rw-r--r--plugins/supereq/nsfft-1.00/simd/Makefile.x86avx35
-rw-r--r--plugins/supereq/nsfft-1.00/simd/SIMDBase.c454
-rw-r--r--plugins/supereq/nsfft-1.00/simd/SIMDBase.h53
-rw-r--r--plugins/supereq/nsfft-1.00/simd/SIMDBaseUndiff.c38
-rw-r--r--plugins/supereq/nsfft-1.00/simd/SIMDBaseUndiff.h231
-rw-r--r--plugins/supereq/paramlist.hpp31
-rw-r--r--plugins/supereq/shibatch_rdft.c71
-rw-r--r--plugins/supereq/supereq.c412
-rw-r--r--plugins/tta/filter.h4
-rw-r--r--plugins/tta/ttadec.c4
-rw-r--r--plugins/tta/ttaplug.c137
-rw-r--r--plugins/uade2/plugin.c692
-rw-r--r--plugins/uade2/uade-2.13/AUTHORS59
-rw-r--r--plugins/uade2/uade-2.13/COPYING12
-rw-r--r--plugins/uade2/uade-2.13/COPYING.GPL340
-rw-r--r--plugins/uade2/uade-2.13/COPYING.LGPL504
-rw-r--r--plugins/uade2/uade-2.13/ChangeLog1907
-rw-r--r--plugins/uade2/uade-2.13/README53
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/amifilemagic.c1168
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/amifilemagic.h9
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/eagleplayer.c502
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/eagleplayer.h127
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/effects.c490
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/effects.h42
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/md5.c247
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/md5.copyright8
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/md5.h21
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/songdb.c798
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/songdb.h24
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/songinfo.c721
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/songinfo.h19
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/support.c183
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/support.h31
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/uadeconf.c888
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/uadeconf.h27
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/uadeconfstructure.h139
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/uadecontrol.c249
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/uadecontrol.h24
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/uadestate.h25
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/unixwalkdir.c69
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/unixwalkdir.h16
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/vplist.c115
-rw-r--r--plugins/uade2/uade-2.13/src/frontends/common/vplist.h44
-rw-r--r--plugins/uade2/uade-2.13/src/include/.gitignore4
-rw-r--r--plugins/uade2/uade-2.13/src/include/amigafilter.h10
-rw-r--r--plugins/uade2/uade-2.13/src/include/amigamsg.h24
-rw-r--r--plugins/uade2/uade-2.13/src/include/audio.h57
-rw-r--r--plugins/uade2/uade-2.13/src/include/cia.h26
-rw-r--r--plugins/uade2/uade-2.13/src/include/commpipe.h155
-rw-r--r--plugins/uade2/uade-2.13/src/include/compiler.h111
-rw-r--r--plugins/uade2/uade-2.13/src/include/custom.h115
-rw-r--r--plugins/uade2/uade-2.13/src/include/debug.h25
-rw-r--r--plugins/uade2/uade-2.13/src/include/events.h83
-rw-r--r--plugins/uade2/uade-2.13/src/include/execlib.h40
-rw-r--r--plugins/uade2/uade-2.13/src/include/gensound.h19
-rw-r--r--plugins/uade2/uade-2.13/src/include/memory.h181
-rw-r--r--plugins/uade2/uade-2.13/src/include/newcpu.h275
-rw-r--r--plugins/uade2/uade-2.13/src/include/options.h262
-rw-r--r--plugins/uade2/uade-2.13/src/include/osemu.h19
-rw-r--r--plugins/uade2/uade-2.13/src/include/readcpu.h99
-rw-r--r--plugins/uade2/uade-2.13/src/include/sinctable.h7
-rw-r--r--plugins/uade2/uade-2.13/src/include/sysdeps.h347
-rw-r--r--plugins/uade2/uade-2.13/src/include/text_scope.h21
-rw-r--r--plugins/uade2/uade-2.13/src/include/uade.h43
-rw-r--r--plugins/uade2/uade-2.13/src/include/uadeconstants.h10
-rw-r--r--plugins/uade2/uade-2.13/src/include/uadeipc.h77
-rw-r--r--plugins/uade2/uade-2.13/src/include/uadeutils.h27
-rw-r--r--plugins/uade2/uade-2.13/src/include/uae.h30
-rw-r--r--plugins/uade2/uade-2.13/src/include/unixatomic.h15
-rw-r--r--plugins/uade2/uade-2.13/src/include/unixsupport.h32
-rw-r--r--plugins/uade2/uade-2.13/src/ossupport.c48
-rw-r--r--plugins/uade2/uade-2.13/src/uadeipc.c291
-rw-r--r--plugins/uade2/uade-2.13/src/unixatomic.c149
-rw-r--r--plugins/uade2/uade-2.13/src/unixsupport.c350
-rw-r--r--plugins/vfs_curl/Makefile.am2
-rw-r--r--plugins/vfs_curl/vfs_curl.c260
-rw-r--r--plugins/vfs_zip/Makefile.am9
-rw-r--r--plugins/vfs_zip/vfs_zip.c255
-rw-r--r--plugins/vorbis/vorbis.c230
-rw-r--r--plugins/vtx/vtx.c81
-rw-r--r--plugins/wavpack/COPYING26
-rw-r--r--plugins/wavpack/wavpack.c257
-rw-r--r--plugins/wildmidi/wildmidiplug.c58
312 files changed, 55684 insertions, 5948 deletions
diff --git a/plugins/aac/aac.c b/plugins/aac/aac.c
index f7925b82..33418593 100644
--- a/plugins/aac/aac.c
+++ b/plugins/aac/aac.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -19,11 +19,13 @@
#include <string.h>
#include <stdio.h>
+#include <unistd.h>
#include <neaacdec.h>
#ifdef HAVE_CONFIG_H
#include "../../config.h"
#endif
#include <stdlib.h>
+#include <math.h>
#include "../../deadbeef.h"
#include "aac_parser.h"
@@ -54,12 +56,26 @@ static DB_functions_t *deadbeef;
#define MP4FILE_CB MP4FileProvider
#endif
+
+// aac channel mapping
+// 0: Defined in AOT Specifc Config
+// 1: 1 channel: front-center
+// 2: 2 channels: front-left, front-right
+// 3: 3 channels: front-center, front-left, front-right
+// 4: 4 channels: front-center, front-left, front-right, back-center
+// 5: 5 channels: front-center, front-left, front-right, back-left, back-right
+// 6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
+// 7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
+// 8-15: Reserved
+
+
typedef struct {
DB_fileinfo_t info;
NeAACDecHandle dec;
DB_FILE *file;
MP4FILE mp4file;
MP4FILE_CB mp4reader;
+ NeAACDecFrameInfo frame_info; // last frame info
int32_t timescale;
uint32_t maxSampleSize;
int mp4track;
@@ -72,16 +88,17 @@ typedef struct {
int currentsample;
char buffer[AAC_BUFFER_SIZE];
int remaining;
- int faad_channels;
char out_buffer[OUT_BUFFER_SIZE];
int out_remaining;
int num_errors;
char *samplebuffer;
+ int remap[10];
+ int noremap;
} aac_info_t;
// allocate codec control structure
static DB_fileinfo_t *
-aac_open (void) {
+aac_open (uint32_t hints) {
DB_fileinfo_t *_info = malloc (sizeof (aac_info_t));
aac_info_t *info = (aac_info_t *)_info;
memset (info, 0, sizeof (aac_info_t));
@@ -101,6 +118,7 @@ aac_fs_seek (void *user_data, uint64_t position) {
DB_FILE *fp = (DB_FILE *)user_data;
return deadbeef->fseek (fp, position, SEEK_SET);
}
+
#else
static void *
aac_fs_open (const char *fname, MP4FileMode mode) {
@@ -134,7 +152,7 @@ parse_aac_stream(DB_FILE *fp, int *psamplerate, int *pchannels, float *pduration
int firstframepos = -1;
int fsize = -1;
int offs = 0;
- if (!fp->vfs->streaming) {
+ if (!fp->vfs->is_streaming ()) {
int skip = deadbeef->junk_get_leading_size (fp);
if (skip >= 0) {
deadbeef->fseek (fp, skip, SEEK_SET);
@@ -158,7 +176,7 @@ parse_aac_stream(DB_FILE *fp, int *psamplerate, int *pchannels, float *pduration
int frame = 0;
int scanframes = 1000;
- if (fp->vfs->streaming) {
+ if (fp->vfs->is_streaming ()) {
scanframes = 1;
}
@@ -183,7 +201,7 @@ parse_aac_stream(DB_FILE *fp, int *psamplerate, int *pchannels, float *pduration
continue;
}
else {
- trace ("aac: frame #%d sync: %d %d %d %d %d\n", frame, channels, samplerate, bitrate, samples, size);
+ trace ("aac: frame #%d sync: %dch %d %d %d %d\n", frame, channels, samplerate, bitrate, samples, size);
frame++;
nsamples += samples;
if (!stream_sr) {
@@ -200,7 +218,7 @@ parse_aac_stream(DB_FILE *fp, int *psamplerate, int *pchannels, float *pduration
// *pchannels = stream_ch;
// }
framepos += size;
- if (deadbeef->fseek (fp, size-sizeof(buf), SEEK_CUR) == -1) {
+ if (deadbeef->fseek (fp, size-(int)sizeof(buf), SEEK_CUR) == -1) {
trace ("parse_aac_stream: invalid seek %d\n", size-sizeof(buf));
break;
}
@@ -213,6 +231,7 @@ parse_aac_stream(DB_FILE *fp, int *psamplerate, int *pchannels, float *pduration
}
*psamplerate = stream_sr;
+
*pchannels = stream_ch;
if (ptotalsamples) {
@@ -227,6 +246,12 @@ parse_aac_stream(DB_FILE *fp, int *psamplerate, int *pchannels, float *pduration
trace ("aac: duration=%f (%d samples @ %d Hz), fsize=%d\n", *pduration, totalsamples, stream_sr, fsize);
}
+ if (*psamplerate <= 24000) {
+ *psamplerate *= 2;
+ if (ptotalsamples) {
+ *ptotalsamples *= 2;
+ }
+ }
return firstframepos;
}
@@ -287,7 +312,9 @@ aac_probe (DB_FILE *fp, const char *fname, MP4FILE_CB *cb, float *duration, int
}
*channels = mp4ff_get_channel_count (mp4, i);
int samples = mp4ff_num_samples(mp4, i) * 1024;
- trace ("mp4 nsamples=%d, samplerate=%d\n", samples, *samplerate);
+ samples = (int64_t)samples * (*samplerate) / mp4ff_time_scale (mp4, i);
+
+ trace ("mp4 nsamples=%d, samplerate=%d, timescale=%d, duration=%lld\n", samples, *samplerate, mp4ff_time_scale(mp4, i), mp4ff_get_track_duration(mp4, i));
*duration = (float)samples / (*samplerate);
if (totalsamples) {
@@ -368,7 +395,7 @@ static int
aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
aac_info_t *info = (aac_info_t *)_info;
- info->file = deadbeef->fopen (it->fname);
+ info->file = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!info->file) {
return -1;
}
@@ -380,7 +407,7 @@ aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
int totalsamples = -1;
int offs = -1;
- if (!info->file->vfs->streaming) {
+ if (!info->file->vfs->is_streaming ()) {
int skip = deadbeef->junk_get_leading_size (info->file);
if (skip >= 0) {
deadbeef->fseek (info->file, skip, SEEK_SET);
@@ -406,9 +433,9 @@ aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
info->mp4reader.close = aac_fs_close;
#endif
- if (!info->file->vfs->streaming) {
+ if (!info->file->vfs->is_streaming ()) {
#ifdef USE_MP4FF
- trace ("aac_init: mp4ff_open_read %s\n", it->fname);
+ trace ("aac_init: mp4ff_open_read %s\n", deadbeef->pl_find_meta (it, ":URI"));
info->mp4file = mp4ff_open_read (&info->mp4reader);
if (info->mp4file) {
int ntracks = mp4ff_total_tracks (info->mp4file);
@@ -446,7 +473,6 @@ aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
trace ("NeAACDecInit2 returned error\n");
return -1;
}
- info->faad_channels = ch;
samplerate = srate;
channels = ch;
NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration (info->dec);
@@ -478,8 +504,8 @@ aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
}
}
#else
- trace ("aac_init: MP4ReadProvider %s\n", it->fname);
- info->mp4file = MP4ReadProvider (it->fname, 0, &info->mp4reader);
+ trace ("aac_init: MP4ReadProvider %s\n", deadbeef->pl_find_meta (it, ":URI"));
+ info->mp4file = MP4ReadProvider (deadbeef->pl_find_meta (it, ":URI"), 0, &info->mp4reader);
info->mp4track = MP4FindTrackId(info->mp4file, 0, "audio", 0);
trace ("aac_init: MP4FindTrackId returned %d\n", info->mp4track);
if (info->mp4track >= 0) {
@@ -494,7 +520,6 @@ aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
if (rc >= 0) {
_info->samplerate = mp4ASC.samplingFrequency;
_info->channels = MP4GetTrackAudioChannels (info->mp4file, info->mp4track);
- info->faad_channels = _info->channels;
totalsamples = MP4GetTrackNumberOfSamples (info->mp4file, info->mp4track) * 1024 * _info->channels;
// init mp4 decoding
@@ -505,7 +530,6 @@ aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
trace ("NeAACDecInit2 returned error\n");
return -1;
}
- info->faad_channels = ch;
samplerate = srate;
channels = ch;
NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration (info->dec);
@@ -551,8 +575,8 @@ aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
trace ("found aac stream\n");
}
- _info->channels = channels;
- _info->samplerate = samplerate;
+ _info->fmt.channels = channels;
+ _info->fmt.samplerate = samplerate;
}
else {
// sync before attempting to init
@@ -563,17 +587,16 @@ aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
trace ("aac: parse_aac_stream failed\n");
return -1;
}
- _info->channels = channels;
- _info->samplerate = samplerate*2;
trace("parse_aac_stream returned %x\n", offs);
}
+
if (offs >= 0) {
deadbeef->fseek (info->file, offs, SEEK_SET);
}
// duration = (float)totalsamples / samplerate;
// deadbeef->pl_set_item_duration (it, duration);
- _info->bps = 16;
+ _info->fmt.bps = 16;
_info->plugin = &plugin;
if (!info->mp4file) {
@@ -586,7 +609,7 @@ aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
info->remaining = deadbeef->fread (info->buffer, 1, AAC_BUFFER_SIZE, info->file);
NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration (info->dec);
- conf->dontUpSampleImplicitSBR = 1;
+// conf->dontUpSampleImplicitSBR = 1;
NeAACDecSetConfiguration (info->dec, conf);
unsigned long srate;
unsigned char ch;
@@ -608,11 +631,11 @@ aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
memmove (info->buffer, info->buffer + consumed, info->remaining - consumed);
info->remaining -= consumed;
}
- info->faad_channels = ch;
- _info->channels = ch;
+ _info->fmt.channels = ch;
+ _info->fmt.samplerate = srate;
}
- if (!info->file->vfs->streaming) {
+ if (!info->file->vfs->is_streaming ()) {
if (it->endsample > 0) {
info->startsample = it->startsample;
info->endsample = it->endsample;
@@ -624,6 +647,11 @@ aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
}
}
+ for (int i = 0; i < _info->fmt.channels; i++) {
+ _info->fmt.channelmask |= 1 << i;
+ }
+ info->noremap = 0;
+ info->remap[0] = -1;
trace ("init success\n");
return 0;
@@ -651,13 +679,14 @@ aac_free (DB_fileinfo_t *_info) {
}
static int
-aac_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
+aac_read (DB_fileinfo_t *_info, char *bytes, int size) {
aac_info_t *info = (aac_info_t *)_info;
- int out_ch = min (_info->channels, 2);
- if (!info->file->vfs->streaming) {
- if (info->currentsample + size / (2 * out_ch) > info->endsample) {
- size = (info->endsample - info->currentsample + 1) * 2 * out_ch;
+ int samplesize = _info->fmt.channels * _info->fmt.bps / 8;
+ if (!info->file->vfs->is_streaming ()) {
+ if (info->currentsample + size / samplesize > info->endsample) {
+ size = (info->endsample - info->currentsample + 1) * samplesize;
if (size <= 0) {
+ trace ("aac_read: eof");
return 0;
}
}
@@ -665,41 +694,105 @@ aac_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
int initsize = size;
int eof = 0;
- int sample_size = out_ch * (_info->bps >> 3);
while (size > 0) {
if (info->skipsamples > 0 && info->out_remaining > 0) {
int skip = min (info->out_remaining, info->skipsamples);
if (skip < info->out_remaining) {
- memmove (info->out_buffer, info->out_buffer + skip * 2 * info->faad_channels, (info->out_remaining - skip) * 2 * info->faad_channels);
+ memmove (info->out_buffer, info->out_buffer + skip * samplesize, (info->out_remaining - skip) * samplesize);
}
info->out_remaining -= skip;
info->skipsamples -= skip;
}
if (info->out_remaining > 0) {
- int n = size / sample_size;
+ int n = size / samplesize;
n = min (info->out_remaining, n);
char *src = info->out_buffer;
- for (int i = 0; i < n; i++) {
- memcpy (bytes, src, sample_size);
- bytes += sample_size;
- src += info->faad_channels * 2;
+ if (info->noremap) {
+ memcpy (bytes, src, n * samplesize);
+ bytes += n * samplesize;
+ src += n * samplesize;
}
+ else {
+ int i, j;
+ if (info->remap[0] == -1) {
+ // build remap mtx
+
+ // FIXME: should build channelmask 1st; then remap based on channelmask
+ for (i = 0; i < _info->fmt.channels; i++) {
+ switch (info->frame_info.channel_position[i]) {
+ case FRONT_CHANNEL_CENTER:
+ trace ("FC->%d\n", i);
+ info->remap[2] = i;
+ break;
+ case FRONT_CHANNEL_LEFT:
+ trace ("FL->%d\n", i);
+ info->remap[0] = i;
+ break;
+ case FRONT_CHANNEL_RIGHT:
+ trace ("FR->%d\n", i);
+ info->remap[1] = i;
+ break;
+ case SIDE_CHANNEL_LEFT:
+ trace ("SL->%d\n", i);
+ info->remap[6] = i;
+ break;
+ case SIDE_CHANNEL_RIGHT:
+ trace ("SR->%d\n", i);
+ info->remap[7] = i;
+ break;
+ case BACK_CHANNEL_LEFT:
+ trace ("RL->%d\n", i);
+ info->remap[4] = i;
+ break;
+ case BACK_CHANNEL_RIGHT:
+ trace ("RR->%d\n", i);
+ info->remap[5] = i;
+ break;
+ case BACK_CHANNEL_CENTER:
+ trace ("BC->%d\n", i);
+ info->remap[8] = i;
+ break;
+ case LFE_CHANNEL:
+ trace ("LFE->%d\n", i);
+ info->remap[3] = i;
+ break;
+ default:
+ trace ("aac: unknown ch(%d)->%d\n", info->frame_info.channel_position[i], i);
+ break;
+ }
+ }
+ if (info->remap[0] == -1) {
+ info->remap[0] = 0;
+ }
+ if ((_info->fmt.channels == 1 && info->remap[0] == FRONT_CHANNEL_CENTER)
+ || (_info->fmt.channels == 2 && info->remap[0] == FRONT_CHANNEL_LEFT && info->remap[1] == FRONT_CHANNEL_RIGHT)) {
+ info->noremap = 1;
+ }
+ }
+
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < _info->fmt.channels; j++) {
+ ((int16_t *)bytes)[info->remap[j]] = ((int16_t *)src)[j];
+ }
+ src += samplesize;
+ bytes += samplesize;
+ }
+ }
+ size -= n * samplesize;
- size -= n * sample_size;
if (n == info->out_remaining) {
info->out_remaining = 0;
}
else {
- memmove (info->out_buffer, src, (info->out_remaining - n) * info->faad_channels * 2);
+ memmove (info->out_buffer, src, (info->out_remaining - n) * samplesize);
info->out_remaining -= n;
}
continue;
}
char *samples = NULL;
- NeAACDecFrameInfo frame_info;
if (info->mp4file) {
unsigned char *buffer = NULL;
@@ -732,7 +825,7 @@ aac_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
break;
}
info->mp4sample++;
- samples = NeAACDecDecode(info->dec, &frame_info, buffer, buffer_size);
+ samples = NeAACDecDecode(info->dec, &info->frame_info, buffer, buffer_size);
if (buffer) {
free (buffer);
@@ -750,11 +843,11 @@ aac_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
info->remaining += res;
}
- samples = NeAACDecDecode (info->dec, &frame_info, info->buffer, info->remaining);
+ samples = NeAACDecDecode (info->dec, &info->frame_info, info->buffer, info->remaining);
if (!samples) {
- trace ("NeAACDecDecode failed, consumed=%d\n", frame_info.bytesconsumed);
+ trace ("NeAACDecDecode failed, consumed=%d\n", info->frame_info.bytesconsumed);
if (info->num_errors > 10) {
- trace ("NeAACDecDecode failed 10 times, interrupting\n");
+ trace ("NeAACDecDecode failed %d times, interrupting\n", info->num_errors);
break;
}
info->num_errors++;
@@ -762,7 +855,7 @@ aac_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
continue;
}
info->num_errors=0;
- int consumed = frame_info.bytesconsumed;
+ int consumed = info->frame_info.bytesconsumed;
if (consumed > info->remaining) {
trace ("NeAACDecDecode consumed more than available! wtf?\n");
break;
@@ -776,26 +869,19 @@ aac_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
}
}
- if (frame_info.samples > 0) {
- memcpy (info->out_buffer, samples, frame_info.samples * 2);
- info->out_remaining = frame_info.samples / frame_info.channels;
+ if (info->frame_info.samples > 0) {
+ memcpy (info->out_buffer, samples, info->frame_info.samples * 2);
+ info->out_remaining = info->frame_info.samples / info->frame_info.channels;
}
}
- info->currentsample += (initsize-size) / sample_size;
+ info->currentsample += (initsize-size) / samplesize;
return initsize-size;
}
// returns -1 on error, 0 on success
int
seek_raw_aac (aac_info_t *info, int sample) {
- deadbeef->rewind (info->file);
- int skip = deadbeef->junk_get_leading_size (info->file);
- if (skip >= 0) {
- deadbeef->fseek (info->file, skip, SEEK_SET);
- }
-
- int offs = deadbeef->ftell (info->file);
uint8_t buf[ADTS_HEADER_SIZE*8];
int nsamples = 0;
@@ -828,14 +914,17 @@ seek_raw_aac (aac_info_t *info, int sample) {
continue;
}
else {
- //trace ("aac: frame #%d sync: %d %d %d %d %d\n", frame, channels, samplerate, bitrate, samples, size);
+ //trace ("aac: frame #%d(%d/%d) sync: %d %d %d %d %d\n", frame, curr_sample, sample, channels, samplerate, bitrate, frame_samples, size);
frame++;
- if (deadbeef->fseek (info->file, size-sizeof(buf), SEEK_CUR) == -1) {
+ if (deadbeef->fseek (info->file, size-(int)sizeof(buf), SEEK_CUR) == -1) {
trace ("seek_raw_aac: invalid seek %d\n", size-sizeof(buf));
break;
}
bufsize = 0;
}
+ if (samplerate <= 24000) {
+ frame_samples *= 2;
+ }
} while (curr_sample + frame_samples < sample);
if (curr_sample + frame_samples < sample) {
@@ -855,6 +944,16 @@ aac_seek_sample (DB_fileinfo_t *_info, int sample) {
info->skipsamples = sample - info->mp4sample * (info->mp4framesize-1);
}
else {
+ if (sample < info->currentsample, 1) {
+ int skip = deadbeef->junk_get_leading_size (info->file);
+ if (skip >= 0) {
+ deadbeef->fseek (info->file, skip, SEEK_SET);
+ }
+ else {
+ deadbeef->fseek (info->file, 0, SEEK_SET);
+ }
+ }
+
int res = seek_raw_aac (info, sample);
if (res < 0) {
return -1;
@@ -864,13 +963,13 @@ aac_seek_sample (DB_fileinfo_t *_info, int sample) {
info->remaining = 0;
info->out_remaining = 0;
info->currentsample = sample;
- _info->readpos = (float)(info->currentsample - info->startsample) / _info->samplerate;
+ _info->readpos = (float)(info->currentsample - info->startsample) / _info->fmt.samplerate;
return 0;
}
static int
aac_seek (DB_fileinfo_t *_info, float t) {
- return aac_seek_sample (_info, t * _info->samplerate);
+ return aac_seek_sample (_info, t * _info->fmt.samplerate);
}
#ifdef USE_MP4FF
@@ -910,24 +1009,20 @@ aac_load_tags (DB_playItem_t *it, mp4ff_t *mp4) {
free (s);
}
}
- it->replaygain_track_gain = 0;
- it->replaygain_track_peak = 1;
- it->replaygain_album_gain = 0;
- it->replaygain_album_peak = 1;
if (mp4ff_meta_find_by_name(mp4, "replaygain_track_gain", &s)) {
- it->replaygain_track_gain = atof (s);
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKGAIN, atof (s));
free (s);
}
if (mp4ff_meta_find_by_name(mp4, "replaygain_track_peak", &s)) {
- it->replaygain_track_peak = atof (s);
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKPEAK, atof (s));
free (s);
}
if (mp4ff_meta_find_by_name(mp4, "replaygain_album_gain", &s)) {
- it->replaygain_album_gain = atof (s);
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMGAIN, atof (s));
free (s);
}
if (mp4ff_meta_find_by_name(mp4, "replaygain_album_peak", &s)) {
- it->replaygain_album_peak = atof (s);
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMPEAK, atof (s));
free (s);
}
deadbeef->pl_add_meta (it, "title", NULL);
@@ -938,12 +1033,12 @@ aac_load_tags (DB_playItem_t *it, mp4ff_t *mp4) {
int
aac_read_metadata (DB_playItem_t *it) {
#ifdef USE_MP4FF
- DB_FILE *fp = deadbeef->fopen (it->fname);
+ DB_FILE *fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!fp) {
return -1;
}
- if (fp->vfs->streaming) {
+ if (fp->vfs->is_streaming ()) {
deadbeef->fclose (fp);
return -1;
}
@@ -971,8 +1066,91 @@ aac_read_metadata (DB_playItem_t *it) {
}
deadbeef->fclose (fp);
#endif
+ return 0;
}
+#ifdef USE_MP4FF
+#if 0
+static uint32_t
+mp4ff_read_cb (void *user_data, void *buffer, uint32_t length) {
+// trace ("aac_fs_read %d\n", length);
+ FILE *fp = (FILE *)user_data;
+ return fread (buffer, 1, length, fp);
+}
+static uint32_t
+mp4ff_seek_cb (void *user_data, uint64_t position) {
+// trace ("aac_fs_seek\n");
+ FILE *fp = (FILE *)user_data;
+ return fseek (fp, position, SEEK_SET);
+}
+static uint32_t
+mp4ff_write_cb(void *user_data, void *buffer, uint32_t length) {
+ FILE *fp = (FILE *)user_data;
+ return fwrite (buffer, 1, length, fp);
+}
+
+static uint32_t
+mp4ff_truncate_cb(void *user_data)
+{
+ FILE *fp = (FILE *)user_data;
+ ftruncate(fileno(fp), ftello(fp));
+ return 0;
+}
+#endif
+#endif
+
+#ifdef USE_MP4FF
+#if 0
+static int
+aac_write_metadata (DB_playItem_t *it) {
+ mp4ff_metadata_t md;
+ memset (&md, 0, sizeof (md));
+ deadbeef->pl_lock ();
+ DB_metaInfo_t *meta = deadbeef->pl_get_metadata_head (it);
+
+ // find numtags 1st
+ while (meta) {
+ if (meta->key[0] != ':') {
+ md.count++;
+ }
+ meta = meta->next;
+ }
+
+ // fill tags
+ if (md.count) {
+ md.tags = malloc (sizeof (mp4ff_tag_t) * md.count);
+ int n = 0;
+ meta = deadbeef->pl_get_metadata_head (it);
+ while (meta) {
+ if (meta->key[0] != ':') {
+ md.tags[n].item = "";//(char *)meta->key;
+ md.tags[n].value = (char *)meta->value;
+ n++;
+ }
+ meta = meta->next;
+ }
+ }
+
+ mp4ff_callback_t f = {
+ .read = mp4ff_read_cb,
+ .write = mp4ff_write_cb,
+ .seek = mp4ff_seek_cb,
+ .truncate = mp4ff_truncate_cb,
+ };
+
+ FILE *fp = fopen (deadbeef->pl_find_meta (it, ":URI"), "w");
+ f.user_data = fp;
+
+ mp4ff_meta_update (&f, &md);
+ if (md.tags) {
+ free (md.tags);
+ }
+ deadbeef->pl_unlock ();
+ return 0;
+}
+#endif
+#endif
+
static DB_playItem_t *
aac_insert (DB_playItem_t *after, const char *fname) {
trace ("adding %s\n", fname);
@@ -986,11 +1164,12 @@ aac_insert (DB_playItem_t *after, const char *fname) {
float duration = -1;
int totalsamples = 0;
int samplerate = 0;
+ int channels = 0;
int mp4track = -1;
MP4FILE mp4 = NULL;
- if (fp->vfs->streaming) {
+ if (fp->vfs->is_streaming ()) {
trace ("streaming aac (%s)\n", fname);
ftype = plugin.filetypes[0];
}
@@ -1000,8 +1179,6 @@ aac_insert (DB_playItem_t *after, const char *fname) {
deadbeef->fseek (fp, skip, SEEK_SET);
}
- int channels;
-
// slowwww!
MP4FILE_CB cb = {
#ifdef USE_MP4FF
@@ -1032,12 +1209,10 @@ aac_insert (DB_playItem_t *after, const char *fname) {
}
}
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (fname);
- it->filetype = ftype;
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
+ deadbeef->pl_add_meta (it, ":FILETYPE", ftype);
deadbeef->pl_set_item_duration (it, duration);
-// trace ("duration: %f sec\n", duration);
+ trace ("duration: %f sec\n", duration);
// read tags
if (mp4) {
@@ -1083,9 +1258,22 @@ aac_insert (DB_playItem_t *after, const char *fname) {
deadbeef->pl_add_meta (it, "title", NULL);
}
+ int64_t fsize = deadbeef->fgetlength (fp);
+
deadbeef->fclose (fp);
if (duration > 0) {
+ char s[100];
+ snprintf (s, sizeof (s), "%lld", fsize);
+ deadbeef->pl_add_meta (it, ":FILE_SIZE", s);
+ deadbeef->pl_add_meta (it, ":BPS", "16");
+ snprintf (s, sizeof (s), "%d", channels);
+ deadbeef->pl_add_meta (it, ":CHANNELS", s);
+ snprintf (s, sizeof (s), "%d", samplerate);
+ deadbeef->pl_add_meta (it, ":SAMPLERATE", s);
+ int br = (int)roundf(fsize / duration * 8 / 1000);
+ snprintf (s, sizeof (s), "%d", br);
+ deadbeef->pl_add_meta (it, ":BITRATE", s);
// embedded cue
deadbeef->pl_lock ();
const char *cuesheet = deadbeef->pl_find_meta (it, "cuesheet");
@@ -1123,23 +1311,45 @@ static const char *filetypes[] = { "RAW AAC", "MP4 AAC", NULL };
// define plugin interface
static DB_decoder_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.id = "aac",
- .plugin.name = "AAC decoder based on FAAD2",
- .plugin.descr = "aac (m4a, mp4, ...) player",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.name = "AAC player",
+ .plugin.descr = "plays aac files, supports raw aac files, as well as mp4 container",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "Uses modified libmp4ff (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.open = aac_open,
.init = aac_init,
.free = aac_free,
- .read_int16 = aac_read_int16,
+ .read = aac_read,
.seek = aac_seek,
.seek_sample = aac_seek_sample,
.insert = aac_insert,
.read_metadata = aac_read_metadata,
+#ifdef USE_MP4FF
+ // mp4ff metadata writer doesn't work
+ // .write_metadata = aac_write_metadata,
+#else
+#endif
.exts = exts,
.filetypes = filetypes
};
diff --git a/plugins/aac/aac_parser.c b/plugins/aac/aac_parser.c
index 230dec9e..07c1ca6a 100644
--- a/plugins/aac/aac_parser.c
+++ b/plugins/aac/aac_parser.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -77,7 +77,7 @@ aac_sync(const uint8_t *buf, int *channels, int *sample_rate, int *bit_rate, int
//trace ("invalid channels\n");
return 0;
}
- trace ("channels %d\n", aac_channels[channel_conf]);
+ trace ("channels %d (#%d)\n", aac_channels[channel_conf], channel_conf);
int orig_copy = (buf[3] & 0x20) >> 5;
int home = (buf[3] & 0x10) >> 4;
int copyright_ident_bit = (buf[3] & 0x08) >> 3;
diff --git a/plugins/aac/aac_parser.h b/plugins/aac/aac_parser.h
index 53e7916d..7d3b886e 100644
--- a/plugins/aac/aac_parser.h
+++ b/plugins/aac/aac_parser.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
diff --git a/plugins/adplug/Makefile.am b/plugins/adplug/Makefile.am
index a75f38b5..393f2d59 100644
--- a/plugins/adplug/Makefile.am
+++ b/plugins/adplug/Makefile.am
@@ -5,11 +5,12 @@ adlibdir = $(libdir)/$(PACKAGE)
pkglib_LTLIBRARIES = adplug.la
AM_CFLAGS = $(CFLAGS) -std=c99 -I$(adplugpath)/adplug -I$(adplugpath)/libbinio
+adplug_la_LDFLAGS = -module -nostdlib -lsupc++
-AM_CPPFLAGS = $(CXXFLAGS) -Dstricmp=strcasecmp -DVERSION=\"2.1\" -I$(adplugpath)/adplug -I$(adplugpath)/libbinio
+AM_CPPFLAGS = $(CXXFLAGS) -Dstricmp=strcasecmp -DVERSION=\"2.1\" -I$(adplugpath)/adplug -I$(adplugpath)/libbinio -fno-exceptions -fno-rtti -nostdlib -fno-unwind-tables
-adplug_la_SOURCES = adplug-db.cpp\
- plugin.c\
+adplug_la_SOURCES = plugin.c\
+ adplug-db.cpp\
libbinio/binfile.h\
libbinio/binio.h\
libbinio/binstr.h\
@@ -134,5 +135,4 @@ adplug_la_SOURCES = adplug-db.cpp\
# adplug/database.cpp
# adplug/database.h
-adplug_la_LDFLAGS = -module
endif
diff --git a/plugins/adplug/adplug-db.cpp b/plugins/adplug/adplug-db.cpp
index 567d55ca..a25f3ffe 100644
--- a/plugins/adplug/adplug-db.cpp
+++ b/plugins/adplug/adplug-db.cpp
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -31,11 +31,22 @@
//#define trace(...) { fprintf (stderr, __VA_ARGS__); }
#define trace(fmt,...)
+int _Unwind_Resume_or_Rethrow;
+int _Unwind_RaiseException;
+int _Unwind_GetLanguageSpecificData;
+int _Unwind_Resume;
+int _Unwind_DeleteException;
+int _Unwind_GetTextRelBase;
+int _Unwind_SetIP;
+int _Unwind_GetDataRelBase;
+int _Unwind_GetRegionStart;
+int _Unwind_SetGR;
+int _Unwind_GetIPInfo;
+
extern "C" {
extern DB_decoder_t adplug_plugin;
-static DB_functions_t *deadbeef;
-
+DB_functions_t *deadbeef;
const char *adplug_exts[] = { "A2M", "ADL", "AMD", "BAM", "CFF", "CMF", "D00", "DFM", "DMO", "DRO", "DTM", "HSC", "HSP", "IMF", "KSM", "LAA", "LDS", "M", "MAD", "MKJ", "MSC", "MTK", "RAD", "RAW", "RIX", "ROL", "S3M", "SA2", "SAT", "SCI", "SNG", "XAD", "XMS", "XSM", "JBM", NULL };
@@ -53,7 +64,7 @@ typedef struct {
} adplug_info_t;
DB_fileinfo_t *
-adplug_open (void) {
+adplug_open (uint32_t hints) {
adplug_info_t *info = (adplug_info_t *)malloc (sizeof (adplug_info_t));
DB_fileinfo_t *_info = (DB_fileinfo_t *)info;
memset (info, 0, sizeof (adplug_info_t));
@@ -67,17 +78,17 @@ adplug_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
adplug_info_t *info = (adplug_info_t *)_info;
int samplerate = deadbeef->conf_get_int ("synth.samplerate", 44100);
- int bps = deadbeef->get_output ()->bitspersample ();
+ int bps = 16; // NOTE: there's no need to support 8bit input, because adplug simply downgrades 16bit signal to 8bits
int channels = 2;
- info->opl = new CEmuopl (samplerate, true, channels == 2);
+ info->opl = new CEmuopl (samplerate, bps == 16 ? true : false, channels == 2);
// opl->settype (Copl::TYPE_OPL2);
- info->decoder = CAdPlug::factory (it->fname, info->opl, CAdPlug::players);
+ info->decoder = CAdPlug::factory (deadbeef->pl_find_meta (it, ":URI"), info->opl, CAdPlug::players);
if (!info->decoder) {
- trace ("adplug: failed to open %s\n", it->fname);
+ trace ("adplug: failed to open %s\n", deadbeef->pl_find_meta (it, ":URI"));
return -1;
}
- info->subsong = it->tracknum;
+ info->subsong = deadbeef->pl_find_meta_int (it, ":TRACKNUM", 0);
info->decoder->rewind (info->subsong);
float dur = deadbeef->pl_get_item_duration (it);
info->totalsamples = dur * samplerate;
@@ -86,9 +97,10 @@ adplug_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
// fill in mandatory plugin fields
_info->plugin = &adplug_plugin;
- _info->bps = bps;
- _info->channels = channels;
- _info->samplerate = samplerate;
+ _info->fmt.bps = bps;
+ _info->fmt.channels = channels;
+ _info->fmt.samplerate = samplerate;
+ _info->fmt.channelmask = _info->fmt.channels == 1 ? DDB_SPEAKER_FRONT_LEFT : (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT);
_info->readpos = 0;
trace ("adplug_init ok (songlength=%d, duration=%f, totalsamples=%d)\n", info->decoder->songlength (info->subsong), deadbeef->pl_get_item_duration (it), info->totalsamples);
@@ -112,16 +124,16 @@ adplug_free (DB_fileinfo_t *_info) {
}
int
-adplug_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
+adplug_read (DB_fileinfo_t *_info, char *bytes, int size) {
// try decode `size' bytes
// return number of decoded bytes
// return 0 on EOF
adplug_info_t *info = (adplug_info_t *)_info;
bool playing = true;
int i;
- int sampsize = (_info->bps >> 3) * _info->channels;
+ int sampsize = (_info->fmt.bps / 8) * _info->fmt.channels;
- if (info->currentsample + size/4 >= info->totalsamples) {
+ if (info->currentsample + size/sampsize >= info->totalsamples) {
// clip
size = (info->totalsamples - info->currentsample) * sampsize;
trace ("adplug: clipped to %d\n", size);
@@ -139,11 +151,11 @@ adplug_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
{
while (info->toadd < 0)
{
- info->toadd += _info->samplerate;
+ info->toadd += _info->fmt.samplerate;
playing = info->decoder->update ();
// decoder->time_ms += 1000 / plr.p->getrefresh ();
}
- i = min (towrite, (long) (info->toadd / info->decoder->getrefresh () + 4) & ~3);
+ i = min (towrite, (long) (info->toadd / info->decoder->getrefresh () + sampsize) & ~(sampsize-1));
info->opl->update ((short *) sndbufpos, i);
sndbufpos += i * sampsize;
size -= i * sampsize;
@@ -152,7 +164,7 @@ adplug_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
info->toadd -= (long) (info->decoder->getrefresh () * i);
}
info->currentsample += size/4;
- _info->readpos = (float)info->currentsample / _info->samplerate;
+ _info->readpos = (float)info->currentsample / _info->fmt.samplerate;
return initsize-size;
}
@@ -172,7 +184,7 @@ adplug_seek_sample (DB_fileinfo_t *_info, int sample) {
while (info->currentsample < sample) {
info->decoder->update ();
- int framesize = _info->samplerate / info->decoder->getrefresh ();
+ int framesize = _info->fmt.samplerate / info->decoder->getrefresh ();
info->currentsample += framesize;
}
@@ -183,7 +195,7 @@ adplug_seek_sample (DB_fileinfo_t *_info, int sample) {
info->toadd = 0;
trace ("adplug: new position after seek: %d of %d\n", info->currentsample, info->totalsamples);
- _info->readpos = (float)info->currentsample / _info->samplerate;
+ _info->readpos = (float)info->currentsample / _info->fmt.samplerate;
return 0;
}
@@ -193,7 +205,7 @@ adplug_seek (DB_fileinfo_t *_info, float time) {
// seek to specified time in seconds
// return 0 on success
// return -1 on failure
- return adplug_seek_sample (_info, time * _info->samplerate);
+ return adplug_seek_sample (_info, time * _info->fmt.samplerate);
}
static const char *
@@ -252,11 +264,9 @@ adplug_insert (DB_playItem_t *after, const char *fname) {
if (dur < 0.1) {
continue;
}
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (adplug_plugin.plugin.id);
- it->fname = strdup (fname);
- it->filetype = adplug_get_extension (fname);
- it->tracknum = i;
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, adplug_plugin.plugin.id);
+ deadbeef->pl_add_meta (it, ":FILETYPE", adplug_get_extension (fname));
+ deadbeef->pl_set_meta_int (it, ":TRACKNUM", i);
deadbeef->pl_set_item_duration (it, dur);
#if 0
// add metainfo
diff --git a/plugins/adplug/libbinio/binfile.cpp b/plugins/adplug/libbinio/binfile.cpp
index 336f1b3b..a20315ac 100644
--- a/plugins/adplug/libbinio/binfile.cpp
+++ b/plugins/adplug/libbinio/binfile.cpp
@@ -22,6 +22,8 @@
#include "binfile.h"
+extern DB_functions_t *deadbeef;
+
/***** binfbase *****/
binfbase::binfbase()
@@ -37,7 +39,8 @@ binfbase::~binfbase()
void binfbase::close()
{
if(f != NULL) {
- if(fclose(f) == EOF) err |= Fatal; else f = NULL;
+ deadbeef->fclose(f);
+ f = NULL;
} else
err |= NotOpen;
}
@@ -49,9 +52,9 @@ void binfbase::seek(long pos, Offset offs)
if(f == NULL) { err |= NotOpen; return; }
switch(offs) {
- case Set: error = fseek(f, pos, SEEK_SET); break;
- case Add: error = fseek(f, pos, SEEK_CUR); break;
- case End: error = fseek(f, pos, SEEK_END); break;
+ case Set: error = deadbeef->fseek(f, pos, SEEK_SET); break;
+ case Add: error = deadbeef->fseek(f, pos, SEEK_CUR); break;
+ case End: error = deadbeef->fseek(f, pos, SEEK_END); break;
}
if(error == -1) err |= Fatal;
@@ -63,7 +66,7 @@ long binfbase::pos()
if(f == NULL) { err |= NotOpen; return 0; }
- pos = ftell(f);
+ pos = deadbeef->ftell(f);
if(pos == -1) {
err |= Fatal;
@@ -96,7 +99,7 @@ binifstream::~binifstream()
void binifstream::open(const char *filename, const Mode mode)
{
- f = fopen(filename, "rb");
+ f = deadbeef->fopen(filename);
if(f == NULL)
switch(errno) {
@@ -118,8 +121,9 @@ binifstream::Byte binifstream::getByte()
int read;
if(f != NULL) {
- read = fgetc(f);
- if(read == EOF) err |= Eof;
+ if (1 != deadbeef->fread (&read, 1, 1, f)) {
+ err |= Eof;
+ }
return (Byte)read;
} else {
err |= NotOpen;
@@ -151,6 +155,7 @@ binofstream::~binofstream()
void binofstream::open(const char *filename, const Mode mode)
{
+#if 0
const char *modestr = "wb";
// Check if append mode is desired
@@ -168,6 +173,7 @@ void binofstream::open(const char *filename, const Mode mode)
case ENOENT: err |= NotFound; break;
default: err |= NotOpen; break;
}
+#endif
}
#if BINIO_ENABLE_STRING
@@ -179,10 +185,12 @@ void binofstream::open(const std::string &filename, const Mode mode)
void binofstream::putByte(Byte b)
{
+#if 0
if(f == NULL) { err |= NotOpen; return; }
if(fputc(b, f) == EOF)
err |= Fatal;
+#endif
}
/***** binfstream *****/
@@ -220,11 +228,11 @@ void binfstream::open(const char *filename, const Mode mode)
if(mode & Append) // Create & append
modestr = "a+b";
- f = fopen(filename, modestr);
+ f = deadbeef->fopen(filename);
// NoCreate & append (emulated -- not possible with standard C fopen())
if(f != NULL && (mode & Append) && (mode & NoCreate))
- ferror = fseek(f, 0, SEEK_END);
+ ferror = deadbeef->fseek(f, 0, SEEK_END);
if(f == NULL || ferror == -1) {
switch(errno) {
diff --git a/plugins/adplug/libbinio/binfile.h b/plugins/adplug/libbinio/binfile.h
index ad24baee..013e5777 100644
--- a/plugins/adplug/libbinio/binfile.h
+++ b/plugins/adplug/libbinio/binfile.h
@@ -24,6 +24,8 @@
#include "binio.h"
+#include "../../../deadbeef.h"
+
class binfbase: virtual public binio
{
public:
@@ -47,7 +49,7 @@ public:
virtual long pos();
protected:
- FILE *f;
+ DB_FILE *f;
};
class binifstream: public binistream, virtual public binfbase
diff --git a/plugins/adplug/plugin.c b/plugins/adplug/plugin.c
index c4e8e04c..0b53da31 100644
--- a/plugins/adplug/plugin.c
+++ b/plugins/adplug/plugin.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -26,13 +26,13 @@ extern const char *adplug_exts[];
extern const char *adplug_filetypes[];
DB_fileinfo_t *
-adplug_open (void);
+adplug_open (uint32_t hints);
int
adplug_init (DB_fileinfo_t *_info, DB_playItem_t *it);
void
adplug_free (DB_fileinfo_t *);
int
-adplug_read_int16 (DB_fileinfo_t *, char *bytes, int size);
+adplug_read (DB_fileinfo_t *, char *bytes, int size);
int
adplug_seek_sample (DB_fileinfo_t *, int sample);
int
@@ -47,21 +47,40 @@ adplug_stop (void);
// define plugin interface
DB_decoder_t adplug_plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.id = "adplug",
.plugin.name = "Adplug player",
.plugin.descr = "Adplug player (ADLIB OPL2/OPL3 emulator)",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "Uses modified AdPlug library\n"
+ "Copyright (C) 1999 - 2010 Simon Peter, et al.\n"
+ "http://adplug.sourceforge.net/\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = adplug_start,
.plugin.stop = adplug_stop,
.open = adplug_open,
.init = adplug_init,
.free = adplug_free,
- .read_int16 = adplug_read_int16,
+ .read = adplug_read,
.seek = adplug_seek,
.seek_sample = adplug_seek_sample,
.insert = adplug_insert,
diff --git a/plugins/alsa/alsa.c b/plugins/alsa/alsa.c
index 96d7645b..809cb7ed 100644
--- a/plugins/alsa/alsa.c
+++ b/plugins/alsa/alsa.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -23,8 +23,8 @@
#include "../../deadbeef.h"
#include "../../config.h"
-//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
-#define trace(fmt,...)
+#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+//#define trace(fmt,...)
#define min(x,y) ((x)<(y)?(x):(y))
@@ -41,8 +41,7 @@ DB_functions_t *deadbeef;
static snd_pcm_t *audio;
static int alsa_terminate;
-static int requested_rate = -1;
-static int alsa_rate = 44100;
+static ddb_waveformat_t requested_fmt;
static int state; // one of output_state_t
static uintptr_t mutex;
static intptr_t alsa_tid;
@@ -53,7 +52,6 @@ static snd_pcm_uframes_t period_size;
static snd_pcm_uframes_t req_buffer_size;
static snd_pcm_uframes_t req_period_size;
-static int conf_alsa_resample = 0;
static char conf_alsa_soundcard[100] = "default";
//static snd_async_handler_t *pcm_callback;
@@ -91,7 +89,7 @@ static int
palsa_free (void);
static int
-palsa_change_rate (int rate);
+palsa_setformat (ddb_waveformat_t *fmt);
static int
palsa_play (void);
@@ -106,12 +104,6 @@ static int
palsa_unpause (void);
static int
-palsa_get_rate (void);
-
-static int
-palsa_get_bps (void);
-
-static int
palsa_get_channels (void);
static int
@@ -121,11 +113,21 @@ static void
palsa_enum_soundcards (void (*callback)(const char *name, const char *desc, void*), void *userdata);
static int
-palsa_set_hw_params (int samplerate) {
+palsa_set_hw_params (ddb_waveformat_t *fmt) {
snd_pcm_hw_params_t *hw_params = NULL;
-// int alsa_resample = conf_get_int ("alsa.resample", 0);
int err = 0;
+ memcpy (&plugin.fmt, fmt, sizeof (ddb_waveformat_t));
+ if (!plugin.fmt.channels) {
+ // generic format
+ plugin.fmt.bps = 16;
+ plugin.fmt.is_float = 0;
+ plugin.fmt.channels = 2;
+ plugin.fmt.samplerate = 44100;
+ plugin.fmt.channelmask = 3;
+ }
+retry:
+
if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",
snd_strerror (err));
@@ -144,25 +146,87 @@ palsa_set_hw_params (int samplerate) {
goto error;
}
- snd_pcm_format_t fmt;
+ snd_pcm_format_t sample_fmt;
+
+ switch (plugin.fmt.bps) {
+ case 8:
+ sample_fmt = SND_PCM_FORMAT_S8;
+ break;
+ case 16:
#if WORDS_BIGENDIAN
- fmt = SND_PCM_FORMAT_S16_BE;
+ sample_fmt = SND_PCM_FORMAT_S16_BE;
#else
- fmt = SND_PCM_FORMAT_S16_LE;
+ sample_fmt = SND_PCM_FORMAT_S16_LE;
#endif
- if ((err = snd_pcm_hw_params_set_format (audio, hw_params, fmt)) < 0) {
- fprintf (stderr, "cannot set sample format (%s)\n",
- snd_strerror (err));
- goto error;
+ break;
+ case 24:
+#if WORDS_BIGENDIAN
+ sample_fmt = SND_PCM_FORMAT_S24_3BE;
+#else
+ sample_fmt = SND_PCM_FORMAT_S24_3LE;
+#endif
+ break;
+ case 32:
+ if (plugin.fmt.is_float) {
+#if WORDS_BIGENDIAN
+ sample_fmt = SND_PCM_FORMAT_FLOAT_BE;
+#else
+ sample_fmt = SND_PCM_FORMAT_FLOAT_LE;
+#endif
+ }
+ else {
+#if WORDS_BIGENDIAN
+ sample_fmt = SND_PCM_FORMAT_S32_BE;
+#else
+ sample_fmt = SND_PCM_FORMAT_S32_LE;
+#endif
+ }
+ break;
+ };
+
+ if ((err = snd_pcm_hw_params_set_format (audio, hw_params, sample_fmt)) < 0) {
+ fprintf (stderr, "cannot set sample format (%s), trying all supported formats\n", snd_strerror (err));
+
+ int fmt_cnt[] = { 16, 24, 32, 32, 8 };
+#if WORDS_BIGENDIAN
+ int fmt[] = { SND_PCM_FORMAT_S16_BE, SND_PCM_FORMAT_S24_3BE, SND_PCM_FORMAT_S32_BE, SND_PCM_FORMAT_FLOAT_BE, SND_PCM_FORMAT_S8, -1 };
+#else
+ int fmt[] = { SND_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S24_3LE, SND_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_FLOAT_LE, SND_PCM_FORMAT_S8, -1 };
+#endif
+
+ // 1st try formats with higher bps
+ int i = 0;
+ for (i = 0; fmt[i] != -1; i++) {
+ if (fmt[i] != sample_fmt && fmt_cnt[i] > plugin.fmt.bps) {
+ if (snd_pcm_hw_params_set_format (audio, hw_params, fmt[i]) >= 0) {
+ break;
+ }
+ }
+ }
+ if (fmt[i] == -1) {
+ // next try formats with lower bps
+ i = 0;
+ for (i = 0; fmt[i] != -1; i++) {
+ if (fmt[i] != sample_fmt && fmt_cnt[i] < plugin.fmt.bps) {
+ if (snd_pcm_hw_params_set_format (audio, hw_params, fmt[i]) >= 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (fmt[i] == -1) {
+ goto error;
+ }
}
- snd_pcm_hw_params_get_format (hw_params, &fmt);
- trace ("chosen sample format: %04Xh\n", (int)fmt);
+ snd_pcm_hw_params_get_format (hw_params, &sample_fmt);
+ trace ("chosen sample format: %04Xh\n", (int)sample_fmt);
- int val = samplerate;
+ int val = plugin.fmt.samplerate;
int ret = 0;
- if ((err = snd_pcm_hw_params_set_rate_resample (audio, hw_params, conf_alsa_resample)) < 0) {
+ if ((err = snd_pcm_hw_params_set_rate_resample (audio, hw_params, 1)) < 0) {
fprintf (stderr, "cannot setup resampling (%s)\n",
snd_strerror (err));
goto error;
@@ -173,10 +237,10 @@ palsa_set_hw_params (int samplerate) {
snd_strerror (err));
goto error;
}
- alsa_rate = val;
- trace ("chosen samplerate: %d Hz\n", alsa_rate);
+ plugin.fmt.samplerate = val;
+ trace ("chosen samplerate: %d Hz\n", val);
- if ((err = snd_pcm_hw_params_set_channels (audio, hw_params, 2)) < 0) {
+ if ((err = snd_pcm_hw_params_set_channels (audio, hw_params, plugin.fmt.channels)) < 0) {
fprintf (stderr, "cannot set channel count (%s)\n",
snd_strerror (err));
goto error;
@@ -201,8 +265,70 @@ palsa_set_hw_params (int samplerate) {
fprintf (stderr, "cannot set parameters (%s)\n",
snd_strerror (err));
goto error;
+
+// if (plugin.fmt.channels > 2 && plugin.fmt.samplerate >= 96000) {
+// plugin.fmt.samplerate = 48000;
+// fprintf (stderr, "falling back to 48000KHz\n");
+// goto retry;
+// }
+ }
+
+ plugin.fmt.is_float = 0;
+ switch (sample_fmt) {
+ case SND_PCM_FORMAT_S8:
+ plugin.fmt.bps = 8;
+ break;
+ case SND_PCM_FORMAT_S16_BE:
+ case SND_PCM_FORMAT_S16_LE:
+ plugin.fmt.bps = 16;
+ break;
+ case SND_PCM_FORMAT_S24_3BE:
+ case SND_PCM_FORMAT_S24_3LE:
+ plugin.fmt.bps = 24;
+ break;
+ case SND_PCM_FORMAT_S32_BE:
+ case SND_PCM_FORMAT_S32_LE:
+ plugin.fmt.bps = 32;
+ break;
+ case SND_PCM_FORMAT_FLOAT_LE:
+ case SND_PCM_FORMAT_FLOAT_BE:
+ plugin.fmt.bps = 32;
+ plugin.fmt.is_float = 1;
+ break;
+ }
+
+ trace ("chosen bps: %d (%s)\n", plugin.fmt.bps, plugin.fmt.is_float ? "float" : "int");
+
+ plugin.fmt.channels = nchan;
+ plugin.fmt.channelmask = 0;
+ if (nchan == 1) {
+ plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT;
+ }
+ if (nchan == 2) {
+ plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT;
+ }
+ if (nchan == 3) {
+ plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_LOW_FREQUENCY;
+ }
+ if (nchan == 4) {
+ plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_BACK_LEFT | DDB_SPEAKER_BACK_RIGHT;
+ }
+ if (nchan == 5) {
+ plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_BACK_LEFT | DDB_SPEAKER_BACK_RIGHT | DDB_SPEAKER_FRONT_CENTER;
+ }
+ if (nchan == 6) {
+ plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_BACK_LEFT | DDB_SPEAKER_BACK_RIGHT | DDB_SPEAKER_FRONT_CENTER | DDB_SPEAKER_LOW_FREQUENCY;
+ }
+ if (nchan == 7) {
+ plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_BACK_LEFT | DDB_SPEAKER_BACK_RIGHT | DDB_SPEAKER_FRONT_CENTER | DDB_SPEAKER_SIDE_LEFT | DDB_SPEAKER_SIDE_RIGHT;
+ }
+ if (nchan == 8) {
+ plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_BACK_LEFT | DDB_SPEAKER_BACK_RIGHT | DDB_SPEAKER_FRONT_CENTER | DDB_SPEAKER_SIDE_LEFT | DDB_SPEAKER_SIDE_RIGHT | DDB_SPEAKER_LOW_FREQUENCY;
}
error:
+ if (err < 0) {
+ memset (&plugin.fmt, 0, sizeof (ddb_waveformat_t));
+ }
if (hw_params) {
snd_pcm_hw_params_free (hw_params);
}
@@ -216,10 +342,8 @@ palsa_init (void) {
mutex = 0;
// get and cache conf variables
- strcpy (conf_alsa_soundcard, deadbeef->conf_get_str ("alsa_soundcard", "default"));
- conf_alsa_resample = deadbeef->conf_get_int ("alsa.resample", 0);
+ deadbeef->conf_get_str ("alsa_soundcard", "default", conf_alsa_soundcard, sizeof (conf_alsa_soundcard));
trace ("alsa_soundcard: %s\n", conf_alsa_soundcard);
- trace ("alsa.resample: %d\n", conf_alsa_resample);
snd_pcm_sw_params_t *sw_params = NULL;
state = OUTPUT_STATE_STOPPED;
@@ -232,11 +356,11 @@ palsa_init (void) {
mutex = deadbeef->mutex_create ();
- if (requested_rate != -1) {
- alsa_rate = requested_rate;
+ if (requested_fmt.samplerate != 0) {
+ memcpy (&plugin.fmt, &requested_fmt, sizeof (ddb_waveformat_t));
}
- if (palsa_set_hw_params (alsa_rate) < 0) {
+ if (palsa_set_hw_params (&plugin.fmt) < 0) {
goto open_error;
}
@@ -309,27 +433,61 @@ open_error:
}
int
-palsa_change_rate (int rate) {
- trace ("palsa_change_rate: %d\n", rate);
- requested_rate = rate;
+palsa_setformat (ddb_waveformat_t *fmt) {
+ memcpy (&requested_fmt, fmt, sizeof (ddb_waveformat_t));
+ trace ("palsa_setformat %dbit %s %dch %dHz channelmask=%X\n", fmt->bps, fmt->is_float ? "float" : "int", fmt->channels, fmt->samplerate, fmt->channelmask);
if (!audio) {
- return alsa_rate;
+ return -1;
}
- if (rate == alsa_rate) {
- trace ("palsa_change_rate %d: ignored\n", rate);
- return rate;
+ if (!memcmp (fmt, &plugin.fmt, sizeof (ddb_waveformat_t))) {
+ trace ("palsa_setformat ignored\n");
+ return 0;
}
- state = OUTPUT_STATE_STOPPED;
+#if 0
+ else {
+ trace ("switching format:\n"
+ "bps %d -> %d\n"
+ "is_float %d -> %d\n"
+ "is_multichannel %d -> %d\n"
+ "channels %d -> %d\n"
+ "samplerate %d -> %d\n"
+ "channelmask %d -> %d\n"
+ , fmt->bps, plugin.fmt.bps
+ , fmt->is_float, plugin.fmt.is_float
+ , fmt->is_multichannel, plugin.fmt.is_multichannel
+ , fmt->channels, plugin.fmt.channels
+ , fmt->samplerate, plugin.fmt.samplerate
+ , fmt->channelmask, plugin.fmt.channelmask
+ );
+ }
+#endif
LOCK;
+ int s = state;
+ state = OUTPUT_STATE_STOPPED;
snd_pcm_drop (audio);
- int ret = palsa_set_hw_params (rate);
+ int ret = palsa_set_hw_params (fmt);
UNLOCK;
if (ret < 0) {
- trace ("palsa_change_rate: impossible to set samplerate to %d\n", rate);
- return alsa_rate;
+ trace ("palsa_change_rate: impossible to set requested format\n");
+ return -1;
}
- trace ("chosen samplerate: %d\n", alsa_rate);
- return alsa_rate;
+ trace ("new format %dbit %s %dch %dHz channelmask=%X\n", plugin.fmt.bps, plugin.fmt.is_float ? "float" : "int", plugin.fmt.channels, plugin.fmt.samplerate, plugin.fmt.channelmask);
+
+ switch (s) {
+ case OUTPUT_STATE_STOPPED:
+ return palsa_stop ();
+ case OUTPUT_STATE_PLAYING:
+ return palsa_play ();
+ case OUTPUT_STATE_PAUSED:
+ if (0 != palsa_play ()) {
+ return -1;
+ }
+ if (0 != palsa_pause ()) {
+ return -1;
+ }
+ break;
+ }
+ return 0;
}
int
@@ -453,33 +611,6 @@ palsa_unpause (void) {
return 0;
}
-int
-palsa_get_rate (void) {
- if (!audio) {
- palsa_init ();
- }
- return alsa_rate;
-}
-
-int
-palsa_get_bps (void) {
- return 16;
-}
-
-int
-palsa_get_channels (void) {
- return 2;
-}
-
-static int
-palsa_get_endianness (void) {
-#if WORDS_BIGENDIAN
- return 1;
-#else
- return 0;
-#endif
-}
-
static void
palsa_thread (void *context) {
prctl (PR_SET_NAME, "deadbeef-alsa", 0, 0, 0, 0);
@@ -500,10 +631,10 @@ palsa_thread (void *context) {
break;
}
err = 0;
- char buf[period_size * 4];
- int bytes_to_write = palsa_callback (buf, period_size * 4);
+ char buf[period_size * (plugin.fmt.bps>>3) * plugin.fmt.channels];
+ int bytes_to_write = palsa_callback (buf, period_size * (plugin.fmt.bps>>3) * plugin.fmt.channels);
- if ( bytes_to_write >= 4 ) {
+ if (bytes_to_write >= (plugin.fmt.bps>>3) * plugin.fmt.channels) {
err = snd_pcm_writei (audio, buf, snd_pcm_bytes_to_frames(audio, bytes_to_write));
}
else {
@@ -541,68 +672,29 @@ palsa_thread (void *context) {
frames_to_deliver = snd_pcm_avail_update (audio);
}
UNLOCK;
- usleep (period_size * 1000000 / alsa_rate / 2);
+ usleep (period_size * 1000000 / plugin.fmt.samplerate / 2);
}
}
static int
palsa_callback (char *stream, int len) {
- int bytesread = deadbeef->streamer_read (stream, len);
-
-// FIXME: move volume control to streamer_read for copy optimization
-#if 0
- int16_t vol[4];
- vol[0] = volume_get_amp () * 255; // that will be extra 8 bits
- // pack 4 times
- vol[1] = vol[2] = vol[3] = vol[0];
-
- // apply volume with mmx
- __asm__ volatile(
- " mov %0, %%ecx\n\t"
- " shr $4, %%ecx\n\t"
- " mov %1, %%eax\n\t"
- " movq %2, %mm1\n\t"
- "1:\n\t"
- " movq [%%eax], %mm0\n\t"
- " movq %mm0, %mm2\n\t"
- " movq %mm0, %mm3\n\t"
- " pmullw %mm1, %mm2\n\t"
- " pmulhw %mm1, %mm3\n\t"
- " psrlw $8, %mm2\n\t" // discard lowest 8 bits
- " psllw $8, %mm3\n\t" // shift left 8 lsbs of hiwords
- " por %mm3, %mm2\n\t" // OR them together
- " movq %mm3, [%%eax]\n\t" // load back to memory
- " add $8, %%eax\n\t"
- " dec %%ecx\n\t"
- " jnz 1b\n\t"
- :
- : "r"(len), "r"(stream), "r"(vol)
- : "%ecx", "%eax"
- );
-
-#else
- int16_t ivolume = deadbeef->volume_get_amp () * 1000;
- for (int i = 0; i < bytesread/2; i++) {
- ((int16_t*)stream)[i] = (int16_t)(((int32_t)(((int16_t*)stream)[i])) * ivolume / 1000);
- }
-#endif
- return bytesread;
+ return deadbeef->streamer_read (stream, len);
}
static int
palsa_configchanged (DB_event_t *ev, uintptr_t data) {
- int alsa_resample = deadbeef->conf_get_int ("alsa.resample", 0);
- const char *alsa_soundcard = deadbeef->conf_get_str ("alsa_soundcard", "default");
+ deadbeef->conf_lock ();
+ const char *alsa_soundcard = deadbeef->conf_get_str_fast ("alsa_soundcard", "default");
int buffer = deadbeef->conf_get_int ("alsa.buffer", DEFAULT_BUFFER_SIZE);
int period = deadbeef->conf_get_int ("alsa.period", DEFAULT_PERIOD_SIZE);
if (audio &&
- (alsa_resample != conf_alsa_resample
- || strcmp (alsa_soundcard, conf_alsa_soundcard)
+ (strcmp (alsa_soundcard, conf_alsa_soundcard)
|| buffer != req_buffer_size
|| period != req_period_size)) {
trace ("alsa: config option changed, restarting\n");
deadbeef->sendmessage (M_REINIT_SOUND, 0, 0, 0);
}
+ deadbeef->conf_unlock ();
return 0;
}
@@ -659,7 +751,6 @@ alsa_load (DB_functions_t *api) {
}
static const char settings_dlg[] =
- "property \"Use ALSA resampling\" checkbox alsa.resample 0;\n"
"property \"Release device while stopped\" checkbox alsa.freeonstop 0;\n"
"property \"Preferred buffer size\" entry alsa.buffer " DEFAULT_BUFFER_SIZE_STR ";\n"
"property \"Preferred period size\" entry alsa.period " DEFAULT_PERIOD_SIZE_STR ";\n"
@@ -668,29 +759,40 @@ static const char settings_dlg[] =
// define plugin interface
static DB_output_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
- .plugin.nostop = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_OUTPUT,
+ .plugin.id = "alsa",
.plugin.name = "ALSA output plugin",
.plugin.descr = "plays sound through linux standard alsa library",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = alsa_start,
.plugin.stop = alsa_stop,
.plugin.configdialog = settings_dlg,
.init = palsa_init,
.free = palsa_free,
- .change_rate = palsa_change_rate,
+ .setformat = palsa_setformat,
.play = palsa_play,
.stop = palsa_stop,
.pause = palsa_pause,
.unpause = palsa_unpause,
.state = palsa_get_state,
- .samplerate = palsa_get_rate,
- .bitspersample = palsa_get_bps,
- .channels = palsa_get_channels,
- .endianness = palsa_get_endianness,
.enum_soundcards = palsa_enum_soundcards,
};
diff --git a/plugins/ao/Makefile b/plugins/ao/Makefile
new file mode 100644
index 00000000..5e0b3f3f
--- /dev/null
+++ b/plugins/ao/Makefile
@@ -0,0 +1,32 @@
+OUT=ao.so
+
+CC=gcc
+
+ZLIB_LIBS=-lz
+
+CFLAGS?=-O2 -fomit-frame-pointer
+CFLAGS+=-Wall -fPIC -DPATH_MAX=1024 -DHAS_PSXCPU=1 -I../.. -I./ -Ieng_ssf -Ieng_qsf -Ieng_dsf
+
+LDFLAGS+=-module -shared $(ZLIB_LIBS) -lm
+
+SOURCES=plugin.c main.c corlett.c\
+eng_dsf/eng_dsf.c eng_dsf/dc_hw.c eng_dsf/aica.c eng_dsf/aicadsp.c eng_dsf/arm7.c eng_dsf/arm7i.c\
+eng_ssf/m68kcpu.c eng_ssf/m68kopac.c eng_ssf/m68kopdm.c eng_ssf/m68kopnz.c eng_ssf/m68kops.c \
+eng_ssf/scsp.c eng_ssf/scspdsp.c eng_ssf/sat_hw.c eng_ssf/eng_ssf.c\
+eng_qsf/eng_qsf.c eng_qsf/kabuki.c eng_qsf/qsound.c eng_qsf/z80.c eng_qsf/z80dasm.c\
+eng_psf/eng_psf.c eng_psf/psx.c eng_psf/psx_hw.c eng_psf/peops/spu.c \
+eng_psf/eng_psf2.c eng_psf/peops2/spu2.c eng_psf/peops2/dma2.c eng_psf/peops2/registers2.c\
+eng_psf/eng_spu.c
+
+OBJECTS=$(SOURCES:.c=.o)
+
+all: $(SOURCES) $(OUT)
+
+$(OUT): $(OBJECTS)
+ $(CC) $(LDFLAGS) $(OBJECTS) -o $@
+
+.c.o:
+ $(CC) $(CFLAGS) $< -c -o $@
+
+clean:
+ rm $(OBJECTS) $(OUT)
diff --git a/plugins/ao/Makefile.am b/plugins/ao/Makefile.am
deleted file mode 100644
index 39ccd749..00000000
--- a/plugins/ao/Makefile.am
+++ /dev/null
@@ -1,27 +0,0 @@
-if HAVE_AO
-aodir = $(libdir)/$(PACKAGE)
-pkglib_LTLIBRARIES = ao.la
-ao_la_SOURCES = plugin.c main.c corlett.c\
-eng_dsf/eng_dsf.c eng_dsf/dc_hw.c eng_dsf/aica.c eng_dsf/aicadsp.c eng_dsf/arm7.c eng_dsf/arm7i.c\
-eng_ssf/m68kcpu.c eng_ssf/m68kopac.c eng_ssf/m68kopdm.c eng_ssf/m68kopnz.c eng_ssf/m68kops.c \
-eng_ssf/scsp.c eng_ssf/scspdsp.c eng_ssf/sat_hw.c eng_ssf/eng_ssf.c\
-eng_qsf/eng_qsf.c eng_qsf/kabuki.c eng_qsf/qsound.c eng_qsf/z80.c eng_qsf/z80dasm.c\
-eng_psf/eng_psf.c eng_psf/psx.c eng_psf/psx_hw.c eng_psf/peops/spu.c \
-eng_psf/eng_psf2.c eng_psf/peops2/spu2.c eng_psf/peops2/dma2.c eng_psf/peops2/registers2.c\
-eng_psf/eng_spu.c\
-ao.h corlett.h cpuintrf.h eng_protos.h mem.h osd_cpu.h\
-eng_dsf/aicadsp.h eng_dsf/aica.h eng_dsf/arm7.h eng_dsf/arm7i.h eng_dsf/arm7thumb.h eng_dsf/dc_hw.h\
-eng_ssf/m68kconf.h eng_ssf/m68kcpu.h eng_ssf/m68k.h eng_ssf/m68kmame.h eng_ssf/m68kops.h eng_ssf/sat_hw.h eng_ssf/scspdsp.h eng_ssf/scsp.h \
-eng_qsf/qsound.h eng_qsf/z80dasm.h eng_qsf/z80.h\
-eng_psf/cpuintrf.h eng_psf/mamemem.h eng_psf/psx.h\
-eng_psf/peops/adsr.h eng_psf/peops/dma.h eng_psf/peops/externals.h eng_psf/peops/gauss_i.h eng_psf/peops/registers.h eng_psf/peops/regs.h eng_psf/peops/spu.h eng_psf/peops/stdafx.h\
-eng_psf/peops2/adsr.h eng_psf/peops2/dma.h eng_psf/peops2/externals.h eng_psf/peops2/gauss_i.h eng_psf/peops2/psemuxa.h eng_psf/peops2/registers.h eng_psf/peops2/regs.h eng_psf/peops2/reverb.h eng_psf/peops2/spu.h eng_psf/peops2/stdafx.h
-
-ao_la_LDFLAGS = -module -fPIC
-
-EXTRA_DIST=eng_psf/peops/reverb.c eng_psf/peops/adsr.c eng_psf/peops/registers.c eng_psf/peops/dma.c eng_psf/peops2/spu2.c eng_psf/peops2/reverb2.c eng_psf/peops2/adsr2.c eng_dsf/arm7memil.c eng_dsf/aicalfo.c eng_ssf/scsplfo.c
-
-ao_la_LIBADD = $(LDADD)
-AM_CFLAGS = $(CFLAGS) -Wall -DPATH_MAX=1024 -DHAS_PSXCPU=1 -I.. -Ieng_ssf -Ieng_qsf -Ieng_dsf -lm $(ZLIB_LIBS)
-endif
-
diff --git a/plugins/ao/eng_ssf/m68kcpu.c b/plugins/ao/eng_ssf/m68kcpu.c
index 9624ea5c..f9b442bc 100644
--- a/plugins/ao/eng_ssf/m68kcpu.c
+++ b/plugins/ao/eng_ssf/m68kcpu.c
@@ -37,8 +37,6 @@ static const char* copyright_notice =
#include "m68kops.h"
#include "m68kcpu.h"
-#pragma GCC optimize("O0")
-
/* ======================================================================== */
/* ================================= DATA ================================= */
/* ======================================================================== */
diff --git a/plugins/ao/plugin.c b/plugins/ao/plugin.c
index 2e29c4e0..02f70ef2 100644
--- a/plugins/ao/plugin.c
+++ b/plugins/ao/plugin.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -48,7 +48,7 @@ typedef struct {
} aoplug_info_t;
static DB_fileinfo_t *
-aoplug_open (void) {
+aoplug_open (uint32_t hints) {
DB_fileinfo_t *_info = malloc (sizeof (aoplug_info_t));
aoplug_info_t *info = (aoplug_info_t *)_info;
memset (info, 0, sizeof (aoplug_info_t));
@@ -59,16 +59,17 @@ static int
aoplug_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
aoplug_info_t *info = (aoplug_info_t *)_info;
- _info->bps = 16;
- _info->channels = 2;
- _info->samplerate = 44100;
+ _info->fmt.bps = 16;
+ _info->fmt.channels = 2;
+ _info->fmt.samplerate = deadbeef->conf_get_int ("synth.samplerate", 44100);
+ _info->fmt.channelmask = _info->fmt.channels == 1 ? DDB_SPEAKER_FRONT_LEFT : (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT);
_info->readpos = 0;
_info->plugin = &plugin;
info->duration = deadbeef->pl_get_item_duration (it);
- DB_FILE *file = deadbeef->fopen (it->fname);
+ DB_FILE *file = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!file) {
- trace ("psf: failed to fopen %s\n", it->fname);
+ trace ("psf: failed to fopen %s\n", deadbeef->pl_find_meta (it, ":URI"));
return -1;
}
@@ -81,7 +82,7 @@ aoplug_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
}
if (deadbeef->fread(info->filebuffer, 1, info->filesize, file) != info->filesize) {
- fprintf(stderr, "psf: file read error: %s\n", it->fname);
+ fprintf(stderr, "psf: file read error: %s\n", deadbeef->pl_find_meta (it, ":URI"));
deadbeef->fclose (file);
return -1;
}
@@ -93,7 +94,7 @@ aoplug_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
return -1;
}
- info->decoder = ao_start (info->type, it->fname, (uint8 *)info->filebuffer, info->filesize);
+ info->decoder = ao_start (info->type, deadbeef->pl_find_meta (it, ":URI"), (uint8 *)info->filebuffer, info->filesize);
if (!info->decoder) {
fprintf (stderr, "psf: ao_start failed\n");
return -1;
@@ -116,11 +117,11 @@ aoplug_free (DB_fileinfo_t *_info) {
}
static int
-aoplug_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
+aoplug_read (DB_fileinfo_t *_info, char *bytes, int size) {
aoplug_info_t *info = (aoplug_info_t *)_info;
// printf ("aoplug_read_int16 %d samples, curr %d, end %d\n", size/4, info->currentsample, (int)(info->duration * _info->samplerate));
- if (info->currentsample >= info->duration * _info->samplerate) {
+ if (info->currentsample >= info->duration * _info->fmt.samplerate) {
return 0;
}
@@ -152,7 +153,8 @@ aoplug_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
info->remaining = 735;
}
}
- info->currentsample += (initsize-size) / (_info->channels * _info->bps/8);
+ info->currentsample += (initsize-size) / (_info->fmt.channels * _info->fmt.bps/8);
+ _info->readpos = (float)info->currentsample / _info->fmt.samplerate;
return initsize-size;
}
@@ -168,13 +170,13 @@ aoplug_seek_sample (DB_fileinfo_t *_info, int sample) {
info->skipsamples = sample;
}
info->currentsample = sample;
- _info->readpos = (float)sample / _info->samplerate;
+ _info->readpos = (float)sample / _info->fmt.samplerate;
return 0;
}
static int
aoplug_seek (DB_fileinfo_t *_info, float time) {
- return aoplug_seek_sample (_info, time * _info->samplerate);
+ return aoplug_seek_sample (_info, time * _info->fmt.samplerate);
}
static void
@@ -250,9 +252,7 @@ aoplug_insert (DB_playItem_t *after, const char *fname) {
free (buffer);
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (fname);
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
const char *ext = fname + strlen (fname);
while (*ext != '.' && ext > fname) {
ext--;
@@ -260,38 +260,44 @@ aoplug_insert (DB_playItem_t *after, const char *fname) {
if (*ext == '.') {
ext++;
if (!strcasecmp (ext, "psf") || !strcasecmp (ext, "minipsf")) {
- it->filetype = filetypes[0];
+ deadbeef->pl_add_meta (it, ":FILETYPE", filetypes[0]);
}
else if (!strcasecmp (ext, "psf2") || !strcasecmp (ext, "minipsf2")) {
- it->filetype = filetypes[1];
+ deadbeef->pl_add_meta (it, ":FILETYPE", filetypes[1]);
}
else if (!strcasecmp (ext, "spu")) {
- it->filetype = filetypes[2];
+ deadbeef->pl_add_meta (it, ":FILETYPE", filetypes[2]);
}
else if (!strcasecmp (ext, "ssf") || !strcasecmp (ext, "minissf")) {
- it->filetype = filetypes[3];
- }
- else if (!strcasecmp (ext, "dsf") || !strcasecmp (ext, "minidsf")) {
- it->filetype = filetypes[5];
+ deadbeef->pl_add_meta (it, ":FILETYPE", filetypes[3]);
}
else if (!strcasecmp (ext, "qsf") || !strcasecmp (ext, "miniqsf")) {
- it->filetype = filetypes[4];
+ deadbeef->pl_add_meta (it, ":FILETYPE", filetypes[4]);
+ }
+ else if (!strcasecmp (ext, "dsf") || !strcasecmp (ext, "minidsf")) {
+ deadbeef->pl_add_meta (it, ":FILETYPE", filetypes[5]);
}
}
else {
- it->filetype = filetypes[0];
+ deadbeef->pl_add_meta (it, ":FILETYPE", filetypes[0]);
}
float duration = 120;
+ float fade = 0;
if (have_info) {
int i;
for (i = 1; i < 9; i++) {
if (!strncasecmp (info.title[i], "Length: ", 8)) {
- int min, sec;
- if (sscanf (info.info[i], "%d:%d", &min, &sec) == 2) {
+ printf ("len: %s\n", info.info[i]);
+ int min;
+ float sec;
+ if (sscanf (info.info[i], "%d:%f", &min, &sec) == 2) {
duration = min * 60 + sec;
}
+ else if (sscanf (info.info[i], "%f", &sec) == 1) {
+ duration = sec;
+ }
aoplug_add_meta (it, NULL, info.info[i], info.title[i]);
}
else if (!strncasecmp (info.title[i], "Name: ", 6) || !strncasecmp (info.title[i], "Song: ", 6)) {
@@ -312,12 +318,16 @@ aoplug_insert (DB_playItem_t *after, const char *fname) {
else if (!strncasecmp (info.title[i], "Ripper: ", 8)) {
aoplug_add_meta (it, "vendor", info.info[i], info.title[i]);
}
+ else if (!strncasecmp (info.title[i], "Fade: ", 6)) {
+ fade = atof (info.info[i]);
+ aoplug_add_meta (it, NULL, info.info[i], info.title[i]);
+ }
else {
aoplug_add_meta (it, NULL, info.info[i], info.title[i]);
}
}
}
- deadbeef->pl_set_item_duration (it, duration);
+ deadbeef->pl_set_item_duration (it, duration+fade);
deadbeef->pl_add_meta (it, "title", NULL);
after = deadbeef->pl_insert_item (after, it);
deadbeef->pl_item_unref (it);
@@ -336,21 +346,40 @@ aoplug_stop (void) {
static DB_decoder_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.id = "psf",
.plugin.name = "Audio Overload plugin",
.plugin.descr = "psf, psf2, spu, ssf, minidsf player based on Audio Overload library",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "Uses modified aosdk-1.4.8 - library for playing .PSF (Sony PlayStation), .SPU (Sony PlayStation), .PSF2 (Sony PlayStation 2), .SSF (Sega Saturn), .DSF (Sega Dreamcast), and .QSF (Capcom QSound) audio file formats,\n"
+ "http://rbelmont.mameworld.info/?page_id=221\n"
+ "Copyright © 2007-2009 R. Belmont and Richard Bannister.\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = aoplug_start,
.plugin.stop = aoplug_stop,
.open = aoplug_open,
.init = aoplug_init,
.free = aoplug_free,
- .read_int16 = aoplug_read_int16,
+ .read = aoplug_read,
.seek = aoplug_seek,
.seek_sample = aoplug_seek_sample,
.insert = aoplug_insert,
diff --git a/plugins/artwork/Makefile.am b/plugins/artwork/Makefile.am
index b60c86cb..8f9ea166 100644
--- a/plugins/artwork/Makefile.am
+++ b/plugins/artwork/Makefile.am
@@ -5,6 +5,6 @@ artwork_la_SOURCES = artwork.c artwork.h albumartorg.c albumartorg.h lastfm.c la
artwork_la_LDFLAGS = -module
-artwork_la_LIBADD = $(LDADD) $(ARTWORK_DEPS_LIBS)
-AM_CFLAGS = -std=c99 $(ARTWORK_DEPS_CFLAGS)
+artwork_la_LIBADD = $(LDADD) $(ARTWORK_DEPS_LIBS) $(IMLIB2_DEPS_LIBS)
+AM_CFLAGS = -std=c99 $(ARTWORK_DEPS_CFLAGS) $(IMLIB2_DEPS_CFLAGS)
endif
diff --git a/plugins/artwork/albumartorg.c b/plugins/artwork/albumartorg.c
index 71b640de..ada7179f 100644
--- a/plugins/artwork/albumartorg.c
+++ b/plugins/artwork/albumartorg.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
diff --git a/plugins/artwork/albumartorg.h b/plugins/artwork/albumartorg.h
index 4d1d494a..49231b04 100644
--- a/plugins/artwork/albumartorg.h
+++ b/plugins/artwork/albumartorg.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
diff --git a/plugins/artwork/artwork.c b/plugins/artwork/artwork.c
index fbbe71d9..b29db8f2 100644
--- a/plugins/artwork/artwork.c
+++ b/plugins/artwork/artwork.c
@@ -6,6 +6,8 @@
#include <dirent.h>
#include <unistd.h>
#include <fnmatch.h>
+#include <inttypes.h>
+#include <Imlib2.h>
#include "../../deadbeef.h"
#include "artwork.h"
#include "lastfm.h"
@@ -16,8 +18,8 @@
//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
#define trace(...)
-#define DEFAULT_COVER_PATH (PREFIX "/share/deadbeef/pixmaps/noartwork.jpg")
-#define DEFAULT_FILEMASK "*cover*.jpg;*front*.jpg"
+static char default_cover[PATH_MAX];
+#define DEFAULT_FILEMASK "*cover*.jpg;*front*.jpg;*folder*.jpg"
static DB_artwork_plugin_t plugin;
DB_functions_t *deadbeef;
@@ -28,6 +30,7 @@ typedef struct cover_query_s {
char *fname;
char *artist;
char *album;
+ int size;
artwork_callback callback;
void *user_data;
struct cover_query_s *next;
@@ -36,44 +39,50 @@ typedef struct cover_query_s {
static cover_query_t *queue;
static cover_query_t *queue_tail;
static uintptr_t mutex;
+static uintptr_t imlib_mutex;
static uintptr_t cond;
static volatile int terminate;
static volatile int clear_queue;
static intptr_t tid;
-int artwork_enable_embedded;
-int artwork_enable_local;
-int artwork_enable_lfm;
-int artwork_enable_aao;
-int artwork_reset_time;
-char artwork_filemask[200];
+static int artwork_enable_embedded;
+static int artwork_enable_local;
+static int artwork_enable_lfm;
+static int artwork_enable_aao;
+static time_t artwork_reset_time;
+static char artwork_filemask[200];
-void
-make_cache_dir_path (char *path, int size, const char *album, const char *artist) {
- int sz = snprintf (path, size, "%s/artcache/", deadbeef->get_config_dir ());
- size -= sz;
+static const char *get_default_cover (void) {
+ return default_cover;
+}
+
+int
+make_cache_dir_path (char *path, int size, const char *artist, int img_size) {
+ const char *cache = getenv ("XDG_CACHE_HOME");
+
+ int sz;
+
+ if (img_size == -1) {
+ sz = snprintf (path, size, cache ? "%s/deadbeef/covers/" : "%s/.cache/deadbeef/covers/", cache ? cache : getenv ("HOME"));
+ }
+ else {
+ sz = snprintf (path, size, cache ? "%s/deadbeef/covers-%d/" : "%s/.cache/deadbeef/covers-%d/", cache ? cache : getenv ("HOME"), img_size);
+ }
path += sz;
- sz = snprintf (path, size, "%s", artist);
+ sz += snprintf (path, size-sz, "%s", artist);
for (char *p = path; *p; p++) {
if (*p == '/') {
*p = '_';
}
}
+ return sz;
}
void
-make_cache_path (char *path, int size, const char *album, const char *artist) {
- int sz = snprintf (path, size, "%s/artcache/", deadbeef->get_config_dir ());
- size -= sz;
- path += sz;
-
- sz = snprintf (path, size, "%s", artist);
- for (char *p = path; *p; p++) {
- if (*p == '/') {
- *p = '_';
- }
- }
+make_cache_path (char *path, int size, const char *album, const char *artist, int img_size) {
+ char *p = path;
+ int sz = make_cache_dir_path (path, size, artist, img_size);
size -= sz;
path += sz;
sz = snprintf (path, size, "/%s.jpg", album);
@@ -85,7 +94,7 @@ make_cache_path (char *path, int size, const char *album, const char *artist) {
}
void
-queue_add (const char *fname, const char *artist, const char *album, artwork_callback callback, void *user_data) {
+queue_add (const char *fname, const char *artist, const char *album, int img_size, artwork_callback callback, void *user_data) {
if (!artist) {
artist = "";
}
@@ -106,6 +115,7 @@ queue_add (const char *fname, const char *artist, const char *album, artwork_cal
q->fname = strdup (fname);
q->artist = strdup (artist);
q->album = strdup (album);
+ q->size = img_size;
q->callback = callback;
q->user_data = user_data;
if (queue_tail) {
@@ -166,8 +176,64 @@ check_dir (const char *dir, mode_t mode)
#define BUFFER_SIZE 4096
static int
-copy_file (const char *in, const char *out) {
+copy_file (const char *in, const char *out, int img_size) {
trace ("copying %s to %s\n", in, out);
+
+ if (img_size != -1) {
+ deadbeef->mutex_lock (imlib_mutex);
+ // need to scale, use imlib2
+ Imlib_Image img = imlib_load_image_immediately (in);
+ if (!img) {
+ trace ("file %s not found, or imlib2 can't load it\n", in);
+ deadbeef->mutex_unlock (imlib_mutex);
+ return -1;
+ }
+ imlib_context_set_image(img);
+ int w = imlib_image_get_width ();
+ int h = imlib_image_get_height ();
+ int sw, sh;
+ if (deadbeef->conf_get_int ("artwork.scale_towards_longer", 1)) {
+ if (w > h) {
+ sh = img_size;
+ sw = img_size * w / h;
+ }
+ else {
+ sw = img_size;
+ sh = img_size * h / w;
+ }
+ }
+ else {
+ if (w < h) {
+ sh = img_size;
+ sw = img_size * w / h;
+ }
+ else {
+ sw = img_size;
+ sh = img_size * h / w;
+ }
+ }
+ Imlib_Image scaled = imlib_create_image (sw, sh);
+ imlib_context_set_image (scaled);
+ imlib_blend_image_onto_image (img, 1, 0, 0, w, h, 0, 0, sw, sh);
+ Imlib_Load_Error err = 0;
+ imlib_image_set_format ("jpg");
+ imlib_save_image_with_error_return (out, &err);
+ if (err != 0) {
+ trace ("imlib save %s returned %d\n", out, err);
+ imlib_free_image ();
+ imlib_context_set_image(img);
+ imlib_free_image ();
+ deadbeef->mutex_unlock (imlib_mutex);
+ return -1;
+ }
+ imlib_free_image ();
+ imlib_context_set_image(img);
+ imlib_free_image ();
+ deadbeef->mutex_unlock (imlib_mutex);
+
+ return 0;
+ }
+
FILE *fin = fopen (in, "rb");
if (!fin) {
trace ("artwork: failed to open file %s for reading\n", in);
@@ -287,19 +353,31 @@ fetcher_thread (void *none)
deadbeef->mutex_unlock (mutex);
while (!terminate && queue && !clear_queue) {
cover_query_t *param = queue;
- char path [1024];
+ char path [PATH_MAX];
struct dirent **files;
int files_count;
- make_cache_dir_path (path, sizeof (path), param->album, param->artist);
+ make_cache_dir_path (path, sizeof (path), param->artist, -1);
trace ("cache folder: %s\n", path);
if (!check_dir (path, 0755)) {
queue_pop ();
trace ("failed to create folder for %s %s\n", param->album, param->artist);
continue;
}
+ if (param->size != -1) {
+ make_cache_dir_path (path, sizeof (path), param->artist, param->size);
+ trace ("cache folder: %s\n", path);
+ if (!check_dir (path, 0755)) {
+ queue_pop ();
+ trace ("failed to create folder for %s %s\n", param->album, param->artist);
+ continue;
+ }
+ }
trace ("fetching cover for %s %s\n", param->album, param->artist);
+ char cache_path[1024];
+ make_cache_path (cache_path, sizeof (cache_path), param->album, param->artist, -1);
+ int got_pic = 0;
// try to load embedded from id3v2
if (deadbeef->is_local_file (param->fname)) {
@@ -309,7 +387,6 @@ fetcher_thread (void *none)
memset (&tag, 0, sizeof (tag));
DB_FILE *fp = deadbeef->fopen (param->fname);
current_file = fp;
- int got_id3v2_pic = 0;
if (fp) {
int res = deadbeef->junk_id3v2_read_full (NULL, &tag, fp);
if (!res) {
@@ -349,8 +426,6 @@ fetcher_thread (void *none)
int sz = f->size - (data - f->data);
char tmp_path[1024];
- char cache_path[1024];
- make_cache_path (cache_path, sizeof (cache_path), param->album, param->artist);
trace ("will write id3v2 APIC into %s\n", cache_path);
snprintf (tmp_path, sizeof (tmp_path), "%s.part", cache_path);
FILE *out = fopen (tmp_path, "w+b");
@@ -372,107 +447,90 @@ fetcher_thread (void *none)
break;
}
unlink (tmp_path);
- got_id3v2_pic = 1;
+ got_pic = 1;
break;
}
}
}
- if (got_id3v2_pic) {
- if (param->callback) {
- param->callback (param->fname, param->artist, param->album, param->user_data);
- }
- queue_pop ();
- continue;
- }
deadbeef->junk_id3v2_free (&tag);
current_file = NULL;
deadbeef->fclose (fp);
}
- }
- }
- // try to load embedded from apev2
- if (deadbeef->is_local_file (param->fname)) {
- if (artwork_enable_embedded) {
- trace ("trying to load artwork from apev2 tag for %s\n", param->fname);
- DB_apev2_tag_t tag;
- memset (&tag, 0, sizeof (tag));
- DB_FILE *fp = deadbeef->fopen (param->fname);
- current_file = fp;
- int got_apev2_pic = 0;
- if (fp) {
- int res = deadbeef->junk_apev2_read_full (NULL, &tag, fp);
- if (!res) {
- for (DB_apev2_frame_t *f = tag.frames; f; f = f->next) {
- if (!strcasecmp (f->key, "cover art (front)")) {
- uint8_t *name = f->data, *ext = f->data, *data = f->data;
- uint8_t *end = f->data + f->size;
- while (data < end && *data)
- data++;
- if (data == end) {
- trace ("artwork: apev2 cover art frame has no name\n");
- continue;
- }
- int sz = end - ++data;
- if (sz < 20) {
- trace ("artwork: apev2 cover art frame is too small\n");
- continue;
- }
- ext = strrchr (name, '.');
- if (!ext || !*++ext) {
- trace ("artwork: apev2 cover art name has no extension\n");
- continue;
- }
- if (strcasecmp (ext, "jpeg") && strcasecmp (ext, "jpg") && strcasecmp (ext, "png")) {
- trace ("artwork: unsupported file type: %s\n", ext);
- continue;
- }
- trace ("found apev2 cover art of %d bytes (%s)\n", sz, ext);
- char tmp_path[1024];
- char cache_path[1024];
- make_cache_path (cache_path, sizeof (cache_path), param->album, param->artist);
- trace ("will write apev2 cover art into %s\n", cache_path);
- snprintf (tmp_path, sizeof (tmp_path), "%s.part", cache_path);
- FILE *out = fopen (tmp_path, "w+b");
- if (!out) {
- trace ("artwork: failed to open %s for writing\n", tmp_path);
- break;
- }
- if (fwrite (data, 1, sz, out) != sz) {
- trace ("artwork: failed to write apev2 picture into %s\n", tmp_path);
+ // try to load embedded from apev2
+ {
+ trace ("trying to load artwork from apev2 tag for %s\n", param->fname);
+ DB_apev2_tag_t tag;
+ memset (&tag, 0, sizeof (tag));
+ DB_FILE *fp = deadbeef->fopen (param->fname);
+ current_file = fp;
+ if (fp) {
+ int res = deadbeef->junk_apev2_read_full (NULL, &tag, fp);
+ if (!res) {
+ for (DB_apev2_frame_t *f = tag.frames; f; f = f->next) {
+ if (!strcasecmp (f->key, "cover art (front)")) {
+ uint8_t *name = f->data, *ext = f->data, *data = f->data;
+ uint8_t *end = f->data + f->size;
+ while (data < end && *data)
+ data++;
+ if (data == end) {
+ trace ("artwork: apev2 cover art frame has no name\n");
+ continue;
+ }
+ int sz = end - ++data;
+ if (sz < 20) {
+ trace ("artwork: apev2 cover art frame is too small\n");
+ continue;
+ }
+ ext = strrchr (name, '.');
+ if (!ext || !*++ext) {
+ trace ("artwork: apev2 cover art name has no extension\n");
+ continue;
+ }
+ if (strcasecmp (ext, "jpeg") && strcasecmp (ext, "jpg") && strcasecmp (ext, "png")) {
+ trace ("artwork: unsupported file type: %s\n", ext);
+ continue;
+ }
+ trace ("found apev2 cover art of %d bytes (%s)\n", sz, ext);
+ char tmp_path[1024];
+ char cache_path[1024];
+ make_cache_path (cache_path, sizeof (cache_path), param->album, param->artist, -1);
+ trace ("will write apev2 cover art into %s\n", cache_path);
+ snprintf (tmp_path, sizeof (tmp_path), "%s.part", cache_path);
+ FILE *out = fopen (tmp_path, "w+b");
+ if (!out) {
+ trace ("artwork: failed to open %s for writing\n", tmp_path);
+ break;
+ }
+ if (fwrite (data, 1, sz, out) != sz) {
+ trace ("artwork: failed to write apev2 picture into %s\n", tmp_path);
+ fclose (out);
+ unlink (tmp_path);
+ break;
+ }
fclose (out);
+ int err = rename (tmp_path, cache_path);
+ if (err != 0) {
+ trace ("Failed not move %s to %s: %s\n", tmp_path, cache_path, strerror (err));
+ unlink (tmp_path);
+ break;
+ }
unlink (tmp_path);
+ got_pic = 1;
break;
}
- fclose (out);
- int err = rename (tmp_path, cache_path);
- if (err != 0) {
- trace ("Failed not move %s to %s: %s\n", tmp_path, cache_path, strerror (err));
- unlink (tmp_path);
- break;
- }
- unlink (tmp_path);
- got_apev2_pic = 1;
- break;
}
}
- }
- if (got_apev2_pic) {
- if (param->callback) {
- param->callback (param->fname, param->artist, param->album, param->user_data);
- }
- queue_pop ();
- continue;
+ deadbeef->junk_apev2_free (&tag);
+ current_file = NULL;
+ deadbeef->fclose (fp);
}
- deadbeef->junk_apev2_free (&tag);
- current_file = NULL;
- deadbeef->fclose (fp);
}
}
- if (artwork_enable_local) {
+ if (!got_pic && artwork_enable_local) {
/* Searching in track directory */
strncpy (path, param->fname, sizeof (path));
char *slash = strrchr (path, '/');
@@ -492,48 +550,50 @@ fetcher_thread (void *none)
strcat (path, files[0]->d_name);
char cache_path[1024];
char tmp_path[1024];
- make_cache_path (cache_path, sizeof (cache_path), param->album, param->artist);
+ make_cache_path (cache_path, sizeof (cache_path), param->album, param->artist, -1);
snprintf (tmp_path, sizeof (tmp_path), "%s.part", cache_path);
- copy_file (path, tmp_path);
+ copy_file (path, tmp_path, -1);
int err = rename (tmp_path, cache_path);
if (err != 0) {
- trace ("Failed not move %s to %s: %s\n", tmp_path, cache_path, strerror (err));
+ trace ("Failed to move %s to %s: %s\n", tmp_path, cache_path, strerror (err));
unlink (tmp_path);
}
int i;
for (i = 0; i < files_count; i++) {
free (files [i]);
}
- if (param->callback) {
- param->callback (param->fname, param->artist, param->album, param->user_data);
- }
- queue_pop ();
- continue;
+ got_pic = 1;
}
}
}
}
- make_cache_path (path, sizeof (path), param->album, param->artist);
-
- if (artwork_enable_lfm && !fetch_from_lastfm (param->artist, param->album, path)) {
- trace ("art found on last.fm for %s %s\n", param->album, param->artist);
- }
- else if (artwork_enable_aao && !fetch_from_albumart_org (param->artist, param->album, path)) {
- trace ("art found on albumart.org for %s %s\n", param->album, param->artist);
- }
- else {
- trace ("art not found for %s %s\n", param->album, param->artist);
-// if (param->callback) {
-// param->callback (DEFAULT_COVER_PATH, param->artist, param->album, param->user_data);
-// }
- queue_pop ();
- continue;
+ if (!got_pic) {
+ if (artwork_enable_lfm && !fetch_from_lastfm (param->artist, param->album, cache_path)) {
+ got_pic = 1;
+ }
+ else if (artwork_enable_aao && !fetch_from_albumart_org (param->artist, param->album, cache_path)) {
+ got_pic = 1;
+ }
}
- trace ("downloaded art for %s %s\n", param->album, param->artist);
- if (param->callback) {
- param->callback (param->fname, param->artist, param->album, param->user_data);
+ if (got_pic) {
+ trace ("downloaded art for %s %s\n", param->album, param->artist);
+ if (param->size != -1) {
+ make_cache_dir_path (path, sizeof (path), param->artist, param->size);
+ trace ("cache folder: %s\n", path);
+ if (!check_dir (path, 0755)) {
+ trace ("failed to create folder %s\n", path);
+ queue_pop ();
+ continue;
+ }
+ char scaled_path[1024];
+ make_cache_path (scaled_path, sizeof (scaled_path), param->album, param->artist, param->size);
+ copy_file (cache_path, scaled_path, param->size);
+ }
+ if (param->callback) {
+ param->callback (param->fname, param->artist, param->album, param->user_data);
+ }
}
queue_pop ();
}
@@ -552,8 +612,27 @@ fetcher_thread (void *none)
}
}
+static char *
+find_image (const char *path) {
+ struct stat stat_buf;
+ if (0 == stat (path, &stat_buf)) {
+ int cache_period = deadbeef->conf_get_int ("artwork.cache.period", 48);
+ time_t tm = time (NULL);
+ // invalidate cache every 2 days
+ if ((cache_period > 0 && (tm - stat_buf.st_mtime > cache_period * 60 * 60))
+ || artwork_reset_time > stat_buf.st_mtime) {
+ trace ("reloading cached file %s\n", path);
+ unlink (path);
+ return NULL;
+ }
+
+ return strdup (path);
+ }
+ return NULL;
+}
+
char*
-get_album_art (const char *fname, const char *artist, const char *album, artwork_callback callback, void *user_data)
+get_album_art (const char *fname, const char *artist, const char *album, int size, artwork_callback callback, void *user_data)
{
// trace ("get_album_art: %s (%s - %s)\n", fname, artist, album);
char path [1024];
@@ -568,33 +647,42 @@ get_album_art (const char *fname, const char *artist, const char *album, artwork
if (!*artist || !*album)
{
//give up
- return strdup (DEFAULT_COVER_PATH);
+ return size == -1 ? strdup (get_default_cover ()) : NULL;
}
if (!deadbeef->is_local_file (fname)) {
- return strdup (DEFAULT_COVER_PATH);
- }
-
- make_cache_path (path, sizeof (path), album, artist);
- struct stat stat_buf;
- if (0 == stat (path, &stat_buf)) {
- int cache_period = deadbeef->conf_get_int ("artwork.cache.period", 48);
- time_t tm = time (NULL);
- // invalidate cache every 2 days
- if ((cache_period > 0 && (tm - stat_buf.st_mtime > cache_period * 60 * 60))
- || artwork_reset_time > stat_buf.st_mtime) {
- trace ("reloading cached file %s\n", path);
- unlink (path);
- queue_add (fname, artist, album, callback, user_data);
- return strdup (DEFAULT_COVER_PATH);
+ return size == -1 ? strdup (get_default_cover ()) : NULL;
+ }
+
+ make_cache_path (path, sizeof (path), album, artist, size);
+ char *p = find_image (path);
+ if (p) {
+ return p;
+ }
+
+ if (size != -1) {
+ // check if we have unscaled image
+ char unscaled_path[1024];
+ make_cache_path (unscaled_path, sizeof (unscaled_path), album, artist, -1);
+ p = find_image (unscaled_path);
+ if (p) {
+ free (p);
+ char dir[1024];
+ make_cache_dir_path (dir, sizeof (dir), artist, size);
+ if (!check_dir (dir, 0755)) {
+ trace ("failed to create folder for %s\n", dir);
+ }
+ else {
+ int res = copy_file (unscaled_path, path, size);
+ if (!res) {
+ return strdup (path);
+ }
+ }
}
-
- trace ("found %s in cache\n", path);
- return strdup (path);
}
- queue_add (fname, artist, album, callback, user_data);
- return strdup (DEFAULT_COVER_PATH);
+ queue_add (fname, artist, album, size, callback, user_data);
+ return size == -1 ? strdup (get_default_cover ()) : NULL;
}
DB_plugin_t *
@@ -639,23 +727,25 @@ artwork_on_configchanged (DB_event_t *ev, uintptr_t data) {
int new_artwork_enable_local = deadbeef->conf_get_int ("artwork.enable_localfolder", 1);
int new_artwork_enable_lfm = deadbeef->conf_get_int ("artwork.enable_lastfm", 0);
int new_artwork_enable_aao = deadbeef->conf_get_int ("artwork.enable_albumartorg", 0);
+
char new_artwork_filemask[200];
- strncpy (new_artwork_filemask, deadbeef->conf_get_str ("artwork.filemask", DEFAULT_FILEMASK), sizeof (new_artwork_filemask));
- new_artwork_filemask[sizeof(new_artwork_filemask)-1] = 0;
+ deadbeef->conf_get_str ("artwork.filemask", DEFAULT_FILEMASK, new_artwork_filemask, sizeof (new_artwork_filemask));
if (new_artwork_enable_embedded != artwork_enable_embedded
|| new_artwork_enable_local != artwork_enable_local
|| new_artwork_enable_lfm != artwork_enable_lfm
|| new_artwork_enable_aao != artwork_enable_aao
|| strcmp (new_artwork_filemask, artwork_filemask)) {
+ trace ("artwork config changed, invalidating cache...\n");
artwork_enable_embedded = new_artwork_enable_embedded;
artwork_enable_local = new_artwork_enable_local;
artwork_enable_lfm = new_artwork_enable_lfm;
artwork_enable_aao = new_artwork_enable_aao;
artwork_reset_time = time (NULL);
strcpy (artwork_filemask, new_artwork_filemask);
- deadbeef->conf_set_int ("artwork.cache_reset_time", artwork_reset_time);
- deadbeef->sendmessage (M_PLAYLISTREFRESH, 0, 0, 0);
+ deadbeef->conf_set_int64 ("artwork.cache_reset_time", artwork_reset_time);
+ artwork_reset (0);
+ deadbeef->sendmessage (M_PLAYLIST_REFRESH, 0, 0, 0);
}
return 0;
@@ -664,20 +754,33 @@ artwork_on_configchanged (DB_event_t *ev, uintptr_t data) {
static int
artwork_plugin_start (void)
{
+ deadbeef->conf_lock ();
+
+ const char *def_art = deadbeef->conf_get_str_fast ("gtkui.nocover_pixmap", NULL);
+ if (!def_art) {
+ snprintf (default_cover, sizeof (default_cover), "%s/noartwork.jpg", deadbeef->get_pixmap_dir ());
+ }
+ else {
+ strcpy (default_cover, def_art);
+ }
terminate = 0;
artwork_enable_embedded = deadbeef->conf_get_int ("artwork.enable_embedded", 1);
artwork_enable_local = deadbeef->conf_get_int ("artwork.enable_localfolder", 1);
artwork_enable_lfm = deadbeef->conf_get_int ("artwork.enable_lastfm", 0);
artwork_enable_aao = deadbeef->conf_get_int ("artwork.enable_albumartorg", 0);
- artwork_reset_time = deadbeef->conf_get_int ("artwork.cache_reset_time", 0);
+ artwork_reset_time = deadbeef->conf_get_int64 ("artwork.cache_reset_time", 0);
+
+ deadbeef->conf_get_str ("artwork.filemask", DEFAULT_FILEMASK, artwork_filemask, sizeof (artwork_filemask));
+
+ deadbeef->conf_unlock ();
- strncpy (artwork_filemask, deadbeef->conf_get_str ("artwork.filemask", DEFAULT_FILEMASK), sizeof (artwork_filemask));
artwork_filemask[sizeof(artwork_filemask)-1] = 0;
deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_CONFIGCHANGED, DB_CALLBACK (artwork_on_configchanged), 0);
mutex = deadbeef->mutex_create_nonrecursive ();
+ imlib_mutex = deadbeef->mutex_create_nonrecursive ();
cond = deadbeef->cond_create ();
tid = deadbeef->thread_start_low_priority (fetcher_thread, NULL);
@@ -704,6 +807,10 @@ artwork_plugin_stop (void)
deadbeef->mutex_free (mutex);
mutex = 0;
}
+ if (imlib_mutex) {
+ deadbeef->mutex_free (imlib_mutex);
+ imlib_mutex = 0;
+ }
if (cond) {
deadbeef->cond_free (cond);
cond = 0;
@@ -719,21 +826,42 @@ static const char settings_dlg[] =
"property \"Local cover file mask\" entry artwork.filemask \"" DEFAULT_FILEMASK "\";\n"
"property \"Fetch from last.fm\" checkbox artwork.enable_lastfm 0;\n"
"property \"Fetch from albumart.org\" checkbox artwork.enable_albumartorg 0;\n"
+ "property \"Scale artwork towards longer side\" checkbox artwork.scale_towards_longer 1;\n"
;
+
// define plugin interface
static DB_artwork_plugin_t plugin = {
.plugin.plugin.api_vmajor = DB_API_VERSION_MAJOR,
.plugin.plugin.api_vminor = DB_API_VERSION_MINOR,
+ .plugin.plugin.version_major = 1,
+ .plugin.plugin.version_minor = 0,
.plugin.plugin.type = DB_PLUGIN_MISC,
- .plugin.plugin.id = "cover_loader",
+ .plugin.plugin.id = "artwork",
.plugin.plugin.name = "Album Artwork",
.plugin.plugin.descr = "Loads album artwork either from local directories or from internet",
- .plugin.plugin.author = "Viktor Semykin, Alexey Yakovenko",
- .plugin.plugin.email = "thesame.ml@gmail.com, waker@users.sourceforge.net",
+ .plugin.plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "Copyright (C) 2009-2011 Viktor Semykin <thesame.ml@gmail.com>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.plugin.website = "http://deadbeef.sf.net",
.plugin.plugin.start = artwork_plugin_start,
.plugin.plugin.stop = artwork_plugin_stop,
.plugin.plugin.configdialog = settings_dlg,
.get_album_art = get_album_art,
.reset = artwork_reset,
+ .get_default_cover = get_default_cover,
};
diff --git a/plugins/artwork/artwork.h b/plugins/artwork/artwork.h
index ab0fead6..130bf3fe 100644
--- a/plugins/artwork/artwork.h
+++ b/plugins/artwork/artwork.h
@@ -10,10 +10,11 @@ typedef void (*artwork_callback) (const char *fname, const char *artist, const c
typedef struct {
DB_misc_t plugin;
// returns filename of cached image, or NULL
- char* (*get_album_art) (const char *fname, const char *artist, const char *album, artwork_callback callback, void *user_data);
+ char* (*get_album_art) (const char *fname, const char *artist, const char *album, int size, artwork_callback callback, void *user_data);
// this has to be called to clear queue on exit, before caller terminates
// `fast=1' means "don't wait, just flush queue"
void (*reset) (int fast);
+ const char *(*get_default_cover) (void);
} DB_artwork_plugin_t;
#endif /*__ARTWORK_H*/
diff --git a/plugins/artwork/escape.h b/plugins/artwork/escape.h
index d87cf0a1..75d24091 100644
--- a/plugins/artwork/escape.h
+++ b/plugins/artwork/escape.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
diff --git a/plugins/artwork/lastfm.c b/plugins/artwork/lastfm.c
index ce95e9d4..2e78fd87 100644
--- a/plugins/artwork/lastfm.c
+++ b/plugins/artwork/lastfm.c
@@ -36,7 +36,7 @@ fetch_from_lastfm (const char *artist, const char *album, const char *dest)
char buffer[1000];
memset (buffer, 0, sizeof (buffer));
char *img = NULL;
- int size = deadbeef->fread (buffer, 1, sizeof (buffer), fp);
+ int size = deadbeef->fread (buffer, 1, sizeof (buffer)-1, fp);
if (size > 0) {
img = strstr (buffer, searchstr);
}
diff --git a/plugins/artwork/lastfm.h b/plugins/artwork/lastfm.h
index 09ec817c..cef71919 100644
--- a/plugins/artwork/lastfm.h
+++ b/plugins/artwork/lastfm.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
diff --git a/plugins/cdda/cdda.c b/plugins/cdda/cdda.c
index 2ed54b51..b49c0cea 100644
--- a/plugins/cdda/cdda.c
+++ b/plugins/cdda/cdda.c
@@ -57,8 +57,6 @@ typedef struct {
unsigned int current_sample;
} cdda_info_t;
-static uintptr_t mutex;
-static intptr_t cddb_tid;
struct cddb_thread_params
{
DB_playItem_t *items[100];
@@ -71,7 +69,7 @@ min (int a, int b) {
}
static DB_fileinfo_t *
-cda_open (void) {
+cda_open (uint32_t hints) {
DB_fileinfo_t *_info = malloc (sizeof (cdda_info_t));
memset (_info, 0, sizeof (cdda_info_t));
return _info;
@@ -81,18 +79,18 @@ static int
cda_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
cdda_info_t *info = (cdda_info_t *)_info;
- trace ("cdda: init %s\n", it->fname);
+ trace ("cdda: init %s\n", deadbeef->pl_find_meta (it, ":URI"));
- size_t l = strlen (it->fname);
+ size_t l = strlen (deadbeef->pl_find_meta (it, ":URI"));
char location[l+1];
- memcpy (location, it->fname, l+1);
+ memcpy (location, deadbeef->pl_find_meta (it, ":URI"), l+1);
char *nr = strchr (location, '#');
if (nr) {
*nr = 0; nr++;
}
else {
- trace ("cdda: bad name: %s\n", it->fname);
+ trace ("cdda: bad name: %s\n", deadbeef->pl_find_meta (it, ":URI"));
return -1;
}
int track_nr = atoi (nr);
@@ -115,9 +113,10 @@ cda_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
trace ("cdio nchannels: %d\n", channels);
_info->plugin = &plugin;
- _info->bps = 16,
- _info->channels = 2,
- _info->samplerate = 44100,
+ _info->fmt.bps = 16;
+ _info->fmt.channels = 2;
+ _info->fmt.samplerate = 44100;
+ _info->fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT;
_info->readpos = 0;
info->first_sector = cdio_get_track_lsn (info->cdio, track_nr);
@@ -129,7 +128,7 @@ cda_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
}
int
-cda_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
+cda_read (DB_fileinfo_t *_info, char *bytes, int size) {
cdda_info_t *info = (cdda_info_t *)_info;
int extrasize = 0;
@@ -181,7 +180,7 @@ cda_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
retsize += extrasize;
// trace ("requested: %d; tail_len: %d; size: %d; sectors_to_read: %d; return: %d\n", initsize, tail_len, size, sectors_to_read, retsize);
info->current_sample += retsize / SAMPLESIZE;
- _info->readpos = (float)info->current_sample / _info->samplerate;
+ _info->readpos = (float)info->current_sample / _info->fmt.samplerate;
return retsize;
}
@@ -211,14 +210,14 @@ cda_seek_sample (DB_fileinfo_t *_info, int sample)
memcpy (info->tail, buf + offset, SECTORSIZE - offset);
info->current_sector = sector;
info->current_sample = sample;
- _info->readpos = (float)info->current_sample / _info->samplerate;
+ _info->readpos = (float)info->current_sample / _info->fmt.samplerate;
return 0;
}
static int
cda_seek (DB_fileinfo_t *_info, float sec)
{
- return cda_seek_sample (_info, sec * _info->samplerate);
+ return cda_seek_sample (_info, sec * _info->fmt.samplerate);
}
cddb_disc_t*
@@ -244,7 +243,8 @@ resolve_disc (CdIo_t *cdio)
conn = cddb_new();
- cddb_set_server_name (conn, deadbeef->conf_get_str ("cdda.freedb.host", DEFAULT_SERVER));
+ deadbeef->conf_lock ();
+ cddb_set_server_name (conn, deadbeef->conf_get_str_fast ("cdda.freedb.host", DEFAULT_SERVER));
cddb_set_server_port (conn, deadbeef->conf_get_int ("cdda.freedb.port", DEFAULT_PORT));
if (!deadbeef->conf_get_int ("cdda.protocol", DEFAULT_PROTOCOL))
@@ -253,9 +253,10 @@ resolve_disc (CdIo_t *cdio)
if (deadbeef->conf_get_int ("network.proxy", 0))
{
cddb_set_server_port(conn, deadbeef->conf_get_int ("network.proxy.port", 8080));
- cddb_set_server_name(conn, deadbeef->conf_get_str ("network.proxy.address", ""));
+ cddb_set_server_name(conn, deadbeef->conf_get_str_fast ("network.proxy.address", ""));
}
}
+ deadbeef->conf_unlock ();
int matches = cddb_query (conn, disc);
if (matches == -1)
@@ -286,10 +287,8 @@ insert_single_track (CdIo_t* cdio, DB_playItem_t *after, const char* file, int t
int sector_count = cdio_get_track_sec_count (cdio, track_nr);
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (tmp);
- it->filetype = "cdda";
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (tmp, plugin.plugin.id);
+ deadbeef->pl_add_meta (it, ":FILETYPE", "cdda");
deadbeef->pl_set_item_duration (it, (float)sector_count / 75.0);
snprintf (tmp, sizeof (tmp), "CD Track %02d", track_nr);
@@ -320,9 +319,7 @@ cddb_thread (void *items_i)
DB_playItem_t **items = params->items;
trace ("calling resolve_disc\n");
- deadbeef->mutex_lock (mutex);
cddb_disc_t* disc = resolve_disc (params->cdio);
- deadbeef->mutex_unlock (mutex);
if (!disc)
{
trace ("disc not resolved\n");
@@ -334,7 +331,6 @@ cddb_thread (void *items_i)
}
trace ("disc resolved\n");
- deadbeef->mutex_lock (mutex);
const char *disc_title = cddb_disc_get_title (disc);
const char *artist = cddb_disc_get_artist (disc);
trace ("disc_title=%s, disk_artist=%s\n", disc_title, artist);
@@ -359,9 +355,7 @@ cddb_thread (void *items_i)
deadbeef->plug_trigger_event_trackinfochanged (items[i]);
}
cddb_disc_destroy (disc);
- deadbeef->mutex_unlock (mutex);
cleanup_thread_params (params);
- cddb_tid = 0;
deadbeef->plug_trigger_event_playlistchanged ();
}
@@ -508,10 +502,8 @@ cda_insert (DB_playItem_t *after, const char *fname) {
if ((!got_cdtext || !prefer_cdtext) && enable_cddb)
{
trace ("cdda: querying freedb...\n");
- if (cddb_tid) {
- deadbeef->thread_join (cddb_tid);
- }
- cddb_tid = deadbeef->thread_start (cddb_thread, p); //will destroy cdio
+ intptr_t tid = deadbeef->thread_start (cddb_thread, p); //will destroy cdio
+ deadbeef->thread_detach (tid);
}
else
cleanup_thread_params (p);
@@ -530,27 +522,12 @@ cda_insert (DB_playItem_t *after, const char *fname) {
}
static int
-cda_start (void) {
- mutex = deadbeef->mutex_create ();
- return 0;
-}
-
-static int
-cda_stop (void) {
- if (cddb_tid) {
- trace ("cdda: waiting cddb query to end\n");
- deadbeef->thread_join (cddb_tid);
- }
- deadbeef->mutex_free (mutex);
- return 0;
-}
-
-static int
cda_action_add_cd (DB_plugin_action_t *act, DB_playItem_t *it)
{
+ deadbeef->pl_add_files_begin (deadbeef->plt_get_curr ());
deadbeef->pl_add_file ("all.cda", NULL, NULL);
- //Wtf?
- //playlist_refresh ();
+ deadbeef->pl_add_files_end ();
+ deadbeef->plug_trigger_event_playlistchanged ();
}
static DB_plugin_action_t add_cd_action = {
@@ -581,23 +558,37 @@ static const char settings_dlg[] =
// define plugin interface
static DB_decoder_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.id = "cda",
.plugin.name = "Audio CD player",
- .plugin.descr = "Audio CD plugins using libcdio and libcddb",
- .plugin.author = "Viktor Semykin, Alexey Yakovenko",
- .plugin.email = "thesame.ml@gmail.com, waker@users.sourceforge.net",
+ .plugin.descr = "Audio CD plugin using libcdio and libcddb",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "Copyright (C) 2009-2011 Viktor Semykin <thesame.ml@gmail.com>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
- .plugin.start = cda_start,
- .plugin.stop = cda_stop,
.plugin.configdialog = settings_dlg,
.plugin.get_actions = cda_get_actions,
.open = cda_open,
.init = cda_init,
.free = cda_free,
- .read_int16 = cda_read_int16,
+ .read = cda_read,
.seek = cda_seek,
.seek_sample = cda_seek_sample,
.insert = cda_insert,
diff --git a/plugins/converter/Makefile b/plugins/converter/Makefile
new file mode 100644
index 00000000..7cd742a0
--- /dev/null
+++ b/plugins/converter/Makefile
@@ -0,0 +1,32 @@
+CONVERTER_OUT=converter.so
+GUI_OUT=converter_gtkui.so
+
+CC=gcc
+
+CFLAGS+=-Wall -D_GNU_SOURCE -std=c99 -fPIC -g -I../..
+
+LDFLAGS+=-module -shared
+
+CONVERTER_SOURCES=converter.c
+GUI_SOURCES=convgui.c interface.c support.c
+
+CONVERTER_OBJECTS=$(CONVERTER_SOURCES:.c=.o)
+GUI_OBJECTS=$(GUI_SOURCES:.c=.o)
+
+all: $(CONVERTER_SOURCES) $(CONVERTER_OUT) $(GUI_SOURCES) $(GUI_OUT)
+
+$(CONVERTER_OUT): $(CONVERTER_OBJECTS)
+ $(CC) $(LDFLAGS) $(CONVERTER_OBJECTS) -o $@
+
+GTK_CFLAGS=`pkg-config --cflags gtk+-2.0`
+GTK_LIBS=`pkg-config --libs gtk+-2.0`
+
+$(GUI_OUT): $(GUI_OBJECTS)
+ $(CC) $(LDFLAGS) $(GUI_OBJECTS) $(GTK_LIBS) -o $@
+
+.c.o:
+ $(CC) $(CFLAGS) $(GTK_CFLAGS) $< -c -o $@
+
+clean:
+ rm $(CONVERTER_OBJECTS) $(CONVERTER_OUT) $(GUI_OBJECTS) $(GUI_OUT)
+
diff --git a/plugins/converter/callbacks.c b/plugins/converter/callbacks.c
new file mode 100644
index 00000000..b8fb56d3
--- /dev/null
+++ b/plugins/converter/callbacks.c
@@ -0,0 +1,11 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+
+#include "callbacks.h"
+#include "interface.h"
+#include "support.h"
+
+
diff --git a/plugins/converter/callbacks.h b/plugins/converter/callbacks.h
new file mode 100644
index 00000000..7e323527
--- /dev/null
+++ b/plugins/converter/callbacks.h
@@ -0,0 +1,124 @@
+#include <gtk/gtk.h>
+
+void
+on_converter_encoder_changed (GtkComboBox *combobox,
+ gpointer user_data);
+
+void
+on_presets_cursor_changed (GtkTreeView *treeview,
+ gpointer user_data);
+
+void
+on_dsp_preset_add_plugin_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_dsp_preset_remove_plugin_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_converter_dsp_preset_changed (GtkComboBox *combobox,
+ gpointer user_data);
+
+void
+on_dsp_preset_plugin_configure_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_dsp_preset_plugin_up_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_dsp_preset_plugin_down_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_converter_output_format_changed (GtkComboBox *combobox,
+ gpointer user_data);
+
+GtkWidget*
+encoder_cmdline_help_link_create (gchar *widget_name, gchar *string1, gchar *string2,
+ gint int1, gint int2);
+
+
+void
+on_edit_encoder_presets_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_edit_dsp_presets_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_converter_output_browse_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_converter_cancel_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_converter_ok_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_converterdlg_close (GtkDialog *dialog,
+ gpointer user_data);
+
+void
+on_converterdlg_response (GtkDialog *dialog,
+ gint response_id,
+ gpointer user_data);
+
+gboolean
+on_converterdlg_delete_event (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data);
+
+GtkWidget*
+title_formatting_help_link_create (gchar *widget_name, gchar *string1, gchar *string2,
+ gint int1, gint int2);
+
+void
+on_output_folder_changed (GtkEditable *editable,
+ gpointer user_data);
+
+void
+on_numthreads_changed (GtkEditable *editable,
+ gpointer user_data);
+
+void
+on_overwrite_action_changed (GtkComboBox *combobox,
+ gpointer user_data);
+
+void
+on_encoder_changed (GtkEditable *editable,
+ gpointer user_data);
+
+void
+on_preserve_folder_browse_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_fname_changed (GtkEditable *editable,
+ gpointer user_data);
+
+void
+on_checkbutton1_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data);
+
+void
+on_preserve_folders_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data);
+
+void
+on_output_file_changed (GtkEditable *editable,
+ gpointer user_data);
+
+void
+on_preserve_folder_root_changed (GtkEditable *editable,
+ gpointer user_data);
+
+void
+on_preserve_root_folder_changed (GtkEditable *editable,
+ gpointer user_data);
diff --git a/plugins/converter/converter.c b/plugins/converter/converter.c
new file mode 100644
index 00000000..99d3b04b
--- /dev/null
+++ b/plugins/converter/converter.c
@@ -0,0 +1,906 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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 <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include "converter.h"
+#include <deadbeef.h>
+
+#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+//#define trace(fmt,...)
+
+static ddb_converter_t plugin;
+static DB_functions_t *deadbeef;
+
+static ddb_encoder_preset_t *encoder_presets;
+static ddb_dsp_preset_t *dsp_presets;
+
+ddb_encoder_preset_t *
+encoder_preset_alloc (void) {
+ ddb_encoder_preset_t *p = malloc (sizeof (ddb_encoder_preset_t));
+ if (!p) {
+ fprintf (stderr, "failed to alloc ddb_encoder_preset_t\n");
+ return NULL;
+ }
+ memset (p, 0, sizeof (ddb_encoder_preset_t));
+ return p;
+}
+
+void
+encoder_preset_free (ddb_encoder_preset_t *p) {
+ if (p) {
+ if (p->title) {
+ free (p->title);
+ }
+ if (p->ext) {
+ free (p->ext);
+ }
+ if (p->encoder) {
+ free (p->encoder);
+ }
+ free (p);
+ }
+}
+
+ddb_encoder_preset_t *
+encoder_preset_load (const char *fname) {
+ int err = 1;
+ FILE *fp = fopen (fname, "rt");
+ if (!fp) {
+ return NULL;
+ }
+ ddb_encoder_preset_t *p = encoder_preset_alloc ();
+
+ char str[1024];
+ while (fgets (str, sizeof (str), fp)) {
+ // chomp
+ char *cr = str + strlen (str) - 1;
+ while (*cr == '\n') {
+ cr--;
+ }
+ cr++;
+ *cr = 0;
+
+ char *sp = strchr (str, ' ');
+ if (!sp) {
+ continue;
+ }
+
+ *sp = 0;
+ char *item = sp + 1;
+
+ if (!strcmp (str, "title")) {
+ p->title = strdup (item);
+ }
+ else if (!strcmp (str, "ext")) {
+ p->ext = strdup (item);
+ }
+ else if (!strcmp (str, "encoder")) {
+ p->encoder = strdup (item);
+ }
+ else if (!strcmp (str, "method")) {
+ p->method = atoi (item);
+ }
+ else if (!strcmp (str, "id3v2_version")) {
+ p->id3v2_version = atoi (item);
+ }
+ else if (!strcmp (str, "tag_id3v2")) {
+ p->tag_id3v2 = atoi (item);
+ }
+ else if (!strcmp (str, "tag_id3v1")) {
+ p->tag_id3v1 = atoi (item);
+ }
+ else if (!strcmp (str, "tag_apev2")) {
+ p->tag_apev2 = atoi (item);
+ }
+ else if (!strcmp (str, "tag_flac")) {
+ p->tag_flac = atoi (item);
+ }
+ else if (!strcmp (str, "tag_oggvorbis")) {
+ p->tag_oggvorbis = atoi (item);
+ }
+ }
+
+ if (!p->title) {
+ p->title = strdup ("Untitled");
+ }
+ if (!p->ext) {
+ p->ext = strdup ("");
+ }
+ if (!p->encoder) {
+ p->encoder = strdup ("");
+ }
+
+ err = 0;
+
+ if (err) {
+ encoder_preset_free (p);
+ p = NULL;
+ }
+ if (fp) {
+ fclose (fp);
+ }
+ return p;
+}
+
+// @return -1 on path/write error, -2 if file already exists
+int
+encoder_preset_save (ddb_encoder_preset_t *p, int overwrite) {
+ const char *confdir = deadbeef->get_config_dir ();
+ char path[1024];
+ if (snprintf (path, sizeof (path), "%s/presets", confdir) < 0) {
+ return -1;
+ }
+ mkdir (path, 0755);
+ if (snprintf (path, sizeof (path), "%s/presets/encoders", confdir) < 0) {
+ return -1;
+ }
+ mkdir (path, 0755);
+ if (snprintf (path, sizeof (path), "%s/presets/encoders/%s.txt", confdir, p->title) < 0) {
+ return -1;
+ }
+
+ if (!overwrite) {
+ FILE *fp = fopen (path, "rb");
+ if (fp) {
+ fclose (fp);
+ return -2;
+ }
+ }
+
+ FILE *fp = fopen (path, "w+b");
+ if (!fp) {
+ return -1;
+ }
+
+ fprintf (fp, "title %s\n", p->title);
+ fprintf (fp, "ext %s\n", p->ext);
+ fprintf (fp, "encoder %s\n", p->encoder);
+ fprintf (fp, "method %d\n", p->method);
+ fprintf (fp, "id3v2_version %d\n", p->id3v2_version);
+ fprintf (fp, "tag_id3v2 %d\n", p->tag_id3v2);
+ fprintf (fp, "tag_id3v1 %d\n", p->tag_id3v1);
+ fprintf (fp, "tag_apev2 %d\n", p->tag_apev2);
+ fprintf (fp, "tag_flac %d\n", p->tag_flac);
+ fprintf (fp, "tag_oggvorbis %d\n", p->tag_oggvorbis);
+
+ fclose (fp);
+ return 0;
+}
+
+void
+encoder_preset_copy (ddb_encoder_preset_t *to, ddb_encoder_preset_t *from) {
+ to->title = strdup (from->title);
+ to->ext = strdup (from->ext);
+ to->encoder = strdup (from->encoder);
+ to->method = from->method;
+ to->tag_id3v2 = from->tag_id3v2;
+ to->tag_id3v1 = from->tag_id3v1;
+ to->tag_apev2 = from->tag_apev2;
+ to->tag_flac = from->tag_flac;
+ to->tag_oggvorbis = from->tag_oggvorbis;
+ to->tag_mp3xing = from->tag_mp3xing;
+ to->id3v2_version = from->id3v2_version;
+}
+
+ddb_encoder_preset_t *
+encoder_preset_get_list (void) {
+ return encoder_presets;
+}
+
+ddb_encoder_preset_t *
+encoder_preset_get_for_idx (int idx) {
+ ddb_encoder_preset_t *p = encoder_presets;
+ while (p && idx--) {
+ p = p->next;
+ }
+ return p;
+}
+
+void
+encoder_preset_append (ddb_encoder_preset_t *p) {
+ // append
+ ddb_encoder_preset_t *tail = encoder_presets;
+ while (tail && tail->next) {
+ tail = tail->next;
+ }
+ if (tail) {
+ tail->next = p;
+ }
+ else {
+ encoder_presets = p;
+ }
+}
+
+void
+encoder_preset_remove (ddb_encoder_preset_t *p) {
+ ddb_encoder_preset_t *prev = encoder_presets;
+ while (prev && prev->next != p) {
+ prev = prev->next;
+ }
+ if (prev) {
+ prev->next = p->next;
+ }
+ else {
+ encoder_presets = p->next;
+ }
+}
+
+void
+encoder_preset_replace (ddb_encoder_preset_t *from, ddb_encoder_preset_t *to) {
+ ddb_encoder_preset_t *prev = encoder_presets;
+ while (prev && prev->next != from) {
+ prev = prev->next;
+ }
+ if (prev) {
+ prev->next = to;
+ }
+ else {
+ encoder_presets = to;
+ }
+ to->next = from->next;
+}
+
+ddb_dsp_preset_t *
+dsp_preset_alloc (void) {
+ ddb_dsp_preset_t *p = malloc (sizeof (ddb_dsp_preset_t));
+ if (!p) {
+ fprintf (stderr, "failed to alloc ddb_dsp_preset_t\n");
+ return NULL;
+ }
+ memset (p, 0, sizeof (ddb_dsp_preset_t));
+ return p;
+}
+
+void
+dsp_preset_free (ddb_dsp_preset_t *p) {
+ if (p) {
+ if (p->title) {
+ free (p->title);
+ }
+ deadbeef->dsp_preset_free (p->chain);
+ free (p);
+ }
+}
+
+void
+dsp_preset_copy (ddb_dsp_preset_t *to, ddb_dsp_preset_t *from) {
+ to->title = strdup (from->title);
+ ddb_dsp_context_t *tail = NULL;
+ ddb_dsp_context_t *dsp = from->chain;
+ while (dsp) {
+ ddb_dsp_context_t *i = dsp->plugin->open ();
+ if (dsp->plugin->num_params) {
+ int n = dsp->plugin->num_params ();
+ for (int j = 0; j < n; j++) {
+ char s[1000] = "";
+ dsp->plugin->get_param (dsp, j, s, sizeof (s));
+ i->plugin->set_param (i, j, s);
+ }
+ }
+ if (tail) {
+ tail->next = i;
+ tail = i;
+ }
+ else {
+ to->chain = tail = i;
+ }
+ dsp = dsp->next;
+ }
+}
+
+ddb_dsp_preset_t *
+dsp_preset_get_list (void) {
+ return dsp_presets;
+}
+
+ddb_dsp_preset_t *
+dsp_preset_load (const char *fname) {
+ ddb_dsp_preset_t *p = dsp_preset_alloc ();
+ if (!p) {
+ return NULL;
+ }
+ memset (p, 0, sizeof (ddb_dsp_preset_t));
+ const char *end = strrchr (fname, '.');
+ if (!end) {
+ end = fname + strlen (fname);
+ }
+ const char *start = strrchr (fname, '/');
+ if (!start) {
+ start = fname;
+ }
+ else {
+ start++;
+ }
+
+ p->title = malloc (end-start+1);
+ memcpy (p->title, start, end-start);
+ p->title[end-start] = 0;
+ int err = deadbeef->dsp_preset_load (fname, &p->chain);
+ if (err != 0) {
+ dsp_preset_free (p);
+ return NULL;
+ }
+ return p;
+}
+
+int
+dsp_preset_save (ddb_dsp_preset_t *p, int overwrite) {
+ const char *confdir = deadbeef->get_config_dir ();
+ char path[1024];
+ if (snprintf (path, sizeof (path), "%s/presets", confdir) < 0) {
+ return -1;
+ }
+ mkdir (path, 0755);
+ if (snprintf (path, sizeof (path), "%s/presets/dsp", confdir) < 0) {
+ return -1;
+ }
+ mkdir (path, 0755);
+ if (snprintf (path, sizeof (path), "%s/presets/dsp/%s.txt", confdir, p->title) < 0) {
+ return -1;
+ }
+
+ if (!overwrite) {
+ FILE *fp = fopen (path, "rb");
+ if (fp) {
+ fclose (fp);
+ return -2;
+ }
+ }
+
+ return deadbeef->dsp_preset_save (path, p->chain);
+}
+
+static int dirent_alphasort (const struct dirent **a, const struct dirent **b) {
+ return strcmp ((*a)->d_name, (*b)->d_name);
+}
+
+int
+scandir_preset_filter (const struct dirent *ent) {
+ char *ext = strrchr (ent->d_name, '.');
+ if (ext && !strcasecmp (ext, ".txt")) {
+ return 1;
+ }
+ return 0;
+}
+
+int
+load_encoder_presets (void) {
+ ddb_encoder_preset_t *tail = NULL;
+ char path[1024];
+ if (snprintf (path, sizeof (path), "%s/presets/encoders", deadbeef->get_config_dir ()) < 0) {
+ return -1;
+ }
+ struct dirent **namelist = NULL;
+ int n = scandir (path, &namelist, scandir_preset_filter, dirent_alphasort);
+ int i;
+ for (i = 0; i < n; i++) {
+ char s[1024];
+ if (snprintf (s, sizeof (s), "%s/%s", path, namelist[i]->d_name) > 0){
+ ddb_encoder_preset_t *p = encoder_preset_load (s);
+ if (p) {
+ if (tail) {
+ tail->next = p;
+ tail = p;
+ }
+ else {
+ encoder_presets = tail = p;
+ }
+ }
+ }
+ free (namelist[i]);
+ }
+ free (namelist);
+ return 0;
+}
+
+int
+load_dsp_presets (void) {
+ ddb_dsp_preset_t *tail = NULL;
+ char path[1024];
+ if (snprintf (path, sizeof (path), "%s/presets/dsp", deadbeef->get_config_dir ()) < 0) {
+ return -1;
+ }
+ struct dirent **namelist = NULL;
+ int n = scandir (path, &namelist, scandir_preset_filter, dirent_alphasort);
+ int i;
+ for (i = 0; i < n; i++) {
+ char s[1024];
+ if (snprintf (s, sizeof (s), "%s/%s", path, namelist[i]->d_name) > 0){
+ ddb_dsp_preset_t *p = dsp_preset_load (s);
+ if (p) {
+ if (tail) {
+ tail->next = p;
+ tail = p;
+ }
+ else {
+ dsp_presets = tail = p;
+ }
+ }
+ }
+ free (namelist[i]);
+ }
+ free (namelist);
+ return 0;
+}
+
+ddb_dsp_preset_t *
+dsp_preset_get_for_idx (int idx) {
+ ddb_dsp_preset_t *p = dsp_presets;
+ while (p && idx--) {
+ p = p->next;
+ }
+ return p;
+}
+
+void
+dsp_preset_append (ddb_dsp_preset_t *p) {
+ // append
+ ddb_dsp_preset_t *tail = dsp_presets;
+ while (tail && tail->next) {
+ tail = tail->next;
+ }
+ if (tail) {
+ tail->next = p;
+ }
+ else {
+ dsp_presets = p;
+ }
+}
+
+void
+dsp_preset_remove (ddb_dsp_preset_t *p) {
+ ddb_dsp_preset_t *prev = dsp_presets;
+ while (prev && prev->next != p) {
+ prev = prev->next;
+ }
+ if (prev) {
+ prev->next = p->next;
+ }
+ else {
+ dsp_presets = p->next;
+ }
+}
+
+void
+dsp_preset_replace (ddb_dsp_preset_t *from, ddb_dsp_preset_t *to) {
+ ddb_dsp_preset_t *prev = dsp_presets;
+ while (prev && prev->next != from) {
+ prev = prev->next;
+ }
+ if (prev) {
+ prev->next = to;
+ }
+ else {
+ dsp_presets = to;
+ }
+ to->next = from->next;
+}
+
+static void
+get_output_path (DB_playItem_t *it, const char *outfolder, const char *outfile, ddb_encoder_preset_t *encoder_preset, char *out, int sz) {
+ char fname[PATH_MAX];
+ int idx = deadbeef->pl_get_idx_of (it);
+ deadbeef->pl_format_title (it, idx, fname, sizeof (fname), -1, outfile);
+ // replace invalid chars
+ char *p = fname;
+ char invalid[] = "/\\?%*:|\"<>";
+ while (*p) {
+ if (strchr (invalid, *p)) {
+ *p = '_';
+ }
+ p++;
+ }
+ snprintf (out, sz, "%s/%s.%s", outfolder, fname, encoder_preset->ext);
+
+}
+
+int
+convert (DB_playItem_t *it, const char *outfolder, const char *outfile, int output_bps, int output_is_float, int preserve_folder_structure, const char *root_folder, ddb_encoder_preset_t *encoder_preset, ddb_dsp_preset_t *dsp_preset, int *abort) {
+ int err = -1;
+ FILE *enc_pipe = NULL;
+ FILE *temp_file = NULL;
+ DB_decoder_t *dec = NULL;
+ DB_fileinfo_t *fileinfo = NULL;
+ char out[PATH_MAX] = ""; // full path to output file
+ char input_file_name[PATH_MAX] = "";
+ dec = (DB_decoder_t *)deadbeef->plug_get_for_id (deadbeef->pl_find_meta (it, ":DECODER"));
+
+ if (dec) {
+ fileinfo = dec->open (0);
+ if (fileinfo && dec->init (fileinfo, DB_PLAYITEM (it)) != 0) {
+ deadbeef->pl_lock ();
+ fprintf (stderr, "converter: failed to decode file %s\n", deadbeef->pl_find_meta (it, ":URI"));
+ deadbeef->pl_unlock ();
+ goto error;
+ }
+ if (fileinfo) {
+ if (output_bps == -1) {
+ output_bps = fileinfo->fmt.bps;
+ output_is_float = fileinfo->fmt.is_float;
+ }
+
+ get_output_path (it, outfolder, outfile, encoder_preset, out, sizeof (out));
+ if (encoder_preset->method == DDB_ENCODER_METHOD_FILE) {
+ const char *tmp = getenv ("TMPDIR");
+ if (!tmp) {
+ tmp = "/tmp";
+ }
+ snprintf (input_file_name, sizeof (input_file_name), "%s/ddbconvXXXXXX", tmp);
+ mktemp (input_file_name);
+ strcat (input_file_name, ".wav");
+ }
+ else {
+ strcpy (input_file_name, "-");
+ }
+
+ char enc[2000];
+
+ // formatting: %o = outfile, %i = infile
+ char *e = encoder_preset->encoder;
+ char *o = enc;
+ *o = 0;
+ int len = sizeof (enc);
+ while (e && *e) {
+ if (len <= 0) {
+ fprintf (stderr, "converter: failed to assemble encoder command line - buffer is not big enough, try to shorten your parameters. max allowed length is %d characters\n", sizeof (enc));
+ goto error;
+ }
+ if (e[0] == '%' && e[1]) {
+ if (e[1] == 'o') {
+ int l = snprintf (o, len, "\"%s\"", out);
+ o += l;
+ len -= l;
+ }
+ else if (e[1] == 'i') {
+ int l = snprintf (o, len, "\"%s\"", input_file_name);
+ o += l;
+ len -= l;
+ }
+ else {
+ strncpy (o, e, 2);
+ o += 2;
+ len -= 2;
+ }
+ e += 2;
+ }
+ else {
+ *o++ = *e++;
+ *o = 0;
+ len--;
+ }
+ }
+
+ fprintf (stderr, "converter: will encode using: %s\n", enc);
+
+ if (!encoder_preset->encoder[0]) {
+ // write to wave file
+ temp_file = fopen (out, "w+b");
+ if (!temp_file) {
+ fprintf (stderr, "converter: failed to open output wave file %s\n", out);
+ goto error;
+ }
+ }
+ else if (encoder_preset->method == DDB_ENCODER_METHOD_FILE) {
+ temp_file = fopen (input_file_name, "w+b");
+ if (!temp_file) {
+ fprintf (stderr, "converter: failed to open temp file %s\n", input_file_name);
+ goto error;
+ }
+ }
+ else {
+ enc_pipe = popen (enc, "w");
+ if (!enc_pipe) {
+ fprintf (stderr, "converter: failed to open encoder\n");
+ goto error;
+ }
+ }
+
+ if (!temp_file) {
+ temp_file = enc_pipe;
+ }
+
+ // write wave header
+ char wavehdr_int[] = {
+ 0x52, 0x49, 0x46, 0x46, 0x24, 0x70, 0x0d, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61
+ };
+ char wavehdr_float[] = {
+ 0x52, 0x49, 0x46, 0x46, 0x2a, 0xdf, 0x02, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20, 0x28, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x02, 0x00, 0x40, 0x1f, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x08, 0x00, 0x20, 0x00, 0x16, 0x00, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71, 0x66, 0x61, 0x63, 0x74, 0x04, 0x00, 0x00, 0x00, 0xc5, 0x5b, 0x00, 0x00, 0x64, 0x61, 0x74, 0x61
+ };
+ char *wavehdr = output_is_float ? wavehdr_float : wavehdr_int;
+ int wavehdr_size = output_is_float ? sizeof (wavehdr_float) : sizeof (wavehdr_int);
+ int header_written = 0;
+ uint32_t outsize = 0;
+ uint32_t outsr = fileinfo->fmt.samplerate;
+ uint16_t outch = fileinfo->fmt.channels;
+
+ int samplesize = fileinfo->fmt.channels * fileinfo->fmt.bps / 8;
+ int bs = 10250 * samplesize;
+ char buffer[bs * 4];
+ int dspsize = bs / samplesize * sizeof (float) * fileinfo->fmt.channels;
+ char dspbuffer[dspsize * 4];
+ int eof = 0;
+ for (;;) {
+ if (eof) {
+ break;
+ }
+ if (abort && *abort) {
+ break;
+ }
+ int sz = dec->read (fileinfo, buffer, bs);
+
+ if (sz != bs) {
+ eof = 1;
+ }
+ if (dsp_preset) {
+ ddb_waveformat_t fmt;
+ ddb_waveformat_t outfmt;
+ memcpy (&fmt, &fileinfo->fmt, sizeof (fmt));
+ memcpy (&outfmt, &fileinfo->fmt, sizeof (fmt));
+ fmt.bps = 32;
+ fmt.is_float = 1;
+ deadbeef->pcm_convert (&fileinfo->fmt, buffer, &fmt, dspbuffer, sz);
+
+ ddb_dsp_context_t *dsp = dsp_preset->chain;
+ int frames = sz / samplesize;
+ while (dsp) {
+ frames = dsp->plugin->process (dsp, (float *)dspbuffer, frames, sizeof (dspbuffer) / (fmt.channels * 4), &fmt, NULL);
+ dsp = dsp->next;
+ }
+
+ outsr = fmt.samplerate;
+ outch = fmt.channels;
+
+ outfmt.bps = output_bps;
+ outfmt.is_float = output_is_float;
+ outfmt.channels = outch;
+ outfmt.samplerate = outsr;
+
+ int n = deadbeef->pcm_convert (&fmt, dspbuffer, &outfmt, buffer, frames * sizeof (float) * fmt.channels);
+ sz = n;
+ }
+ else if (fileinfo->fmt.bps != output_bps || fileinfo->fmt.is_float != output_is_float) {
+ ddb_waveformat_t outfmt;
+ memcpy (&outfmt, &fileinfo->fmt, sizeof (outfmt));
+ outfmt.bps = output_bps;
+ outfmt.is_float = output_is_float;
+ outfmt.channels = outch;
+ outfmt.samplerate = outsr;
+
+ int frames = sz / samplesize;
+ int n = deadbeef->pcm_convert (&fileinfo->fmt, buffer, &outfmt, dspbuffer, frames * samplesize);
+ memcpy (buffer, dspbuffer, n);
+ sz = n;
+ }
+ outsize += sz;
+
+ if (!header_written) {
+ uint32_t size = (it->endsample-it->startsample) * outch * output_bps / 8;
+ if (!size) {
+ size = deadbeef->pl_get_item_duration (it) * fileinfo->fmt.samplerate * outch * output_bps / 8;
+
+ }
+
+ if (outsr != fileinfo->fmt.samplerate) {
+ uint64_t temp = size;
+ temp *= outsr;
+ temp /= fileinfo->fmt.samplerate;
+ size = temp;
+ }
+
+ memcpy (&wavehdr[22], &outch, 2);
+ memcpy (&wavehdr[24], &outsr, 4);
+ uint16_t blockalign = outch * output_bps / 8;
+ memcpy (&wavehdr[32], &blockalign, 2);
+ memcpy (&wavehdr[34], &output_bps, 2);
+
+ fwrite (wavehdr, 1, wavehdr_size, temp_file);
+ fwrite (&size, 1, sizeof (size), temp_file);
+ header_written = 1;
+ }
+
+ if (sz != fwrite (buffer, 1, sz, temp_file)) {
+ fprintf (stderr, "converter: write error\n");
+ goto error;
+ }
+ }
+ if (abort && *abort) {
+ goto error;
+ }
+ if (temp_file && temp_file != enc_pipe) {
+ fseek (temp_file, wavehdr_size, SEEK_SET);
+ fwrite (&outsize, 1, 4, temp_file);
+
+ fclose (temp_file);
+ temp_file = NULL;
+ }
+
+ if (encoder_preset->encoder[0] && encoder_preset->method == DDB_ENCODER_METHOD_FILE) {
+ enc_pipe = popen (enc, "w");
+ }
+ }
+ }
+ err = 0;
+error:
+ if (temp_file && temp_file != enc_pipe) {
+ fclose (temp_file);
+ temp_file = NULL;
+ }
+ if (enc_pipe) {
+ pclose (enc_pipe);
+ enc_pipe = NULL;
+ }
+ if (dec && fileinfo) {
+ dec->free (fileinfo);
+ fileinfo = NULL;
+ }
+ if (abort && *abort && out[0]) {
+ unlink (out);
+ }
+ if (input_file_name[0] && strcmp (input_file_name, "-")) {
+ unlink (input_file_name);
+ }
+
+ // write junklib tags
+ uint32_t tagflags = JUNK_STRIP_ID3V2 | JUNK_STRIP_APEV2 | JUNK_STRIP_ID3V1;
+ if (encoder_preset->tag_id3v2) {
+ tagflags |= JUNK_WRITE_ID3V2;
+ }
+ if (encoder_preset->tag_id3v1) {
+ tagflags |= JUNK_WRITE_ID3V1;
+ }
+ if (encoder_preset->tag_apev2) {
+ tagflags |= JUNK_WRITE_APEV2;
+ }
+ DB_playItem_t *out_it = deadbeef->pl_item_alloc ();
+ deadbeef->pl_item_copy (out_it, it);
+ deadbeef->pl_replace_meta (out_it, ":URI", out);
+ deadbeef->pl_delete_meta (out_it, "cuesheet");
+
+ deadbeef->junk_rewrite_tags (out_it, tagflags, encoder_preset->id3v2_version + 3, "iso8859-1");
+
+ // write flac tags
+ if (encoder_preset->tag_flac) {
+ // find flac decoder plugin
+ DB_decoder_t **plugs = deadbeef->plug_get_decoder_list ();
+ DB_decoder_t *flac = NULL;
+ for (int i = 0; plugs[i]; i++) {
+ if (!strcmp (plugs[i]->plugin.id, "stdflac")) {
+ flac = plugs[i];
+ break;
+ }
+ }
+ if (!flac) {
+ fprintf (stderr, "converter: flac plugin not found, cannot write flac metadata\n");
+ }
+ else {
+ if (0 != flac->write_metadata (out_it)) {
+ fprintf (stderr, "converter: failed to write flac metadata, not a flac file?\n");
+ }
+ }
+ }
+
+ // write vorbis tags
+ if (encoder_preset->tag_oggvorbis) {
+ // find flac decoder plugin
+ DB_decoder_t **plugs = deadbeef->plug_get_decoder_list ();
+ DB_decoder_t *ogg = NULL;
+ for (int i = 0; plugs[i]; i++) {
+ if (!strcmp (plugs[i]->plugin.id, "stdogg")) {
+ ogg = plugs[i];
+ break;
+ }
+ }
+ if (!ogg) {
+ fprintf (stderr, "converter: ogg plugin not found, cannot write ogg metadata\n");
+ }
+ else {
+ if (0 != ogg->write_metadata (out_it)) {
+ fprintf (stderr, "converter: failed to write ogg metadata, not an ogg file?\n");
+ }
+ }
+ }
+
+ deadbeef->pl_item_unref (out_it);
+
+
+ return err;
+}
+
+int
+converter_cmd (int cmd, ...) {
+ return -1;
+}
+
+int
+converter_start (void) {
+ load_encoder_presets ();
+ load_dsp_presets ();
+
+ return 0;
+}
+
+int
+converter_stop (void) {
+ return 0;
+}
+
+// define plugin interface
+static ddb_converter_t plugin = {
+ .misc.plugin.api_vmajor = DB_API_VERSION_MAJOR,
+ .misc.plugin.api_vminor = DB_API_VERSION_MINOR,
+ .misc.plugin.version_major = 1,
+ .misc.plugin.version_minor = 0,
+ .misc.plugin.type = DB_PLUGIN_MISC,
+ .misc.plugin.name = "Converter",
+ .misc.plugin.id = "converter",
+ .misc.plugin.descr = "Converts any supported formats to other formats.\n"
+ "Requires separate GUI plugin, e.g. Converter GTK UI\n",
+ .misc.plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
+ .misc.plugin.website = "http://deadbeef.sf.net",
+ .misc.plugin.start = converter_start,
+ .misc.plugin.stop = converter_stop,
+ .misc.plugin.command = converter_cmd,
+ .encoder_preset_alloc = encoder_preset_alloc,
+ .encoder_preset_free = encoder_preset_free,
+ .encoder_preset_load = encoder_preset_load,
+ .encoder_preset_save = encoder_preset_save,
+ .encoder_preset_copy = encoder_preset_copy,
+ .encoder_preset_get_list = encoder_preset_get_list,
+ .encoder_preset_get_for_idx = encoder_preset_get_for_idx,
+ .encoder_preset_append = encoder_preset_append,
+ .encoder_preset_remove = encoder_preset_remove,
+ .encoder_preset_replace = encoder_preset_replace,
+ .dsp_preset_alloc = dsp_preset_alloc,
+ .dsp_preset_free = dsp_preset_free,
+ .dsp_preset_load = dsp_preset_load,
+ .dsp_preset_save = dsp_preset_save,
+ .dsp_preset_copy = dsp_preset_copy,
+ .dsp_preset_get_list = dsp_preset_get_list,
+ .dsp_preset_get_for_idx = dsp_preset_get_for_idx,
+ .dsp_preset_append = dsp_preset_append,
+ .dsp_preset_remove = dsp_preset_remove,
+ .dsp_preset_replace = dsp_preset_replace,
+ .get_output_path = get_output_path,
+ .convert = convert,
+};
+
+DB_plugin_t *
+converter_load (DB_functions_t *api) {
+ deadbeef = api;
+ return DB_PLUGIN (&plugin);
+}
diff --git a/plugins/converter/converter.glade b/plugins/converter/converter.glade
new file mode 100644
index 00000000..fce698c5
--- /dev/null
+++ b/plugins/converter/converter.glade
@@ -0,0 +1,1839 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkDialog" id="converterdlg">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Converter</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">True</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox6">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area5">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="converter_cancel">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="converter_ok">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox26">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox67">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label103">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Output folder:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox68">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkEntry" id="output_folder">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">â—</property>
+ <property name="activates_default">False</property>
+ <signal name="changed" handler="on_output_folder_changed" last_modification_time="Sun, 13 Mar 2011 11:25:59 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="converter_output_browse">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">...</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_converter_output_browse_clicked" last_modification_time="Thu, 02 Dec 2010 19:59:50 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox100">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label122">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Output file name:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox101">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkEntry" id="output_file">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Extension (e.g. .mp3) will be appended automatically.
+Leave the field empty for default (%a - %t).</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">•</property>
+ <property name="activates_default">False</property>
+ <signal name="changed" handler="on_output_file_changed" last_modification_time="Sun, 13 Mar 2011 20:02:34 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="Custom" id="custom6">
+ <property name="visible">True</property>
+ <property name="creation_function">title_formatting_help_link_create</property>
+ <property name="int1">0</property>
+ <property name="int2">0</property>
+ <property name="last_modification_time">Fri, 03 Dec 2010 20:39:24 GMT</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox69">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label104">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Encoder:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox90">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkComboBox" id="encoder">
+ <property name="visible">True</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ <signal name="changed" handler="on_converter_encoder_changed" last_modification_time="Mon, 06 Dec 2010 20:55:31 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="edit_encoder_presets">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_edit_encoder_presets_clicked" last_modification_time="Sat, 04 Dec 2010 15:20:49 GMT"/>
+
+ <child>
+ <widget class="GtkImage" id="image469">
+ <property name="visible">True</property>
+ <property name="stock">gtk-edit</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox86">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label114">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">DSP preset:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox91">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkComboBox" id="dsp_preset">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes"></property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ <signal name="changed" handler="on_converter_dsp_preset_changed" last_modification_time="Wed, 08 Dec 2010 21:22:19 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="edit_dsp_presets">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_edit_dsp_presets_clicked" last_modification_time="Sat, 04 Dec 2010 15:20:53 GMT"/>
+
+ <child>
+ <widget class="GtkImage" id="image470">
+ <property name="visible">True</property>
+ <property name="stock">gtk-edit</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox88">
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label116">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Number of threads:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="numthreads">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">False</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">1 0 100 1 10 0</property>
+ <signal name="changed" handler="on_numthreads_changed" last_modification_time="Sun, 13 Mar 2011 11:26:21 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox89">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label117">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Output sample format:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="output_format">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">Keep source format
+8 bit signed int
+16 bit signed int
+24 bit signed int
+32 bit signed int
+32 bit float</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ <signal name="changed" handler="on_converter_output_format_changed" last_modification_time="Sun, 12 Dec 2010 16:55:42 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox99">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label121">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">When file exists:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="overwrite_action">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">Prompt
+Overwrite</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ <signal name="changed" handler="on_overwrite_action_changed" last_modification_time="Sun, 13 Mar 2011 11:26:30 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="preserve_folders">
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Preserve folder structure, starting from:</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_preserve_folders_toggled" last_modification_time="Sun, 13 Mar 2011 12:34:49 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox102">
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkEntry" id="preserve_root_folder">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">•</property>
+ <property name="activates_default">False</property>
+ <signal name="changed" handler="on_preserve_root_folder_changed" last_modification_time="Mon, 14 Mar 2011 21:00:54 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="preserve_folder_browse">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">...</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_preserve_folder_browse_clicked" last_modification_time="Sun, 13 Mar 2011 12:29:48 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="convpreset_editor">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Edit Encoder Preset</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">True</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox7">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area6">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="convpreset_cancel">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="convpreset_ok">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox27">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox70">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label105">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Title:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="title">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes">Untitled Encoder</property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">â—</property>
+ <property name="activates_default">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox96">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">9</property>
+
+ <child>
+ <widget class="GtkLabel" id="label120">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Output file extension:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="ext">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">E.g. mp3</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">â—</property>
+ <property name="activates_default">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox72">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label106">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Command line:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox93">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkEntry" id="encoder">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Example: lame - %o
+%i for input file, %o for output file, - for stdin</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">â—</property>
+ <property name="activates_default">True</property>
+ <signal name="changed" handler="on_encoder_changed" last_modification_time="Sun, 13 Mar 2011 11:48:10 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="Custom" id="custom4">
+ <property name="visible">True</property>
+ <property name="creation_function">encoder_cmdline_help_link_create</property>
+ <property name="int1">0</property>
+ <property name="int2">0</property>
+ <property name="last_modification_time">Sat, 04 Dec 2010 15:30:13 GMT</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label124">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;small&gt;%o - output file name
+%i - temporary input file name&lt;/small&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox73">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label107">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Method:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="method">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">Pipe
+Temporary file</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame9">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment21">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkTable" id="table2">
+ <property name="border_width">8</property>
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">0</property>
+ <property name="column_spacing">8</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="apev2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">APEv2</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="id3v1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">ID3v1</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="oggvorbis">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">OggVorbis</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="flac">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">FLAC</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox104">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="id3v2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">ID3v2</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="id3v2_version">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">2.3
+2.4</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label125">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Tag writer&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="dsppreset_editor">
+ <property name="width_request">468</property>
+ <property name="height_request">254</property>
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">DSP Preset Editor</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">True</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox9">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area8">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="cancelbutton6">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="okbutton6">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox30">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox81">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label111">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Title</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="title">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes">Untitled DSP Preset</property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">â—</property>
+ <property name="activates_default">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox29">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox82">
+ <property name="visible">True</property>
+ <property name="homogeneous">True</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkButton" id="add">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Add</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_dsp_preset_add_plugin_clicked" last_modification_time="Tue, 07 Dec 2010 20:11:31 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="remove">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Remove</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_dsp_preset_remove_plugin_clicked" last_modification_time="Tue, 07 Dec 2010 20:12:20 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="configure">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Configure</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_dsp_preset_plugin_configure_clicked" last_modification_time="Thu, 09 Dec 2010 20:31:42 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox98">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow7">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="plugins">
+ <property name="width_request">196</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox34">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkButton" id="up">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-go-up</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_dsp_preset_plugin_up_clicked" last_modification_time="Sun, 12 Dec 2010 13:42:49 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="down">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-go-down</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_dsp_preset_plugin_down_clicked" last_modification_time="Sun, 12 Dec 2010 13:42:59 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="select_dsp_plugin">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Select DSP Plugin</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">True</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox10">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area9">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="cancelbutton7">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="okbutton7">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox31">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox85">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label113">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Plugin</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="plugin">
+ <property name="visible">True</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="preset_list">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Presets</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">True</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox11">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area10">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="okbutton8">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-7</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox33">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox94">
+ <property name="visible">True</property>
+ <property name="homogeneous">True</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkButton" id="add">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-add</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="remove">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-remove</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="edit">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-edit</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow8">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="presets">
+ <property name="width_request">400</property>
+ <property name="height_request">176</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/plugins/converter/converter.gladep b/plugins/converter/converter.gladep
new file mode 100644
index 00000000..fc0e5ab2
--- /dev/null
+++ b/plugins/converter/converter.gladep
@@ -0,0 +1,11 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-project SYSTEM "http://glade.gnome.org/glade-project-2.0.dtd">
+
+<glade-project>
+ <name>converter</name>
+ <program_name>converter</program_name>
+ <source_directory></source_directory>
+ <gnome_support>FALSE</gnome_support>
+ <output_main_file>FALSE</output_main_file>
+ <output_build_files>FALSE</output_build_files>
+</glade-project>
diff --git a/plugins/converter/converter.h b/plugins/converter/converter.h
new file mode 100644
index 00000000..173d35b4
--- /dev/null
+++ b/plugins/converter/converter.h
@@ -0,0 +1,150 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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.
+*/
+#ifndef __CONVERTER_H
+#define __CONVERTER_H
+
+#include <stdint.h>
+#include <deadbeef.h>
+
+enum {
+ DDB_ENCODER_METHOD_PIPE = 0,
+ DDB_ENCODER_METHOD_FILE = 1,
+};
+
+enum {
+ DDB_ENCODER_FMT_8BIT = 0x1,
+ DDB_ENCODER_FMT_16BIT = 0x2,
+ DDB_ENCODER_FMT_24BIT = 0x4,
+ DDB_ENCODER_FMT_32BIT = 0x8,
+ DDB_ENCODER_FMT_32BITFLOAT = 0x10,
+};
+
+typedef struct ddb_preset_s {
+ char *title;
+ struct ddb_preset_s *next;
+} ddb_preset_t;
+
+typedef struct ddb_encoder_preset_s {
+ char *title;
+ struct ddb_encoder_preset_s *next;
+ char *ext;
+ char *encoder;
+ int method; // pipe or file
+ int tag_id3v2;
+ int tag_id3v1;
+ int tag_apev2;
+ int tag_flac;
+ int tag_oggvorbis;
+ int tag_mp3xing;
+ int id3v2_version;
+} ddb_encoder_preset_t;
+
+typedef struct ddb_dsp_preset_s {
+ char *title;
+ struct ddb_dsp_preset_s *next;
+ ddb_dsp_context_t *chain;
+} ddb_dsp_preset_t;
+
+typedef struct {
+ DB_misc_t misc;
+
+ /////////////////////////////
+ // encoder preset management
+ /////////////////////////////
+
+ ddb_encoder_preset_t *
+ (*encoder_preset_alloc) (void);
+
+ void
+ (*encoder_preset_free) (ddb_encoder_preset_t *p);
+
+ ddb_encoder_preset_t *
+ (*encoder_preset_load) (const char *fname);
+
+ // @return -1 on path/write error, -2 if file already exists
+ int
+ (*encoder_preset_save) (ddb_encoder_preset_t *p, int overwrite);
+
+ void
+ (*encoder_preset_copy) (ddb_encoder_preset_t *to, ddb_encoder_preset_t *from);
+
+ ddb_encoder_preset_t *
+ (*encoder_preset_get_list) (void);
+
+ ddb_encoder_preset_t *
+ (*encoder_preset_get_for_idx) (int idx);
+
+ void
+ (*encoder_preset_append) (ddb_encoder_preset_t *p);
+
+ void
+ (*encoder_preset_remove) (ddb_encoder_preset_t *p);
+
+ void
+ (*encoder_preset_replace) (ddb_encoder_preset_t *from, ddb_encoder_preset_t *to);
+
+ /////////////////////////////
+ // dsp preset management
+ /////////////////////////////
+
+ ddb_dsp_preset_t *
+ (*dsp_preset_alloc) (void);
+
+ void
+ (*dsp_preset_free) (ddb_dsp_preset_t *p);
+
+ ddb_dsp_preset_t *
+ (*dsp_preset_load) (const char *fname);
+
+ // @return -1 on path/write error, -2 if file already exists
+ int
+ (*dsp_preset_save) (ddb_dsp_preset_t *p, int overwrite);
+
+ void
+ (*dsp_preset_copy) (ddb_dsp_preset_t *to, ddb_dsp_preset_t *from);
+
+ ddb_dsp_preset_t *
+ (*dsp_preset_get_list) (void);
+
+ ddb_dsp_preset_t *
+ (*dsp_preset_get_for_idx) (int idx);
+
+ void
+ (*dsp_preset_append) (ddb_dsp_preset_t *p);
+
+ void
+ (*dsp_preset_remove) (ddb_dsp_preset_t *p);
+
+ void
+ (*dsp_preset_replace) (ddb_dsp_preset_t *from, ddb_dsp_preset_t *to);
+
+ /////////////////////////////
+ // converter
+ /////////////////////////////
+
+
+ void
+ (*get_output_path) (DB_playItem_t *it, const char *outfolder, const char *outfile, ddb_encoder_preset_t *encoder_preset, char *out, int sz);
+
+ int
+ (*convert) (DB_playItem_t *it, const char *outfolder, const char *outfile, int output_bps, int output_is_float, int preserve_folder_structure, const char *root_folder, ddb_encoder_preset_t *encoder_preset, ddb_dsp_preset_t *dsp_preset, int *abort);
+
+} ddb_converter_t;
+
+#endif
diff --git a/plugins/converter/convgui.c b/plugins/converter/convgui.c
new file mode 100644
index 00000000..286bfdd4
--- /dev/null
+++ b/plugins/converter/convgui.c
@@ -0,0 +1,1301 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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 <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include "converter.h"
+#include "support.h"
+#include "interface.h"
+#include "../gtkui/gtkui_api.h"
+
+DB_functions_t *deadbeef;
+
+ddb_converter_t *converter_plugin;
+ddb_gtkui_t *gtkui_plugin;
+
+typedef struct {
+ GtkWidget *converter;
+ ddb_encoder_preset_t *current_encoder_preset;
+ ddb_dsp_preset_t *current_dsp_preset;
+
+ DB_playItem_t **convert_items;
+ int convert_items_count;
+ char *outfolder;
+ char *outfile;
+ int preserve_folder_structure;
+ char *preserve_root_folder;
+ int output_bps;
+ int output_is_float;
+ int overwrite_action;
+ ddb_encoder_preset_t *encoder_preset;
+ ddb_dsp_preset_t *dsp_preset;
+ GtkWidget *progress;
+ GtkWidget *progress_entry;
+ int cancelled;
+ char *progress_text;
+} converter_ctx_t;
+
+converter_ctx_t *current_ctx;
+
+void
+fill_presets (GtkListStore *mdl, ddb_preset_t *head) {
+ ddb_preset_t *p = head;
+ while (p) {
+ GtkTreeIter iter;
+ gtk_list_store_append (mdl, &iter);
+ gtk_list_store_set (mdl, &iter, 0, p->title, -1);
+ p = p->next;
+ }
+}
+
+void
+on_converter_progress_cancel (GtkDialog *dialog, gint response_id, gpointer user_data) {
+ converter_ctx_t *ctx = user_data;
+ ctx->cancelled = 1;
+}
+
+typedef struct {
+ GtkWidget *entry;
+ char *text;
+} update_progress_info_t;
+
+static gboolean
+update_progress_cb (gpointer ctx) {
+ update_progress_info_t *info = ctx;
+ gtk_entry_set_text (GTK_ENTRY (info->entry), info->text);
+ free (info->text);
+ g_object_unref (info->entry);
+ free (info);
+ return FALSE;
+}
+
+static gboolean
+destroy_progress_cb (gpointer ctx) {
+ gtk_widget_destroy (ctx);
+ return FALSE;
+}
+
+struct overwrite_prompt_ctx {
+ char *fname;
+ uintptr_t mutex;
+ uintptr_t cond;
+ int result;
+};
+
+static gboolean
+overwrite_prompt_cb (void *ctx) {
+ struct overwrite_prompt_ctx *ctl = ctx;
+ GtkWidget *mainwin = gtkui_plugin->get_mainwin ();
+ GtkWidget *dlg = gtk_message_dialog_new (GTK_WINDOW (mainwin), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("The file already exists. Overwrite?"));
+ gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (mainwin));
+ gtk_window_set_title (GTK_WINDOW (dlg), _("Converter warning"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg), ctl->fname);
+
+ int response = gtk_dialog_run (GTK_DIALOG (dlg));
+ gtk_widget_destroy (dlg);
+ ctl->result = response == GTK_RESPONSE_YES ? 1 : 0;
+ deadbeef->cond_signal (ctl->cond);
+ return FALSE;
+}
+
+static void
+converter_worker (void *ctx) {
+ converter_ctx_t *conv = ctx;
+
+ for (int n = 0; n < conv->convert_items_count; n++) {
+ update_progress_info_t *info = malloc (sizeof (update_progress_info_t));
+ info->entry = conv->progress_entry;
+ g_object_ref (info->entry);
+ info->text = strdup (deadbeef->pl_find_meta (conv->convert_items[n], ":URI"));
+ g_idle_add (update_progress_cb, info);
+
+ char outpath[2000];
+ converter_plugin->get_output_path (conv->convert_items[n], conv->outfolder, conv->outfile, conv->encoder_preset, outpath, sizeof (outpath));
+
+ int skip = 0;
+ struct stat st;
+ int res = stat(outpath, &st);
+ if (res == 0) {
+ if (conv->overwrite_action > 1 || conv->overwrite_action < 0) {
+ conv->overwrite_action = 0;
+ }
+ if (conv->overwrite_action == 0) {
+ // prompt if file exists
+ struct overwrite_prompt_ctx ctl;
+ ctl.mutex = deadbeef->mutex_create ();
+ ctl.cond = deadbeef->cond_create ();
+ ctl.fname = outpath;
+ ctl.result = 0;
+ gdk_threads_add_idle (overwrite_prompt_cb, &ctl);
+ deadbeef->cond_wait (ctl.cond, ctl.mutex);
+ deadbeef->cond_free (ctl.cond);
+ deadbeef->mutex_free (ctl.mutex);
+ if (ctl.result) {
+ unlink (outpath);
+ }
+ else {
+ skip = 1;
+ }
+ }
+ else if (conv->overwrite_action == 1) {
+ unlink (outpath);
+ }
+ }
+
+ if (!skip) {
+ converter_plugin->convert (conv->convert_items[n], conv->outfolder, conv->outfile, conv->output_bps, conv->output_is_float, conv->preserve_folder_structure, conv->preserve_root_folder, conv->encoder_preset, conv->dsp_preset, &conv->cancelled);
+ }
+ if (conv->cancelled) {
+ for (; n < conv->convert_items_count; n++) {
+ deadbeef->pl_item_unref (conv->convert_items[n]);
+ }
+ break;
+ }
+ deadbeef->pl_item_unref (conv->convert_items[n]);
+ }
+ g_idle_add (destroy_progress_cb, conv->progress);
+ if (conv->convert_items) {
+ free (conv->convert_items);
+ }
+ free (conv->outfolder);
+ converter_plugin->encoder_preset_free (conv->encoder_preset);
+ converter_plugin->dsp_preset_free (conv->dsp_preset);
+ free (conv);
+}
+
+int
+converter_process (converter_ctx_t *conv)
+{
+ conv->outfolder = strdup (gtk_entry_get_text (GTK_ENTRY (lookup_widget (conv->converter, "output_folder"))));
+ const char *outfile = gtk_entry_get_text (GTK_ENTRY (lookup_widget (conv->converter, "output_file")));
+ if (outfile[0] == 0) {
+ outfile = "%a - %t";
+ }
+ conv->outfile = strdup (outfile);
+ conv->preserve_folder_structure = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (lookup_widget (conv->converter, "preserve_folders")));
+ conv->preserve_root_folder = strdup (gtk_entry_get_text (GTK_ENTRY (lookup_widget (conv->converter, "preserve_root_folder"))));
+ conv->overwrite_action = gtk_combo_box_get_active (GTK_COMBO_BOX (lookup_widget (conv->converter, "overwrite_action")));
+
+ GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (conv->converter, "output_format"));
+ int selected_format = gtk_combo_box_get_active (combo);
+ switch (selected_format) {
+ case 1 ... 4:
+ conv->output_bps = selected_format * 8;
+ conv->output_is_float = 0;
+ break;
+ case 5:
+ conv->output_bps = 32;
+ conv->output_is_float = 1;
+ break;
+ default:
+ conv->output_bps = -1; // same as input, or encoder default
+ break;
+ }
+
+ combo = GTK_COMBO_BOX (lookup_widget (conv->converter, "encoder"));
+ int enc_preset = gtk_combo_box_get_active (combo);
+ ddb_encoder_preset_t *encoder_preset = NULL;
+
+ if (enc_preset >= 0) {
+ encoder_preset = converter_plugin->encoder_preset_get_for_idx (enc_preset);
+ }
+ if (!encoder_preset) {
+ GtkWidget *dlg = gtk_message_dialog_new (GTK_WINDOW (conv->converter), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Please select encoder"));
+ gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (conv->converter));
+ gtk_window_set_title (GTK_WINDOW (dlg), _("Converter error"));
+
+ gtk_dialog_run (GTK_DIALOG (dlg));
+ gtk_widget_destroy (dlg);
+ return -1;
+ }
+
+ combo = GTK_COMBO_BOX (lookup_widget (conv->converter, "dsp_preset"));
+ int dsp_idx = gtk_combo_box_get_active (combo) - 1;
+
+ ddb_dsp_preset_t *dsp_preset = NULL;
+ if (dsp_idx >= 0) {
+ dsp_preset = converter_plugin->dsp_preset_get_for_idx (dsp_idx);
+ }
+
+ if (encoder_preset) {
+ conv->encoder_preset = converter_plugin->encoder_preset_alloc ();
+ converter_plugin->encoder_preset_copy (conv->encoder_preset, encoder_preset);
+ }
+ if (dsp_preset) {
+ conv->dsp_preset = converter_plugin->dsp_preset_alloc ();
+ converter_plugin->dsp_preset_copy (conv->dsp_preset, dsp_preset);
+ }
+
+ GtkWidget *progress = gtk_dialog_new_with_buttons (_("Converting..."), GTK_WINDOW (gtkui_plugin->get_mainwin ()), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
+ GtkWidget *vbox = GTK_DIALOG (progress)->vbox;
+ GtkWidget *entry = gtk_entry_new ();
+ gtk_widget_set_size_request (entry, 400, -1);
+ gtk_editable_set_editable (GTK_EDITABLE (entry), FALSE);
+ gtk_widget_show (entry);
+ gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 12);
+
+ g_signal_connect ((gpointer)progress, "response", G_CALLBACK (on_converter_progress_cancel), conv);
+
+ gtk_widget_show (progress);
+
+ conv->progress = progress;
+ conv->progress_entry = entry;
+ intptr_t tid = deadbeef->thread_start (converter_worker, conv);
+ deadbeef->thread_detach (tid);
+ return 0;
+}
+
+static int
+converter_show (DB_plugin_action_t *act, DB_playItem_t *it) {
+ converter_ctx_t *conv = malloc (sizeof (converter_ctx_t));
+ current_ctx = conv;
+ memset (conv, 0, sizeof (converter_ctx_t));
+
+ deadbeef->pl_lock ();
+ // copy list
+ int nsel = deadbeef->pl_getselcount ();
+ conv->convert_items_count = nsel;
+ if (0 < nsel) {
+ conv->convert_items = malloc (sizeof (DB_playItem_t *) * nsel);
+ if (conv->convert_items) {
+ int n = 0;
+ DB_playItem_t *it = deadbeef->pl_get_first (PL_MAIN);
+ while (it) {
+ if (deadbeef->pl_is_selected (it)) {
+ assert (n < nsel);
+ deadbeef->pl_item_ref (it);
+ conv->convert_items[n++] = it;
+ }
+ DB_playItem_t *next = deadbeef->pl_get_next (it, PL_MAIN);
+ deadbeef->pl_item_unref (it);
+ it = next;
+ }
+ }
+ }
+ deadbeef->pl_unlock ();
+
+ conv->converter = create_converterdlg ();
+ deadbeef->conf_lock ();
+ gtk_entry_set_text (GTK_ENTRY (lookup_widget (conv->converter, "output_folder")), deadbeef->conf_get_str_fast ("converter.output_folder", ""));
+ gtk_entry_set_text (GTK_ENTRY (lookup_widget (conv->converter, "output_file")), deadbeef->conf_get_str_fast ("converter.output_file", ""));
+ gtk_entry_set_text (GTK_ENTRY (lookup_widget (conv->converter, "preserve_root_folder")), deadbeef->conf_get_str_fast ("converter.preserve_root_folder", ""));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (conv->converter, "preserve_folders")), deadbeef->conf_get_int ("converter.preserve_folder_structure", 0));
+ gtk_combo_box_set_active (GTK_COMBO_BOX (lookup_widget (conv->converter, "overwrite_action")), deadbeef->conf_get_int ("converter.overwrite_action", 0));
+ deadbeef->conf_unlock ();
+
+ GtkComboBox *combo;
+ // fill encoder presets
+ combo = GTK_COMBO_BOX (lookup_widget (conv->converter, "encoder"));
+ GtkListStore *mdl = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
+ fill_presets (mdl, (ddb_preset_t *)converter_plugin->encoder_preset_get_list ());
+ gtk_combo_box_set_active (combo, deadbeef->conf_get_int ("converter.encoder_preset", 0));
+
+ // fill dsp presets
+ combo = GTK_COMBO_BOX (lookup_widget (conv->converter, "dsp_preset"));
+ mdl = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
+ GtkTreeIter iter;
+ gtk_list_store_append (mdl, &iter);
+ gtk_list_store_set (mdl, &iter, 0, "Pass through", -1);
+ fill_presets (mdl, (ddb_preset_t *)converter_plugin->dsp_preset_get_list ());
+
+ gtk_combo_box_set_active (combo, deadbeef->conf_get_int ("converter.dsp_preset", -1) + 1);
+
+ // select output format
+ combo = GTK_COMBO_BOX (lookup_widget (conv->converter, "output_format"));
+ gtk_combo_box_set_active (combo, deadbeef->conf_get_int ("converter.output_format", 0));
+
+ // overwrite action
+ combo = GTK_COMBO_BOX (lookup_widget (conv->converter, "overwrite_action"));
+ gtk_combo_box_set_active (combo, deadbeef->conf_get_int ("converter.overwrite_action", 0));
+
+ for (;;) {
+ int response = gtk_dialog_run (GTK_DIALOG (conv->converter));
+ if (response == GTK_RESPONSE_OK) {
+ int err = converter_process (conv);
+ if (err != 0) {
+ continue;
+ }
+ gtk_widget_destroy (conv->converter);
+ }
+ else {
+ // FIXME: clean up properly
+ gtk_widget_destroy (conv->converter);
+ if (conv->convert_items) {
+ for (int n = 0; n < conv->convert_items_count; n++) {
+ deadbeef->pl_item_unref (conv->convert_items[n]);
+ }
+ free (conv->convert_items);
+ }
+ free (conv);
+ }
+ current_ctx = NULL;
+ break;
+ }
+ return 0;
+}
+
+void
+on_converter_encoder_changed (GtkComboBox *combobox,
+ gpointer user_data)
+{
+ GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (current_ctx->converter, "encoder"));
+ int act = gtk_combo_box_get_active (combo);
+ deadbeef->conf_set_int ("converter.encoder_preset", act);
+}
+
+void
+on_converter_dsp_preset_changed (GtkComboBox *combobox,
+ gpointer user_data)
+{
+ GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (current_ctx->converter, "dsp_preset"));
+ int act = gtk_combo_box_get_active (combo);
+ deadbeef->conf_set_int ("converter.dsp_preset", act-1);
+}
+
+void
+on_converter_output_browse_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *dlg = gtk_file_chooser_dialog_new (_("Select folder..."), GTK_WINDOW (current_ctx->converter), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
+ gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (current_ctx->converter));
+
+ gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), FALSE);
+ // restore folder
+ deadbeef->conf_lock ();
+ gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str_fast ("filechooser.lastdir", ""));
+ deadbeef->conf_unlock ();
+ int response = gtk_dialog_run (GTK_DIALOG (dlg));
+ // store folder
+ gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
+ if (folder) {
+ deadbeef->conf_set_str ("filechooser.lastdir", folder);
+ g_free (folder);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
+ }
+ if (response == GTK_RESPONSE_OK) {
+ folder = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
+ gtk_widget_destroy (dlg);
+ if (folder) {
+ GtkWidget *entry = lookup_widget (current_ctx->converter, "output_folder");
+ gtk_entry_set_text (GTK_ENTRY (entry), folder);
+ g_free (folder);
+ }
+ }
+ else {
+ gtk_widget_destroy (dlg);
+ }
+}
+
+
+void
+on_output_folder_changed (GtkEntry *entry,
+ gpointer user_data)
+{
+ deadbeef->conf_set_str ("converter.output_folder", gtk_entry_get_text (entry));
+ deadbeef->conf_save ();
+}
+
+
+void
+on_numthreads_changed (GtkEditable *editable,
+ gpointer user_data)
+{
+ deadbeef->conf_set_int ("converter.threads", gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editable)));
+ deadbeef->conf_save ();
+}
+
+void
+on_overwrite_action_changed (GtkComboBox *combobox,
+ gpointer user_data)
+{
+ deadbeef->conf_set_int ("converter.overwrite_action", gtk_combo_box_get_active (combobox));
+ deadbeef->conf_save ();
+}
+
+void
+on_encoder_changed (GtkEditable *editable,
+ gpointer user_data)
+{
+ gtk_widget_set_has_tooltip (GTK_WIDGET (editable), TRUE);
+
+ char enc[2000];
+ const char *e = gtk_entry_get_text (GTK_ENTRY (editable));
+ char *o = enc;
+ *o = 0;
+ int len = sizeof (enc);
+ while (e && *e) {
+ if (len <= 0) {
+ break;
+ }
+ if (e[0] == '%' && e[1]) {
+ if (e[1] == 'o') {
+ int l = snprintf (o, len, "\"OUTPUT_FILE_NAME\"");
+ o += l;
+ len -= l;
+ }
+ else if (e[1] == 'i') {
+ int l = snprintf (o, len, "\"TEMP_FILE_NAME\"");
+ o += l;
+ len -= l;
+ }
+ else {
+ strncpy (o, e, 2);
+ o += 2;
+ len -= 2;
+ }
+ e += 2;
+ }
+ else {
+ *o++ = *e++;
+ *o = 0;
+ len--;
+ }
+ }
+
+ gtk_widget_set_tooltip_text (GTK_WIDGET (editable), enc);
+}
+
+void
+on_preserve_folder_browse_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *dlg = gtk_file_chooser_dialog_new (_("Select folder..."), GTK_WINDOW (current_ctx->converter), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
+ gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (current_ctx->converter));
+
+ gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), FALSE);
+ // restore folder
+ deadbeef->conf_lock ();
+ gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str_fast ("filechooser.lastdir", ""));
+ deadbeef->conf_unlock ();
+ int response = gtk_dialog_run (GTK_DIALOG (dlg));
+ // store folder
+ gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
+ if (folder) {
+ deadbeef->conf_set_str ("filechooser.lastdir", folder);
+ g_free (folder);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
+ }
+ if (response == GTK_RESPONSE_OK) {
+ folder = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
+ gtk_widget_destroy (dlg);
+ if (folder) {
+ GtkWidget *entry = lookup_widget (current_ctx->converter, "preserve_root_folder");
+ gtk_entry_set_text (GTK_ENTRY (entry), folder);
+ g_free (folder);
+ }
+ }
+ else {
+ gtk_widget_destroy (dlg);
+ }
+}
+
+void
+on_output_file_changed (GtkEntry *entry,
+ gpointer user_data)
+{
+ deadbeef->conf_set_str ("converter.output_file", gtk_entry_get_text (entry));
+ deadbeef->conf_save ();
+}
+
+void
+on_preserve_folders_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data)
+{
+ deadbeef->conf_set_int ("converter.preserve_folder_structure", gtk_toggle_button_get_active (togglebutton));
+ deadbeef->conf_save ();
+}
+
+void
+on_preserve_root_folder_changed (GtkEntry *entry,
+ gpointer user_data)
+{
+ deadbeef->conf_set_str ("converter.preserve_root_folder", gtk_entry_get_text (entry));
+ deadbeef->conf_save ();
+}
+
+DB_decoder_t *
+plug_get_decoder_for_id (const char *id) {
+ DB_decoder_t **plugins = deadbeef->plug_get_decoder_list ();
+ for (int c = 0; plugins[c]; c++) {
+ if (!strcmp (id, plugins[c]->plugin.id)) {
+ return plugins[c];
+ }
+ }
+ return NULL;
+}
+
+void
+init_encoder_preset_from_dlg (GtkWidget *dlg, ddb_encoder_preset_t *p) {
+ p->title = strdup (gtk_entry_get_text (GTK_ENTRY (lookup_widget (dlg, "title"))));
+ p->ext = strdup (gtk_entry_get_text (GTK_ENTRY (lookup_widget (dlg, "ext"))));
+ p->encoder = strdup (gtk_entry_get_text (GTK_ENTRY (lookup_widget (dlg, "encoder"))));
+ int method_idx = gtk_combo_box_get_active (GTK_COMBO_BOX (lookup_widget (dlg, "method")));
+ switch (method_idx) {
+ case 0:
+ p->method = DDB_ENCODER_METHOD_PIPE;
+ break;
+ case 1:
+ p->method = DDB_ENCODER_METHOD_FILE;
+ break;
+ }
+
+ p->id3v2_version = gtk_combo_box_get_active (GTK_COMBO_BOX (lookup_widget (dlg, "id3v2_version")));
+ p->tag_id3v2 = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "id3v2")));
+ p->tag_id3v1 = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "id3v1")));
+ p->tag_apev2 = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "apev2")));
+ p->tag_flac = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "flac")));
+ p->tag_oggvorbis = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "oggvorbis")));
+}
+
+int
+edit_encoder_preset (char *title, GtkWidget *toplevel, int overwrite) {
+ GtkWidget *dlg = create_convpreset_editor ();
+ gtk_window_set_title (GTK_WINDOW (dlg), title);
+ gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK);
+
+ gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (toplevel));
+
+ ddb_encoder_preset_t *p = current_ctx->current_encoder_preset;
+
+ if (p->title) {
+ gtk_entry_set_text (GTK_ENTRY (lookup_widget (dlg, "title")), p->title);
+ }
+ if (p->ext) {
+ gtk_entry_set_text (GTK_ENTRY (lookup_widget (dlg, "ext")), p->ext);
+ }
+ if (p->encoder) {
+ gtk_entry_set_text (GTK_ENTRY (lookup_widget (dlg, "encoder")), p->encoder);
+ }
+ gtk_combo_box_set_active (GTK_COMBO_BOX (lookup_widget (dlg, "method")), p->method);
+
+ gtk_combo_box_set_active (GTK_COMBO_BOX (lookup_widget (dlg, "id3v2_version")), p->id3v2_version);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "id3v2")), p->tag_id3v2);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "id3v1")), p->tag_id3v1);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "apev2")), p->tag_apev2);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "flac")), p->tag_flac);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "oggvorbis")), p->tag_oggvorbis);
+
+ ddb_encoder_preset_t *old = p;
+ int r = GTK_RESPONSE_CANCEL;
+ for (;;) {
+ r = gtk_dialog_run (GTK_DIALOG (dlg));
+ if (r == GTK_RESPONSE_OK) {
+ ddb_encoder_preset_t *p = converter_plugin->encoder_preset_alloc ();
+ if (p) {
+ init_encoder_preset_from_dlg (dlg, p);
+ int err = converter_plugin->encoder_preset_save (p, overwrite);
+ if (!err) {
+ if (old->title && strcmp (p->title, old->title)) {
+ char path[1024];
+ if (snprintf (path, sizeof (path), "%s/presets/encoders/%s.txt", deadbeef->get_config_dir (), old->title) > 0) {
+ unlink (path);
+ }
+ }
+ free (old->title);
+ free (old->ext);
+ free (old->encoder);
+
+ converter_plugin->encoder_preset_copy (old, p);
+ converter_plugin->encoder_preset_free (p);
+ }
+ else {
+ GtkWidget *warndlg = gtk_message_dialog_new (GTK_WINDOW (gtkui_plugin->get_mainwin ()), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Failed to save encoder preset"));
+ gtk_window_set_transient_for (GTK_WINDOW (warndlg), GTK_WINDOW (dlg));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (warndlg), err == -1 ? _("Check preset folder permissions, try to pick different title, or free up some disk space") : _("Preset with the same name already exists. Try to pick another title."));
+ gtk_window_set_title (GTK_WINDOW (warndlg), _("Error"));
+
+ /*int response = */gtk_dialog_run (GTK_DIALOG (warndlg));
+ gtk_widget_destroy (warndlg);
+ continue;
+ }
+ }
+ }
+ break;
+ }
+
+ gtk_widget_destroy (dlg);
+ return r;
+}
+
+void
+refresh_encoder_lists (GtkComboBox *combo, GtkTreeView *list) {
+ // presets list view
+ GtkListStore *mdl = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (list)));
+
+ GtkTreePath *path;
+ GtkTreeViewColumn *col;
+ gtk_tree_view_get_cursor (GTK_TREE_VIEW (list), &path, &col);
+ int idx = -1;
+ if (path && col) {
+ int *indices = gtk_tree_path_get_indices (path);
+ idx = *indices;
+ g_free (indices);
+ }
+
+ gtk_list_store_clear (mdl);
+ fill_presets (mdl, (ddb_preset_t *)converter_plugin->encoder_preset_get_list ());
+ if (idx != -1) {
+ path = gtk_tree_path_new_from_indices (idx, -1);
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, col, FALSE);
+ gtk_tree_path_free (path);
+ }
+
+ // presets combo box
+ int act = gtk_combo_box_get_active (combo);
+ mdl = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
+ gtk_list_store_clear (mdl);
+ fill_presets (mdl, (ddb_preset_t *)converter_plugin->encoder_preset_get_list ());
+ gtk_combo_box_set_active (combo, act);
+}
+
+void
+on_encoder_preset_add (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
+
+ current_ctx->current_encoder_preset = converter_plugin->encoder_preset_alloc ();
+
+ if (GTK_RESPONSE_OK == edit_encoder_preset (_("Add new encoder"), toplevel, 0)) {
+ printf ("added new enc preset\n");
+ converter_plugin->encoder_preset_append (current_ctx->current_encoder_preset);
+ GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (current_ctx->converter, "encoder"));
+ GtkWidget *list = lookup_widget (toplevel, "presets");
+ printf ("refresh list\n");
+ refresh_encoder_lists (combo, GTK_TREE_VIEW (list));
+ }
+
+ current_ctx->current_encoder_preset = NULL;
+}
+
+void
+on_encoder_preset_edit (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
+ GtkWidget *list = lookup_widget (toplevel, "presets");
+ GtkTreePath *path;
+ GtkTreeViewColumn *col;
+ gtk_tree_view_get_cursor (GTK_TREE_VIEW (list), &path, &col);
+ if (!path || !col) {
+ // nothing selected
+ return;
+ }
+ int *indices = gtk_tree_path_get_indices (path);
+ int idx = *indices;
+ g_free (indices);
+
+ ddb_encoder_preset_t *p = converter_plugin->encoder_preset_get_for_idx (idx);
+ current_ctx->current_encoder_preset = p;
+
+ int r = edit_encoder_preset (_("Edit encoder"), toplevel, 1);
+ if (r == GTK_RESPONSE_OK) {
+ GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (current_ctx->converter, "encoder"));
+ refresh_encoder_lists (combo, GTK_TREE_VIEW (list));
+ }
+
+ current_ctx->current_encoder_preset = NULL;
+}
+
+void
+on_encoder_preset_remove (GtkButton *button,
+ gpointer user_data)
+{
+
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
+ GtkWidget *list = lookup_widget (toplevel, "presets");
+ GtkTreePath *path;
+ GtkTreeViewColumn *col;
+ gtk_tree_view_get_cursor (GTK_TREE_VIEW (list), &path, &col);
+ if (!path || !col) {
+ // nothing selected
+ return;
+ }
+ int *indices = gtk_tree_path_get_indices (path);
+ int idx = *indices;
+ g_free (indices);
+
+ ddb_encoder_preset_t *p = converter_plugin->encoder_preset_get_for_idx (idx);
+ if (!p) {
+ return;
+ }
+
+ GtkWidget *dlg = gtk_message_dialog_new (GTK_WINDOW (gtkui_plugin->get_mainwin ()), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("Remove preset"));
+ gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (toplevel));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg), _("This action will delete the selected preset. Are you sure?"));
+ gtk_window_set_title (GTK_WINDOW (dlg), _("Warning"));
+
+ int response = gtk_dialog_run (GTK_DIALOG (dlg));
+ gtk_widget_destroy (dlg);
+ if (response == GTK_RESPONSE_YES) {
+ char path[1024];
+ if (snprintf (path, sizeof (path), "%s/presets/encoders/%s.txt", deadbeef->get_config_dir (), p->title) > 0) {
+ unlink (path);
+ }
+
+ converter_plugin->encoder_preset_remove (p);
+ converter_plugin->encoder_preset_free (p);
+
+ GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (current_ctx->converter, "encoder"));
+ refresh_encoder_lists (combo, GTK_TREE_VIEW (list));
+ }
+}
+
+void
+on_edit_encoder_presets_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *dlg = create_preset_list ();
+ gtk_window_set_title (GTK_WINDOW (dlg), _("Encoders"));
+ gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (current_ctx->converter));
+ g_signal_connect ((gpointer)lookup_widget (dlg, "add"), "clicked", G_CALLBACK (on_encoder_preset_add), NULL);
+ g_signal_connect ((gpointer)lookup_widget (dlg, "remove"), "clicked", G_CALLBACK (on_encoder_preset_remove), NULL);
+ g_signal_connect ((gpointer)lookup_widget (dlg, "edit"), "clicked", G_CALLBACK (on_encoder_preset_edit), NULL);
+
+ GtkWidget *list = lookup_widget (dlg, "presets");
+ GtkCellRenderer *title_cell = gtk_cell_renderer_text_new ();
+ GtkTreeViewColumn *col = gtk_tree_view_column_new_with_attributes (_("Title"), title_cell, "text", 0, NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (list), GTK_TREE_VIEW_COLUMN (col));
+ GtkListStore *mdl = gtk_list_store_new (1, G_TYPE_STRING);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (list), GTK_TREE_MODEL (mdl));
+ fill_presets (mdl, (ddb_preset_t *)converter_plugin->encoder_preset_get_list ());
+ int curr = deadbeef->conf_get_int ("converter.encoder_preset", -1);
+ if (curr != -1) {
+ GtkTreePath *path = gtk_tree_path_new_from_indices (curr, -1);
+ if (path && gtk_tree_path_get_depth (path) > 0) {
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, col, FALSE);
+ gtk_tree_path_free (path);
+ }
+ }
+ gtk_dialog_run (GTK_DIALOG (dlg));
+ gtk_widget_destroy (dlg);
+}
+
+///// dsp preset gui
+
+void
+fill_dsp_plugin_list (GtkListStore *mdl) {
+ struct DB_dsp_s **dsp = deadbeef->plug_get_dsp_list ();
+ int i;
+ for (i = 0; dsp[i]; i++) {
+ GtkTreeIter iter;
+ gtk_list_store_append (mdl, &iter);
+ gtk_list_store_set (mdl, &iter, 0, dsp[i]->plugin.name, -1);
+ }
+}
+
+void
+fill_dsp_preset_chain (GtkListStore *mdl) {
+ ddb_dsp_context_t *dsp = current_ctx->current_dsp_preset->chain;
+ while (dsp) {
+ GtkTreeIter iter;
+ gtk_list_store_append (mdl, &iter);
+ gtk_list_store_set (mdl, &iter, 0, dsp->plugin->plugin.name, -1);
+ dsp = dsp->next;
+ }
+}
+
+void
+on_dsp_preset_add_plugin_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *dlg = create_select_dsp_plugin ();
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
+ gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (toplevel));
+ gtk_window_set_title (GTK_WINDOW (dlg), _("Add plugin to DSP chain"));
+
+ GtkComboBox *combo;
+ // fill encoder presets
+ combo = GTK_COMBO_BOX (lookup_widget (dlg, "plugin"));
+ GtkListStore *mdl = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
+ fill_dsp_plugin_list (mdl);
+ gtk_combo_box_set_active (combo, deadbeef->conf_get_int ("converter.last_selected_dsp", 0));
+
+ int r = gtk_dialog_run (GTK_DIALOG (dlg));
+ if (r == GTK_RESPONSE_OK) {
+ // create new instance of the selected plugin
+ int idx = gtk_combo_box_get_active (combo);
+ struct DB_dsp_s **dsp = deadbeef->plug_get_dsp_list ();
+ int i;
+ ddb_dsp_context_t *inst = NULL;
+ for (i = 0; dsp[i]; i++) {
+ if (i == idx) {
+ inst = dsp[i]->open ();
+ break;
+ }
+ }
+ if (inst) {
+ // append to DSP chain
+ ddb_dsp_context_t *tail = current_ctx->current_dsp_preset->chain;
+ while (tail && tail->next) {
+ tail = tail->next;
+ }
+ if (tail) {
+ tail->next = inst;
+ }
+ else {
+ current_ctx->current_dsp_preset->chain = inst;
+ }
+
+ // reinit list of instances
+ GtkWidget *list = lookup_widget (toplevel, "plugins");
+ GtkListStore *mdl = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW(list)));
+ gtk_list_store_clear (mdl);
+ fill_dsp_preset_chain (mdl);
+ }
+ else {
+ fprintf (stderr, "converter: failed to add DSP plugin to chain\n");
+ }
+ }
+ gtk_widget_destroy (dlg);
+}
+
+
+void
+on_dsp_preset_remove_plugin_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
+ GtkWidget *list = lookup_widget (toplevel, "plugins");
+ GtkTreePath *path;
+ GtkTreeViewColumn *col;
+ gtk_tree_view_get_cursor (GTK_TREE_VIEW (list), &path, &col);
+ if (!path || !col) {
+ // nothing selected
+ return;
+ }
+ int *indices = gtk_tree_path_get_indices (path);
+ int idx = *indices;
+ g_free (indices);
+ if (idx == -1) {
+ return;
+ }
+
+ ddb_dsp_context_t *p = current_ctx->current_dsp_preset->chain;
+ ddb_dsp_context_t *prev = NULL;
+ int i = idx;
+ while (p && i--) {
+ prev = p;
+ p = p->next;
+ }
+ if (p) {
+ if (prev) {
+ prev->next = p->next;
+ }
+ else {
+ current_ctx->current_dsp_preset->chain = p->next;
+ }
+ p->plugin->close (p);
+ GtkListStore *mdl = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW(list)));
+ gtk_list_store_clear (mdl);
+ fill_dsp_preset_chain (mdl);
+ path = gtk_tree_path_new_from_indices (idx, -1);
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, col, FALSE);
+ gtk_tree_path_free (path);
+ }
+}
+
+static ddb_dsp_context_t *current_dsp_context = NULL;
+
+void
+dsp_ctx_set_param (const char *key, const char *value) {
+ current_dsp_context->plugin->set_param (current_dsp_context, atoi (key), value);
+}
+
+void
+dsp_ctx_get_param (const char *key, char *value, int len, const char *def) {
+ strncpy (value, def, len);
+ current_dsp_context->plugin->get_param (current_dsp_context, atoi (key), value, len);
+}
+
+void
+on_dsp_preset_plugin_configure_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
+ GtkWidget *list = lookup_widget (toplevel, "plugins");
+ GtkTreePath *path;
+ GtkTreeViewColumn *col;
+ gtk_tree_view_get_cursor (GTK_TREE_VIEW (list), &path, &col);
+ if (!path || !col) {
+ // nothing selected
+ return;
+ }
+ int *indices = gtk_tree_path_get_indices (path);
+ int idx = *indices;
+ g_free (indices);
+ if (idx == -1) {
+ return;
+ }
+ ddb_dsp_context_t *p = current_ctx->current_dsp_preset->chain;
+ int i = idx;
+ while (p && i--) {
+ p = p->next;
+ }
+ if (!p || !p->plugin->configdialog) {
+ return;
+ }
+ current_dsp_context = p;
+ ddb_dialog_t conf = {
+ .title = p->plugin->plugin.name,
+ .layout = p->plugin->configdialog,
+ .set_param = dsp_ctx_set_param,
+ .get_param = dsp_ctx_get_param,
+ };
+ gtkui_plugin->gui.run_dialog (&conf, 0, NULL, NULL);
+ current_dsp_context = NULL;
+}
+
+void
+on_dsp_preset_plugin_up_clicked (GtkButton *button,
+ gpointer user_data)
+{
+
+}
+
+
+void
+on_dsp_preset_plugin_down_clicked (GtkButton *button,
+ gpointer user_data)
+{
+
+}
+
+
+int
+edit_dsp_preset (const char *title, GtkWidget *toplevel, int overwrite) {
+ int r = GTK_RESPONSE_CANCEL;
+
+ GtkWidget *dlg = create_dsppreset_editor ();
+ gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK);
+ gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (toplevel));
+ gtk_window_set_title (GTK_WINDOW (dlg), title);
+
+
+ // title
+ if (current_ctx->current_dsp_preset->title) {
+ gtk_entry_set_text (GTK_ENTRY (lookup_widget (dlg, "title")), current_ctx->current_dsp_preset->title);
+ }
+
+ {
+ GtkWidget *list = lookup_widget (dlg, "plugins");
+ GtkCellRenderer *title_cell = gtk_cell_renderer_text_new ();
+ GtkTreeViewColumn *col = gtk_tree_view_column_new_with_attributes (_("Plugin"), title_cell, "text", 0, NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (list), GTK_TREE_VIEW_COLUMN (col));
+ GtkListStore *mdl = gtk_list_store_new (1, G_TYPE_STRING);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (list), GTK_TREE_MODEL (mdl));
+
+ fill_dsp_preset_chain (mdl);
+ }
+
+ for (;;) {
+ r = gtk_dialog_run (GTK_DIALOG (dlg));
+
+ if (r == GTK_RESPONSE_OK) {
+ if (current_ctx->current_dsp_preset->title) {
+ free (current_ctx->current_dsp_preset->title);
+ }
+ current_ctx->current_dsp_preset->title = strdup (gtk_entry_get_text (GTK_ENTRY (lookup_widget (dlg, "title"))));
+ int err = converter_plugin->dsp_preset_save (current_ctx->current_dsp_preset, overwrite);
+ if (err < 0) {
+ GtkWidget *warndlg = gtk_message_dialog_new (GTK_WINDOW (gtkui_plugin->get_mainwin ()), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Failed to save DSP preset"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (warndlg), err == -1 ? _("Check preset folder permissions, try to pick different title, or free up some disk space") : _("Preset with the same name already exists. Try to pick another title."));
+ gtk_window_set_title (GTK_WINDOW (warndlg), _("Error"));
+
+ gtk_window_set_transient_for (GTK_WINDOW (warndlg), GTK_WINDOW (dlg));
+ /*int response = */gtk_dialog_run (GTK_DIALOG (warndlg));
+ gtk_widget_destroy (warndlg);
+ continue;
+ }
+
+ }
+
+ break;
+ }
+
+ gtk_widget_destroy (dlg);
+ return r;
+}
+
+void
+refresh_dsp_lists (GtkComboBox *combo, GtkTreeView *list) {
+ // presets list view
+ GtkListStore *mdl = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (list)));
+
+ GtkTreePath *path;
+ GtkTreeViewColumn *col;
+ int idx = -1;
+
+ gtk_tree_view_get_cursor (GTK_TREE_VIEW (list), &path, &col);
+ if (path && col) {
+ int *indices = gtk_tree_path_get_indices (path);
+ idx = *indices;
+ g_free (indices);
+ }
+
+ gtk_list_store_clear (mdl);
+ fill_presets (mdl, (ddb_preset_t *)converter_plugin->dsp_preset_get_list ());
+ if (idx != -1) {
+ path = gtk_tree_path_new_from_indices (idx, -1);
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, col, FALSE);
+ gtk_tree_path_free (path);
+ }
+
+ // presets combo box
+ int act = gtk_combo_box_get_active (combo);
+ mdl = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
+ gtk_list_store_clear (mdl);
+ GtkTreeIter iter;
+ gtk_list_store_append (mdl, &iter);
+ gtk_list_store_set (mdl, &iter, 0, "Pass through", -1);
+ fill_presets (mdl, (ddb_preset_t *)converter_plugin->dsp_preset_get_list ());
+ gtk_combo_box_set_active (combo, act);
+}
+
+
+void
+on_dsp_preset_add (GtkButton *button,
+ gpointer user_data)
+{
+
+ current_ctx->current_dsp_preset = converter_plugin->dsp_preset_alloc ();
+
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
+
+ if (GTK_RESPONSE_OK == edit_dsp_preset (_("New DSP Preset"), toplevel, 0)) {
+ converter_plugin->dsp_preset_append (current_ctx->current_dsp_preset);
+ GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (current_ctx->converter, "dsp_preset"));
+ GtkWidget *list = lookup_widget (toplevel, "presets");
+ refresh_dsp_lists (combo, GTK_TREE_VIEW (list));
+ }
+ else {
+ converter_plugin->dsp_preset_free (current_ctx->current_dsp_preset);
+ }
+
+ current_ctx->current_dsp_preset = NULL;
+}
+
+void
+on_dsp_preset_remove (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
+ GtkWidget *list = lookup_widget (toplevel, "presets");
+ GtkTreePath *path;
+ GtkTreeViewColumn *col;
+ gtk_tree_view_get_cursor (GTK_TREE_VIEW (list), &path, &col);
+ if (!path || !col) {
+ // nothing selected
+ return;
+ }
+ int *indices = gtk_tree_path_get_indices (path);
+ int idx = *indices;
+ g_free (indices);
+
+ ddb_dsp_preset_t *p = converter_plugin->dsp_preset_get_for_idx (idx);
+ if (!p) {
+ return;
+ }
+
+ GtkWidget *dlg = gtk_message_dialog_new (GTK_WINDOW (gtkui_plugin->get_mainwin ()), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("Remove preset"));
+ gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (toplevel));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg), _("This action will delete the selected preset. Are you sure?"));
+ gtk_window_set_title (GTK_WINDOW (dlg), _("Warning"));
+
+ int response = gtk_dialog_run (GTK_DIALOG (dlg));
+ gtk_widget_destroy (dlg);
+ if (response == GTK_RESPONSE_YES) {
+ char path[1024];
+ if (snprintf (path, sizeof (path), "%s/presets/dsp/%s.txt", deadbeef->get_config_dir (), p->title) > 0) {
+ unlink (path);
+ }
+
+ converter_plugin->dsp_preset_remove (p);
+ converter_plugin->dsp_preset_free (p);
+
+ GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (current_ctx->converter, "dsp_preset"));
+ refresh_dsp_lists (combo, GTK_TREE_VIEW (list));
+ }
+}
+
+void
+on_dsp_preset_edit (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
+
+ GtkWidget *list = lookup_widget (toplevel, "presets");
+ GtkTreePath *path;
+ GtkTreeViewColumn *col;
+ gtk_tree_view_get_cursor (GTK_TREE_VIEW (list), &path, &col);
+ if (!path || !col) {
+ // nothing selected
+ return;
+ }
+ int *indices = gtk_tree_path_get_indices (path);
+ int idx = *indices;
+ g_free (indices);
+ if (idx == -1) {
+ return;
+ }
+ if (idx == 0) {
+ return;
+ }
+
+ ddb_dsp_preset_t *p = converter_plugin->dsp_preset_get_for_idx (idx);
+ if (!p) {
+ return;
+ }
+
+ current_ctx->current_dsp_preset = converter_plugin->dsp_preset_alloc ();
+ converter_plugin->dsp_preset_copy (current_ctx->current_dsp_preset, p);
+
+ int r = edit_dsp_preset (_("Edit DSP Preset"), toplevel, 1);
+ if (r == GTK_RESPONSE_OK) {
+ // replace preset
+ converter_plugin->dsp_preset_replace (p, current_ctx->current_dsp_preset);
+ converter_plugin->dsp_preset_free (p);
+ GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (current_ctx->converter, "dsp_preset"));
+ refresh_dsp_lists (combo, GTK_TREE_VIEW (list));
+ }
+ else {
+ converter_plugin->dsp_preset_free (current_ctx->current_dsp_preset);
+ }
+
+ current_ctx->current_dsp_preset = NULL;
+}
+
+void
+on_edit_dsp_presets_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *dlg = create_preset_list ();
+ gtk_window_set_title (GTK_WINDOW (dlg), _("DSP Presets"));
+ gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (current_ctx->converter));
+ g_signal_connect ((gpointer)lookup_widget (dlg, "add"), "clicked", G_CALLBACK (on_dsp_preset_add), NULL);
+ g_signal_connect ((gpointer)lookup_widget (dlg, "remove"), "clicked", G_CALLBACK (on_dsp_preset_remove), NULL);
+ g_signal_connect ((gpointer)lookup_widget (dlg, "edit"), "clicked", G_CALLBACK (on_dsp_preset_edit), NULL);
+
+ GtkWidget *list = lookup_widget (dlg, "presets");
+ GtkCellRenderer *title_cell = gtk_cell_renderer_text_new ();
+ GtkTreeViewColumn *col = gtk_tree_view_column_new_with_attributes (_("Title"), title_cell, "text", 0, NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (list), GTK_TREE_VIEW_COLUMN (col));
+ GtkListStore *mdl = gtk_list_store_new (1, G_TYPE_STRING);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (list), GTK_TREE_MODEL (mdl));
+ fill_presets (mdl, (ddb_preset_t *)converter_plugin->dsp_preset_get_list ());
+ int curr = deadbeef->conf_get_int ("converter.dsp_preset", -1);
+ if (curr >= 0) {
+ GtkTreePath *path = gtk_tree_path_new_from_indices (curr, -1);
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, col, FALSE);
+ gtk_tree_path_free (path);
+ }
+ gtk_dialog_run (GTK_DIALOG (dlg));
+ gtk_widget_destroy (dlg);
+}
+
+
+void
+on_converter_output_format_changed (GtkComboBox *combobox,
+ gpointer user_data)
+{
+ int idx = gtk_combo_box_get_active (combobox);
+ deadbeef->conf_set_int ("converter.output_format", idx);
+}
+
+GtkWidget*
+title_formatting_help_link_create (gchar *widget_name, gchar *string1, gchar *string2,
+ gint int1, gint int2)
+{
+ GtkWidget *link = gtk_link_button_new_with_label ("http://sourceforge.net/apps/mediawiki/deadbeef/index.php?title=Title_Formatting", "Help");
+ return link;
+}
+
+GtkWidget*
+encoder_cmdline_help_link_create (gchar *widget_name, gchar *string1, gchar *string2,
+ gint int1, gint int2)
+{
+ GtkWidget *link = gtk_link_button_new_with_label ("http://sourceforge.net/apps/mediawiki/deadbeef/index.php?title=Encoder_Command_Line", "Help");
+ return link;
+}
+
+static DB_plugin_action_t convert_action = {
+ .title = "Convert",
+ .name = "convert",
+ .flags = DB_ACTION_CAN_MULTIPLE_TRACKS | DB_ACTION_ALLOW_MULTIPLE_TRACKS | DB_ACTION_SINGLE_TRACK,
+ .callback = converter_show,
+ .next = NULL
+};
+
+static DB_plugin_action_t *
+convgui_get_actions (DB_playItem_t *it)
+{
+ return &convert_action;
+}
+
+int
+convgui_connect (void) {
+ gtkui_plugin = (ddb_gtkui_t *)deadbeef->plug_get_for_id ("gtkui");
+ converter_plugin = (ddb_converter_t *)deadbeef->plug_get_for_id ("converter");
+ if (!gtkui_plugin || !converter_plugin) {
+ return -1;
+ }
+ return 0;
+}
+
+DB_misc_t plugin = {
+ DB_PLUGIN_SET_API_VERSION
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
+ .plugin.type = DB_PLUGIN_MISC,
+ .plugin.name = "Converter GTK UI",
+ .plugin.descr = "GTK2 User interface for the Converter plugin\n"
+ "Usage:\n"
+ "· select some tracks in playlist\n"
+ "· right click\n"
+ "· select «Convert»",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
+ .plugin.website = "http://deadbeef.sf.net",
+ .plugin.get_actions = convgui_get_actions,
+ .plugin.connect = convgui_connect,
+};
+
+DB_plugin_t *
+converter_gtkui_load (DB_functions_t *api) {
+ deadbeef = api;
+ return DB_PLUGIN (&plugin);
+}
+
diff --git a/plugins/converter/interface.c b/plugins/converter/interface.c
new file mode 100644
index 00000000..5045a79d
--- /dev/null
+++ b/plugins/converter/interface.c
@@ -0,0 +1,890 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "callbacks.h"
+#include "interface.h"
+#include "support.h"
+
+#define GLADE_HOOKUP_OBJECT(component,widget,name) \
+ g_object_set_data_full (G_OBJECT (component), name, \
+ gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)
+
+#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \
+ g_object_set_data (G_OBJECT (component), name, widget)
+
+GtkWidget*
+create_converterdlg (void)
+{
+ GtkWidget *converterdlg;
+ GtkWidget *dialog_vbox6;
+ GtkWidget *vbox26;
+ GtkWidget *hbox67;
+ GtkWidget *label103;
+ GtkWidget *hbox68;
+ GtkWidget *output_folder;
+ GtkWidget *converter_output_browse;
+ GtkWidget *hbox100;
+ GtkWidget *label122;
+ GtkWidget *hbox101;
+ GtkWidget *output_file;
+ GtkWidget *custom6;
+ GtkWidget *hbox69;
+ GtkWidget *label104;
+ GtkWidget *hbox90;
+ GtkWidget *encoder;
+ GtkWidget *edit_encoder_presets;
+ GtkWidget *image469;
+ GtkWidget *hbox86;
+ GtkWidget *label114;
+ GtkWidget *hbox91;
+ GtkWidget *dsp_preset;
+ GtkWidget *edit_dsp_presets;
+ GtkWidget *image470;
+ GtkWidget *hbox88;
+ GtkWidget *label116;
+ GtkObject *numthreads_adj;
+ GtkWidget *numthreads;
+ GtkWidget *hbox89;
+ GtkWidget *label117;
+ GtkWidget *output_format;
+ GtkWidget *hbox99;
+ GtkWidget *label121;
+ GtkWidget *overwrite_action;
+ GtkWidget *preserve_folders;
+ GtkWidget *hbox102;
+ GtkWidget *preserve_root_folder;
+ GtkWidget *preserve_folder_browse;
+ GtkWidget *dialog_action_area5;
+ GtkWidget *converter_cancel;
+ GtkWidget *converter_ok;
+ GtkTooltips *tooltips;
+
+ tooltips = gtk_tooltips_new ();
+
+ converterdlg = gtk_dialog_new ();
+ gtk_window_set_title (GTK_WINDOW (converterdlg), _("Converter"));
+ gtk_window_set_modal (GTK_WINDOW (converterdlg), TRUE);
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (converterdlg), TRUE);
+ gtk_window_set_type_hint (GTK_WINDOW (converterdlg), GDK_WINDOW_TYPE_HINT_DIALOG);
+ gtk_dialog_set_has_separator (GTK_DIALOG (converterdlg), FALSE);
+
+ dialog_vbox6 = GTK_DIALOG (converterdlg)->vbox;
+ gtk_widget_show (dialog_vbox6);
+
+ vbox26 = gtk_vbox_new (FALSE, 8);
+ gtk_widget_show (vbox26);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox6), vbox26, TRUE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox26), 12);
+
+ hbox67 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox67);
+ gtk_box_pack_start (GTK_BOX (vbox26), hbox67, FALSE, TRUE, 0);
+
+ label103 = gtk_label_new (_("Output folder:"));
+ gtk_widget_show (label103);
+ gtk_box_pack_start (GTK_BOX (hbox67), label103, FALSE, FALSE, 0);
+
+ hbox68 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (hbox68);
+ gtk_box_pack_start (GTK_BOX (hbox67), hbox68, TRUE, TRUE, 0);
+
+ output_folder = gtk_entry_new ();
+ gtk_widget_show (output_folder);
+ gtk_box_pack_start (GTK_BOX (hbox68), output_folder, TRUE, TRUE, 0);
+ gtk_entry_set_invisible_char (GTK_ENTRY (output_folder), 9679);
+
+ converter_output_browse = gtk_button_new_with_mnemonic (_("..."));
+ gtk_widget_show (converter_output_browse);
+ gtk_box_pack_start (GTK_BOX (hbox68), converter_output_browse, FALSE, FALSE, 0);
+
+ hbox100 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox100);
+ gtk_box_pack_start (GTK_BOX (vbox26), hbox100, TRUE, TRUE, 0);
+
+ label122 = gtk_label_new (_("Output file name:"));
+ gtk_widget_show (label122);
+ gtk_box_pack_start (GTK_BOX (hbox100), label122, FALSE, FALSE, 0);
+
+ hbox101 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (hbox101);
+ gtk_box_pack_start (GTK_BOX (hbox100), hbox101, TRUE, TRUE, 0);
+
+ output_file = gtk_entry_new ();
+ gtk_widget_show (output_file);
+ gtk_box_pack_start (GTK_BOX (hbox101), output_file, TRUE, TRUE, 0);
+ gtk_tooltips_set_tip (tooltips, output_file, _("Extension (e.g. .mp3) will be appended automatically.\nLeave the field empty for default (%a - %t)."), NULL);
+ gtk_entry_set_invisible_char (GTK_ENTRY (output_file), 8226);
+
+ custom6 = title_formatting_help_link_create ("custom6", "", "", 0, 0);
+ gtk_widget_show (custom6);
+ gtk_box_pack_start (GTK_BOX (hbox101), custom6, TRUE, TRUE, 0);
+ GTK_WIDGET_UNSET_FLAGS (custom6, GTK_CAN_FOCUS);
+ GTK_WIDGET_UNSET_FLAGS (custom6, GTK_CAN_DEFAULT);
+
+ hbox69 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox69);
+ gtk_box_pack_start (GTK_BOX (vbox26), hbox69, FALSE, FALSE, 0);
+
+ label104 = gtk_label_new (_("Encoder:"));
+ gtk_widget_show (label104);
+ gtk_box_pack_start (GTK_BOX (hbox69), label104, FALSE, FALSE, 0);
+
+ hbox90 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (hbox90);
+ gtk_box_pack_start (GTK_BOX (hbox69), hbox90, TRUE, TRUE, 0);
+
+ encoder = gtk_combo_box_new_text ();
+ gtk_widget_show (encoder);
+ gtk_box_pack_start (GTK_BOX (hbox90), encoder, TRUE, TRUE, 0);
+
+ edit_encoder_presets = gtk_button_new ();
+ gtk_widget_show (edit_encoder_presets);
+ gtk_box_pack_start (GTK_BOX (hbox90), edit_encoder_presets, FALSE, FALSE, 0);
+
+ image469 = gtk_image_new_from_stock ("gtk-edit", GTK_ICON_SIZE_BUTTON);
+ gtk_widget_show (image469);
+ gtk_container_add (GTK_CONTAINER (edit_encoder_presets), image469);
+
+ hbox86 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox86);
+ gtk_box_pack_start (GTK_BOX (vbox26), hbox86, FALSE, TRUE, 0);
+
+ label114 = gtk_label_new (_("DSP preset:"));
+ gtk_widget_show (label114);
+ gtk_box_pack_start (GTK_BOX (hbox86), label114, FALSE, FALSE, 0);
+
+ hbox91 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (hbox91);
+ gtk_box_pack_start (GTK_BOX (hbox86), hbox91, TRUE, TRUE, 0);
+
+ dsp_preset = gtk_combo_box_new_text ();
+ gtk_widget_show (dsp_preset);
+ gtk_box_pack_start (GTK_BOX (hbox91), dsp_preset, TRUE, TRUE, 0);
+
+ edit_dsp_presets = gtk_button_new ();
+ gtk_widget_show (edit_dsp_presets);
+ gtk_box_pack_start (GTK_BOX (hbox91), edit_dsp_presets, FALSE, FALSE, 0);
+
+ image470 = gtk_image_new_from_stock ("gtk-edit", GTK_ICON_SIZE_BUTTON);
+ gtk_widget_show (image470);
+ gtk_container_add (GTK_CONTAINER (edit_dsp_presets), image470);
+
+ hbox88 = gtk_hbox_new (FALSE, 8);
+ gtk_box_pack_start (GTK_BOX (vbox26), hbox88, FALSE, TRUE, 0);
+
+ label116 = gtk_label_new (_("Number of threads:"));
+ gtk_widget_show (label116);
+ gtk_box_pack_start (GTK_BOX (hbox88), label116, FALSE, FALSE, 0);
+
+ numthreads_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 0);
+ numthreads = gtk_spin_button_new (GTK_ADJUSTMENT (numthreads_adj), 1, 0);
+ gtk_widget_show (numthreads);
+ gtk_box_pack_start (GTK_BOX (hbox88), numthreads, TRUE, TRUE, 0);
+
+ hbox89 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox89);
+ gtk_box_pack_start (GTK_BOX (vbox26), hbox89, FALSE, TRUE, 0);
+
+ label117 = gtk_label_new (_("Output sample format:"));
+ gtk_widget_show (label117);
+ gtk_box_pack_start (GTK_BOX (hbox89), label117, FALSE, FALSE, 0);
+
+ output_format = gtk_combo_box_new_text ();
+ gtk_widget_show (output_format);
+ gtk_box_pack_start (GTK_BOX (hbox89), output_format, TRUE, TRUE, 0);
+ gtk_combo_box_append_text (GTK_COMBO_BOX (output_format), _("Keep source format"));
+ gtk_combo_box_append_text (GTK_COMBO_BOX (output_format), _("8 bit signed int"));
+ gtk_combo_box_append_text (GTK_COMBO_BOX (output_format), _("16 bit signed int"));
+ gtk_combo_box_append_text (GTK_COMBO_BOX (output_format), _("24 bit signed int"));
+ gtk_combo_box_append_text (GTK_COMBO_BOX (output_format), _("32 bit signed int"));
+ gtk_combo_box_append_text (GTK_COMBO_BOX (output_format), _("32 bit float"));
+
+ hbox99 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox99);
+ gtk_box_pack_start (GTK_BOX (vbox26), hbox99, TRUE, TRUE, 0);
+
+ label121 = gtk_label_new (_("When file exists:"));
+ gtk_widget_show (label121);
+ gtk_box_pack_start (GTK_BOX (hbox99), label121, FALSE, FALSE, 0);
+
+ overwrite_action = gtk_combo_box_new_text ();
+ gtk_widget_show (overwrite_action);
+ gtk_box_pack_start (GTK_BOX (hbox99), overwrite_action, TRUE, TRUE, 0);
+ gtk_combo_box_append_text (GTK_COMBO_BOX (overwrite_action), _("Prompt"));
+ gtk_combo_box_append_text (GTK_COMBO_BOX (overwrite_action), _("Overwrite"));
+
+ preserve_folders = gtk_check_button_new_with_mnemonic (_("Preserve folder structure, starting from:"));
+ gtk_box_pack_start (GTK_BOX (vbox26), preserve_folders, FALSE, FALSE, 0);
+
+ hbox102 = gtk_hbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox26), hbox102, TRUE, TRUE, 0);
+
+ preserve_root_folder = gtk_entry_new ();
+ gtk_widget_show (preserve_root_folder);
+ gtk_box_pack_start (GTK_BOX (hbox102), preserve_root_folder, TRUE, TRUE, 0);
+ gtk_entry_set_invisible_char (GTK_ENTRY (preserve_root_folder), 8226);
+
+ preserve_folder_browse = gtk_button_new_with_mnemonic (_("..."));
+ gtk_widget_show (preserve_folder_browse);
+ gtk_box_pack_start (GTK_BOX (hbox102), preserve_folder_browse, FALSE, FALSE, 0);
+
+ dialog_action_area5 = GTK_DIALOG (converterdlg)->action_area;
+ gtk_widget_show (dialog_action_area5);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area5), GTK_BUTTONBOX_END);
+
+ converter_cancel = gtk_button_new_from_stock ("gtk-cancel");
+ gtk_widget_show (converter_cancel);
+ gtk_dialog_add_action_widget (GTK_DIALOG (converterdlg), converter_cancel, GTK_RESPONSE_CANCEL);
+ GTK_WIDGET_SET_FLAGS (converter_cancel, GTK_CAN_DEFAULT);
+
+ converter_ok = gtk_button_new_from_stock ("gtk-ok");
+ gtk_widget_show (converter_ok);
+ gtk_dialog_add_action_widget (GTK_DIALOG (converterdlg), converter_ok, GTK_RESPONSE_OK);
+ GTK_WIDGET_SET_FLAGS (converter_ok, GTK_CAN_DEFAULT);
+
+ g_signal_connect ((gpointer) output_folder, "changed",
+ G_CALLBACK (on_output_folder_changed),
+ NULL);
+ g_signal_connect ((gpointer) converter_output_browse, "clicked",
+ G_CALLBACK (on_converter_output_browse_clicked),
+ NULL);
+ g_signal_connect ((gpointer) output_file, "changed",
+ G_CALLBACK (on_output_file_changed),
+ NULL);
+ g_signal_connect ((gpointer) encoder, "changed",
+ G_CALLBACK (on_converter_encoder_changed),
+ NULL);
+ g_signal_connect ((gpointer) edit_encoder_presets, "clicked",
+ G_CALLBACK (on_edit_encoder_presets_clicked),
+ NULL);
+ g_signal_connect ((gpointer) dsp_preset, "changed",
+ G_CALLBACK (on_converter_dsp_preset_changed),
+ NULL);
+ g_signal_connect ((gpointer) edit_dsp_presets, "clicked",
+ G_CALLBACK (on_edit_dsp_presets_clicked),
+ NULL);
+ g_signal_connect ((gpointer) numthreads, "changed",
+ G_CALLBACK (on_numthreads_changed),
+ NULL);
+ g_signal_connect ((gpointer) output_format, "changed",
+ G_CALLBACK (on_converter_output_format_changed),
+ NULL);
+ g_signal_connect ((gpointer) overwrite_action, "changed",
+ G_CALLBACK (on_overwrite_action_changed),
+ NULL);
+ g_signal_connect ((gpointer) preserve_folders, "toggled",
+ G_CALLBACK (on_preserve_folders_toggled),
+ NULL);
+ g_signal_connect ((gpointer) preserve_root_folder, "changed",
+ G_CALLBACK (on_preserve_root_folder_changed),
+ NULL);
+ g_signal_connect ((gpointer) preserve_folder_browse, "clicked",
+ G_CALLBACK (on_preserve_folder_browse_clicked),
+ NULL);
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT_NO_REF (converterdlg, converterdlg, "converterdlg");
+ GLADE_HOOKUP_OBJECT_NO_REF (converterdlg, dialog_vbox6, "dialog_vbox6");
+ GLADE_HOOKUP_OBJECT (converterdlg, vbox26, "vbox26");
+ GLADE_HOOKUP_OBJECT (converterdlg, hbox67, "hbox67");
+ GLADE_HOOKUP_OBJECT (converterdlg, label103, "label103");
+ GLADE_HOOKUP_OBJECT (converterdlg, hbox68, "hbox68");
+ GLADE_HOOKUP_OBJECT (converterdlg, output_folder, "output_folder");
+ GLADE_HOOKUP_OBJECT (converterdlg, converter_output_browse, "converter_output_browse");
+ GLADE_HOOKUP_OBJECT (converterdlg, hbox100, "hbox100");
+ GLADE_HOOKUP_OBJECT (converterdlg, label122, "label122");
+ GLADE_HOOKUP_OBJECT (converterdlg, hbox101, "hbox101");
+ GLADE_HOOKUP_OBJECT (converterdlg, output_file, "output_file");
+ GLADE_HOOKUP_OBJECT (converterdlg, custom6, "custom6");
+ GLADE_HOOKUP_OBJECT (converterdlg, hbox69, "hbox69");
+ GLADE_HOOKUP_OBJECT (converterdlg, label104, "label104");
+ GLADE_HOOKUP_OBJECT (converterdlg, hbox90, "hbox90");
+ GLADE_HOOKUP_OBJECT (converterdlg, encoder, "encoder");
+ GLADE_HOOKUP_OBJECT (converterdlg, edit_encoder_presets, "edit_encoder_presets");
+ GLADE_HOOKUP_OBJECT (converterdlg, image469, "image469");
+ GLADE_HOOKUP_OBJECT (converterdlg, hbox86, "hbox86");
+ GLADE_HOOKUP_OBJECT (converterdlg, label114, "label114");
+ GLADE_HOOKUP_OBJECT (converterdlg, hbox91, "hbox91");
+ GLADE_HOOKUP_OBJECT (converterdlg, dsp_preset, "dsp_preset");
+ GLADE_HOOKUP_OBJECT (converterdlg, edit_dsp_presets, "edit_dsp_presets");
+ GLADE_HOOKUP_OBJECT (converterdlg, image470, "image470");
+ GLADE_HOOKUP_OBJECT (converterdlg, hbox88, "hbox88");
+ GLADE_HOOKUP_OBJECT (converterdlg, label116, "label116");
+ GLADE_HOOKUP_OBJECT (converterdlg, numthreads, "numthreads");
+ GLADE_HOOKUP_OBJECT (converterdlg, hbox89, "hbox89");
+ GLADE_HOOKUP_OBJECT (converterdlg, label117, "label117");
+ GLADE_HOOKUP_OBJECT (converterdlg, output_format, "output_format");
+ GLADE_HOOKUP_OBJECT (converterdlg, hbox99, "hbox99");
+ GLADE_HOOKUP_OBJECT (converterdlg, label121, "label121");
+ GLADE_HOOKUP_OBJECT (converterdlg, overwrite_action, "overwrite_action");
+ GLADE_HOOKUP_OBJECT (converterdlg, preserve_folders, "preserve_folders");
+ GLADE_HOOKUP_OBJECT (converterdlg, hbox102, "hbox102");
+ GLADE_HOOKUP_OBJECT (converterdlg, preserve_root_folder, "preserve_root_folder");
+ GLADE_HOOKUP_OBJECT (converterdlg, preserve_folder_browse, "preserve_folder_browse");
+ GLADE_HOOKUP_OBJECT_NO_REF (converterdlg, dialog_action_area5, "dialog_action_area5");
+ GLADE_HOOKUP_OBJECT (converterdlg, converter_cancel, "converter_cancel");
+ GLADE_HOOKUP_OBJECT (converterdlg, converter_ok, "converter_ok");
+ GLADE_HOOKUP_OBJECT_NO_REF (converterdlg, tooltips, "tooltips");
+
+ return converterdlg;
+}
+
+GtkWidget*
+create_convpreset_editor (void)
+{
+ GtkWidget *convpreset_editor;
+ GtkWidget *dialog_vbox7;
+ GtkWidget *vbox27;
+ GtkWidget *hbox70;
+ GtkWidget *label105;
+ GtkWidget *title;
+ GtkWidget *hbox96;
+ GtkWidget *label120;
+ GtkWidget *ext;
+ GtkWidget *hbox72;
+ GtkWidget *label106;
+ GtkWidget *hbox93;
+ GtkWidget *encoder;
+ GtkWidget *custom4;
+ GtkWidget *label124;
+ GtkWidget *hbox73;
+ GtkWidget *label107;
+ GtkWidget *method;
+ GtkWidget *frame9;
+ GtkWidget *alignment21;
+ GtkWidget *table2;
+ GtkWidget *apev2;
+ GtkWidget *id3v1;
+ GtkWidget *oggvorbis;
+ GtkWidget *flac;
+ GtkWidget *hbox104;
+ GtkWidget *id3v2;
+ GtkWidget *id3v2_version;
+ GtkWidget *label125;
+ GtkWidget *dialog_action_area6;
+ GtkWidget *convpreset_cancel;
+ GtkWidget *convpreset_ok;
+ GtkTooltips *tooltips;
+
+ tooltips = gtk_tooltips_new ();
+
+ convpreset_editor = gtk_dialog_new ();
+ gtk_window_set_title (GTK_WINDOW (convpreset_editor), _("Edit Encoder Preset"));
+ gtk_window_set_modal (GTK_WINDOW (convpreset_editor), TRUE);
+ gtk_window_set_type_hint (GTK_WINDOW (convpreset_editor), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+ dialog_vbox7 = GTK_DIALOG (convpreset_editor)->vbox;
+ gtk_widget_show (dialog_vbox7);
+
+ vbox27 = gtk_vbox_new (FALSE, 8);
+ gtk_widget_show (vbox27);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox7), vbox27, TRUE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox27), 12);
+
+ hbox70 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox70);
+ gtk_box_pack_start (GTK_BOX (vbox27), hbox70, FALSE, TRUE, 0);
+
+ label105 = gtk_label_new (_("Title:"));
+ gtk_widget_show (label105);
+ gtk_box_pack_start (GTK_BOX (hbox70), label105, FALSE, FALSE, 0);
+
+ title = gtk_entry_new ();
+ gtk_widget_show (title);
+ gtk_box_pack_start (GTK_BOX (hbox70), title, TRUE, TRUE, 0);
+ gtk_entry_set_text (GTK_ENTRY (title), _("Untitled Encoder"));
+ gtk_entry_set_invisible_char (GTK_ENTRY (title), 9679);
+ gtk_entry_set_activates_default (GTK_ENTRY (title), TRUE);
+
+ hbox96 = gtk_hbox_new (FALSE, 9);
+ gtk_widget_show (hbox96);
+ gtk_box_pack_start (GTK_BOX (vbox27), hbox96, FALSE, TRUE, 0);
+
+ label120 = gtk_label_new (_("Output file extension:"));
+ gtk_widget_show (label120);
+ gtk_box_pack_start (GTK_BOX (hbox96), label120, FALSE, FALSE, 0);
+
+ ext = gtk_entry_new ();
+ gtk_widget_show (ext);
+ gtk_box_pack_start (GTK_BOX (hbox96), ext, TRUE, TRUE, 0);
+ gtk_tooltips_set_tip (tooltips, ext, _("E.g. mp3"), NULL);
+ gtk_entry_set_invisible_char (GTK_ENTRY (ext), 9679);
+ gtk_entry_set_activates_default (GTK_ENTRY (ext), TRUE);
+
+ hbox72 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox72);
+ gtk_box_pack_start (GTK_BOX (vbox27), hbox72, FALSE, TRUE, 0);
+
+ label106 = gtk_label_new (_("Command line:"));
+ gtk_widget_show (label106);
+ gtk_box_pack_start (GTK_BOX (hbox72), label106, FALSE, FALSE, 0);
+
+ hbox93 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (hbox93);
+ gtk_box_pack_start (GTK_BOX (hbox72), hbox93, TRUE, TRUE, 0);
+
+ encoder = gtk_entry_new ();
+ gtk_widget_show (encoder);
+ gtk_box_pack_start (GTK_BOX (hbox93), encoder, TRUE, TRUE, 0);
+ gtk_tooltips_set_tip (tooltips, encoder, _("Example: lame - %o\n%i for input file, %o for output file, - for stdin"), NULL);
+ gtk_entry_set_invisible_char (GTK_ENTRY (encoder), 9679);
+ gtk_entry_set_activates_default (GTK_ENTRY (encoder), TRUE);
+
+ custom4 = encoder_cmdline_help_link_create ("custom4", "", "", 0, 0);
+ gtk_widget_show (custom4);
+ gtk_box_pack_start (GTK_BOX (hbox93), custom4, TRUE, TRUE, 0);
+ GTK_WIDGET_UNSET_FLAGS (custom4, GTK_CAN_FOCUS);
+ GTK_WIDGET_UNSET_FLAGS (custom4, GTK_CAN_DEFAULT);
+
+ label124 = gtk_label_new (_("<small>%o - output file name\n%i - temporary input file name</small>"));
+ gtk_widget_show (label124);
+ gtk_box_pack_start (GTK_BOX (vbox27), label124, FALSE, FALSE, 0);
+ gtk_label_set_use_markup (GTK_LABEL (label124), TRUE);
+
+ hbox73 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox73);
+ gtk_box_pack_start (GTK_BOX (vbox27), hbox73, FALSE, TRUE, 0);
+
+ label107 = gtk_label_new (_("Method:"));
+ gtk_widget_show (label107);
+ gtk_box_pack_start (GTK_BOX (hbox73), label107, FALSE, FALSE, 0);
+
+ method = gtk_combo_box_new_text ();
+ gtk_widget_show (method);
+ gtk_box_pack_start (GTK_BOX (hbox73), method, TRUE, TRUE, 0);
+ gtk_combo_box_append_text (GTK_COMBO_BOX (method), _("Pipe"));
+ gtk_combo_box_append_text (GTK_COMBO_BOX (method), _("Temporary file"));
+
+ frame9 = gtk_frame_new (NULL);
+ gtk_widget_show (frame9);
+ gtk_box_pack_start (GTK_BOX (vbox27), frame9, FALSE, FALSE, 0);
+
+ alignment21 = gtk_alignment_new (0.5, 0.5, 1, 1);
+ gtk_widget_show (alignment21);
+ gtk_container_add (GTK_CONTAINER (frame9), alignment21);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment21), 0, 0, 12, 0);
+
+ table2 = gtk_table_new (2, 3, FALSE);
+ gtk_widget_show (table2);
+ gtk_container_add (GTK_CONTAINER (alignment21), table2);
+ gtk_container_set_border_width (GTK_CONTAINER (table2), 8);
+ gtk_table_set_col_spacings (GTK_TABLE (table2), 8);
+
+ apev2 = gtk_check_button_new_with_mnemonic (_("APEv2"));
+ gtk_widget_show (apev2);
+ gtk_table_attach (GTK_TABLE (table2), apev2, 1, 2, 0, 1,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ id3v1 = gtk_check_button_new_with_mnemonic (_("ID3v1"));
+ gtk_widget_show (id3v1);
+ gtk_table_attach (GTK_TABLE (table2), id3v1, 2, 3, 0, 1,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ oggvorbis = gtk_check_button_new_with_mnemonic (_("OggVorbis"));
+ gtk_widget_show (oggvorbis);
+ gtk_table_attach (GTK_TABLE (table2), oggvorbis, 2, 3, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ flac = gtk_check_button_new_with_mnemonic (_("FLAC"));
+ gtk_widget_show (flac);
+ gtk_table_attach (GTK_TABLE (table2), flac, 1, 2, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ hbox104 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (hbox104);
+ gtk_table_attach (GTK_TABLE (table2), hbox104, 0, 1, 0, 1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (GTK_FILL), 0, 0);
+
+ id3v2 = gtk_check_button_new_with_mnemonic (_("ID3v2"));
+ gtk_widget_show (id3v2);
+ gtk_box_pack_start (GTK_BOX (hbox104), id3v2, FALSE, FALSE, 0);
+
+ id3v2_version = gtk_combo_box_new_text ();
+ gtk_widget_show (id3v2_version);
+ gtk_box_pack_start (GTK_BOX (hbox104), id3v2_version, TRUE, TRUE, 0);
+ gtk_combo_box_append_text (GTK_COMBO_BOX (id3v2_version), _("2.3"));
+ gtk_combo_box_append_text (GTK_COMBO_BOX (id3v2_version), _("2.4"));
+
+ label125 = gtk_label_new (_("<b>Tag writer</b>"));
+ gtk_widget_show (label125);
+ gtk_frame_set_label_widget (GTK_FRAME (frame9), label125);
+ gtk_label_set_use_markup (GTK_LABEL (label125), TRUE);
+
+ dialog_action_area6 = GTK_DIALOG (convpreset_editor)->action_area;
+ gtk_widget_show (dialog_action_area6);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area6), GTK_BUTTONBOX_END);
+
+ convpreset_cancel = gtk_button_new_from_stock ("gtk-cancel");
+ gtk_widget_show (convpreset_cancel);
+ gtk_dialog_add_action_widget (GTK_DIALOG (convpreset_editor), convpreset_cancel, GTK_RESPONSE_CANCEL);
+ GTK_WIDGET_SET_FLAGS (convpreset_cancel, GTK_CAN_DEFAULT);
+
+ convpreset_ok = gtk_button_new_from_stock ("gtk-ok");
+ gtk_widget_show (convpreset_ok);
+ gtk_dialog_add_action_widget (GTK_DIALOG (convpreset_editor), convpreset_ok, GTK_RESPONSE_OK);
+ GTK_WIDGET_SET_FLAGS (convpreset_ok, GTK_CAN_DEFAULT);
+
+ g_signal_connect ((gpointer) encoder, "changed",
+ G_CALLBACK (on_encoder_changed),
+ NULL);
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT_NO_REF (convpreset_editor, convpreset_editor, "convpreset_editor");
+ GLADE_HOOKUP_OBJECT_NO_REF (convpreset_editor, dialog_vbox7, "dialog_vbox7");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, vbox27, "vbox27");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, hbox70, "hbox70");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, label105, "label105");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, title, "title");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, hbox96, "hbox96");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, label120, "label120");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, ext, "ext");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, hbox72, "hbox72");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, label106, "label106");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, hbox93, "hbox93");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, encoder, "encoder");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, custom4, "custom4");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, label124, "label124");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, hbox73, "hbox73");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, label107, "label107");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, method, "method");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, frame9, "frame9");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, alignment21, "alignment21");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, table2, "table2");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, apev2, "apev2");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, id3v1, "id3v1");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, oggvorbis, "oggvorbis");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, flac, "flac");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, hbox104, "hbox104");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, id3v2, "id3v2");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, id3v2_version, "id3v2_version");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, label125, "label125");
+ GLADE_HOOKUP_OBJECT_NO_REF (convpreset_editor, dialog_action_area6, "dialog_action_area6");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, convpreset_cancel, "convpreset_cancel");
+ GLADE_HOOKUP_OBJECT (convpreset_editor, convpreset_ok, "convpreset_ok");
+ GLADE_HOOKUP_OBJECT_NO_REF (convpreset_editor, tooltips, "tooltips");
+
+ return convpreset_editor;
+}
+
+GtkWidget*
+create_dsppreset_editor (void)
+{
+ GtkWidget *dsppreset_editor;
+ GtkWidget *dialog_vbox9;
+ GtkWidget *vbox30;
+ GtkWidget *hbox81;
+ GtkWidget *label111;
+ GtkWidget *title;
+ GtkWidget *vbox29;
+ GtkWidget *hbox82;
+ GtkWidget *add;
+ GtkWidget *remove;
+ GtkWidget *configure;
+ GtkWidget *hbox98;
+ GtkWidget *scrolledwindow7;
+ GtkWidget *plugins;
+ GtkWidget *vbox34;
+ GtkWidget *up;
+ GtkWidget *down;
+ GtkWidget *dialog_action_area8;
+ GtkWidget *cancelbutton6;
+ GtkWidget *okbutton6;
+
+ dsppreset_editor = gtk_dialog_new ();
+ gtk_widget_set_size_request (dsppreset_editor, 468, 254);
+ gtk_window_set_title (GTK_WINDOW (dsppreset_editor), _("DSP Preset Editor"));
+ gtk_window_set_modal (GTK_WINDOW (dsppreset_editor), TRUE);
+ gtk_window_set_type_hint (GTK_WINDOW (dsppreset_editor), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+ dialog_vbox9 = GTK_DIALOG (dsppreset_editor)->vbox;
+ gtk_widget_show (dialog_vbox9);
+
+ vbox30 = gtk_vbox_new (FALSE, 8);
+ gtk_widget_show (vbox30);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox9), vbox30, TRUE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox30), 12);
+
+ hbox81 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox81);
+ gtk_box_pack_start (GTK_BOX (vbox30), hbox81, FALSE, TRUE, 0);
+
+ label111 = gtk_label_new (_("Title"));
+ gtk_widget_show (label111);
+ gtk_box_pack_start (GTK_BOX (hbox81), label111, FALSE, FALSE, 0);
+
+ title = gtk_entry_new ();
+ gtk_widget_show (title);
+ gtk_box_pack_start (GTK_BOX (hbox81), title, TRUE, TRUE, 0);
+ gtk_entry_set_text (GTK_ENTRY (title), _("Untitled DSP Preset"));
+ gtk_entry_set_invisible_char (GTK_ENTRY (title), 9679);
+ gtk_entry_set_activates_default (GTK_ENTRY (title), TRUE);
+
+ vbox29 = gtk_vbox_new (FALSE, 8);
+ gtk_widget_show (vbox29);
+ gtk_box_pack_start (GTK_BOX (vbox30), vbox29, TRUE, TRUE, 0);
+
+ hbox82 = gtk_hbox_new (TRUE, 8);
+ gtk_widget_show (hbox82);
+ gtk_box_pack_start (GTK_BOX (vbox29), hbox82, FALSE, TRUE, 0);
+
+ add = gtk_button_new_with_mnemonic (_("Add"));
+ gtk_widget_show (add);
+ gtk_box_pack_start (GTK_BOX (hbox82), add, TRUE, TRUE, 0);
+
+ remove = gtk_button_new_with_mnemonic (_("Remove"));
+ gtk_widget_show (remove);
+ gtk_box_pack_start (GTK_BOX (hbox82), remove, TRUE, TRUE, 0);
+
+ configure = gtk_button_new_with_mnemonic (_("Configure"));
+ gtk_widget_show (configure);
+ gtk_box_pack_start (GTK_BOX (hbox82), configure, TRUE, TRUE, 0);
+
+ hbox98 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox98);
+ gtk_box_pack_start (GTK_BOX (vbox29), hbox98, TRUE, TRUE, 0);
+
+ scrolledwindow7 = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_show (scrolledwindow7);
+ gtk_box_pack_start (GTK_BOX (hbox98), scrolledwindow7, TRUE, TRUE, 0);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow7), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow7), GTK_SHADOW_IN);
+
+ plugins = gtk_tree_view_new ();
+ gtk_widget_show (plugins);
+ gtk_container_add (GTK_CONTAINER (scrolledwindow7), plugins);
+ gtk_widget_set_size_request (plugins, 196, -1);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (plugins), FALSE);
+
+ vbox34 = gtk_vbox_new (FALSE, 8);
+ gtk_widget_show (vbox34);
+ gtk_box_pack_start (GTK_BOX (hbox98), vbox34, FALSE, FALSE, 0);
+
+ up = gtk_button_new_from_stock ("gtk-go-up");
+ gtk_widget_show (up);
+ gtk_box_pack_start (GTK_BOX (vbox34), up, FALSE, FALSE, 0);
+
+ down = gtk_button_new_from_stock ("gtk-go-down");
+ gtk_widget_show (down);
+ gtk_box_pack_start (GTK_BOX (vbox34), down, FALSE, FALSE, 0);
+
+ dialog_action_area8 = GTK_DIALOG (dsppreset_editor)->action_area;
+ gtk_widget_show (dialog_action_area8);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area8), GTK_BUTTONBOX_END);
+
+ cancelbutton6 = gtk_button_new_from_stock ("gtk-cancel");
+ gtk_widget_show (cancelbutton6);
+ gtk_dialog_add_action_widget (GTK_DIALOG (dsppreset_editor), cancelbutton6, GTK_RESPONSE_CANCEL);
+ GTK_WIDGET_SET_FLAGS (cancelbutton6, GTK_CAN_DEFAULT);
+
+ okbutton6 = gtk_button_new_from_stock ("gtk-ok");
+ gtk_widget_show (okbutton6);
+ gtk_dialog_add_action_widget (GTK_DIALOG (dsppreset_editor), okbutton6, GTK_RESPONSE_OK);
+ GTK_WIDGET_SET_FLAGS (okbutton6, GTK_CAN_DEFAULT);
+
+ g_signal_connect ((gpointer) add, "clicked",
+ G_CALLBACK (on_dsp_preset_add_plugin_clicked),
+ NULL);
+ g_signal_connect ((gpointer) remove, "clicked",
+ G_CALLBACK (on_dsp_preset_remove_plugin_clicked),
+ NULL);
+ g_signal_connect ((gpointer) configure, "clicked",
+ G_CALLBACK (on_dsp_preset_plugin_configure_clicked),
+ NULL);
+ g_signal_connect ((gpointer) up, "clicked",
+ G_CALLBACK (on_dsp_preset_plugin_up_clicked),
+ NULL);
+ g_signal_connect ((gpointer) down, "clicked",
+ G_CALLBACK (on_dsp_preset_plugin_down_clicked),
+ NULL);
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT_NO_REF (dsppreset_editor, dsppreset_editor, "dsppreset_editor");
+ GLADE_HOOKUP_OBJECT_NO_REF (dsppreset_editor, dialog_vbox9, "dialog_vbox9");
+ GLADE_HOOKUP_OBJECT (dsppreset_editor, vbox30, "vbox30");
+ GLADE_HOOKUP_OBJECT (dsppreset_editor, hbox81, "hbox81");
+ GLADE_HOOKUP_OBJECT (dsppreset_editor, label111, "label111");
+ GLADE_HOOKUP_OBJECT (dsppreset_editor, title, "title");
+ GLADE_HOOKUP_OBJECT (dsppreset_editor, vbox29, "vbox29");
+ GLADE_HOOKUP_OBJECT (dsppreset_editor, hbox82, "hbox82");
+ GLADE_HOOKUP_OBJECT (dsppreset_editor, add, "add");
+ GLADE_HOOKUP_OBJECT (dsppreset_editor, remove, "remove");
+ GLADE_HOOKUP_OBJECT (dsppreset_editor, configure, "configure");
+ GLADE_HOOKUP_OBJECT (dsppreset_editor, hbox98, "hbox98");
+ GLADE_HOOKUP_OBJECT (dsppreset_editor, scrolledwindow7, "scrolledwindow7");
+ GLADE_HOOKUP_OBJECT (dsppreset_editor, plugins, "plugins");
+ GLADE_HOOKUP_OBJECT (dsppreset_editor, vbox34, "vbox34");
+ GLADE_HOOKUP_OBJECT (dsppreset_editor, up, "up");
+ GLADE_HOOKUP_OBJECT (dsppreset_editor, down, "down");
+ GLADE_HOOKUP_OBJECT_NO_REF (dsppreset_editor, dialog_action_area8, "dialog_action_area8");
+ GLADE_HOOKUP_OBJECT (dsppreset_editor, cancelbutton6, "cancelbutton6");
+ GLADE_HOOKUP_OBJECT (dsppreset_editor, okbutton6, "okbutton6");
+
+ return dsppreset_editor;
+}
+
+GtkWidget*
+create_select_dsp_plugin (void)
+{
+ GtkWidget *select_dsp_plugin;
+ GtkWidget *dialog_vbox10;
+ GtkWidget *vbox31;
+ GtkWidget *hbox85;
+ GtkWidget *label113;
+ GtkWidget *plugin;
+ GtkWidget *dialog_action_area9;
+ GtkWidget *cancelbutton7;
+ GtkWidget *okbutton7;
+
+ select_dsp_plugin = gtk_dialog_new ();
+ gtk_window_set_title (GTK_WINDOW (select_dsp_plugin), _("Select DSP Plugin"));
+ gtk_window_set_modal (GTK_WINDOW (select_dsp_plugin), TRUE);
+ gtk_window_set_type_hint (GTK_WINDOW (select_dsp_plugin), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+ dialog_vbox10 = GTK_DIALOG (select_dsp_plugin)->vbox;
+ gtk_widget_show (dialog_vbox10);
+
+ vbox31 = gtk_vbox_new (FALSE, 8);
+ gtk_widget_show (vbox31);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox10), vbox31, TRUE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox31), 12);
+
+ hbox85 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox85);
+ gtk_box_pack_start (GTK_BOX (vbox31), hbox85, FALSE, FALSE, 0);
+
+ label113 = gtk_label_new (_("Plugin"));
+ gtk_widget_show (label113);
+ gtk_box_pack_start (GTK_BOX (hbox85), label113, FALSE, FALSE, 0);
+
+ plugin = gtk_combo_box_new_text ();
+ gtk_widget_show (plugin);
+ gtk_box_pack_start (GTK_BOX (hbox85), plugin, TRUE, TRUE, 0);
+
+ dialog_action_area9 = GTK_DIALOG (select_dsp_plugin)->action_area;
+ gtk_widget_show (dialog_action_area9);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area9), GTK_BUTTONBOX_END);
+
+ cancelbutton7 = gtk_button_new_from_stock ("gtk-cancel");
+ gtk_widget_show (cancelbutton7);
+ gtk_dialog_add_action_widget (GTK_DIALOG (select_dsp_plugin), cancelbutton7, GTK_RESPONSE_CANCEL);
+ GTK_WIDGET_SET_FLAGS (cancelbutton7, GTK_CAN_DEFAULT);
+
+ okbutton7 = gtk_button_new_from_stock ("gtk-ok");
+ gtk_widget_show (okbutton7);
+ gtk_dialog_add_action_widget (GTK_DIALOG (select_dsp_plugin), okbutton7, GTK_RESPONSE_OK);
+ GTK_WIDGET_SET_FLAGS (okbutton7, GTK_CAN_DEFAULT);
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT_NO_REF (select_dsp_plugin, select_dsp_plugin, "select_dsp_plugin");
+ GLADE_HOOKUP_OBJECT_NO_REF (select_dsp_plugin, dialog_vbox10, "dialog_vbox10");
+ GLADE_HOOKUP_OBJECT (select_dsp_plugin, vbox31, "vbox31");
+ GLADE_HOOKUP_OBJECT (select_dsp_plugin, hbox85, "hbox85");
+ GLADE_HOOKUP_OBJECT (select_dsp_plugin, label113, "label113");
+ GLADE_HOOKUP_OBJECT (select_dsp_plugin, plugin, "plugin");
+ GLADE_HOOKUP_OBJECT_NO_REF (select_dsp_plugin, dialog_action_area9, "dialog_action_area9");
+ GLADE_HOOKUP_OBJECT (select_dsp_plugin, cancelbutton7, "cancelbutton7");
+ GLADE_HOOKUP_OBJECT (select_dsp_plugin, okbutton7, "okbutton7");
+
+ return select_dsp_plugin;
+}
+
+GtkWidget*
+create_preset_list (void)
+{
+ GtkWidget *preset_list;
+ GtkWidget *dialog_vbox11;
+ GtkWidget *vbox33;
+ GtkWidget *hbox94;
+ GtkWidget *add;
+ GtkWidget *remove;
+ GtkWidget *edit;
+ GtkWidget *scrolledwindow8;
+ GtkWidget *presets;
+ GtkWidget *dialog_action_area10;
+ GtkWidget *okbutton8;
+
+ preset_list = gtk_dialog_new ();
+ gtk_window_set_title (GTK_WINDOW (preset_list), _("Presets"));
+ gtk_window_set_modal (GTK_WINDOW (preset_list), TRUE);
+ gtk_window_set_type_hint (GTK_WINDOW (preset_list), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+ dialog_vbox11 = GTK_DIALOG (preset_list)->vbox;
+ gtk_widget_show (dialog_vbox11);
+
+ vbox33 = gtk_vbox_new (FALSE, 8);
+ gtk_widget_show (vbox33);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox11), vbox33, TRUE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox33), 12);
+
+ hbox94 = gtk_hbox_new (TRUE, 8);
+ gtk_widget_show (hbox94);
+ gtk_box_pack_start (GTK_BOX (vbox33), hbox94, FALSE, TRUE, 0);
+
+ add = gtk_button_new_from_stock ("gtk-add");
+ gtk_widget_show (add);
+ gtk_box_pack_start (GTK_BOX (hbox94), add, FALSE, TRUE, 0);
+
+ remove = gtk_button_new_from_stock ("gtk-remove");
+ gtk_widget_show (remove);
+ gtk_box_pack_start (GTK_BOX (hbox94), remove, FALSE, TRUE, 0);
+
+ edit = gtk_button_new_from_stock ("gtk-edit");
+ gtk_widget_show (edit);
+ gtk_box_pack_start (GTK_BOX (hbox94), edit, FALSE, TRUE, 0);
+
+ scrolledwindow8 = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_show (scrolledwindow8);
+ gtk_box_pack_start (GTK_BOX (vbox33), scrolledwindow8, TRUE, TRUE, 0);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow8), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow8), GTK_SHADOW_IN);
+
+ presets = gtk_tree_view_new ();
+ gtk_widget_show (presets);
+ gtk_container_add (GTK_CONTAINER (scrolledwindow8), presets);
+ gtk_widget_set_size_request (presets, 400, 176);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (presets), FALSE);
+
+ dialog_action_area10 = GTK_DIALOG (preset_list)->action_area;
+ gtk_widget_show (dialog_action_area10);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area10), GTK_BUTTONBOX_END);
+
+ okbutton8 = gtk_button_new_from_stock ("gtk-close");
+ gtk_widget_show (okbutton8);
+ gtk_dialog_add_action_widget (GTK_DIALOG (preset_list), okbutton8, GTK_RESPONSE_CLOSE);
+ GTK_WIDGET_SET_FLAGS (okbutton8, GTK_CAN_DEFAULT);
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT_NO_REF (preset_list, preset_list, "preset_list");
+ GLADE_HOOKUP_OBJECT_NO_REF (preset_list, dialog_vbox11, "dialog_vbox11");
+ GLADE_HOOKUP_OBJECT (preset_list, vbox33, "vbox33");
+ GLADE_HOOKUP_OBJECT (preset_list, hbox94, "hbox94");
+ GLADE_HOOKUP_OBJECT (preset_list, add, "add");
+ GLADE_HOOKUP_OBJECT (preset_list, remove, "remove");
+ GLADE_HOOKUP_OBJECT (preset_list, edit, "edit");
+ GLADE_HOOKUP_OBJECT (preset_list, scrolledwindow8, "scrolledwindow8");
+ GLADE_HOOKUP_OBJECT (preset_list, presets, "presets");
+ GLADE_HOOKUP_OBJECT_NO_REF (preset_list, dialog_action_area10, "dialog_action_area10");
+ GLADE_HOOKUP_OBJECT (preset_list, okbutton8, "okbutton8");
+
+ return preset_list;
+}
+
diff --git a/plugins/converter/interface.h b/plugins/converter/interface.h
new file mode 100644
index 00000000..346f63af
--- /dev/null
+++ b/plugins/converter/interface.h
@@ -0,0 +1,9 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+GtkWidget* create_converterdlg (void);
+GtkWidget* create_convpreset_editor (void);
+GtkWidget* create_dsppreset_editor (void);
+GtkWidget* create_select_dsp_plugin (void);
+GtkWidget* create_preset_list (void);
diff --git a/plugins/converter/support.c b/plugins/converter/support.c
new file mode 100644
index 00000000..00aff298
--- /dev/null
+++ b/plugins/converter/support.c
@@ -0,0 +1,144 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <gtk/gtk.h>
+
+#include "support.h"
+
+GtkWidget*
+lookup_widget (GtkWidget *widget,
+ const gchar *widget_name)
+{
+ GtkWidget *parent, *found_widget;
+
+ for (;;)
+ {
+ if (GTK_IS_MENU (widget))
+ parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
+ else
+ parent = widget->parent;
+ if (!parent)
+ parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey");
+ if (parent == NULL)
+ break;
+ widget = parent;
+ }
+
+ found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget),
+ widget_name);
+ if (!found_widget)
+ g_warning ("Widget not found: %s", widget_name);
+ return found_widget;
+}
+
+static GList *pixmaps_directories = NULL;
+
+/* Use this function to set the directory containing installed pixmaps. */
+void
+add_pixmap_directory (const gchar *directory)
+{
+ pixmaps_directories = g_list_prepend (pixmaps_directories,
+ g_strdup (directory));
+}
+
+/* This is an internally used function to find pixmap files. */
+static gchar*
+find_pixmap_file (const gchar *filename)
+{
+ GList *elem;
+
+ /* We step through each of the pixmaps directory to find it. */
+ elem = pixmaps_directories;
+ while (elem)
+ {
+ gchar *pathname = g_strdup_printf ("%s%s%s", (gchar*)elem->data,
+ G_DIR_SEPARATOR_S, filename);
+ if (g_file_test (pathname, G_FILE_TEST_EXISTS))
+ return pathname;
+ g_free (pathname);
+ elem = elem->next;
+ }
+ return NULL;
+}
+
+/* This is an internally used function to create pixmaps. */
+GtkWidget*
+create_pixmap (GtkWidget *widget,
+ const gchar *filename)
+{
+ gchar *pathname = NULL;
+ GtkWidget *pixmap;
+
+ if (!filename || !filename[0])
+ return gtk_image_new ();
+
+ pathname = find_pixmap_file (filename);
+
+ if (!pathname)
+ {
+ g_warning (_("Couldn't find pixmap file: %s"), filename);
+ return gtk_image_new ();
+ }
+
+ pixmap = gtk_image_new_from_file (pathname);
+ g_free (pathname);
+ return pixmap;
+}
+
+/* This is an internally used function to create pixmaps. */
+GdkPixbuf*
+create_pixbuf (const gchar *filename)
+{
+ gchar *pathname = NULL;
+ GdkPixbuf *pixbuf;
+ GError *error = NULL;
+
+ if (!filename || !filename[0])
+ return NULL;
+
+ pathname = find_pixmap_file (filename);
+
+ if (!pathname)
+ {
+ g_warning (_("Couldn't find pixmap file: %s"), filename);
+ return NULL;
+ }
+
+ pixbuf = gdk_pixbuf_new_from_file (pathname, &error);
+ if (!pixbuf)
+ {
+ fprintf (stderr, "Failed to load pixbuf file: %s: %s\n",
+ pathname, error->message);
+ g_error_free (error);
+ }
+ g_free (pathname);
+ return pixbuf;
+}
+
+/* This is used to set ATK action descriptions. */
+void
+glade_set_atk_action_description (AtkAction *action,
+ const gchar *action_name,
+ const gchar *description)
+{
+ gint n_actions, i;
+
+ n_actions = atk_action_get_n_actions (action);
+ for (i = 0; i < n_actions; i++)
+ {
+ if (!strcmp (atk_action_get_name (action, i), action_name))
+ atk_action_set_description (action, i, description);
+ }
+}
+
diff --git a/plugins/converter/support.h b/plugins/converter/support.h
new file mode 100644
index 00000000..a32649e5
--- /dev/null
+++ b/plugins/converter/support.h
@@ -0,0 +1,69 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+
+/*
+ * Standard gettext macros.
+ */
+#ifdef ENABLE_NLS
+# include <libintl.h>
+# undef _
+# define _(String) dgettext (PACKAGE, String)
+# define Q_(String) g_strip_context ((String), gettext (String))
+# ifdef gettext_noop
+# define N_(String) gettext_noop (String)
+# else
+# define N_(String) (String)
+# endif
+#else
+# define textdomain(String) (String)
+# define gettext(String) (String)
+# define dgettext(Domain,Message) (Message)
+# define dcgettext(Domain,Message,Type) (Message)
+# define bindtextdomain(Domain,Directory) (Domain)
+# define _(String) (String)
+# define Q_(String) g_strip_context ((String), (String))
+# define N_(String) (String)
+#endif
+
+
+/*
+ * Public Functions.
+ */
+
+/*
+ * This function returns a widget in a component created by Glade.
+ * Call it with the toplevel widget in the component (i.e. a window/dialog),
+ * or alternatively any widget in the component, and the name of the widget
+ * you want returned.
+ */
+GtkWidget* lookup_widget (GtkWidget *widget,
+ const gchar *widget_name);
+
+
+/* Use this function to set the directory containing installed pixmaps. */
+void add_pixmap_directory (const gchar *directory);
+
+
+/*
+ * Private Functions.
+ */
+
+/* This is used to create the pixmaps used in the interface. */
+GtkWidget* create_pixmap (GtkWidget *widget,
+ const gchar *filename);
+
+/* This is used to create the pixbufs used in the interface. */
+GdkPixbuf* create_pixbuf (const gchar *filename);
+
+/* This is used to set ATK action descriptions. */
+void glade_set_atk_action_description (AtkAction *action,
+ const gchar *action_name,
+ const gchar *description);
+
diff --git a/plugins/dca/Makefile.am b/plugins/dca/Makefile.am
index 0ae4734c..9819c5aa 100644
--- a/plugins/dca/Makefile.am
+++ b/plugins/dca/Makefile.am
@@ -8,7 +8,6 @@ gettimeofday.c\
parse.c\
bitstream.c\
downmix.c\
-convert2s16.c\
audio_out.h\
dca.h\
dts.h\
@@ -26,6 +25,6 @@ bitstream.h
dca_la_LDFLAGS = -module
dca_la_LIBADD = $(LDADD) -lm
-AM_CFLAGS = $(CFLAGS) -fPIC
+AM_CFLAGS = $(CFLAGS) -fPIC -std=c99
endif
diff --git a/plugins/dca/convert2s16.c b/plugins/dca/convert2s16.c
deleted file mode 100644
index b0647eae..00000000
--- a/plugins/dca/convert2s16.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * convert2s16.c
- * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
- * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
- *
- * This file is part of a52dec, a free ATSC A-52 stream decoder.
- * See http://liba52.sourceforge.net/ for updates.
- *
- * a52dec 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.
- *
- * a52dec 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 "config.h"
-
-#include <inttypes.h>
-
-#include "dca.h"
-
-#include <stdio.h>
-
-#ifdef LIBDCA_DOUBLE
-typedef float convert_t;
-#else
-typedef sample_t convert_t;
-#endif
-
-static inline int16_t convert (int32_t i)
-{
-#ifdef LIBDCA_FIXED
- i >>= 15;
-#else
- i -= 0x43c00000;
-#endif
- return (i > 32767) ? 32767 : ((i < -32768) ? -32768 : i);
-}
-
-void convert2s16_1 (convert_t * _f, int16_t * s16)
-{
- int i;
- int32_t * f = (int32_t *) _f;
-
- for (i = 0; i < 256; i++) {
- s16[i] = convert (f[i]);
- }
-}
-
-void convert2s16_2 (convert_t * _f, int16_t * s16)
-{
- int i;
- int32_t * f = (int32_t *) _f;
-
- for (i = 0; i < 256; i++) {
- s16[2*i] = convert (f[i]);
- s16[2*i+1] = convert (f[i+256]);
- }
-}
-
-void convert2s16_3 (convert_t * _f, int16_t * s16)
-{
- int i;
- int32_t * f = (int32_t *) _f;
-
- for (i = 0; i < 256; i++) {
- s16[3*i] = convert (f[i]);
- s16[3*i+1] = convert (f[i+256]);
- s16[3*i+2] = convert (f[i+512]);
- }
-}
-
-void convert2s16_4 (convert_t * _f, int16_t * s16)
-{
- int i;
- int32_t * f = (int32_t *) _f;
-
- for (i = 0; i < 256; i++) {
- s16[4*i] = convert (f[i]);
- s16[4*i+1] = convert (f[i+256]);
- s16[4*i+2] = convert (f[i+512]);
- s16[4*i+3] = convert (f[i+768]);
- }
-}
-
-void convert2s16_5 (convert_t * _f, int16_t * s16)
-{
- int i;
- int32_t * f = (int32_t *) _f;
-
- for (i = 0; i < 256; i++) {
- s16[5*i] = convert (f[i]);
- s16[5*i+1] = convert (f[i+256]);
- s16[5*i+2] = convert (f[i+512]);
- s16[5*i+3] = convert (f[i+768]);
- s16[5*i+4] = convert (f[i+1024]);
- }
-}
-
-int channels_multi (int flags)
-{
- if (flags & DCA_LFE)
- return 6;
- else if (flags & 1) /* center channel */
- return 5;
- else if ((flags & DCA_CHANNEL_MASK) == DCA_2F2R)
- return 4;
- else
- return 2;
-}
-
-void convert2s16_multi (convert_t * _f, int16_t * s16, int flags)
-{
- int i;
- int32_t * f = (int32_t *) _f;
-
- switch (flags) {
- case DCA_MONO:
- for (i = 0; i < 256; i++) {
- s16[5*i] = s16[5*i+1] = s16[5*i+2] = s16[5*i+3] = 0;
- s16[5*i+4] = convert (f[i]);
- }
- break;
- case DCA_CHANNEL:
- case DCA_STEREO:
- case DCA_DOLBY:
- convert2s16_2 (_f, s16);
- break;
- case DCA_3F:
- for (i = 0; i < 256; i++) {
- s16[5*i] = convert (f[i]);
- s16[5*i+1] = convert (f[i+512]);
- s16[5*i+2] = s16[5*i+3] = 0;
- s16[5*i+4] = convert (f[i+256]);
- }
- break;
- case DCA_2F2R:
- convert2s16_4 (_f, s16);
- break;
- case DCA_3F2R:
- convert2s16_5 (_f, s16);
- break;
- case DCA_MONO | DCA_LFE:
- for (i = 0; i < 256; i++) {
- s16[6*i] = s16[6*i+1] = s16[6*i+2] = s16[6*i+3] = 0;
- s16[6*i+4] = convert (f[i+256]);
- s16[6*i+5] = convert (f[i]);
- }
- break;
- case DCA_CHANNEL | DCA_LFE:
- case DCA_STEREO | DCA_LFE:
- case DCA_DOLBY | DCA_LFE:
- for (i = 0; i < 256; i++) {
- s16[6*i] = convert (f[i+256]);
- s16[6*i+1] = convert (f[i+512]);
- s16[6*i+2] = s16[6*i+3] = s16[6*i+4] = 0;
- s16[6*i+5] = convert (f[i]);
- }
- break;
- case DCA_3F | DCA_LFE:
- for (i = 0; i < 256; i++) {
- s16[6*i] = convert (f[i+256]);
- s16[6*i+1] = convert (f[i+768]);
- s16[6*i+2] = s16[6*i+3] = 0;
- s16[6*i+4] = convert (f[i+512]);
- s16[6*i+5] = convert (f[i]);
- }
- break;
- case DCA_2F2R | DCA_LFE:
- for (i = 0; i < 256; i++) {
- s16[6*i] = convert (f[i+256]);
- s16[6*i+1] = convert (f[i+512]);
- s16[6*i+2] = convert (f[i+768]);
- s16[6*i+3] = convert (f[i+1024]);
- s16[6*i+4] = 0;
- s16[6*i+5] = convert (f[i]);
- }
- break;
- case DCA_3F2R | DCA_LFE:
- for (i = 0; i < 256; i++) {
- s16[6*i] = convert (f[i+256]);
- s16[6*i+1] = convert (f[i+768]);
- s16[6*i+2] = convert (f[i+1024]);
- s16[6*i+3] = convert (f[i+1280]);
- s16[6*i+4] = convert (f[i+512]);
- s16[6*i+5] = convert (f[i]);
- }
- break;
- }
-}
-
-void s16_swap (int16_t * s16, int channels)
-{
- int i;
- uint16_t * u16 = (uint16_t *) s16;
-
- for (i = 0; i < 256 * channels; i++)
- u16[i] = (u16[i] >> 8) | (u16[i] << 8);
-}
-
-void s32_swap (int32_t * s32, int channels)
-{
- int i;
- uint32_t * u32 = (uint32_t *) s32;
-
- for (i = 0; i < 256 * channels; i++)
- u32[i] = (u32[i] << 24) | ((u32[i] << 8)&0xFF0000) |
- ((u32[i] >> 8)&0xFF00) | (u32[i] >> 24);
-}
diff --git a/plugins/dca/dcaplug.c b/plugins/dca/dcaplug.c
index 9d7f251f..84a876ab 100644
--- a/plugins/dca/dcaplug.c
+++ b/plugins/dca/dcaplug.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -73,7 +73,7 @@ static DB_decoder_t plugin;
DB_functions_t *deadbeef;
#define BUFFER_SIZE 24576
-#define OUT_BUFFER_SIZE 100000 // one block may be up to 22K samples, which is 88Kb for stereo
+#define OUT_BUFFER_SIZE 25000 // one block may be up to 22K samples, which is 88Kb for stereo
#define HEADER_SIZE 14
typedef struct {
DB_fileinfo_t info;
@@ -82,7 +82,6 @@ typedef struct {
int startsample;
int endsample;
int currentsample;
- int wavchannels;
dca_state_t * state;
int disable_adjust;// = 0;
float gain;// = 1;
@@ -95,7 +94,7 @@ typedef struct {
int flags;
int bit_rate;
int frame_byte_size;
- char output_buffer[OUT_BUFFER_SIZE];
+ int16_t output_buffer[OUT_BUFFER_SIZE*6];
int remaining;
int skipsamples;
} ddb_dca_state_t;
@@ -157,32 +156,35 @@ static int wav_channels (int flags, uint32_t * speaker_flags)
return chans;
}
+static inline int16_t convert (int32_t i)
+{
+#ifdef LIBDCA_FIXED
+ i >>= 15;
+#else
+ i -= 0x43c00000;
+#endif
+ return (i > 32767) ? 32767 : ((i < -32768) ? -32768 : i);
+}
+
static int
convert_samples (ddb_dca_state_t *state, int flags)
{
sample_t *_samples = dca_samples (state->state);
- int chans, size;
- uint32_t speaker_flags;
- int16_t int16_samples[256*6];
- convert_t * samples = _samples;
- chans = channels_multi (flags);
- flags &= DCA_CHANNEL_MASK | DCA_LFE;
+ int samplesize = state->info.fmt.channels * state->info.fmt.bps / 8;
- convert2s16_multi (samples, int16_samples, flags);
+ int n, i, c;
+ n = 256;
+ int16_t *dst = state->output_buffer + state->remaining * state->info.fmt.channels;
- int16_t *dest = (int16_t*)(state->output_buffer + state->remaining * sizeof (int16_t) * 2);
- int i;
- for (i = 0; i < 256; i++) {
- *dest = int16_samples[i * chans + 0];
- dest++;
- *dest = int16_samples[i * chans + 1];
- dest++;
+ for (i = 0; i < n; i++) {
+ for (c = 0; c < state->info.fmt.channels; c++) {
+ *dst++ = convert (*((int32_t*)(_samples + 256 * c)));
+ }
+ _samples ++;
}
- state->remaining += 256;
- //trace ("wrote %d bytes (chans=%d)\n", size, chans);
- //fwrite (&ordered_samples, 1, size, out);
+ state->remaining += 256;
return 0;
}
@@ -318,7 +320,7 @@ dts_open_wav (DB_FILE *fp, wavfmt_t *fmt, int64_t *totalsamples) {
return -1;
}
- deadbeef->fseek (fp, fmtsize - sizeof (wavfmt_t), SEEK_CUR);
+ deadbeef->fseek (fp, (int)fmtsize - (int)sizeof (wavfmt_t), SEEK_CUR);
// data subchunk
@@ -343,7 +345,7 @@ dts_open_wav (DB_FILE *fp, wavfmt_t *fmt, int64_t *totalsamples) {
}
static DB_fileinfo_t *
-dts_open (void) {
+dts_open (uint32_t hints) {
DB_fileinfo_t *_info = malloc (sizeof (ddb_dca_state_t));
ddb_dca_state_t *info = (ddb_dca_state_t *)_info;
memset (info, 0, sizeof (ddb_dca_state_t));
@@ -354,9 +356,9 @@ static int
dts_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
ddb_dca_state_t *info = (ddb_dca_state_t *)_info;
- info->file = deadbeef->fopen (it->fname);
+ info->file = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!info->file) {
- trace ("dca: failed to open %s\n", it->fname);
+ trace ("dca: failed to open %s\n", deadbeef->pl_find_meta (it, ":URI"));
return -1;
}
@@ -364,17 +366,15 @@ dts_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
int64_t totalsamples = -1;
// WAV format
if ((info->offset = dts_open_wav (info->file, &fmt, &totalsamples)) == -1) {
- // try raw DTS @ 48KHz
+ // raw dts, leave detection to libdca
info->offset = 0;
totalsamples = -1;
- info->wavchannels = 2;
- _info->bps = 16;
+ _info->fmt.bps = 16;
}
else {
- _info->bps = fmt.wBitsPerSample;
- _info->channels = fmt.nChannels;
- info->wavchannels = fmt.nChannels;
- _info->samplerate = fmt.nSamplesPerSec;
+ _info->fmt.bps = fmt.wBitsPerSample;
+ _info->fmt.channels = fmt.nChannels;
+ _info->fmt.samplerate = fmt.nSamplesPerSec;
}
_info->plugin = &plugin;
@@ -400,40 +400,48 @@ dts_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
int flags = info->flags &~ (DCA_LFE | DCA_ADJUST_LEVEL);
switch (flags) {
case DCA_MONO:
- _info->channels = 1;
+ _info->fmt.channels = 1;
+ _info->fmt.channelmask = DDB_SPEAKER_FRONT_LEFT;
break;
case DCA_CHANNEL:
case DCA_STEREO:
case DCA_DOLBY:
case DCA_STEREO_SUMDIFF:
case DCA_STEREO_TOTAL:
- _info->channels = 2;
+ _info->fmt.channels = 2;
+ _info->fmt.channelmask = (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT);
break;
case DCA_3F:
case DCA_2F1R:
- _info->channels = 3;
+ _info->fmt.channels = 3;
+ _info->fmt.channelmask = (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_FRONT_CENTER);
break;
case DCA_2F2R:
case DCA_3F1R:
- _info->channels = 4;
+ _info->fmt.channels = 4;
+ _info->fmt.channelmask = (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_BACK_LEFT | DDB_SPEAKER_BACK_RIGHT);
break;
case DCA_3F2R:
- _info->channels = 5;
+ _info->fmt.channels = 5;
+ _info->fmt.channelmask = (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_BACK_LEFT | DDB_SPEAKER_BACK_RIGHT | DDB_SPEAKER_FRONT_CENTER);
break;
case DCA_4F2R:
- _info->channels = 6;
+ _info->fmt.channels = 6;
+ _info->fmt.channelmask = (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_BACK_LEFT | DDB_SPEAKER_BACK_RIGHT | DDB_SPEAKER_SIDE_LEFT | DDB_SPEAKER_SIDE_RIGHT);
break;
}
if (info->flags & DCA_LFE) {
- _info->channels++;
+ _info->fmt.channelmask |= DDB_SPEAKER_LOW_FREQUENCY;
+ _info->fmt.channels++;
}
- if (!_info->channels) {
+
+ if (!_info->fmt.channels) {
trace ("dts: invalid numchannels\n");
return -1;
}
- _info->samplerate = info->sample_rate;
+ _info->fmt.samplerate = info->sample_rate;
if (it->endsample > 0) {
info->startsample = it->startsample;
@@ -445,7 +453,7 @@ dts_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
info->endsample = totalsamples-1;
}
- trace ("dca_init: nchannels: %d, samplerate: %d\n", _info->channels, _info->samplerate);
+ trace ("dca_init: nchannels: %d, samplerate: %d\n", _info->fmt.channels, _info->fmt.samplerate);
return 0;
}
@@ -464,11 +472,12 @@ dts_free (DB_fileinfo_t *_info) {
}
static int
-dts_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
+dts_read (DB_fileinfo_t *_info, char *bytes, int size) {
ddb_dca_state_t *info = (ddb_dca_state_t *)_info;
+ int samplesize = _info->fmt.channels * _info->fmt.bps / 8;
if (info->endsample >= 0) {
- if (info->currentsample + size / (2 * _info->channels) > info->endsample) {
- size = (info->endsample - info->currentsample + 1) * 2 * _info->channels;
+ if (info->currentsample + size / samplesize > info->endsample) {
+ size = (info->endsample - info->currentsample + 1) * samplesize;
if (size <= 0) {
return 0;
}
@@ -476,30 +485,25 @@ dts_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
}
int initsize = size;
- int out_channels = _info->channels;
- if (out_channels > 2) {
- out_channels = 2;
- }
- int sample_size = ((_info->bps >> 3) * out_channels);
while (size > 0) {
if (info->skipsamples > 0 && info->remaining > 0) {
int skip = min (info->remaining, info->skipsamples);
- int sample_size = _info->bps/8 * info->wavchannels;
if (skip < info->remaining) {
- memmove (info->output_buffer, info->output_buffer + skip * sample_size, (info->remaining - skip) * sample_size);
+ memmove (info->output_buffer, info->output_buffer + skip * _info->fmt.channels, (info->remaining - skip) * samplesize);
}
info->remaining -= skip;
info->skipsamples -= skip;
}
if (info->remaining > 0) {
- int n = size / sample_size;
+ int n = size / samplesize;
n = min (n, info->remaining);
- memcpy (bytes, info->output_buffer, n * sample_size);
+ memcpy (bytes, info->output_buffer, n * samplesize);
+
if (info->remaining > n) {
- memmove (info->output_buffer, info->output_buffer + n * sample_size, (info->remaining - n) * sample_size);
+ memmove (info->output_buffer, info->output_buffer + n * _info->fmt.channels, (info->remaining - n) * samplesize);
}
- bytes += n * sample_size;
- size -= n * sample_size;
+ bytes += n * samplesize;
+ size -= n * samplesize;
info->remaining -= n;
// trace ("dca: write %d samples\n", n);
}
@@ -514,7 +518,7 @@ dts_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
}
}
- info->currentsample += (initsize-size) / sample_size;
+ info->currentsample += (initsize-size) / samplesize;
deadbeef->streamer_set_bitrate (info->bit_rate/1000);
return initsize-size;
}
@@ -532,14 +536,14 @@ dts_seek_sample (DB_fileinfo_t *_info, int sample) {
info->skipsamples = sample - nframe * info->frame_length;
info->currentsample = sample;
- _info->readpos = (float)(sample - info->startsample) / _info->samplerate;
+ _info->readpos = (float)(sample - info->startsample) / _info->fmt.samplerate;
return 0;
}
static int
dts_seek (DB_fileinfo_t *_info, float time) {
ddb_dca_state_t *info = (ddb_dca_state_t *)_info;
- return dts_seek_sample (_info, time * _info->samplerate);
+ return dts_seek_sample (_info, time * _info->fmt.samplerate);
}
static DB_playItem_t *
@@ -576,6 +580,7 @@ dts_insert (DB_playItem_t *after, const char *fname) {
// it's dts
uint8_t buffer[BUFFER_SIZE];
size_t size = deadbeef->fread (buffer, 1, sizeof (buffer), fp);
+ trace ("got size: %d (requested %d)\n", size, sizeof (buffer));
ddb_dca_state_t state;
memset (&state, 0, sizeof (state));
state.state = dca_init (0);
@@ -602,10 +607,8 @@ dts_insert (DB_playItem_t *after, const char *fname) {
dur = (float)totalsamples / state.sample_rate;
}
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (fname);
- it->filetype = filetype;
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
+ deadbeef->pl_add_meta (it, ":FILETYPE", filetype);
deadbeef->pl_set_item_duration (it, dur);
deadbeef->fclose (fp);
@@ -644,22 +647,39 @@ dts_stop (void) {
// define plugin interface
static DB_decoder_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.id = "dts",
.plugin.name = "dts decoder",
- .plugin.descr = "dts decoder using libdca from VLC project",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.descr = "plays dts-encoded files using libdca from VLC project",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "Uses modified libdca from VLC Player project,\n"
+ "developed by Gildas Bazin <gbazin@videolan.org>"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = dts_start,
.plugin.stop = dts_stop,
.open = dts_open,
.init = dts_init,
.free = dts_free,
- .read_int16 = dts_read_int16,
-// .read_float32 = dts_read_float32,
+ .read = dts_read,
.seek = dts_seek,
.seek_sample = dts_seek_sample,
.insert = dts_insert,
diff --git a/plugins/dsp_libsrc/Makefile.am b/plugins/dsp_libsrc/Makefile.am
new file mode 100644
index 00000000..42c6a347
--- /dev/null
+++ b/plugins/dsp_libsrc/Makefile.am
@@ -0,0 +1,12 @@
+if HAVE_DSP_SRC
+pkglib_LTLIBRARIES = dsp_libsrc.la
+
+dsp_libsrc_la_SOURCES = src.c src.h
+
+dsp_libsrc_la_LDFLAGS = -module
+
+dsp_libsrc_la_LIBADD = $(LIBADD) $(LIBSAMPLERATE_DEPS_LIBS)
+
+dsp_libsrc_la_CFLAGS = $(CFLAGS) $(LIBSAMPLERATE_DEPS_CFLAGS) -std=c99
+
+endif
diff --git a/plugins/dsp_libsrc/src.c b/plugins/dsp_libsrc/src.c
new file mode 100644
index 00000000..be9c350e
--- /dev/null
+++ b/plugins/dsp_libsrc/src.c
@@ -0,0 +1,286 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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 <samplerate.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "conf.h"
+#include "threading.h"
+#include "deadbeef.h"
+#include "src.h"
+
+//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+#define trace(fmt,...)
+
+static DB_functions_t *deadbeef;
+
+#define SRC_BUFFER 16000
+#define SRC_MAX_CHANNELS 8
+
+static DB_dsp_t plugin;
+
+typedef struct {
+ ddb_dsp_context_t ctx;
+
+ int channels;
+ int quality;
+ float samplerate;
+ SRC_STATE *src;
+ SRC_DATA srcdata;
+ int remaining; // number of input samples in SRC buffer
+ __attribute__((__aligned__(16))) char in_fbuffer[sizeof(float)*SRC_BUFFER*SRC_MAX_CHANNELS];
+ unsigned quality_changed : 1;
+ unsigned need_reset : 1;
+} ddb_src_libsamplerate_t;
+
+ddb_dsp_context_t*
+ddb_src_open (void) {
+ ddb_src_libsamplerate_t *src = malloc (sizeof (ddb_src_libsamplerate_t));
+ DDB_INIT_DSP_CONTEXT (src,ddb_src_libsamplerate_t,&plugin);
+
+ src->samplerate = 44100;
+ src->quality = 2;
+ src->channels = -1;
+ return (ddb_dsp_context_t *)src;
+}
+
+void
+ddb_src_close (ddb_dsp_context_t *_src) {
+ ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src;
+ if (src->src) {
+ src_delete (src->src);
+ src->src = NULL;
+ }
+ free (src);
+}
+
+void
+ddb_src_reset (ddb_dsp_context_t *_src) {
+ ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src;
+ src->need_reset = 1;
+}
+
+
+void
+ddb_src_set_ratio (ddb_dsp_context_t *_src, float ratio) {
+ ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src;
+ if (src->srcdata.src_ratio != ratio) {
+ src->srcdata.src_ratio = ratio;
+ src_set_ratio (src->src, ratio);
+ }
+}
+
+int
+ddb_src_process (ddb_dsp_context_t *_src, float *samples, int nframes, int maxframes, ddb_waveformat_t *fmt, float *r) {
+ ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src;
+
+ if (fmt->samplerate == src->samplerate) {
+ return nframes;
+ }
+
+ if (src->need_reset || src->channels != fmt->channels || src->quality_changed || !src->src) {
+ src->quality_changed = 0;
+ src->remaining = 0;
+ if (src->src) {
+ src_delete (src->src);
+ src->src = NULL;
+ }
+ src->channels = fmt->channels;
+ src->src = src_new (src->quality, src->channels, NULL);
+ src->need_reset = 0;
+ }
+
+ float ratio = src->samplerate / fmt->samplerate;
+ ddb_src_set_ratio (_src, ratio);
+ fmt->samplerate = src->samplerate;
+
+ int numoutframes = 0;
+ int outsize = nframes*24;
+ float outbuf[outsize*fmt->channels];
+ memset (outbuf, 0, sizeof (outbuf));
+ char *output = (char *)outbuf;
+ float *input = samples;
+ int inputsize = nframes;
+
+ int samplesize = fmt->channels * sizeof (float);
+
+ do {
+ // add more frames to input SRC buffer
+ int n = inputsize;
+ if (n >= SRC_BUFFER - src->remaining) {
+ n = SRC_BUFFER - src->remaining;
+ }
+
+ if (n > 0) {
+ memcpy (&src->in_fbuffer[src->remaining*samplesize], samples, n * samplesize);
+
+ src->remaining += n;
+ samples += n * fmt->channels;
+ }
+ if (!src->remaining) {
+ trace ("WARNING: SRC input buffer starved\n");
+ break;
+ }
+
+ // call libsamplerate
+ src->srcdata.data_in = (float *)src->in_fbuffer;
+ src->srcdata.data_out = (float *)output;
+ src->srcdata.input_frames = src->remaining;
+ src->srcdata.output_frames = outsize;
+ src->srcdata.end_of_input = 0;
+ trace ("src input: %d, ratio %f, buffersize: %d\n", src->srcdata.input_frames, src->srcdata.src_ratio, sizeof (outbuf));
+ int src_err = src_process (src->src, &src->srcdata);
+ trace ("src output: %d, used: %d\n", src->srcdata.output_frames_gen, src->srcdata.input_frames_used);
+
+ if (src_err) {
+ const char *err = src_strerror (src_err) ;
+ fprintf (stderr, "src_process error %s\n"
+ "srcdata.data_in=%p, srcdata.data_out=%p, srcdata.input_frames=%d, srcdata.output_frames=%d, srcdata.src_ratio=%f", err, src->srcdata.data_in, src->srcdata.data_out, (int)src->srcdata.input_frames, (int)src->srcdata.output_frames, src->srcdata.src_ratio);
+ return nframes;
+ }
+
+ inputsize -= n;
+ output += src->srcdata.output_frames_gen * samplesize;
+ numoutframes += src->srcdata.output_frames_gen;
+ outsize -= src->srcdata.output_frames_gen;
+
+ // calculate how many unused input samples left
+ src->remaining -= src->srcdata.input_frames_used;
+ // copy spare samples for next update
+ if (src->remaining > 0 && src->srcdata.input_frames_used > 0) {
+ memmove (src->in_fbuffer, &src->in_fbuffer[src->srcdata.input_frames_used*samplesize], src->remaining * samplesize);
+ }
+ if (src->srcdata.output_frames_gen == 0) {
+ trace ("src: output_frames_gen=0, interrupt\n");
+ break;
+ }
+ } while (inputsize > 0 && outsize > 0);
+
+ memcpy (input, outbuf, numoutframes * fmt->channels * sizeof (float));
+ //static FILE *out = NULL;
+ //if (!out) {
+ // out = fopen ("out.raw", "w+b");
+ //}
+ //fwrite (input, 1, numoutframes*sizeof(float)*(*nchannels), out);
+
+ fmt->samplerate = src->samplerate;
+ trace ("src: ratio=%f, in=%d, out=%d\n", ratio, nframes, numoutframes);
+ return numoutframes;
+}
+
+int
+ddb_src_num_params (void) {
+ return SRC_PARAM_COUNT;
+}
+
+const char *
+ddb_src_get_param_name (int p) {
+ switch (p) {
+ case SRC_PARAM_QUALITY:
+ return "Quality";
+ case SRC_PARAM_SAMPLERATE:
+ return "Samplerate";
+ default:
+ fprintf (stderr, "ddb_src_get_param_name: invalid param index (%d)\n", p);
+ }
+}
+
+void
+ddb_src_set_param (ddb_dsp_context_t *ctx, int p, const char *val) {
+ switch (p) {
+ case SRC_PARAM_SAMPLERATE:
+ ((ddb_src_libsamplerate_t*)ctx)->samplerate = atof (val);
+ if (((ddb_src_libsamplerate_t*)ctx)->samplerate < 8000) {
+ ((ddb_src_libsamplerate_t*)ctx)->samplerate = 8000;
+ }
+ if (((ddb_src_libsamplerate_t*)ctx)->samplerate > 192000) {
+ ((ddb_src_libsamplerate_t*)ctx)->samplerate = 192000;
+ }
+ break;
+ case SRC_PARAM_QUALITY:
+ ((ddb_src_libsamplerate_t*)ctx)->quality = atoi (val);
+ ((ddb_src_libsamplerate_t*)ctx)->quality_changed = 1;
+ break;
+ default:
+ fprintf (stderr, "ddb_src_set_param: invalid param index (%d)\n", p);
+ }
+}
+
+void
+ddb_src_get_param (ddb_dsp_context_t *ctx, int p, char *val, int sz) {
+ switch (p) {
+ case SRC_PARAM_SAMPLERATE:
+ snprintf (val, sz, "%f", ((ddb_src_libsamplerate_t*)ctx)->samplerate);
+ break;
+ case SRC_PARAM_QUALITY:
+ snprintf (val, sz, "%d", ((ddb_src_libsamplerate_t*)ctx)->quality);
+ break;
+ default:
+ fprintf (stderr, "ddb_src_get_param: invalid param index (%d)\n", p);
+ }
+}
+
+static const char settings_dlg[] =
+ "property \"Target Samplerate\" spinbtn[8192,192000,1] 0 48000;\n"
+ "property \"Quality / Algorythm\" select[5] 1 2 SINC_BEST_QUALITY SINC_MEDIUM_QUALITY SINC_FASTEST ZERO_ORDER_HOLD LINEAR;\n"
+;
+
+static DB_dsp_t plugin = {
+ .plugin.api_vmajor = DB_API_VERSION_MAJOR,
+ .plugin.api_vminor = DB_API_VERSION_MINOR,
+ .open = ddb_src_open,
+ .close = ddb_src_close,
+ .process = ddb_src_process,
+ .plugin.version_major = 0,
+ .plugin.version_minor = 1,
+ .plugin.type = DB_PLUGIN_DSP,
+ .plugin.id = "SRC",
+ .plugin.name = "Resampler (Secret Rabbit Code)",
+ .plugin.descr = "High quality samplerate converter using libsamplerate, http://www.mega-nerd.com/SRC/",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
+ .plugin.website = "http://deadbeef.sf.net",
+ .num_params = ddb_src_num_params,
+ .get_param_name = ddb_src_get_param_name,
+ .set_param = ddb_src_set_param,
+ .get_param = ddb_src_get_param,
+ .reset = ddb_src_reset,
+ .configdialog = settings_dlg,
+};
+
+DB_plugin_t *
+dsp_libsrc_load (DB_functions_t *f) {
+ deadbeef = f;
+ return &plugin.plugin;
+}
diff --git a/plugins/dsp_libsrc/src.h b/plugins/dsp_libsrc/src.h
new file mode 100644
index 00000000..bb9a15e2
--- /dev/null
+++ b/plugins/dsp_libsrc/src.h
@@ -0,0 +1,28 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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.
+*/
+#ifndef __SRC_H
+#define __SRC_H
+
+enum {
+ SRC_PARAM_SAMPLERATE = 0,
+ SRC_PARAM_QUALITY = 1,
+ SRC_PARAM_COUNT
+};
+
+#endif
diff --git a/plugins/dumb/Makefile.am b/plugins/dumb/Makefile
index de165bdd..e9b05233 100644
--- a/plugins/dumb/Makefile.am
+++ b/plugins/dumb/Makefile
@@ -1,14 +1,12 @@
-if HAVE_DUMB
-dumbpath=@top_srcdir@/plugins/dumb/dumb-kode54
+CC=gcc
-EXTRA_DIST = $(dumbpath)/readme.txt $(dumbpath)/ChangeLog $(dumbpath)/licence.txt $(dumbpath)/release.txt $(dumbpath)/todo.txt
+dumbpath=dumb-kode54
-pkglib_LTLIBRARIES = dumb.la
+CFLAGS+=-Wall -fPIC -D_GNU_SOURCE -I$(dumbpath)/include -std=c99
-AM_CFLAGS = $(CFLAGS) -I$(dumbpath)/include
-dumb_la_LDFLAGS = -module -lm
+LDFLAGS+=-module -shared -lm
-dumb_la_SOURCES =\
+SOURCES=\
dumb-kode54/src/it/readam.c\
dumb-kode54/src/it/readstm.c\
dumb-kode54/src/it/loads3m.c\
@@ -79,29 +77,20 @@ dumb-kode54/src/helpers/riff.c\
dumb-kode54/src/helpers/memfile.c\
dumb-kode54/src/helpers/sampbuf.c\
dumb-kode54/src/helpers/barray.c\
-dumb-kode54/studio/include/guitop.h\
-dumb-kode54/studio/include/dumbgui.h\
-dumb-kode54/studio/include/options.h\
-dumb-kode54/studio/include/subclip.h\
-dumb-kode54/studio/include/main.h\
-dumb-kode54/studio/include/guiproc.h\
-dumb-kode54/studio/include/dumbmenu.h\
-dumb-kode54/studio/include/dumbdesk.h\
-dumb-kode54/src/tools/it/modulus.h\
-dumb-kode54/include/internal/it.h\
-dumb-kode54/include/internal/dumb.h\
-dumb-kode54/include/internal/barray.h\
-dumb-kode54/include/internal/riff.h\
-dumb-kode54/include/internal/aldumb.h\
-dumb-kode54/include/dumb.h\
-dumb-kode54/include/aldumb.h\
-dumb-kode54/winamp/in_duh.h\
-dumb-kode54/winamp/in2.h\
-dumb-kode54/winamp/resource.h\
-dumb-kode54/winamp/out.h\
-dumb-kode54/winamp/gui.h\
-dumb-kode54/src/helpers/resample.inc\
-dumb-kode54/src/helpers/resamp2.inc\
-dumb-kode54/src/helpers/resamp3.inc\
cdumb.c
-endif
+
+OBJECTS=$(SOURCES:.c=.o)
+
+OUT=dumb.so
+
+all: $(SOURCES) $(OUT)
+
+$(OUT): $(OBJECTS)
+ $(CC) $(LDFLAGS) $(OBJECTS) -o $@
+
+.c.o:
+ $(CC) $(CFLAGS) $< -c -o $@
+
+clean:
+ rm $(OBJECTS) $(OUT)
+
diff --git a/plugins/dumb/cdumb.c b/plugins/dumb/cdumb.c
index b8189eeb..b5367640 100644
--- a/plugins/dumb/cdumb.c
+++ b/plugins/dumb/cdumb.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -51,7 +51,7 @@ static DUH*
open_module(const char *fname, const char *ext, int *start_order, int *is_it, int *is_dos, const char **filetype);
static DB_fileinfo_t *
-cdumb_open (void) {
+cdumb_open (uint32_t hints) {
DB_fileinfo_t *_info = malloc (sizeof (dumb_info_t));
memset (_info, 0, sizeof (dumb_info_t));
return _info;
@@ -59,26 +59,27 @@ cdumb_open (void) {
static int
cdumb_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
- trace ("cdumb_init %s\n", it->fname);
+ trace ("cdumb_init %s\n", deadbeef->pl_find_meta (it, ":URI"));
dumb_info_t *info = (dumb_info_t *)_info;
int start_order = 0;
int is_dos, is_it;
- const char *ext = it->fname + strlen (it->fname) - 1;
- while (*ext != '.' && ext > it->fname) {
+ const char *ext = deadbeef->pl_find_meta (it, ":URI") + strlen (deadbeef->pl_find_meta (it, ":URI")) - 1;
+ while (*ext != '.' && ext > deadbeef->pl_find_meta (it, ":URI")) {
ext--;
}
ext++;
const char *ftype;
- info->duh = open_module(it->fname, ext, &start_order, &is_it, &is_dos, &ftype);
+ info->duh = open_module(deadbeef->pl_find_meta (it, ":URI"), ext, &start_order, &is_it, &is_dos, &ftype);
dumb_it_do_initial_runthrough (info->duh);
_info->plugin = &plugin;
- _info->bps = 16;
- _info->channels = 2;
- _info->samplerate = deadbeef->conf_get_int ("synth.samplerate", 44100);
+ _info->fmt.bps = deadbeef->conf_get_int ("dumb.8bitoutput", 0) ? 8 : 16;
+ _info->fmt.channels = 2;
+ _info->fmt.samplerate = deadbeef->conf_get_int ("synth.samplerate", 44100);
_info->readpos = 0;
+ _info->fmt.channelmask = _info->fmt.channels == 1 ? DDB_SPEAKER_FRONT_LEFT : (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT);
if (cdumb_startrenderer (_info) < 0) {
return -1;
@@ -139,12 +140,13 @@ static int
cdumb_read (DB_fileinfo_t *_info, char *bytes, int size) {
trace ("cdumb_read req %d\n", size);
dumb_info_t *info = (dumb_info_t *)_info;
- int length = size / 4;
+ int samplesize = (_info->fmt.bps >> 3) * _info->fmt.channels;
+ int length = size / samplesize;
long ret;
- ret = duh_render (info->renderer, 16, 0, 1, 65536.f / _info->samplerate, length, bytes);
- _info->readpos += ret / (float)_info->samplerate;
- trace ("cdumb_read %d\n", ret*4);
- return ret*4;
+ ret = duh_render (info->renderer, _info->fmt.bps, 0, 1, 65536.f / _info->fmt.samplerate, length, bytes);
+ _info->readpos += ret / (float)_info->fmt.samplerate;
+ trace ("cdumb_read %d\n", ret*samplesize);
+ return ret*samplesize;
}
static int
@@ -159,8 +161,8 @@ cdumb_seek (DB_fileinfo_t *_info, float time) {
else {
time -= _info->readpos;
}
- int pos = time * _info->samplerate;
- duh_sigrenderer_generate_samples (info->renderer, 0, 65536.0f / _info->samplerate, pos, NULL);
+ int pos = time * _info->fmt.samplerate;
+ duh_sigrenderer_generate_samples (info->renderer, 0, 65536.0f / _info->fmt.samplerate, pos, NULL);
_info->readpos = duh_sigrenderer_get_position (info->renderer) / 65536.f;
return 0;
}
@@ -691,8 +693,8 @@ static DUH * open_module(const char *fname, const char *ext, int *start_order, i
return duh;
}
-static const char *convstr (const char* str, int sz) {
- static char out[2048];
+static const char *
+convstr (const char* str, int sz, char *out, int out_sz) {
int i;
for (i = 0; i < sz; i++) {
if (str[i] != ' ') {
@@ -705,11 +707,11 @@ static const char *convstr (const char* str, int sz) {
}
// check for utf8 (hack)
- if (deadbeef->junk_iconv (str, sz, out, sizeof (out), "utf-8", "utf-8") >= 0) {
+ if (deadbeef->junk_iconv (str, sz, out, out_sz, "utf-8", "utf-8") >= 0) {
return out;
}
- if (deadbeef->junk_iconv (str, sz, out, sizeof (out), "utf-8", "iso8859-1") >= 0) {
+ if (deadbeef->junk_iconv (str, sz, out, out_sz, "cp1252", "utf-8") >= 0) {
return out;
}
@@ -717,25 +719,10 @@ static const char *convstr (const char* str, int sz) {
return NULL;
}
-static DB_playItem_t *
-cdumb_insert (DB_playItem_t *after, const char *fname) {
- const char *ext = fname + strlen (fname) - 1;
- while (*ext != '.' && ext > fname) {
- ext--;
- }
- ext++;
- int start_order = 0;
- int is_it;
- int is_dos;
- const char *ftype;
- DUH* duh = open_module(fname, ext, &start_order, &is_it, &is_dos, &ftype);
- if (!duh) {
- return NULL;
- }
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (fname);
- DUMB_IT_SIGDATA * itsd = duh_get_it_sigdata(duh);
+static void
+read_metadata_internal (DB_playItem_t *it, DUMB_IT_SIGDATA *itsd) {
+ char temp[2048];
+
if (itsd->name[0]) {
int tl = sizeof(itsd->name);
int i;
@@ -744,15 +731,90 @@ cdumb_insert (DB_playItem_t *after, const char *fname) {
deadbeef->pl_add_meta (it, "title", NULL);
}
else {
- deadbeef->pl_add_meta (it, "title", convstr ((char*)&itsd->name, sizeof(itsd->name)));
+ deadbeef->pl_add_meta (it, "title", convstr ((char*)&itsd->name, sizeof(itsd->name), temp, sizeof (temp)));
}
}
else {
deadbeef->pl_add_meta (it, "title", NULL);
}
+ int i;
+ for (i = 0; i < itsd->n_instruments; i++) {
+ char key[100];
+ snprintf (key, sizeof (key), "INST%03d", i);
+ deadbeef->pl_add_meta (it, key, convstr ((char *)&itsd->instrument[i].name, sizeof (itsd->instrument[i].name), temp, sizeof (temp)));
+ }
+ for (i = 0; i < itsd->n_samples; i++) {
+ char key[100];
+ snprintf (key, sizeof (key), "SAMP%03d", i);
+ deadbeef->pl_add_meta (it, key, convstr ((char *)&itsd->sample[i].name, sizeof (itsd->sample[i].name), temp, sizeof (temp)));
+ }
+
+ char s[100];
+
+ snprintf (s, sizeof (s), "%d", itsd->n_orders);
+ deadbeef->pl_add_meta (it, ":MOD_ORDERS", s);
+ snprintf (s, sizeof (s), "%d", itsd->n_instruments);
+ deadbeef->pl_add_meta (it, ":MOD_INSTRUMENTS", s);
+ snprintf (s, sizeof (s), "%d", itsd->n_samples);
+ deadbeef->pl_add_meta (it, ":MOD_SAMPLES", s);
+ snprintf (s, sizeof (s), "%d", itsd->n_patterns);
+ deadbeef->pl_add_meta (it, ":MOD_PATTERNS", s);
+ snprintf (s, sizeof (s), "%d", itsd->n_pchannels);
+ deadbeef->pl_add_meta (it, ":MOD_CHANNELS", s);
+}
+
+static int
+cdumb_read_metadata (DB_playItem_t *it) {
+ const char *fname = deadbeef->pl_find_meta (it, ":URI");
+ const char *ext = strrchr (fname, '.');
+ if (ext) {
+ ext++;
+ }
+ else {
+ ext = "";
+ }
+ int start_order = 0;
+ int is_it;
+ int is_dos;
+ const char *ftype;
+ DUH* duh = open_module(fname, ext, &start_order, &is_it, &is_dos, &ftype);
+ if (!duh) {
+ unload_duh (duh);
+ return -1;
+ }
+ DUMB_IT_SIGDATA * itsd = duh_get_it_sigdata(duh);
+
+ deadbeef->pl_delete_all_meta (it);
+ read_metadata_internal (it, itsd);
+ unload_duh (duh);
+ return 0;
+}
+
+static DB_playItem_t *
+cdumb_insert (DB_playItem_t *after, const char *fname) {
+ const char *ext = strrchr (fname, '.');
+ if (ext) {
+ ext++;
+ }
+ else {
+ ext = "";
+ }
+ int start_order = 0;
+ int is_it;
+ int is_dos;
+ const char *ftype;
+ DUH* duh = open_module(fname, ext, &start_order, &is_it, &is_dos, &ftype);
+ if (!duh) {
+ return NULL;
+ }
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
+ DUMB_IT_SIGDATA * itsd = duh_get_it_sigdata(duh);
+
+ read_metadata_internal (it, itsd);
+
dumb_it_do_initial_runthrough (duh);
deadbeef->pl_set_item_duration (it, duh_get_length (duh)/65536.0f);
- it->filetype = ftype;
+ deadbeef->pl_add_meta (it, ":FILETYPE", ftype);
// printf ("duration: %f\n", _info->duration);
after = deadbeef->pl_insert_item (after, it);
deadbeef->pl_item_unref (it);
@@ -811,18 +873,39 @@ static const char *filetypes[] = { "IT", "XM", "S3M", "STM", "669", "PTM", "PSM"
static const char settings_dlg[] =
"property \"Resampling quality (0..2, higher is better)\" entry dumb.resampling_quality 2;\n"
+ "property \"8-bit output (default is 16)\" checkbox dumb.8bitoutput 0;\n"
;
+
// define plugin interface
static DB_decoder_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.id = "stddumb",
.plugin.name = "DUMB module player",
.plugin.descr = "module player based on DUMB library",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "Uses a fork of DUMB (Dynamic Universal Music Bibliotheque), Version 0.9.3\n"
+ "Copyright (C) 2001-2005 Ben Davis, Robert J Ohannessian and Julien Cugniere\n"
+ "Uses code from kode54's foobar2000 plugin, http://kode54.foobar2000.org/\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = cgme_start,
.plugin.stop = cgme_stop,
@@ -830,9 +913,10 @@ static DB_decoder_t plugin = {
.open = cdumb_open,
.init = cdumb_init,
.free = cdumb_free,
- .read_int16 = cdumb_read,
+ .read = cdumb_read,
.seek = cdumb_seek,
.insert = cdumb_insert,
+ .read_metadata = cdumb_read_metadata,
.exts = exts,
.filetypes = filetypes
};
diff --git a/plugins/dumb/dumb-kode54/src/it/loadmod.c b/plugins/dumb/dumb-kode54/src/it/loadmod.c
index 0b7dc618..dd43b611 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadmod.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadmod.c
@@ -26,7 +26,7 @@
* pointer to the DUH struct. When you have finished with it, you must
* pass the pointer to unload_duh() so that the memory can be freed.
*/
-DUH *dumb_load_mod_quick(const char *filename, int restrict)
+DUH *dumb_load_mod_quick(const char *filename, int restr)
{
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
@@ -34,7 +34,7 @@ DUH *dumb_load_mod_quick(const char *filename, int restrict)
if (!f)
return NULL;
- duh = dumb_read_mod_quick(f, restrict);
+ duh = dumb_read_mod_quick(f, restr);
dumbfile_close(f);
diff --git a/plugins/dumb/dumb-kode54/src/it/loadmod2.c b/plugins/dumb/dumb-kode54/src/it/loadmod2.c
index 7847d19f..c1f46e4c 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadmod2.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadmod2.c
@@ -21,9 +21,9 @@
-DUH *dumb_load_mod(const char *filename, int restrict)
+DUH *dumb_load_mod(const char *filename, int restr)
{
- DUH *duh = dumb_load_mod_quick(filename, restrict);
+ DUH *duh = dumb_load_mod_quick(filename, restr);
dumb_it_do_initial_runthrough(duh);
return duh;
}
diff --git a/plugins/dumb/dumb-kode54/src/it/readmod.c b/plugins/dumb/dumb-kode54/src/it/readmod.c
index a934af40..538d86ba 100644
--- a/plugins/dumb/dumb-kode54/src/it/readmod.c
+++ b/plugins/dumb/dumb-kode54/src/it/readmod.c
@@ -439,7 +439,7 @@ static DUMBFILE *dumbfile_buffer_mod_2(DUMBFILE *f, long *remain)
}
-static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict)
+static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restr)
{
DUMB_IT_SIGDATA *sigdata;
int n_channels;
@@ -554,7 +554,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict)
}
// moo
- if ( restrict && sigdata->n_samples == 15 )
+ if ( restr && sigdata->n_samples == 15 )
{
free(sigdata);
dumbfile_close(f);
@@ -760,13 +760,13 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict)
return sigdata;
}
-DUH *dumb_read_mod_quick(DUMBFILE *f, int restrict)
+DUH *dumb_read_mod_quick(DUMBFILE *f, int restr)
{
sigdata_t *sigdata;
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
- sigdata = it_mod_load_sigdata(f, restrict);
+ sigdata = it_mod_load_sigdata(f, restr);
if (!sigdata)
return NULL;
diff --git a/plugins/dumb/dumb-kode54/src/it/readmod2.c b/plugins/dumb/dumb-kode54/src/it/readmod2.c
index 102ead12..299c584e 100644
--- a/plugins/dumb/dumb-kode54/src/it/readmod2.c
+++ b/plugins/dumb/dumb-kode54/src/it/readmod2.c
@@ -21,9 +21,9 @@
-DUH *dumb_read_mod(DUMBFILE *f, int restrict)
+DUH *dumb_read_mod(DUMBFILE *f, int restr)
{
- DUH *duh = dumb_read_mod_quick(f, restrict);
+ DUH *duh = dumb_read_mod_quick(f, restr);
dumb_it_do_initial_runthrough(duh);
return duh;
}
diff --git a/plugins/ffap/ffap.c b/plugins/ffap/ffap.c
index deaa06dc..7abf0103 100644
--- a/plugins/ffap/ffap.c
+++ b/plugins/ffap/ffap.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>
based on apedec from FFMpeg Copyright (c) 2007 Benjamin Zores <ben@geexbox.org>
based upon libdemac from Dave Chapman.
@@ -36,6 +36,7 @@
#include <stdlib.h>
//#include <alloca.h>
#include <assert.h>
+#include <math.h>
#include "../../deadbeef.h"
#ifdef TARGET_ANDROID
@@ -678,7 +679,7 @@ ffap_free (DB_fileinfo_t *_info)
}
static DB_fileinfo_t *
-ffap_open (void) {
+ffap_open (uint32_t hints) {
DB_fileinfo_t *_info = malloc (sizeof (ape_info_t));
memset (_info, 0, sizeof (ape_info_t));
return _info;
@@ -689,7 +690,7 @@ ffap_init (DB_fileinfo_t *_info, DB_playItem_t *it)
{
ape_info_t *info = (ape_info_t*)_info;
- info->fp = deadbeef->fopen (it->fname);
+ info->fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!info->fp) {
return -1;
}
@@ -726,9 +727,10 @@ ffap_init (DB_fileinfo_t *_info, DB_playItem_t *it)
}
_info->plugin = &plugin;
- _info->bps = info->ape_ctx.bps;
- _info->samplerate = info->ape_ctx.samplerate;
- _info->channels = info->ape_ctx.channels;
+ _info->fmt.bps = info->ape_ctx.bps;
+ _info->fmt.samplerate = info->ape_ctx.samplerate;
+ _info->fmt.channels = info->ape_ctx.channels;
+ _info->fmt.channelmask = _info->fmt.channels == 1 ? DDB_SPEAKER_FRONT_LEFT : (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT);
_info->readpos = 0;
if (it->endsample > 0) {
info->startsample = it->startsample;
@@ -1560,16 +1562,16 @@ ape_decode_frame(DB_fileinfo_t *_info, void *data, int *data_size)
{
ape_info_t *info = (ape_info_t*)_info;
APEContext *s = &info->ape_ctx;
- int16_t *samples = data;
+ char *samples = data;
int nblocks;
int i, n;
int blockstodecode;
int bytes_used;
- int samplesize = _info->bps>>3;
+ int samplesize = _info->fmt.bps/8 * s->channels;;
/* should not happen but who knows */
- if (BLOCKS_PER_LOOP * samplesize * s->channels > *data_size) {
- fprintf (stderr, "ape: Packet size is too big! (max is %d where you have %d)\n", *data_size, BLOCKS_PER_LOOP * samplesize * s->channels);
+ if (BLOCKS_PER_LOOP * samplesize > *data_size) {
+ fprintf (stderr, "ape: Packet size is too big! (max is %d where you have %d)\n", *data_size, BLOCKS_PER_LOOP * samplesize);
return -1;
}
@@ -1665,17 +1667,58 @@ ape_decode_frame(DB_fileinfo_t *_info, void *data, int *data_size)
int skip = min (s->samplestoskip, blockstodecode);
i = skip;
- for (; i < blockstodecode; i++) {
- *samples++ = (int16_t)(s->decoded0[i]>>(_info->bps-16));
- if(s->channels == 2) {
- *samples++ = (int16_t)(s->decoded1[i]>>(_info->bps-16));
+ if (_info->fmt.bps == 32) {
+ for (; i < blockstodecode; i++) {
+ *((int32_t*)samples) = s->decoded0[i];
+ samples += 4;
+ if(s->channels > 1) {
+ *((int32_t*)samples) = s->decoded1[i];
+ samples += 4;
+ }
+ }
+ }
+ else if (_info->fmt.bps == 24) {
+ for (; i < blockstodecode; i++) {
+ int32_t sample = s->decoded0[i];
+
+ samples[0] = sample&0xff;
+ samples[1] = (sample&0xff00)>>8;
+ samples[2] = (sample&0xff0000)>>16;
+ samples += 3;
+ if(s->channels > 1) {
+ sample = s->decoded1[i];
+ samples[0] = sample&0xff;
+ samples[1] = (sample&0xff00)>>8;
+ samples[2] = (sample&0xff0000)>>16;
+ samples += 3;
+ }
+ }
+ }
+ else if (_info->fmt.bps == 16) {
+ for (; i < blockstodecode; i++) {
+ *((int16_t*)samples) = (int16_t)s->decoded0[i];
+ samples += 2;
+ if(s->channels > 1) {
+ *((int16_t*)samples) = (int16_t)s->decoded1[i];
+ samples += 2;
+ }
+ }
+ }
+ else if (_info->fmt.bps == 8) {
+ for (; i < blockstodecode; i++) {
+ *samples = (int16_t)s->decoded0[i];
+ samples++;
+ if(s->channels > 1) {
+ *samples = (int16_t)s->decoded1[i];
+ samples++;
+ }
}
}
s->samplestoskip -= skip;
s->samples -= blockstodecode;
- *data_size = (blockstodecode - skip) * 2 * s->channels;
+ *data_size = (blockstodecode - skip) * samplesize;
// ape_ctx.currentsample += blockstodecode - skip;
bytes_used = s->samples ? s->ptr - s->last_ptr : s->packet_remaining;
@@ -1699,6 +1742,9 @@ ffap_insert (DB_playItem_t *after, const char *fname) {
if (!fp) {
return NULL;
}
+
+ int64_t fsize = deadbeef->fgetlength (fp);
+
int skip = deadbeef->junk_get_leading_size (fp);
if (skip > 0) {
deadbeef->fseek (fp, skip, SEEK_SET);
@@ -1718,10 +1764,8 @@ ffap_insert (DB_playItem_t *after, const char *fname) {
float duration = ape_ctx.totalsamples / (float)ape_ctx.samplerate;
DB_playItem_t *it = NULL;
- it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (fname);
- it->filetype = "APE";
+ it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
+ deadbeef->pl_add_meta (it, ":FILETYPE", "APE");
deadbeef->pl_set_item_duration (it, duration);
/*int v2err = */deadbeef->junk_id3v2_read (it, fp);
@@ -1752,6 +1796,19 @@ ffap_insert (DB_playItem_t *after, const char *fname) {
}
deadbeef->pl_unlock ();
+ char s[100];
+ snprintf (s, sizeof (s), "%lld", fsize);
+ deadbeef->pl_add_meta (it, ":FILE_SIZE", s);
+ snprintf (s, sizeof (s), "%d", ape_ctx.bps);
+ deadbeef->pl_add_meta (it, ":BPS", s);
+ snprintf (s, sizeof (s), "%d", ape_ctx.channels);
+ deadbeef->pl_add_meta (it, ":CHANNELS", s);
+ snprintf (s, sizeof (s), "%d", ape_ctx.samplerate);
+ deadbeef->pl_add_meta (it, ":SAMPLERATE", s);
+ int br = (int)roundf(fsize / duration * 8 / 1000);
+ snprintf (s, sizeof (s), "%d", br);
+ deadbeef->pl_add_meta (it, ":BITRATE", s);
+
cue = deadbeef->pl_insert_cue (after, it, ape_ctx.totalsamples, ape_ctx.samplerate);
if (cue) {
deadbeef->pl_item_unref (it);
@@ -1760,6 +1817,7 @@ ffap_insert (DB_playItem_t *after, const char *fname) {
}
deadbeef->pl_add_meta (it, "title", NULL);
+
after = deadbeef->pl_insert_item (after, it);
deadbeef->pl_item_unref (it);
@@ -1767,11 +1825,14 @@ ffap_insert (DB_playItem_t *after, const char *fname) {
}
static int
-ffap_read_int16 (DB_fileinfo_t *_info, char *buffer, int size) {
+ffap_read (DB_fileinfo_t *_info, char *buffer, int size) {
ape_info_t *info = (ape_info_t*)_info;
- if (info->ape_ctx.currentsample + size / ((info->info.bps / 8) * info->ape_ctx.channels) > info->endsample) {
- size = (info->endsample - info->ape_ctx.currentsample + 1) * (info->info.bps / 8) * info->ape_ctx.channels;
- trace ("size truncated to %d bytes (%d samples), cursample=%d, info->endsample=%d, totalsamples=%d\n", size, size / (info->info.bps / 8) / info->ape_ctx.channels, info->ape_ctx.currentsample, info->endsample, info->ape_ctx.totalsamples);
+
+ int samplesize = _info->fmt.bps / 8 * info->ape_ctx.channels;
+
+ if (info->ape_ctx.currentsample + size / samplesize > info->endsample) {
+ size = (info->endsample - info->ape_ctx.currentsample + 1) * samplesize;
+ trace ("size truncated to %d bytes (%d samples), cursample=%d, info->endsample=%d, totalsamples=%d\n", size, size / samplesize, info->ape_ctx.currentsample, info->endsample, info->ape_ctx.totalsamples);
if (size <= 0) {
return 0;
}
@@ -1808,8 +1869,8 @@ ffap_read_int16 (DB_fileinfo_t *_info, char *buffer, int size) {
}
info->ape_ctx.remaining -= sz;
}
- info->ape_ctx.currentsample += (inits - size) / (2 * info->ape_ctx.channels);
- _info->readpos = (info->ape_ctx.currentsample-info->startsample) / (float)_info->samplerate;
+ info->ape_ctx.currentsample += (inits - size) / samplesize;
+ _info->readpos = (info->ape_ctx.currentsample-info->startsample) / (float)_info->fmt.samplerate;
return inits - size;
}
@@ -1844,12 +1905,12 @@ ffap_seek_sample (DB_fileinfo_t *_info, int sample) {
static int
ffap_seek (DB_fileinfo_t *_info, float seconds) {
- return ffap_seek_sample (_info, seconds * _info->samplerate);
+ return ffap_seek_sample (_info, seconds * _info->fmt.samplerate);
}
static int ffap_read_metadata (DB_playItem_t *it) {
- DB_FILE *fp = deadbeef->fopen (it->fname);
+ DB_FILE *fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!fp) {
return -1;
}
@@ -1899,19 +1960,37 @@ static const char *filetypes[] = { "APE", NULL };
// define plugin interface
static DB_decoder_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.id = "ffap",
.plugin.name = "Monkey's Audio (APE) decoder",
.plugin.descr = "APE player based on code from libavc and rockbox",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "based on apedec from FFMpeg Copyright (c) 2007 Benjamin Zores <ben@geexbox.org>\n"
+ "based upon libdemac from Dave Chapman.\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.open = ffap_open,
.init = ffap_init,
.free = ffap_free,
- .read_int16 = ffap_read_int16,
+ .read = ffap_read,
.seek = ffap_seek,
.seek_sample = ffap_seek_sample,
.insert = ffap_insert,
diff --git a/plugins/ffmpeg/ChangeLog b/plugins/ffmpeg/ChangeLog
new file mode 100644
index 00000000..f3179866
--- /dev/null
+++ b/plugins/ffmpeg/ChangeLog
@@ -0,0 +1,5 @@
+version 1.2
+ Added AMR support via libopencore
+
+version 1.1
+ Switched to ffmpeg commit 25472
diff --git a/plugins/ffmpeg/ffmpeg.c b/plugins/ffmpeg/ffmpeg.c
index f27e403b..020f2a1c 100644
--- a/plugins/ffmpeg/ffmpeg.c
+++ b/plugins/ffmpeg/ffmpeg.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -55,7 +55,11 @@
static DB_decoder_t plugin;
static DB_functions_t *deadbeef;
-static const char * exts[] = { "m4a", "wma", "aa3", "oma", "ac3", "vqf", NULL };
+#define DEFAULT_EXTS "m4a;wma;aa3;oma;ac3;vqf;amr"
+
+#define EXT_MAX 100
+
+static char * exts[EXT_MAX] = {NULL};
enum {
FT_ALAC = 0,
@@ -63,10 +67,11 @@ enum {
FT_ATRAC3 = 2,
FT_VQF = 3,
FT_AC3 = 4,
+ FT_AMR = 5,
FT_UNKNOWN = 5
};
-static const char *filetypes[] = { "ALAC", "WMA", "ATRAC3", "VQF", "AC3", "FFMPEG (unknown)", NULL };
+static const char *filetypes[] = { "FFMPEG", NULL };
#define FF_PROTOCOL_NAME "deadbeef"
@@ -93,7 +98,7 @@ static DB_playItem_t *current_track;
static DB_fileinfo_t *current_info;
static DB_fileinfo_t *
-ffmpeg_open (void) {
+ffmpeg_open (uint32_t hints) {
DB_fileinfo_t *_info = malloc (sizeof (ffmpeg_info_t));
memset (_info, 0, sizeof (ffmpeg_info_t));
return _info;
@@ -102,19 +107,19 @@ ffmpeg_open (void) {
static int
ffmpeg_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
ffmpeg_info_t *info = (ffmpeg_info_t *)_info;
- trace ("ffmpeg init %s\n", it->fname);
+ trace ("ffmpeg init %s\n", deadbeef->pl_find_meta (it, ":URI"));
// prepare to decode the track
// return -1 on failure
int ret;
- int l = strlen (it->fname);
+ int l = strlen (deadbeef->pl_find_meta (it, ":URI"));
char *uri = alloca (l + sizeof (FF_PROTOCOL_NAME) + 1);
int i;
// construct uri
memcpy (uri, FF_PROTOCOL_NAME, sizeof (FF_PROTOCOL_NAME)-1);
memcpy (uri + sizeof (FF_PROTOCOL_NAME)-1, ":", 1);
- memcpy (uri + sizeof (FF_PROTOCOL_NAME), it->fname, l);
+ memcpy (uri + sizeof (FF_PROTOCOL_NAME), deadbeef->pl_find_meta (it, ":URI"), l);
uri[sizeof (FF_PROTOCOL_NAME) + l] = 0;
trace ("ffmpeg: uri: %s\n", uri);
@@ -149,10 +154,10 @@ ffmpeg_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
if (info->codec == NULL)
{
- trace ("ffmpeg can't decode %s\n", it->fname);
+ trace ("ffmpeg can't decode %s\n", deadbeef->pl_find_meta (it, ":URI"));
return -1;
}
- trace ("ffmpeg can decode %s\n", it->fname);
+ trace ("ffmpeg can decode %s\n", deadbeef->pl_find_meta (it, ":URI"));
trace ("ffmpeg: codec=%s, stream=%d\n", info->codec->name, i);
if (avcodec_open (info->ctx, info->codec) < 0) {
@@ -160,18 +165,7 @@ ffmpeg_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
return -1;
}
- if (!strcasecmp (info->codec->name, "alac")) {
- it->filetype = filetypes[FT_ALAC];
- }
- else if (strcasestr (info->codec->name, "wma")) {
- it->filetype = filetypes[FT_WMA];
- }
- else if (strcasestr (info->codec->name, "ac3")) {
- it->filetype = filetypes[FT_AC3];
- }
- else {
- it->filetype = filetypes[FT_UNKNOWN];
- }
+ deadbeef->pl_replace_meta (it, ":FILETYPE", info->codec->name);
int bps = av_get_bits_per_sample_format (info->ctx->sample_fmt);
int samplerate = info->ctx->sample_rate;
@@ -196,9 +190,20 @@ ffmpeg_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
// fill in mandatory plugin fields
_info->plugin = &plugin;
_info->readpos = 0;
- _info->bps = bps;
- _info->channels = info->ctx->channels;
- _info->samplerate = samplerate;
+ _info->fmt.bps = bps;
+ _info->fmt.channels = info->ctx->channels;
+ _info->fmt.samplerate = samplerate;
+
+
+ int64_t layout = info->ctx->channel_layout;
+ if (layout != 0, 0) {
+ _info->fmt.channelmask = layout;
+ }
+ else {
+ for (int i = 0; i < _info->fmt.channels; i++) {
+ _info->fmt.channelmask |= 1 << i;
+ }
+ }
// subtrack info
info->currentsample = 0;
@@ -222,7 +227,7 @@ ffmpeg_free (DB_fileinfo_t *_info) {
if (info->buffer) {
free (info->buffer);
}
- // free everything allocated in _init and _read_int16
+ // free everything allocated in _init and _read
if (info->have_packet) {
av_free_packet (&info->pkt);
}
@@ -237,14 +242,14 @@ ffmpeg_free (DB_fileinfo_t *_info) {
}
static int
-ffmpeg_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
+ffmpeg_read (DB_fileinfo_t *_info, char *bytes, int size) {
trace ("ffmpeg_read_int16 %d\n", size);
ffmpeg_info_t *info = (ffmpeg_info_t*)_info;
- int out_ch = min (2, _info->channels);
+ int samplesize = _info->fmt.channels * _info->fmt.bps / 8;
- if (info->endsample >= 0 && info->currentsample + size / (2 * out_ch) > info->endsample) {
- size = (info->endsample - info->currentsample + 1) * 2 * out_ch;
+ if (info->endsample >= 0 && info->currentsample + size / samplesize > info->endsample) {
+ size = (info->endsample - info->currentsample + 1) * samplesize;
if (size <= 0) {
return 0;
}
@@ -259,20 +264,13 @@ ffmpeg_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
if (info->left_in_buffer > 0) {
// int sz = min (size, info->left_in_buffer);
- int nsamples = size / out_ch / 2;
- int nsamples_buf = info->left_in_buffer / 2 / _info->channels;
+ int nsamples = size / samplesize;
+ int nsamples_buf = info->left_in_buffer / samplesize;
nsamples = min (nsamples, nsamples_buf);
- int sz = nsamples * 2 * _info->channels;
- for (int i = 0; i < nsamples; i++) {
- *((int16_t*)bytes) = ((int16_t*)info->buffer)[i * _info->channels + 0];
- bytes += 2;
- size -= 2;
- if (out_ch > 1) {
- *((int16_t*)bytes) = ((int16_t*)info->buffer)[i * _info->channels + 1];
- bytes += 2;
- size -= 2;
- }
- }
+ int sz = nsamples * samplesize;
+ memcpy (bytes, info->buffer, nsamples*samplesize);
+ bytes += nsamples * samplesize;
+ size -= nsamples * samplesize;
if (sz != info->left_in_buffer) {
memmove (info->buffer, info->buffer+sz, info->left_in_buffer-sz);
}
@@ -359,8 +357,8 @@ ffmpeg_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
}
}
- info->currentsample += (initsize-size) / (2 * out_ch);
- _info->readpos = (float)info->currentsample / _info->samplerate;
+ info->currentsample += (initsize-size) / samplesize;
+ _info->readpos = (float)info->currentsample / _info->fmt.samplerate;
return initsize-size;
}
@@ -376,7 +374,7 @@ ffmpeg_seek_sample (DB_fileinfo_t *_info, int sample) {
info->have_packet = 0;
}
sample += info->startsample;
- int64_t tm = (int64_t)sample/ _info->samplerate * AV_TIME_BASE;
+ int64_t tm = (int64_t)sample/ _info->fmt.samplerate * AV_TIME_BASE;
trace ("ffmpeg: seek to sample: %d, t: %d\n", sample, (int)tm);
info->left_in_packet = 0;
info->left_in_buffer = 0;
@@ -387,7 +385,7 @@ ffmpeg_seek_sample (DB_fileinfo_t *_info, int sample) {
// update readpos
info->currentsample = sample;
- _info->readpos = (float)(sample - info->startsample) / _info->samplerate;
+ _info->readpos = (float)(sample - info->startsample) / _info->fmt.samplerate;
return 0;
}
@@ -397,7 +395,7 @@ ffmpeg_seek (DB_fileinfo_t *_info, float time) {
// seek to specified time in seconds
// return 0 on success
// return -1 on failure
- return ffmpeg_seek_sample (_info, time * _info->samplerate);
+ return ffmpeg_seek_sample (_info, time * _info->fmt.samplerate);
}
static const char *map[] = {
@@ -529,13 +527,11 @@ ffmpeg_insert (DB_playItem_t *after, const char *fname) {
int totalsamples = fctx->duration * samplerate / AV_TIME_BASE;
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (fname);
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
// FIXME: get proper codec
- it->filetype = filetypes[FT_UNKNOWN];
+ deadbeef->pl_replace_meta (it, ":FILETYPE", codec->name);
- if (!deadbeef->is_local_file (it->fname)) {
+ if (!deadbeef->is_local_file (deadbeef->pl_find_meta (it, ":URI"))) {
deadbeef->pl_set_item_duration (it, -1);
}
else {
@@ -544,6 +540,32 @@ ffmpeg_insert (DB_playItem_t *after, const char *fname) {
// add metainfo
ffmpeg_read_metadata_internal (it, fctx);
+
+ int64_t fsize = -1;
+
+ DB_FILE *fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
+ if (fp) {
+ if (!fp->vfs->is_streaming ()) {
+ fsize = deadbeef->fgetlength (fp);
+ }
+ deadbeef->fclose (fp);
+ }
+
+ if (fsize >= 0 && duration > 0) {
+ char s[100];
+ snprintf (s, sizeof (s), "%lld", fsize);
+ deadbeef->pl_add_meta (it, ":FILE_SIZE", s);
+ snprintf (s, sizeof (s), "%d", av_get_bits_per_sample_format (ctx->sample_fmt));
+ deadbeef->pl_add_meta (it, ":BPS", s);
+ snprintf (s, sizeof (s), "%d", ctx->channels);
+ deadbeef->pl_add_meta (it, ":CHANNELS", s);
+ snprintf (s, sizeof (s), "%d", samplerate);
+ deadbeef->pl_add_meta (it, ":SAMPLERATE", s);
+ int br = (int)roundf(fsize / duration * 8 / 1000);
+ snprintf (s, sizeof (s), "%d", br);
+ deadbeef->pl_add_meta (it, ":BITRATE", s);
+ }
+
// free decoder
avcodec_close (ctx);
av_close_input_file(fctx);
@@ -576,7 +598,7 @@ ffmpeg_vfs_open(URLContext *h, const char *filename, int flags)
if (f == NULL)
return -ENOENT;
- if (f->vfs->streaming) {
+ if (f->vfs->is_streaming ()) {
deadbeef->fset_track (f, current_track);
if (current_info) {
current_info->file = f;
@@ -608,9 +630,9 @@ ffmpeg_vfs_seek(URLContext *h, int64_t pos, int whence)
DB_FILE *f = h->priv_data;
if (whence == AVSEEK_SIZE) {
- return f->vfs->streaming ? -1 : deadbeef->fgetlength (h->priv_data);
+ return f->vfs->is_streaming () ? -1 : deadbeef->fgetlength (h->priv_data);
}
- else if (f->vfs->streaming) {
+ else if (f->vfs->is_streaming ()) {
return -1;
}
else {
@@ -636,12 +658,50 @@ static URLProtocol vfswrapper = {
.url_close = ffmpeg_vfs_close,
};
+static void
+ffmpeg_init_exts (void) {
+ deadbeef->conf_lock ();
+ const char *new_exts = deadbeef->conf_get_str_fast ("ffmpeg.extensions", DEFAULT_EXTS);
+ for (int i = 0; exts[i]; i++) {
+ free (exts[i]);
+ }
+ exts[0] = NULL;
+
+ int n = 0;
+ while (*new_exts) {
+ if (n >= EXT_MAX) {
+ fprintf (stderr, "ffmpeg: too many extensions, max is %d\n", EXT_MAX);
+ break;
+ }
+ const char *e = new_exts;
+ while (*e && *e != ';') {
+ e++;
+ }
+ if (e != new_exts) {
+ char *ext = malloc (e-new_exts+1);
+ memcpy (ext, new_exts, e-new_exts);
+ ext[e-new_exts] = 0;
+ exts[n++] = ext;
+ }
+ if (*e == 0) {
+ break;
+ }
+ new_exts = e+1;
+ }
+ exts[n] = NULL;
+ deadbeef->conf_unlock ();
+}
+
+static int
+ffmpeg_on_configchanged (DB_event_t *ev, uintptr_t data) {
+ ffmpeg_init_exts ();
+ return 0;
+}
+
static int
ffmpeg_start (void) {
- // do one-time plugin initialization here
- // e.g. starting threads for background processing, subscribing to events, etc
- // return 0 on success
- // return -1 on failure
+ ffmpeg_init_exts ();
+ deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_CONFIGCHANGED, DB_CALLBACK (ffmpeg_on_configchanged), 0);
avcodec_init ();
av_register_all ();
av_register_protocol (&vfswrapper);
@@ -650,28 +710,29 @@ ffmpeg_start (void) {
static int
ffmpeg_stop (void) {
- // undo everything done in _start here
- // return 0 on success
- // return -1 on failure
- trace ("ffmpeg stop\n");
+ deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_CONFIGCHANGED, DB_CALLBACK (ffmpeg_on_configchanged), 0);
+ for (int i = 0; exts[i]; i++) {
+ free (exts[i]);
+ }
+ exts[0] = NULL;
return 0;
}
int
ffmpeg_read_metadata (DB_playItem_t *it) {
- trace ("ffmpeg_read_metadata: fname %s\n", it->fname);
+ trace ("ffmpeg_read_metadata: fname %s\n", deadbeef->pl_find_meta (it, ":URI"));
AVCodec *codec = NULL;
AVCodecContext *ctx = NULL;
AVFormatContext *fctx = NULL;
int ret;
- int l = strlen (it->fname);
+ int l = strlen (deadbeef->pl_find_meta (it, ":URI"));
char *uri = alloca (l + sizeof (FF_PROTOCOL_NAME) + 1);
int i;
// construct uri
memcpy (uri, FF_PROTOCOL_NAME, sizeof (FF_PROTOCOL_NAME)-1);
memcpy (uri + sizeof (FF_PROTOCOL_NAME)-1, ":", 1);
- memcpy (uri + sizeof (FF_PROTOCOL_NAME), it->fname, l);
+ memcpy (uri + sizeof (FF_PROTOCOL_NAME), deadbeef->pl_find_meta (it, ":URI"), l);
uri[sizeof (FF_PROTOCOL_NAME) + l] = 0;
trace ("ffmpeg: uri: %s\n", uri);
@@ -694,7 +755,7 @@ ffmpeg_read_metadata (DB_playItem_t *it) {
}
if (codec == NULL)
{
- trace ("ffmpeg can't decode %s\n", it->fname);
+ trace ("ffmpeg can't decode %s\n", deadbeef->pl_find_meta (it, ":URI"));
av_close_input_file(fctx);
return -1;
}
@@ -711,30 +772,49 @@ ffmpeg_read_metadata (DB_playItem_t *it) {
return 0;
}
+static const char settings_dlg[] =
+ "property \"File Extensions (separate with ';')\" entry ffmpeg.extensions \"" DEFAULT_EXTS "\";\n"
+;
+
// define plugin interface
static DB_decoder_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 2,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.id = "ffmpeg",
.plugin.name = "FFMPEG audio player",
.plugin.descr = "decodes audio formats using FFMPEG libavcodec",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = ffmpeg_start,
.plugin.stop = ffmpeg_stop,
+ .plugin.configdialog = settings_dlg,
.open = ffmpeg_open,
.init = ffmpeg_init,
.free = ffmpeg_free,
- .read_int16 = ffmpeg_read_int16,
-// .read_float32 = ffmpeg_read_float32,
+ .read = ffmpeg_read,
.seek = ffmpeg_seek,
.seek_sample = ffmpeg_seek_sample,
.insert = ffmpeg_insert,
.read_metadata = ffmpeg_read_metadata,
- .exts = exts,
+ .exts = (const char **)exts,
.filetypes = filetypes
};
diff --git a/plugins/flac/flac.c b/plugins/flac/flac.c
index 00cdf598..6c136e9d 100644
--- a/plugins/flac/flac.c
+++ b/plugins/flac/flac.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <FLAC/stream_decoder.h>
#include <FLAC/metadata.h>
+#include <math.h>
#include "../../deadbeef.h"
static DB_decoder_t plugin;
@@ -38,12 +39,13 @@ typedef struct {
FLAC__StreamDecoder *decoder;
char *buffer; // this buffer always has float samples
int remaining; // bytes remaining in buffer from last read
- int startsample;
- int endsample;
- int currentsample;
- int totalsamples;
+ int64_t startsample;
+ int64_t endsample;
+ int64_t currentsample;
+ int64_t totalsamples;
int flac_critical_error;
int init_stop_decoding;
+ int tagsize;
DB_FILE *file;
// used only on insert
@@ -104,24 +106,52 @@ cflac_write_callback (const FLAC__StreamDecoder *decoder, const FLAC__Frame *fra
if (info->bitrate > 0) {
deadbeef->streamer_set_bitrate (info->bitrate);
}
+ int samplesize = _info->fmt.channels * _info->fmt.bps / 8;
int bufsize = BUFFERSIZE - info->remaining;
- int bufsamples = bufsize / (_info->channels * _info->bps / 8);
+ int bufsamples = bufsize / samplesize;
int nsamples = min (bufsamples, frame->header.blocksize);
char *bufptr = &info->buffer[info->remaining];
- float mul = 1.f/ ((1 << (_info->bps-1))-1);
- int channels = _info->channels;
- if (channels > 2) {
- channels = 2;
- }
- int readbytes = frame->header.blocksize * channels * _info->bps / 8;
+ int readbytes = frame->header.blocksize * samplesize;
- for (int i = 0; i < nsamples; i++) {
- for (int c = 0; c < channels; c++) {
- int32_t sample = inputbuffer[c][i];
- *((float*)bufptr) = sample * mul;
- bufptr += sizeof (float);
- info->remaining += sizeof (float);
+ if (_info->fmt.bps == 32) {
+ for (int i = 0; i < nsamples; i++) {
+ for (int c = 0; c < _info->fmt.channels; c++) {
+ int32_t sample = inputbuffer[c][i];
+ *((int32_t*)bufptr) = sample;
+ bufptr += 4;
+ info->remaining += 4;
+ }
+ }
+ }
+ else if (_info->fmt.bps == 24) {
+ for (int i = 0; i < nsamples; i++) {
+ for (int c = 0; c < _info->fmt.channels; c++) {
+ int32_t sample = inputbuffer[c][i];
+ *bufptr++ = sample&0xff;
+ *bufptr++ = (sample&0xff00)>>8;
+ *bufptr++ = (sample&0xff0000)>>16;
+ info->remaining += 3;
+ }
+ }
+ }
+ else if (_info->fmt.bps == 16) {
+ for (int i = 0; i < nsamples; i++) {
+ for (int c = 0; c < _info->fmt.channels; c++) {
+ int32_t sample = inputbuffer[c][i];
+ *bufptr++ = sample&0xff;
+ *bufptr++ = (sample&0xff00)>>8;
+ info->remaining += 2;
+ }
+ }
+ }
+ else if (_info->fmt.bps == 8) {
+ for (int i = 0; i < nsamples; i++) {
+ for (int c = 0; c < _info->fmt.channels; c++) {
+ int32_t sample = inputbuffer[c][i];
+ *bufptr++ = sample&0xff;
+ info->remaining += 1;
+ }
}
}
if (readbytes > bufsize) {
@@ -136,10 +166,12 @@ cflac_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMe
DB_fileinfo_t *_info = (DB_fileinfo_t *)client_data;
flac_info_t *info = (flac_info_t *)_info;
info->totalsamples = metadata->data.stream_info.total_samples;
- _info->samplerate = metadata->data.stream_info.sample_rate;
- _info->channels = metadata->data.stream_info.channels;
- _info->bps = metadata->data.stream_info.bits_per_sample;
-
+ _info->fmt.samplerate = metadata->data.stream_info.sample_rate;
+ _info->fmt.channels = metadata->data.stream_info.channels;
+ _info->fmt.bps = metadata->data.stream_info.bits_per_sample;
+ for (int i = 0; i < _info->fmt.channels; i++) {
+ _info->fmt.channelmask |= 1 << i;
+ }
}
static void
@@ -164,7 +196,7 @@ cflac_init_error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecode
}
static DB_fileinfo_t *
-cflac_open (void) {
+cflac_open (uint32_t hints) {
DB_fileinfo_t *_info = malloc (sizeof (flac_info_t));
memset (_info, 0, sizeof (flac_info_t));
return _info;
@@ -172,10 +204,10 @@ cflac_open (void) {
static int
cflac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
- trace ("cflac_init %s\n", it->fname);
+ trace ("cflac_init %s\n", deadbeef->pl_find_meta (it, ":URI"));
flac_info_t *info = (flac_info_t *)_info;
- info->file = deadbeef->fopen (it->fname);
+ info->file = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!info->file) {
trace ("cflac_init failed to open file\n");
return -1;
@@ -183,8 +215,8 @@ cflac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
info->flac_critical_error = 0;
- const char *ext = it->fname + strlen (it->fname);
- while (ext > it->fname && *ext != '/' && *ext != '.') {
+ const char *ext = deadbeef->pl_find_meta (it, ":URI") + strlen (deadbeef->pl_find_meta (it, ":URI"));
+ while (ext > deadbeef->pl_find_meta (it, ":URI") && *ext != '/' && *ext != '.') {
ext--;
}
if (*ext == '.') {
@@ -237,7 +269,7 @@ cflac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
trace ("cflac_init bad decoder status\n");
return -1;
}
- //_info->samplerate = -1;
+ //_info->fmt.samplerate = -1;
if (!FLAC__stream_decoder_process_until_end_of_metadata (info->decoder)) {
trace ("cflac_init metadata failed\n");
return -1;
@@ -247,7 +279,7 @@ cflac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
_info->plugin = &plugin;
_info->readpos = 0;
- if (_info->samplerate <= 0) { // not a FLAC stream
+ if (_info->fmt.samplerate <= 0) { // not a FLAC stream
fprintf (stderr, "corrupted/invalid flac stream\n");
return -1;
}
@@ -259,14 +291,24 @@ cflac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
if (res) {
fsize -= position;
}
- FLAC__uint64 flac_totalsamples = FLAC__stream_decoder_get_total_samples (info->decoder);
- float sec = flac_totalsamples / _info->samplerate;
+ int64_t totalsamples = FLAC__stream_decoder_get_total_samples (info->decoder);
+ if (totalsamples <= 0) {
+ return -1;
+ }
+ float sec = totalsamples / (float)_info->fmt.samplerate;
if (sec > 0) {
info->bitrate = fsize / sec * 8 / 1000;
}
else {
info->bitrate = -1;
}
+ const char *channelmask = deadbeef->pl_find_meta (it, "WAVEFORMAT_EXTENSIBLE_CHANNELMASK");
+ if (channelmask) {
+ uint32_t cm = 0;
+ if (1 == sscanf (channelmask, "0x%X", &cm)) {
+ _info->fmt.channelmask = cm;
+ }
+ }
info->buffer = malloc (BUFFERSIZE);
info->remaining = 0;
@@ -304,53 +346,39 @@ cflac_free (DB_fileinfo_t *_info) {
if (info->buffer) {
free (info->buffer);
}
+ if (info->file) {
+ deadbeef->fclose (info->file);
+ }
free (_info);
}
}
static int
-cflac_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
+cflac_read (DB_fileinfo_t *_info, char *bytes, int size) {
flac_info_t *info = (flac_info_t *)_info;
- if (size / (2 * _info->channels) + info->currentsample > info->endsample) {
- size = (info->endsample - info->currentsample + 1) * 2 * _info->channels;
+ int samplesize = _info->fmt.channels * _info->fmt.bps / 8;
+ if (size / samplesize + info->currentsample > info->endsample) {
+ size = (info->endsample - info->currentsample + 1) * samplesize;
trace ("size truncated to %d bytes, cursample=%d, endsample=%d\n", size, info->currentsample, info->endsample);
if (size <= 0) {
return 0;
}
}
- int n_output_channels = _info->channels;
- if (n_output_channels > 2) {
- n_output_channels = 2;
- }
int initsize = size;
do {
if (info->remaining) {
- int n_input_frames = info->remaining / sizeof (float) / n_output_channels;
- int n_output_frames = size / n_output_channels / sizeof (int16_t);
- int n = min (n_input_frames, n_output_frames);
+ int sz = min(size, info->remaining);
+ memcpy (bytes, info->buffer, sz);
-// trace ("flac: [1] if=%d, of=%d, n=%d, rem=%d, size=%d\n", n_input_frames, n_output_frames, n, info->remaining, size);
- // convert from float to int16
- float *in = (float *)info->buffer;
- for (int i = 0; i < n; i++) {
- *((int16_t *)bytes) = (int16_t)((*in) * 0x7fff);
- size -= sizeof (int16_t);
- bytes += sizeof (int16_t);
- if (n_output_channels == 2) {
- *((int16_t *)bytes) = (int16_t)((*(in+1)) * 0x7fff);
- size -= sizeof (int16_t);
- bytes += sizeof (int16_t);
- }
- in += n_output_channels;
- }
- int sz = n * sizeof (float) * n_output_channels;
+ size -= sz;
+ bytes += sz;
if (sz < info->remaining) {
memmove (info->buffer, &info->buffer[sz], info->remaining - sz);
}
info->remaining -= sz;
- info->currentsample += n;
- _info->readpos += (float)n / _info->samplerate;
-// trace ("flac: [2] if=%d, of=%d, n=%d, rem=%d, size=%d\n", n_input_frames, n_output_frames, n, info->remaining, size);
+ int n = sz / samplesize;
+ info->currentsample += sz / samplesize;
+ _info->readpos += (float)n / _info->fmt.samplerate;
}
if (!size) {
break;
@@ -372,17 +400,18 @@ cflac_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
return initsize - size;
}
+#if 0
static int
cflac_read_float32 (DB_fileinfo_t *_info, char *bytes, int size) {
flac_info_t *info = (flac_info_t *)_info;
- if (size / (4 * _info->channels) + info->currentsample > info->endsample) {
- size = (info->endsample - info->currentsample + 1) * 4 * _info->channels;
+ if (size / (4 * _info->fmt.channels) + info->currentsample > info->endsample) {
+ size = (info->endsample - info->currentsample + 1) * 4 * _info->fmt.channels;
trace ("size truncated to %d bytes, cursample=%d, endsample=%d\n", size, info->currentsample, info->endsample);
if (size <= 0) {
return 0;
}
}
- int n_output_channels = _info->channels;
+ int n_output_channels = _info->fmt.channels;
if (n_output_channels > 2) {
n_output_channels = 2;
}
@@ -411,7 +440,7 @@ cflac_read_float32 (DB_fileinfo_t *_info, char *bytes, int size) {
}
info->remaining -= sz;
info->currentsample += n;
- _info->readpos += (float)n / _info->samplerate;
+ _info->readpos += (float)n / _info->fmt.samplerate;
}
if (!size) {
break;
@@ -432,6 +461,7 @@ cflac_read_float32 (DB_fileinfo_t *_info, char *bytes, int size) {
return initsize - size;
}
+#endif
static int
cflac_seek_sample (DB_fileinfo_t *_info, int sample) {
@@ -442,13 +472,13 @@ cflac_seek_sample (DB_fileinfo_t *_info, int sample) {
if (!FLAC__stream_decoder_seek_absolute (info->decoder, (FLAC__uint64)(sample))) {
return -1;
}
- _info->readpos = (float)(sample - info->startsample)/ _info->samplerate;
+ _info->readpos = (float)(sample - info->startsample)/ _info->fmt.samplerate;
return 0;
}
static int
cflac_seek (DB_fileinfo_t *_info, float time) {
- return cflac_seek_sample (_info, time * _info->samplerate);
+ return cflac_seek_sample (_info, time * _info->fmt.samplerate);
}
static FLAC__StreamDecoderWriteStatus
@@ -493,13 +523,53 @@ static const char *metainfo[] = {
"DISCNUMBER", "disc",
"COPYRIGHT", "copyright",
"TOTALTRACKS", "numtracks",
+ "TRACKTOTAL", "numtracks",
"ALBUM ARTIST", "band",
NULL
};
static void
+cflac_add_metadata (DB_playItem_t *it, char *s, int length) {
+ int m;
+ for (m = 0; metainfo[m]; m += 2) {
+ int l = strlen (metainfo[m]);
+ if (length > l && !strncasecmp (metainfo[m], s, l) && s[l] == '=') {
+ deadbeef->pl_append_meta (it, metainfo[m+1], s + l + 1);
+ break;
+ }
+ }
+ if (!metainfo[m]) {
+ if (!strncasecmp (s, "CUESHEET=", 9)) {
+ deadbeef->pl_add_meta (it, "cuesheet", s + 9);
+ }
+ else if (!strncasecmp (s, "replaygain_album_gain=", 22)) {
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMGAIN, atof (s+22));
+ }
+ else if (!strncasecmp (s, "replaygain_album_peak=", 22)) {
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMPEAK, atof (s+22));
+ }
+ else if (!strncasecmp (s, "replaygain_track_gain=", 22)) {
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKGAIN, atof (s+22));
+ }
+ else if (!strncasecmp (s, "replaygain_track_peak=", 22)) {
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKPEAK, atof (s+22));
+ }
+ else {
+ const char *eq = strchr (s, '=');
+ if (eq) {
+ char key[eq - s+1];
+ strncpy (key, s, eq-s);
+ key[eq-s] = 0;
+ deadbeef->pl_append_meta (it, key, eq+1);
+ }
+ }
+ }
+}
+
+static void
cflac_init_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) {
flac_info_t *info = (flac_info_t *)client_data;
+ info->tagsize += metadata->length;
DB_fileinfo_t *_info = &info->info;
if (info->init_stop_decoding) {
trace ("error flag is set, ignoring init_metadata callback..\n");
@@ -508,9 +578,10 @@ cflac_init_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__Str
DB_playItem_t *it = info->it;
//it->tracknum = 0;
if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
- trace ("flac: samplerate=%d, channels=%d\n", metadata->data.stream_info.sample_rate, metadata->data.stream_info.channels);
- _info->samplerate = metadata->data.stream_info.sample_rate;
- _info->channels = metadata->data.stream_info.channels;
+ trace ("flac: samplerate=%d, channels=%d, totalsamples=%d\n", metadata->data.stream_info.sample_rate, metadata->data.stream_info.channels, metadata->data.stream_info.total_samples);
+ _info->fmt.samplerate = metadata->data.stream_info.sample_rate;
+ _info->fmt.channels = metadata->data.stream_info.channels;
+ _info->fmt.bps = metadata->data.stream_info.bits_per_sample;
info->totalsamples = metadata->data.stream_info.total_samples;
deadbeef->pl_set_item_duration (it, metadata->data.stream_info.total_samples / (float)metadata->data.stream_info.sample_rate);
}
@@ -520,30 +591,7 @@ cflac_init_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__Str
const FLAC__StreamMetadata_VorbisComment_Entry *c = &vc->comments[i];
if (c->length > 0) {
char *s = c->entry;
- int m;
- for (m = 0; metainfo[m]; m += 2) {
- int l = strlen (metainfo[m]);
- if (c->length > l && !strncasecmp (metainfo[m], s, l) && s[l] == '=') {
- deadbeef->pl_append_meta (it, metainfo[m+1], s + l + 1);
- }
- }
- if (!metainfo[m]) {
- if (!strncasecmp (s, "CUESHEET=", 9)) {
- deadbeef->pl_add_meta (it, "cuesheet", s + 9);
- }
- else if (!strncasecmp (s, "replaygain_album_gain=", 22)) {
- it->replaygain_album_gain = atof (s + 22);
- }
- else if (!strncasecmp (s, "replaygain_album_peak=", 22)) {
- it->replaygain_album_peak = atof (s + 22);
- }
- else if (!strncasecmp (s, "replaygain_track_gain=", 22)) {
- it->replaygain_track_gain = atof (s + 22);
- }
- else if (!strncasecmp (s, "replaygain_track_peak=", 22)) {
- it->replaygain_track_peak = atof (s + 22);
- }
- }
+ cflac_add_metadata (it, s, c->length);
}
}
deadbeef->pl_add_meta (it, "title", NULL);
@@ -621,9 +669,7 @@ cflac_insert (DB_playItem_t *after, const char *fname) {
// read all metadata
FLAC__stream_decoder_set_md5_checking(decoder, 0);
FLAC__stream_decoder_set_metadata_respond_all (decoder);
- it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (fname);
+ it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
info.it = it;
if (skip > 0) {
deadbeef->fseek (info.file, skip, SEEK_SET);
@@ -648,12 +694,25 @@ cflac_insert (DB_playItem_t *after, const char *fname) {
}
FLAC__stream_decoder_delete(decoder);
decoder = NULL;
- it->filetype = isogg ? "OggFLAC" : "FLAC";
+ deadbeef->pl_add_meta (it, ":FILETYPE", isogg ? "OggFLAC" : "FLAC");
+
+ char s[100];
+ int64_t fsize = deadbeef->fgetlength (info.file);
+ snprintf (s, sizeof (s), "%lld", fsize);
+ deadbeef->pl_add_meta (it, ":FILE_SIZE", s);
+ snprintf (s, sizeof (s), "%d", info.info.fmt.channels);
+ deadbeef->pl_add_meta (it, ":CHANNELS", s);
+ snprintf (s, sizeof (s), "%d", info.info.fmt.bps);
+ deadbeef->pl_add_meta (it, ":BPS", s);
+ snprintf (s, sizeof (s), "%d", info.info.fmt.samplerate);
+ deadbeef->pl_add_meta (it, ":SAMPLERATE", s);
+ snprintf (s, sizeof (s), "%d", (int)roundf((fsize-info.tagsize) / deadbeef->pl_get_item_duration (it) * 8 / 1000));
+ deadbeef->pl_add_meta (it, ":BITRATE", s);
// try embedded cue
const char *cuesheet = deadbeef->pl_find_meta (it, "cuesheet");
if (cuesheet) {
- DB_playItem_t *last = deadbeef->pl_insert_cue_from_buffer (after, it, cuesheet, strlen (cuesheet), info.totalsamples, info.info.samplerate);
+ DB_playItem_t *last = deadbeef->pl_insert_cue_from_buffer (after, it, cuesheet, strlen (cuesheet), info.totalsamples, info.info.fmt.samplerate);
if (last) {
deadbeef->pl_item_unref (it);
deadbeef->pl_item_unref (last);
@@ -662,7 +721,7 @@ cflac_insert (DB_playItem_t *after, const char *fname) {
}
// try external cue
- DB_playItem_t *cue_after = deadbeef->pl_insert_cue (after, it, info.totalsamples, info.info.samplerate);
+ DB_playItem_t *cue_after = deadbeef->pl_insert_cue (after, it, info.totalsamples, info.info.fmt.samplerate);
if (cue_after) {
if (info.file) {
deadbeef->fclose (info.file);
@@ -702,7 +761,7 @@ cflac_read_metadata (DB_playItem_t *it) {
trace ("cflac_read_metadata: FLAC__metadata_chain_new failed\n");
return -1;
}
- FLAC__bool res = FLAC__metadata_chain_read (chain, it->fname);
+ FLAC__bool res = FLAC__metadata_chain_read (chain, deadbeef->pl_find_meta (it, ":URI"));
if (!res) {
trace ("cflac_read_metadata: FLAC__metadata_chain_read failed\n");
goto error;
@@ -719,17 +778,20 @@ cflac_read_metadata (DB_playItem_t *it) {
do {
FLAC__StreamMetadata *data = FLAC__metadata_iterator_get_block (iter);
if (data && data->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
- // delete all crap
- for (int m = 0; metainfo[m]; m += 2) {
- int offs = 0;
- do {
- offs = FLAC__metadata_object_vorbiscomment_find_entry_from (data, offs, metainfo[m]);
- if (offs != -1) {
- FLAC__StreamMetadata_VorbisComment_Entry *comm = &data->data.vorbis_comment.comments[offs];
- deadbeef->pl_append_meta (it, metainfo[m+1], comm->entry + strlen (metainfo[m])+1);
- offs++;
- }
- } while (offs != -1);
+ const FLAC__StreamMetadata_VorbisComment *vc = &data->data.vorbis_comment;
+ for (int i = 0; i < vc->num_comments; i++) {
+ const FLAC__StreamMetadata_VorbisComment_Entry *c = &vc->comments[i];
+ if (c->length > 0) {
+ char *s = c->entry;
+ cflac_add_metadata (it, s, c->length);
+ }
+ }
+ deadbeef->pl_add_meta (it, "title", NULL);
+ if (vc->num_comments > 0) {
+ uint32_t f = deadbeef->pl_get_item_flags (it);
+ f &= ~DDB_TAG_MASK;
+ f |= DDB_TAG_VORBISCOMMENTS;
+ deadbeef->pl_set_item_flags (it, f);
}
}
} while (FLAC__metadata_iterator_next (iter));
@@ -764,7 +826,7 @@ cflac_write_metadata (DB_playItem_t *it) {
trace ("cflac_write_metadata: FLAC__metadata_chain_new failed\n");
return -1;
}
- FLAC__bool res = FLAC__metadata_chain_read (chain, it->fname);
+ FLAC__bool res = FLAC__metadata_chain_read (chain, deadbeef->pl_find_meta (it, ":URI"));
if (!res) {
trace ("cflac_write_metadata: FLAC__metadata_chain_read failed\n");
goto error;
@@ -776,53 +838,80 @@ cflac_write_metadata (DB_playItem_t *it) {
trace ("cflac_write_metadata: FLAC__metadata_iterator_new failed\n");
goto error;
}
+ FLAC__StreamMetadata *data = NULL;
+ // find existing vorbiscomment block
FLAC__metadata_iterator_init (iter, chain);
do {
- FLAC__StreamMetadata *data = FLAC__metadata_iterator_get_block (iter);
+ data = FLAC__metadata_iterator_get_block (iter);
if (data && data->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
- for (int m = 0; metainfo[m]; m += 2) {
- const char *val = deadbeef->pl_find_meta (it, metainfo[m+1]);
- if (val) {
- do {} while (1 == FLAC__metadata_object_vorbiscomment_remove_entry_matching (data, metainfo[m]));
+ break;
+ }
+ } while (FLAC__metadata_iterator_next (iter));
+
+ if (data) {
+ // delete all comments
+ FLAC__metadata_object_vorbiscomment_resize_comments (data, 0);
+ }
+ else {
+ // create new and add to chain
+ data = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ if (!data) {
+ fprintf (stderr, "flac: failed to allocate new vorbis comment block\n");
+ goto error;
+ }
+ if(!FLAC__metadata_iterator_insert_block_after(iter, data)) {
+ fprintf (stderr, "flac: failed to append vorbis comment block to chain\n");
+ goto error;
+ }
+ }
+
+ DB_metaInfo_t *m = deadbeef->pl_get_metadata_head (it);
+ while (m) {
+ if (m->key[0] != ':') {
+ int i;
+ for (i = 0; metainfo[i]; i += 2) {
+ if (!strcasecmp (metainfo[i+1], m->key)) {
+ break;
}
- if (val && *val) {
- while (val) {
- const char *next = strchr (val, '\n');
- int l;
- if (next) {
- l = next - val;
- next++;
- }
- else {
- l = strlen (val);
- }
- if (l > 0) {
- char s[100+l+1];
- int n = snprintf (s, sizeof (s), "%s=", metainfo[m]);
- strncpy (s+n, val, l);
- *(s+n+l) = 0;
- FLAC__StreamMetadata_VorbisComment_Entry ent = {
- .length = strlen (s),
- .entry = (FLAC__byte*)s
- };
- //FLAC__metadata_object_vorbiscomment_replace_comment (data, ent, 1, 1);
- FLAC__metadata_object_vorbiscomment_append_comment (data, ent, 1);
- }
- val = next;
+ }
+ const char *val = m->value;
+ if (val && *val) {
+ while (val) {
+ const char *next = strchr (val, '\n');
+ int l;
+ if (next) {
+ l = next - val;
+ next++;
+ }
+ else {
+ l = strlen (val);
+ }
+ if (l > 0) {
+ char s[100+l+1];
+ int n = snprintf (s, sizeof (s), "%s=", metainfo[i] ? metainfo[i] : m->key);
+ strncpy (s+n, val, l);
+ *(s+n+l) = 0;
+ FLAC__StreamMetadata_VorbisComment_Entry ent = {
+ .length = strlen (s),
+ .entry = (FLAC__byte*)s
+ };
+ FLAC__metadata_object_vorbiscomment_append_comment (data, ent, 1);
}
+ val = next;
}
}
}
- } while (FLAC__metadata_iterator_next (iter));
+ m = m->next;
+ }
- FLAC__metadata_iterator_delete (iter);
if (!FLAC__metadata_chain_write (chain, 1, 0)) {
trace ("cflac_write_metadata: FLAC__metadata_chain_write failed\n");
goto error;
}
err = 0;
error:
+ FLAC__metadata_iterator_delete (iter);
if (chain) {
FLAC__metadata_chain_delete (chain);
}
@@ -837,20 +926,35 @@ static const char *filetypes[] = { "FLAC", "OggFLAC", NULL };
// define plugin interface
static DB_decoder_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.id = "stdflac",
.plugin.name = "FLAC decoder",
.plugin.descr = "FLAC decoder using libFLAC",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.open = cflac_open,
.init = cflac_init,
.free = cflac_free,
- .read_int16 = cflac_read_int16,
- .read_float32 = cflac_read_float32,
+ .read = cflac_read,
+// .read_float32 = cflac_read_float32,
.seek = cflac_seek,
.seek_sample = cflac_seek_sample,
.insert = cflac_insert,
diff --git a/plugins/gme/Makefile.am b/plugins/gme/Makefile.am
index 61351f9c..b325cbdf 100644
--- a/plugins/gme/Makefile.am
+++ b/plugins/gme/Makefile.am
@@ -112,8 +112,9 @@ game-music-emu-0.5.5/gme/Ym2413_Emu.h\
game-music-emu-0.5.5/gme/Ym2612_Emu.h\
game-music-emu-0.5.5/gme/gme_types.h
-gme_la_LDFLAGS = -module
+gme_la_LDFLAGS = -module -nostdlib -lsupc++
+gme_la_LIBADD = $(ZLIB_LIBS)
-gme_la_LIBADD = $(LDADD) -lstdc++
-AM_CFLAGS = $(CFLAGS) -I$(gmepath) -std=c99 -DGME_VERSION_055
+AM_CFLAGS = $(CFLAGS) $(ZLIB_CFLAGS) -I$(gmepath) -std=c99 -DGME_VERSION_055
+AM_CPPFLAGS = $(CXXFLAGS) -fno-exceptions -fno-rtti -nostdlib -fno-unwind-tables
endif
diff --git a/plugins/gme/cgme.c b/plugins/gme/cgme.c
index 5d2920f0..8eb6d8d3 100644
--- a/plugins/gme/cgme.c
+++ b/plugins/gme/cgme.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -19,8 +19,21 @@
#include <stdlib.h>
#include <string.h>
#include "gme/gme.h"
+#include <zlib.h>
#include "../../deadbeef.h"
+int _Unwind_Resume_or_Rethrow;
+int _Unwind_RaiseException;
+int _Unwind_GetLanguageSpecificData;
+int _Unwind_Resume;
+int _Unwind_DeleteException;
+int _Unwind_GetTextRelBase;
+int _Unwind_SetIP;
+int _Unwind_GetDataRelBase;
+int _Unwind_GetRegionStart;
+int _Unwind_SetGR;
+int _Unwind_GetIPInfo;
+
//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
#define trace(fmt,...)
@@ -36,35 +49,124 @@ typedef struct {
} gme_fileinfo_t;
static DB_fileinfo_t *
-cgme_open (void) {
+cgme_open (uint32_t hint) {
DB_fileinfo_t *_info = malloc (sizeof (gme_fileinfo_t));
memset (_info, 0, sizeof (gme_fileinfo_t));
return _info;
}
static int
+read_gzfile (const char *fname, char **buffer, int *size) {
+ FILE *fp = fopen (fname, "rb");
+ if (!fp) {
+ trace ("failed to fopen %s\n", fname);
+ return -1;
+ }
+ fseek (fp, 0, SEEK_END);
+ size_t sz = ftell (fp);
+ fclose (fp);
+
+ sz *= 2;
+ int readsize = sz;
+ *buffer = malloc (sz);
+ if (!(*buffer)) {
+ return -1;
+ }
+
+ gzFile gz = gzopen (fname, "rb");
+ if (!gz) {
+ trace ("failed to gzopen %s\n", fname);
+ return -1;
+ }
+ *size = 0;
+ int nb;
+ int pos = 0;
+ do {
+ nb = gzread (gz, *buffer + pos, readsize);
+ if (nb < 0) {
+ free (*buffer);
+ trace ("failed to gzread from %s\n", fname);
+ return -1;
+ }
+ if (nb > 0) {
+ pos += nb;
+ *size += nb;
+ }
+ if (nb != readsize) {
+ break;
+ }
+ else {
+ readsize = sz;
+ sz *= 2;
+ *buffer = realloc (*buffer, sz);
+ }
+ } while (nb > 0);
+ gzclose (gz);
+ trace ("got %d bytes from %s\n", *size, fname);
+
+ return 0;
+}
+
+static int
cgme_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
gme_fileinfo_t *info = (gme_fileinfo_t*)_info;
int samplerate = deadbeef->conf_get_int ("synth.samplerate", 44100);
- if (gme_open_file (it->fname, &info->emu, samplerate)) {
+
+ gme_err_t res;
+ const char *ext = strrchr (deadbeef->pl_find_meta (it, ":URI"), '.');
+ if (ext && !strcasecmp (ext, ".vgz")) {
+ trace ("opening gzipped vgm...\n");
+ char *buffer;
+ int sz;
+ if (!read_gzfile (deadbeef->pl_find_meta (it, ":URI"), &buffer, &sz)) {
+ res = gme_open_data (buffer, sz, &info->emu, samplerate);
+ free (buffer);
+ }
+ }
+ else {
+ DB_FILE *f = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
+ int64_t sz = deadbeef->fgetlength (f);
+ if (sz <= 0) {
+ deadbeef->fclose (f);
+ return -1;
+ }
+ char *buf = malloc (sz);
+ if (!buf) {
+ deadbeef->fclose (f);
+ return -1;
+ }
+ int64_t rb = deadbeef->fread (buf, 1, sz, f);
+ deadbeef->fclose(f);
+ if (rb != sz) {
+ free (buf);
+ return -1;
+ }
+
+ res = gme_open_data (buf, sz, &info->emu, samplerate);
+ free (buf);
+ }
+
+ if (res) {
+ trace ("failed with error %d\n", res);
return -1;
}
gme_mute_voices (info->emu, info->cgme_voicemask);
- gme_start_track (info->emu, it->tracknum);
+ gme_start_track (info->emu, deadbeef->pl_find_meta_int (it, ":TRACKNUM", 0));
#ifdef GME_VERSION_055
gme_info_t *inf;
- gme_track_info (info->emu, &inf, it->tracknum);
+ gme_track_info (info->emu, &inf, deadbeef->pl_find_meta_int (it, ":TRACKNUM", 0));
#else
track_info_t _inf;
- gme_track_info (info->emu, &inf, it->tracknum);
+ gme_track_info (info->emu, &inf, deadbeef->pl_find_meta_int (it, ":TRACKNUM", 0));
track_info_t *inf = &_inf;
#endif
_info->plugin = &plugin;
- _info->bps = 16;
- _info->channels = 2;
- _info->samplerate = samplerate;
+ _info->fmt.bps = 16;
+ _info->fmt.channels = 2;
+ _info->fmt.samplerate = samplerate;
+ _info->fmt.channelmask = _info->fmt.channels == 1 ? DDB_SPEAKER_FRONT_LEFT : (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT);
info->duration = deadbeef->pl_get_item_duration (it);
info->reallength = inf->length;
_info->readpos = 0;
@@ -83,7 +185,7 @@ cgme_free (DB_fileinfo_t *_info) {
static int
cgme_read (DB_fileinfo_t *_info, char *bytes, int size) {
gme_fileinfo_t *info = (gme_fileinfo_t*)_info;
- float t = (size/4) / (float)_info->samplerate;
+ float t = (size/4) / (float)_info->fmt.samplerate;
if (_info->readpos + t >= info->duration) {
t = info->duration - _info->readpos;
if (t <= 0) {
@@ -114,11 +216,76 @@ cgme_seek (DB_fileinfo_t *_info, float time) {
return 0;
}
+static void
+cgme_add_meta (DB_playItem_t *it, const char *key, const char *value) {
+ if (!value) {
+ return;
+ }
+ char len = strlen (value);
+ char out[1024];
+ // check for utf8 (hack)
+ if (deadbeef->junk_iconv (value, len, out, sizeof (out), "utf-8", "utf-8") >= 0) {
+ deadbeef->pl_add_meta (it, key, out);
+ return;
+ }
+
+ if (deadbeef->junk_iconv (value, len, out, sizeof (out), "iso8859-1", "utf-8") >= 0) {
+ deadbeef->pl_add_meta (it, key, out);
+ return;
+ }
+
+ if (deadbeef->junk_iconv (value, len, out, sizeof (out), "SHIFT-JIS", "utf-8") >= 0) {
+ deadbeef->pl_add_meta (it, key, out);
+ return;
+ }
+
+ // FIXME: try other encodings?
+
+ return;
+}
+
static DB_playItem_t *
cgme_insert (DB_playItem_t *after, const char *fname) {
Music_Emu *emu;
trace ("gme_open_file %s\n", fname);
- if (!gme_open_file (fname, &emu, gme_info_only)) {
+
+ gme_err_t res;
+
+ const char *ext = strrchr (fname, '.');
+ if (ext && !strcasecmp (ext, ".vgz")) {
+ trace ("opening gzipped vgm...\n");
+ char *buffer;
+ int sz;
+ if (!read_gzfile (fname, &buffer, &sz)) {
+ res = gme_open_data (buffer, sz, &emu, gme_info_only);
+ free (buffer);
+ }
+ }
+ else {
+ DB_FILE *f = deadbeef->fopen (fname);
+ int64_t sz = deadbeef->fgetlength (f);
+ if (sz <= 0) {
+ deadbeef->fclose (f);
+ return NULL;
+ }
+ char *buf = malloc (sz);
+ if (!buf) {
+ deadbeef->fclose (f);
+ return NULL;
+ }
+ int64_t rb = deadbeef->fread (buf, 1, sz, f);
+ deadbeef->fclose(f);
+ if (rb != sz) {
+ free (buf);
+ return NULL;
+ }
+
+ res = gme_open_data (buf, sz, &emu, gme_info_only);
+ free (buf);
+ }
+
+
+ if (!res) {
int cnt = gme_track_count (emu);
trace ("track cnt %d\n", cnt);
for (int i = 0; i < cnt; i++) {
@@ -131,9 +298,7 @@ cgme_insert (DB_playItem_t *after, const char *fname) {
track_info_t *inf = &_inf;
#endif
if (!ret) {
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (fname);
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
char str[1024];
if (inf->song[0]) {
snprintf (str, 1024, "%d %s - %s", i, inf->game, inf->song);
@@ -142,11 +307,11 @@ cgme_insert (DB_playItem_t *after, const char *fname) {
snprintf (str, 1024, "%d %s - ?", i, inf->game);
}
trace ("track subtune %d %s, length=%d\n", i, str, inf->length);
- it->tracknum = i;
+ deadbeef->pl_set_meta_int (it, ":TRACKNUM", i);
// add metadata
- deadbeef->pl_add_meta (it, "system", inf->system);
- deadbeef->pl_add_meta (it, "album", inf->game);
+ cgme_add_meta (it, "system", inf->system);
+ cgme_add_meta (it, "album", inf->game);
int tl = sizeof (inf->song);
int n;
for (n = 0; i < tl && inf->song[n] && inf->song[n] == ' '; n++);
@@ -154,16 +319,16 @@ cgme_insert (DB_playItem_t *after, const char *fname) {
deadbeef->pl_add_meta (it, "title", NULL);
}
else {
- deadbeef->pl_add_meta (it, "title", inf->song);
+ cgme_add_meta (it, "title", inf->song);
}
- deadbeef->pl_add_meta (it, "artist", inf->author);
- deadbeef->pl_add_meta (it, "copyright", inf->copyright);
- deadbeef->pl_add_meta (it, "comment", inf->comment);
- deadbeef->pl_add_meta (it, "dumper", inf->dumper);
+ cgme_add_meta (it, "artist", inf->author);
+ cgme_add_meta (it, "copyright", inf->copyright);
+ cgme_add_meta (it, "comment", inf->comment);
+ cgme_add_meta (it, "dumper", inf->dumper);
char trk[10];
snprintf (trk, 10, "%d", i+1);
- deadbeef->pl_add_meta (it, "track", trk);
- if (inf->length == -1) {
+ cgme_add_meta (it, "track", trk);
+ if (inf->length == -1 || inf->length == 0) {
float songlength = deadbeef->conf_get_float ("gme.songlength", 3);
deadbeef->pl_set_item_duration (it, songlength * 60.f);
}
@@ -174,12 +339,12 @@ cgme_insert (DB_playItem_t *after, const char *fname) {
while (ext >= fname && *ext != '.') {
ext--;
}
- it->filetype = NULL;
if (*ext == '.') {
ext++;
for (int i = 0; plugin.exts[i]; i++) {
if (!strcasecmp (ext, plugin.exts[i])) {
- it->filetype = plugin.exts[i];
+ deadbeef->pl_add_meta (it, ":FILETYPE", plugin.exts[i]);
+ break;
}
}
}
@@ -187,7 +352,7 @@ cgme_insert (DB_playItem_t *after, const char *fname) {
deadbeef->pl_item_unref (it);
}
else {
- printf ("gme error: %s\n", ret);
+ trace ("gme error: %s\n", ret);
}
}
if (emu) {
@@ -195,7 +360,7 @@ cgme_insert (DB_playItem_t *after, const char *fname) {
}
}
else {
- printf ("error adding %s\n", fname);
+ trace ("gme_open_file/data failed\n");
}
return after;
}
@@ -241,14 +406,31 @@ static const char settings_dlg[] =
// define plugin interface
static DB_decoder_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.id = "stdgme",
.plugin.name = "Game_Music_Emu decoder",
.plugin.descr = "chiptune music player based on GME",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "Uses Game-Music-Emu v0.5.5 by Shay Green <gblargg@gmail.com>, http://www.slack.net/~ant/libs\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = cgme_start,
.plugin.stop = cgme_stop,
@@ -256,7 +438,7 @@ static DB_decoder_t plugin = {
.open = cgme_open,
.init = cgme_init,
.free = cgme_free,
- .read_int16 = cgme_read,
+ .read = cgme_read,
.seek = cgme_seek,
.insert = cgme_insert,
.exts = exts,
diff --git a/plugins/gme/game-music-emu-0.5.5/gme/Sap_Apu.cpp b/plugins/gme/game-music-emu-0.5.5/gme/Sap_Apu.cpp
index fa9bc4b1..fb56f5dc 100644
--- a/plugins/gme/game-music-emu-0.5.5/gme/Sap_Apu.cpp
+++ b/plugins/gme/game-music-emu-0.5.5/gme/Sap_Apu.cpp
@@ -90,7 +90,7 @@ void Sap_Apu::reset( Sap_Apu_Impl* new_impl )
memset( &oscs [i], 0, offsetof (osc_t,output) );
}
-inline void Sap_Apu::calc_periods()
+void Sap_Apu::calc_periods()
{
// 15/64 kHz clock
int divider = 28;
diff --git a/plugins/gtkui/Makefile.am b/plugins/gtkui/Makefile.am
index 609917ed..3cfc1cce 100644
--- a/plugins/gtkui/Makefile.am
+++ b/plugins/gtkui/Makefile.am
@@ -1,10 +1,7 @@
if HAVE_GTKUI
gtkuidir = $(libdir)/$(PACKAGE)
-pkglib_LTLIBRARIES = gtkui.la
-
gtkui_VALASOURCES = ddbequalizer.vala ddbseekbar.vala ddbcellrenderertextmultiline.vala
gtkui_VALABUILTSOURCES = $(gtkui_VALASOURCES:.vala=.c) ddbequalizer.h ddbseekbar.h ddbcellrenderertextmultiline.h
-
if MAINTAINER_MODE
BUILT_SOURCES = vala.stamp
vala.stamp: $(gtkui_VALASOURCES)
@@ -12,10 +9,13 @@ vala.stamp: $(gtkui_VALASOURCES)
$(VALAC) -C -H ddbequalizer.h --library ddbequalizer gtkui.vapi --pkg=gtk+-2.0 ddbequalizer.vala
$(VALAC) -C -H ddbseekbar.h --library ddbseekbar gtkui.vapi --pkg=gtk+-2.0 ddbseekbar.vala
touch $@
+
+CLEANFILES = \
+ $(BUILT_SOURCES) \
+ $(gtkui_VALABUILTSOURCES)
endif
-gtkui_la_SOURCES = $(gtkui_VALABUILTSOURCES)\
- gtkui.c gtkui.h\
+GTKUI_SOURCES = gtkui.c gtkui.h\
callbacks.c interface.c support.c callbacks.h interface.h support.h\
ddblistview.c ddblistview.h\
mainplaylist.c mainplaylist.h\
@@ -32,18 +32,39 @@ gtkui_la_SOURCES = $(gtkui_VALABUILTSOURCES)\
plcommon.c plcommon.h\
prefwin.c\
eq.c eq.h\
- actions.c actions.h
-
-gtkui_la_LDFLAGS = -module
+ actions.c actions.h\
+ dspconfig.c dspconfig.h\
+ tagwritersettings.c tagwritersettings.h\
+ wingeom.c wingeom.h
-gtkui_la_LIBADD = $(LDADD) $(GTKUI_DEPS_LIBS) $(NOTIFY_DEPS_LIBS)
-AM_CFLAGS = -std=c99 $(GTKUI_DEPS_CFLAGS) $(NOTIFY_DEPS_CFLAGS)
+sdkdir = $(pkgincludedir)
+sdk_HEADERS = gtkui_api.h
EXTRA_DIST = $(gtkui_VALASOURCES) deadbeef.glade
-if MAINTAINER_MODE
-CLEANFILES = \
- $(BUILT_SOURCES) \
- $(gtkui_VALABUILTSOURCES)
+if STATICLINK
+pkglib_LTLIBRARIES = ddb_gui_GTK2.la ddb_gui_GTK2.fallback.la
+else
+pkglib_LTLIBRARIES = ddb_gui_GTK2.la
endif
+
+# normal lib
+ddb_gui_GTK2_la_SOURCES = $(gtkui_VALABUILTSOURCES) $(GTKUI_SOURCES)
+ddb_gui_GTK2_la_LDFLAGS = -module
+ddb_gui_GTK2_la_LIBADD = $(LDADD) $(GTKUI_DEPS_LIBS)
+ddb_gui_GTK2_la_CFLAGS = -std=c99 $(GTKUI_DEPS_CFLAGS)
+
+# fallback lib
+if STATICLINK
+GTK_ROOT=../../../deadbeef-deps/gtk-debian/usr
+
+ddb_gui_GTK2_fallback_la_SOURCES = $(gtkui_VALABUILTSOURCES) $(GTKUI_SOURCES)
+ddb_gui_GTK2_fallback_la_LDFLAGS = -module
+
+ddb_gui_GTK2_fallback_la_LIBADD = $(LDADD) -L$(GTK_ROOT)/lib $(GTK_ROOT)/lib/libgtk-x11-2.0.la $(GTK_ROOT)/lib/libgdk-x11-2.0.la $(GTK_ROOT)/lib/libpangoft2-1.0.la $(GTK_ROOT)/lib/libpangocairo-1.0.la $(GTK_ROOT)/lib/libgdk_pixbuf-2.0.la -lm $(GTK_ROOT)/lib/libcairo.la $(GTK_ROOT)/lib/libpango-1.0.la $(GTK_ROOT)/lib/libgobject-2.0.la $(GTK_ROOT)/lib/libgmodule-2.0.la $(GTK_ROOT)/lib/libgthread-2.0.la -lrt $(GTK_ROOT)/lib/libglib-2.0.la
+
+ddb_gui_GTK2_fallback_la_CFLAGS = -std=c99 -I $(GTK_ROOT)/include -I $(GTK_ROOT)/lib/gtk-2.0/include -I $(GTK_ROOT)/include/glib-2.0 -I $(GTK_ROOT)/include/gtk-2.0 -I $(GTK_ROOT)/include/cairo -I $(GTK_ROOT)/lib/glib-2.0/include/ -I $(GTK_ROOT)/include/pango-1.0 -I $(GTK_ROOT)/include/atk-1.0 -DULTRA_COMPATIBLE=1
+
+endif
+
endif
diff --git a/plugins/gtkui/actions.c b/plugins/gtkui/actions.c
index ac2904d2..0ddbdceb 100644
--- a/plugins/gtkui/actions.c
+++ b/plugins/gtkui/actions.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>,
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>,
Viktor Semykin <thesame.ml@gmail.com>
This program is free software; you can redistribute it and/or
diff --git a/plugins/gtkui/actions.h b/plugins/gtkui/actions.h
index b064647f..aacff34b 100644
--- a/plugins/gtkui/actions.h
+++ b/plugins/gtkui/actions.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>,
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>,
Viktor Semykin <thesame.ml@gmail.com>
This program is free software; you can redistribute it and/or
diff --git a/plugins/gtkui/callbacks.c b/plugins/gtkui/callbacks.c
index dd26a422..3c775f16 100644
--- a/plugins/gtkui/callbacks.c
+++ b/plugins/gtkui/callbacks.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -43,6 +43,7 @@
#include "parser.h"
#include "drawing.h"
#include "eq.h"
+#include "wingeom.h"
//#define trace(...) { fprintf (stderr, __VA_ARGS__); }
#define trace(fmt,...)
@@ -58,26 +59,37 @@ extern DB_functions_t *deadbeef; // defined in gtkui.c
static gboolean
file_filter_func (const GtkFileFilterInfo *filter_info, gpointer data) {
// get ext
- const char *p = filter_info->filename + strlen (filter_info->filename)-1;
- while (p >= filter_info->filename) {
- if (*p == '.') {
- break;
- }
- p--;
- }
- if (*p != '.') {
+ const char *p = strrchr (filter_info->filename, '.');
+ if (!p) {
return FALSE;
}
p++;
+
+ // get beginning of fname
+ const char *fn = strrchr (filter_info->filename, '/');
+ if (!fn) {
+ fn = filter_info->filename;
+ }
+ else {
+ fn++;
+ }
+
+
DB_decoder_t **codecs = deadbeef->plug_get_decoder_list ();
for (int i = 0; codecs[i]; i++) {
if (codecs[i]->exts && codecs[i]->insert) {
const char **exts = codecs[i]->exts;
- if (exts) {
- for (int e = 0; exts[e]; e++) {
- if (!strcasecmp (exts[e], p)) {
- return TRUE;
- }
+ for (int e = 0; exts[e]; e++) {
+ if (!strcasecmp (exts[e], p)) {
+ return TRUE;
+ }
+ }
+ }
+ if (codecs[i]->prefixes && codecs[i]->insert) {
+ const char **prefixes = codecs[i]->prefixes;
+ for (int e = 0; prefixes[e]; e++) {
+ if (!strncasecmp (prefixes[e], fn, strlen(prefixes[e])) && *(fn + strlen (prefixes[e])) == '.') {
+ return TRUE;
}
}
}
@@ -88,6 +100,18 @@ file_filter_func (const GtkFileFilterInfo *filter_info, gpointer data) {
if (!strcasecmp (p, "m3u")) {
return TRUE;
}
+
+ // test container (vfs) formats
+ DB_vfs_t **vfsplugs = deadbeef->plug_get_vfs_list ();
+ for (int i = 0; vfsplugs[i]; i++) {
+ if (vfsplugs[i]->is_container) {
+ if (vfsplugs[i]->is_container (filter_info->filename)) {
+ return TRUE;
+ }
+ }
+ }
+
+
return FALSE;
}
@@ -121,7 +145,9 @@ on_open_activate (GtkMenuItem *menuitem,
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), TRUE);
// restore folder
- gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str ("filechooser.lastdir", ""));
+ deadbeef->conf_lock ();
+ gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str_fast ("filechooser.lastdir", ""));
+ deadbeef->conf_unlock ();
int response = gtk_dialog_run (GTK_DIALOG (dlg));
// store folder
gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
@@ -155,7 +181,9 @@ on_add_files_activate (GtkMenuItem *menuitem,
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), TRUE);
// restore folder
- gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str ("filechooser.lastdir", ""));
+ deadbeef->conf_lock ();
+ gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str_fast ("filechooser.lastdir", ""));
+ deadbeef->conf_unlock ();
int response = gtk_dialog_run (GTK_DIALOG (dlg));
// store folder
gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
@@ -189,19 +217,26 @@ on_add_folders_activate (GtkMenuItem *menuitem,
{
GtkWidget *dlg = gtk_file_chooser_dialog_new (_("Add folder(s) to playlist..."), GTK_WINDOW (mainwin), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
+ GtkWidget *box = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (box);
+
GtkWidget *check = gtk_check_button_new_with_mnemonic (_("Follow symlinks"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), deadbeef->conf_get_int ("add_folders_follow_symlinks", 0));
g_signal_connect ((gpointer) check, "toggled",
G_CALLBACK (on_follow_symlinks_toggled),
NULL);
gtk_widget_show (check);
- gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dlg), check);
+ gtk_box_pack_start (GTK_BOX (box), check, FALSE, FALSE, 0);
+
+ gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dlg), box);
set_file_filter (dlg, NULL);
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), TRUE);
// restore folder
- gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str ("filechooser.lastdir", ""));
+ deadbeef->conf_lock ();
+ gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str_fast ("filechooser.lastdir", ""));
+ deadbeef->conf_unlock ();
int response = gtk_dialog_run (GTK_DIALOG (dlg));
// store folder
gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
@@ -248,10 +283,10 @@ on_select_all1_activate (GtkMenuItem *menuitem,
{
deadbeef->pl_select_all ();
DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_EXPOSE_LIST);
+ ddb_listview_refresh (pl, DDB_REFRESH_LIST);
pl = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist"));
if (pl) {
- ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_EXPOSE_LIST);
+ ddb_listview_refresh (pl, DDB_REFRESH_LIST);
}
}
@@ -263,7 +298,7 @@ void
on_stopbtn_clicked (GtkButton *button,
gpointer user_data)
{
- deadbeef->sendmessage (M_STOPSONG, 0, 0, 0);
+ deadbeef->sendmessage (M_STOP, 0, 0, 0);
}
@@ -271,7 +306,7 @@ void
on_playbtn_clicked (GtkButton *button,
gpointer user_data)
{
- deadbeef->sendmessage (M_PLAYSONG, 0, 0, 0);
+ deadbeef->sendmessage (M_PLAY_CURRENT, 0, 0, 0);
}
@@ -279,7 +314,7 @@ void
on_pausebtn_clicked (GtkButton *button,
gpointer user_data)
{
- deadbeef->sendmessage (M_PAUSESONG, 0, 0, 0);
+ deadbeef->sendmessage (M_TOGGLE_PAUSE, 0, 0, 0);
}
@@ -287,7 +322,7 @@ void
on_prevbtn_clicked (GtkButton *button,
gpointer user_data)
{
- deadbeef->sendmessage (M_PREVSONG, 0, 0, 0);
+ deadbeef->sendmessage (M_PREV, 0, 0, 0);
}
@@ -295,7 +330,7 @@ void
on_nextbtn_clicked (GtkButton *button,
gpointer user_data)
{
- deadbeef->sendmessage (M_NEXTSONG, 0, 0, 0);
+ deadbeef->sendmessage (M_NEXT, 0, 0, 0);
}
@@ -303,7 +338,7 @@ void
on_playrand_clicked (GtkButton *button,
gpointer user_data)
{
- deadbeef->sendmessage (M_PLAYRANDOM, 0, 0, 0);
+ deadbeef->sendmessage (M_PLAY_RANDOM, 0, 0, 0);
}
gboolean
@@ -314,7 +349,7 @@ on_mainwin_key_press_event (GtkWidget *widget,
uint32_t maskedstate = (event->state &~ (GDK_LOCK_MASK | GDK_MOD2_MASK | GDK_MOD3_MASK | GDK_MOD5_MASK)) & 0xfff;
if ((maskedstate == GDK_MOD1_MASK || maskedstate == 0) && event->keyval == GDK_n) {
// button for that one is not in toolbar anymore, so handle it manually
- deadbeef->sendmessage (M_PLAYRANDOM, 0, 0, 0);
+ deadbeef->sendmessage (M_PLAY_RANDOM, 0, 0, 0);
}
else if ((maskedstate == GDK_MOD1_MASK || maskedstate == 0) && event->keyval >= GDK_1 && event->keyval <= GDK_9) {
int pl = event->keyval - GDK_1;
@@ -334,7 +369,8 @@ void
on_order_linear_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
- deadbeef->conf_set_int ("playback.order", 0);
+ deadbeef->conf_set_int ("playback.order", PLAYBACK_ORDER_LINEAR);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
}
@@ -342,15 +378,24 @@ void
on_order_shuffle_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
- deadbeef->conf_set_int ("playback.order", 1);
+ deadbeef->conf_set_int ("playback.order", PLAYBACK_ORDER_SHUFFLE_TRACKS);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
}
+void
+on_order_shuffle_albums_activate (GtkMenuItem *menuitem,
+ gpointer user_data)
+{
+ deadbeef->conf_set_int ("playback.order", PLAYBACK_ORDER_SHUFFLE_ALBUMS);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
+}
void
on_order_random_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
- deadbeef->conf_set_int ("playback.order", 2);
+ deadbeef->conf_set_int ("playback.order", PLAYBACK_ORDER_RANDOM);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
}
@@ -601,21 +646,7 @@ on_mainwin_configure_event (GtkWidget *widget,
GdkEventConfigure *event,
gpointer user_data)
{
-#if GTK_CHECK_VERSION(2,2,0)
- GdkWindowState window_state = gdk_window_get_state (GDK_WINDOW (widget->window));
-#else
- GdkWindowState window_state = gdk_window_get_state (G_OBJECT (widget));
-#endif
- if (!(window_state & GDK_WINDOW_STATE_MAXIMIZED) && gtk_widget_get_visible (widget)) {
- int x, y;
- int w, h;
- gtk_window_get_position (GTK_WINDOW (widget), &x, &y);
- gtk_window_get_size (GTK_WINDOW (widget), &w, &h);
- deadbeef->conf_set_int ("mainwin.geometry.x", x);
- deadbeef->conf_set_int ("mainwin.geometry.y", y);
- deadbeef->conf_set_int ("mainwin.geometry.w", w);
- deadbeef->conf_set_int ("mainwin.geometry.h", h);
- }
+ wingeom_save (widget, "mainwin");
return FALSE;
}
@@ -633,7 +664,6 @@ on_find_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
search_start ();
- search_restore_attrs ();
}
void
@@ -689,7 +719,7 @@ on_help1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
char fname[PATH_MAX];
- snprintf (fname, sizeof (fname), DOCDIR "/%s", _("help.txt"));
+ snprintf (fname, sizeof (fname), "%s/%s", deadbeef->get_doc_dir (), _("help.txt"));
show_info_window (fname, _("Help"), &helpwindow);
}
@@ -702,7 +732,7 @@ on_about1_activate (GtkMenuItem *menuitem,
char s[200];
snprintf (s, sizeof (s), _("About DeaDBeeF %s"), VERSION);
char fname[PATH_MAX];
- snprintf (fname, sizeof (fname), DOCDIR "/%s", "about.txt");
+ snprintf (fname, sizeof (fname), "%s/%s", deadbeef->get_doc_dir (), "about.txt");
show_info_window (fname, s, &aboutwindow);
}
@@ -715,7 +745,7 @@ on_changelog1_activate (GtkMenuItem *menuitem,
char s[200];
snprintf (s, sizeof (s), _("DeaDBeeF %s ChangeLog"), VERSION);
char fname[PATH_MAX];
- snprintf (fname, sizeof (fname), DOCDIR "/%s", "ChangeLog");
+ snprintf (fname, sizeof (fname), "%s/%s", deadbeef->get_doc_dir (), "ChangeLog");
show_info_window (fname, s, &changelogwindow);
}
@@ -726,7 +756,7 @@ on_gpl1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
char fname[PATH_MAX];
- snprintf (fname, sizeof (fname), DOCDIR "/%s", "COPYING.GPLv2");
+ snprintf (fname, sizeof (fname), "%s/%s", deadbeef->get_doc_dir (), "COPYING.GPLv2");
show_info_window (fname, "GNU GENERAL PUBLIC LICENSE Version 2", &gplwindow);
}
@@ -737,7 +767,7 @@ on_lgpl1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
char fname[PATH_MAX];
- snprintf (fname, sizeof (fname), DOCDIR "/%s", "COPYING.LGPLv2.1");
+ snprintf (fname, sizeof (fname), "%s/%s", deadbeef->get_doc_dir (), "COPYING.LGPLv2.1");
show_info_window (fname, "GNU LESSER GENERAL PUBLIC LICENSE Version 2.1", &lgplwindow);
}
@@ -781,26 +811,7 @@ on_mainwin_window_state_event (GtkWidget *widget,
GdkEventWindowState *event,
gpointer user_data)
{
- // based on pidgin maximization handler
-#if GTK_CHECK_VERSION(2,2,0)
- if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) {
- if (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
- deadbeef->conf_set_int ("mainwin.geometry.maximized", 1);
- }
- else {
- deadbeef->conf_set_int ("mainwin.geometry.maximized", 0);
- }
- }
-#else
- GdkWindowState new_window_state = gdk_window_get_state(G_OBJECT(widget));
-
- if (new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
- deadbeef->conf_set_int ("mainwin.geometry.maximized", 1);
- }
- else {
- deadbeef->conf_set_int ("mainwin.geometry.maximized", 0);
- }
-#endif
+ wingeom_save_max (event, widget, "mainwin");
return FALSE;
}
@@ -935,10 +946,10 @@ on_deselect_all1_activate (GtkMenuItem *menuitem,
}
deadbeef->pl_unlock ();
DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_EXPOSE_LIST);
+ ddb_listview_refresh (pl, DDB_REFRESH_LIST);
pl = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist"));
if (pl) {
- ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_EXPOSE_LIST);
+ ddb_listview_refresh (pl, DDB_REFRESH_LIST);
}
}
@@ -962,7 +973,7 @@ on_invert_selection1_activate (GtkMenuItem *menuitem,
}
deadbeef->pl_unlock ();
DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_EXPOSE_LIST);
+ ddb_listview_refresh (pl, DDB_REFRESH_LIST);
}
@@ -1079,7 +1090,96 @@ on_translators1_activate (GtkMenuItem *menuitem,
char s[200];
snprintf (s, sizeof (s), _("DeaDBeeF Translators"));
char fname[PATH_MAX];
- snprintf (fname, sizeof (fname), DOCDIR "/%s", "translators.txt");
+ snprintf (fname, sizeof (fname), "%s/%s", deadbeef->get_doc_dir (), "translators.txt");
show_info_window (fname, s, &translatorswindow);
}
+
+GtkWidget*
+title_formatting_help_link_create (gchar *widget_name, gchar *string1, gchar *string2,
+ gint int1, gint int2)
+{
+ GtkWidget *link = gtk_link_button_new_with_label ("http://sourceforge.net/apps/mediawiki/deadbeef/index.php?title=Title_Formatting", "Help");
+ return link;
+}
+
+
+void
+on_album1_activate (GtkMenuItem *menuitem,
+ gpointer user_data)
+{
+
+}
+
+
+void
+on_artist1_activate (GtkMenuItem *menuitem,
+ gpointer user_data)
+{
+
+}
+
+
+void
+on_date1_activate (GtkMenuItem *menuitem,
+ gpointer user_data)
+{
+
+}
+
+void
+on_custom2_activate (GtkMenuItem *menuitem,
+ gpointer user_data)
+{
+ GtkWidget *dlg = create_sortbydlg ();
+ gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK);
+
+ GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (dlg, "sortorder"));
+ GtkEntry *entry = GTK_ENTRY (lookup_widget (dlg, "sortfmt"));
+
+ gtk_combo_box_set_active (combo, deadbeef->conf_get_int ("gtkui.sortby_order", 0));
+ deadbeef->conf_lock ();
+ gtk_entry_set_text (entry, deadbeef->conf_get_str_fast ("gtkui.sortby_fmt", ""));
+ deadbeef->conf_unlock ();
+
+ int r = gtk_dialog_run (GTK_DIALOG (dlg));
+
+ if (r == GTK_RESPONSE_OK) {
+ GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (dlg, "sortorder"));
+ GtkEntry *entry = GTK_ENTRY (lookup_widget (dlg, "sortfmt"));
+ int order = gtk_combo_box_get_active (combo);
+ const char *fmt = gtk_entry_get_text (entry);
+
+ deadbeef->conf_set_int ("gtkui.sortby_order", order);
+ deadbeef->conf_set_str ("gtkui.sortby_fmt", fmt);
+
+ deadbeef->pl_sort (PL_MAIN, -1, fmt, order == 0 ? 1 : 0);
+
+ DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
+ ddb_listview_clear_sort (pl);
+ ddb_listview_refresh (pl, DDB_REFRESH_LIST);
+ }
+
+ gtk_widget_destroy (dlg);
+ dlg = NULL;
+}
+
+
+void
+on_sortfmt_activate (GtkEntry *entry,
+ gpointer user_data)
+{
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (entry));
+ gtk_dialog_response (GTK_DIALOG (toplevel), GTK_RESPONSE_OK);
+}
+
+
+
+GtkWidget*
+create_plugin_weblink (gchar *widget_name, gchar *string1, gchar *string2,
+ gint int1, gint int2)
+{
+ GtkWidget *link = gtk_link_button_new_with_label ("", "WWW");
+ gtk_widget_set_sensitive (link, FALSE);
+ return link;
+}
diff --git a/plugins/gtkui/callbacks.h b/plugins/gtkui/callbacks.h
index b88df53c..4f15d342 100644
--- a/plugins/gtkui/callbacks.h
+++ b/plugins/gtkui/callbacks.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -291,16 +291,6 @@ void
volumebar_expose (GtkWidget *widget, int x, int y, int w, int h);
-
-void
-on_progress_abort (GtkButton *button,
- gpointer user_data);
-
-gboolean
-on_addprogress_delete_event (GtkWidget *widget,
- GdkEvent *event,
- gpointer user_data);
-
gboolean
on_volumebar_scroll_event (GtkWidget *widget,
GdkEventScroll *event,
@@ -983,3 +973,157 @@ on_jump_to_current_track1_activate (GtkMenuItem *menuitem,
void
on_translators1_activate (GtkMenuItem *menuitem,
gpointer user_data);
+
+
+GtkWidget*
+title_formatting_help_link_create (gchar *widget_name, gchar *string1, gchar *string2,
+ gint int1, gint int2);
+
+void
+on_album1_activate (GtkMenuItem *menuitem,
+ gpointer user_data);
+
+void
+on_artist1_activate (GtkMenuItem *menuitem,
+ gpointer user_data);
+
+void
+on_date1_activate (GtkMenuItem *menuitem,
+ gpointer user_data);
+
+void
+on_custom2_activate (GtkMenuItem *menuitem,
+ gpointer user_data);
+
+void
+on_sortfmt_activate (GtkEntry *entry,
+ gpointer user_data);
+
+void
+gtkui_dialog_response_ok (GtkEntry *entry,
+ gpointer user_data);
+
+
+void
+on_shuffle_albums1_activate (GtkMenuItem *menuitem,
+ gpointer user_data);
+
+void
+on_order_shuffle_albums_activate (GtkMenuItem *menuitem,
+ gpointer user_data);
+
+void
+on_dsp_add_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_dsp_remove_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_dsp_configure_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_dsp_up_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_dsp_down_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_auto_name_playlist_from_folder_toggled
+ (GtkToggleButton *togglebutton,
+ gpointer user_data);
+
+void
+on_dsp_preset_changed (GtkComboBox *combobox,
+ gpointer user_data);
+
+void
+on_dsp_preset_save_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_dsp_preset_load_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_plug_copyright_clicked (GtkButton *button,
+ gpointer user_data);
+
+GtkWidget*
+create_plugin_weblink (gchar *widget_name, gchar *string1, gchar *string2,
+ gint int1, gint int2);
+
+gboolean
+on_metalist_button_press_event (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer user_data);
+
+void
+on_tagwriter_settings_clicked (GtkButton *button,
+ gpointer user_data);
+
+gboolean
+on_trackproperties_configure_event (GtkWidget *widget,
+ GdkEventConfigure *event,
+ gpointer user_data);
+
+void
+on_trackproperties_state_changed (GtkWidget *widget,
+ GtkStateType state,
+ gpointer user_data);
+
+gboolean
+on_trackproperties_window_state_event (GtkWidget *widget,
+ GdkEventWindowState *event,
+ gpointer user_data);
+
+gboolean
+on_prefwin_configure_event (GtkWidget *widget,
+ GdkEventConfigure *event,
+ gpointer user_data);
+
+gboolean
+on_prefwin_window_state_event (GtkWidget *widget,
+ GdkEventWindowState *event,
+ gpointer user_data);
+
+void
+on_prefwin_realize (GtkWidget *widget,
+ gpointer user_data);
+
+gboolean
+on_prefwin_map_event (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data);
+
+void
+on_replaygain_preamp_value_changed (GtkRange *range,
+ gpointer user_data);
+
+void
+on_tabstrip_text_color_set (GtkColorButton *colorbutton,
+ gpointer user_data);
+
+void
+on_gui_plugin_changed (GtkComboBox *combobox,
+ gpointer user_data);
+
+void
+on_seekbar_fps_value_changed (GtkRange *range,
+ gpointer user_data);
+
+void
+on_gui_fps_value_changed (GtkRange *range,
+ gpointer user_data);
+
+void
+on_add_from_archives_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data);
+
+void
+on_ignore_archives_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data);
diff --git a/plugins/gtkui/coverart.c b/plugins/gtkui/coverart.c
index 7fb50554..4118aa66 100644
--- a/plugins/gtkui/coverart.c
+++ b/plugins/gtkui/coverart.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -21,12 +21,11 @@
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
+#include <sys/stat.h>
#include "coverart.h"
#include "../artwork/artwork.h"
#include "gtkui.h"
-#define DEFAULT_COVER_PATH (PREFIX "/share/deadbeef/pixmaps/noartwork.jpg")
-
//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
#define trace(...)
@@ -38,6 +37,7 @@ extern DB_artwork_plugin_t *coverart_plugin;
typedef struct {
struct timeval tm;
char *fname;
+ time_t filetime;
int width;
GdkPixbuf *pixbuf;
} cached_pixbuf_t;
@@ -140,10 +140,13 @@ loading_thread (void *none) {
usleep (500000);
continue;
}
-
-// GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (queue->fname, NULL);
+ struct stat stat_buf;
+ if (stat (queue->fname, &stat_buf) < 0) {
+ trace ("failed to stat file %s\n", queue->fname);
+ }
+ GdkPixbuf *pixbuf = NULL;
GError *error = NULL;
- GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_scale (queue->fname, queue->width, queue->width, TRUE, &error);
+ pixbuf = gdk_pixbuf_new_from_file_at_scale (queue->fname, queue->width, queue->width, TRUE, &error);
if (!pixbuf) {
unlink (queue->fname);
fprintf (stderr, "gdk_pixbuf_new_from_file_at_scale %s %d failed, error: %s\n", queue->fname, queue->width, error->message);
@@ -151,9 +154,13 @@ loading_thread (void *none) {
g_error_free (error);
error = NULL;
}
- pixbuf = gdk_pixbuf_new_from_file_at_scale (DEFAULT_COVER_PATH, queue->width, queue->width, TRUE, &error);
+ const char *defpath = coverart_plugin->get_default_cover ();
+ if (stat (defpath, &stat_buf) < 0) {
+ trace ("failed to stat file %s\n", queue->fname);
+ }
+ pixbuf = gdk_pixbuf_new_from_file_at_scale (defpath, queue->width, queue->width, TRUE, &error);
if (!pixbuf) {
- fprintf (stderr, "gdk_pixbuf_new_from_file_at_scale %s %d failed, error: %s\n", DEFAULT_COVER_PATH, queue->width, error->message);
+ fprintf (stderr, "gdk_pixbuf_new_from_file_at_scale %s %d failed, error: %s\n", defpath, queue->width, error->message);
}
}
if (error) {
@@ -163,43 +170,16 @@ loading_thread (void *none) {
if (!pixbuf) {
// make default empty image
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 2, 2);
+ stat_buf.st_mtime = 0;
}
-#if 0
- else {
- int w, h;
- w = gdk_pixbuf_get_width (pixbuf);
- h = gdk_pixbuf_get_height (pixbuf);
- int width = queue->width;
- if (w != width) {
- int height;
- if (w > h) {
- height = width * h / w;
- }
- else if (h > w) {
- height = width;
- width = height * w / h;
- }
- else {
- height = width;
- }
- if (width < 5 || height < 5) {
- trace ("will not scale to %dx%d\n", width, height);
- queue_pop ();
- continue;
- }
- trace ("scaling %dx%d -> %dx%d\n", w, h, width, height);
- GdkPixbuf *scaled = gdk_pixbuf_scale_simple (pixbuf, width, height, GDK_INTERP_BILINEAR);
- g_object_unref (pixbuf);
- pixbuf = scaled;
- }
- }
-#endif
if (cache_min != -1) {
deadbeef->mutex_lock (mutex);
+ cache[cache_min].filetime = stat_buf.st_mtime;
cache[cache_min].pixbuf = pixbuf;
cache[cache_min].fname = strdup (queue->fname);
gettimeofday (&cache[cache_min].tm, NULL);
cache[cache_min].width = queue->width;
+ struct stat stat_buf;
deadbeef->mutex_unlock (mutex);
}
queue_pop ();
@@ -231,11 +211,15 @@ get_pixbuf (const char *fname, int width) {
for (int i = 0; i < CACHE_SIZE; i++) {
if (cache[i].pixbuf) {
if (!strcmp (fname, cache[i].fname) && cache[i].width == width) {
- gettimeofday (&cache[i].tm, NULL);
- GdkPixbuf *pb = cache[i].pixbuf;
- g_object_ref (pb);
- deadbeef->mutex_unlock (mutex);
- return pb;
+ // check if cached filetime hasn't changed
+ struct stat stat_buf;
+ if (!stat (fname, &stat_buf) && stat_buf.st_mtime == cache[i].filetime) {
+ gettimeofday (&cache[i].tm, NULL);
+ GdkPixbuf *pb = cache[i].pixbuf;
+ g_object_ref (pb);
+ deadbeef->mutex_unlock (mutex);
+ return pb;
+ }
}
}
}
@@ -257,7 +241,7 @@ get_cover_art (const char *fname, const char *artist, const char *album, int wid
if (!coverart_plugin) {
return NULL;
}
- char *image_fname = coverart_plugin->get_album_art (fname, artist, album, cover_avail_callback, (void *)(intptr_t)width);
+ char *image_fname = coverart_plugin->get_album_art (fname, artist, album, -1, cover_avail_callback, (void *)(intptr_t)width);
if (image_fname) {
GdkPixbuf *pb = get_pixbuf (image_fname, width);
free (image_fname);
diff --git a/plugins/gtkui/coverart.h b/plugins/gtkui/coverart.h
index 75a96429..689e0f80 100644
--- a/plugins/gtkui/coverart.h
+++ b/plugins/gtkui/coverart.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
diff --git a/plugins/gtkui/ddbcellrenderertextmultiline.c b/plugins/gtkui/ddbcellrenderertextmultiline.c
index 867c70e4..a6e95853 100644
--- a/plugins/gtkui/ddbcellrenderertextmultiline.c
+++ b/plugins/gtkui/ddbcellrenderertextmultiline.c
@@ -1,4 +1,4 @@
-/* ddbcellrenderertextmultiline.c generated by valac 0.10.0, the Vala compiler
+/* ddbcellrenderertextmultiline.c generated by valac 0.10.2, the Vala compiler
* generated from ddbcellrenderertextmultiline.vala, do not modify */
/*
@@ -52,6 +52,7 @@ typedef struct _DdbCellRendererTextMultiline DdbCellRendererTextMultiline;
typedef struct _DdbCellRendererTextMultilineClass DdbCellRendererTextMultilineClass;
typedef struct _DdbCellRendererTextMultilinePrivate DdbCellRendererTextMultilinePrivate;
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
+#define _gtk_tree_path_free0(var) ((var == NULL) ? NULL : (var = (gtk_tree_path_free (var), NULL)))
struct _DdbCellEditableTextView {
GtkTextView parent_instance;
@@ -213,7 +214,7 @@ static void ddb_cell_renderer_text_multiline_gtk_cell_renderer_text_editing_done
buf = _g_object_ref0 (gtk_text_view_get_buffer ((GtkTextView*) entry));
gtk_text_buffer_get_iter_at_offset (buf, &begin, 0);
gtk_text_buffer_get_iter_at_offset (buf, &end, -1);
- new_text = g_strdup (gtk_text_buffer_get_text (buf, &begin, &end, TRUE));
+ new_text = gtk_text_buffer_get_text (buf, &begin, &end, TRUE);
g_signal_emit_by_name ((GtkCellRendererText*) _self_, "edited", entry->tree_path, new_text);
_g_free0 (new_text);
_g_object_unref0 (buf);
@@ -236,12 +237,20 @@ static GtkCellEditable* ddb_cell_renderer_text_multiline_real_start_editing (Gtk
DdbCellRendererTextMultiline * self;
GtkCellEditable* result = NULL;
gboolean _tmp0_;
- DdbCellEditableTextView* _tmp1_;
- char* _tmp2_;
- GtkTextBuffer* buf;
- char* _tmp3_ = NULL;
+ GtkTreePath* p;
+ GtkTreeView* tv;
+ GtkListStore* store;
+ GtkTreeIter iter = {0};
+ GValue v = {0};
+ GValue _tmp1_ = {0};
+ GValue _tmp2_;
+ gint mult;
+ DdbCellEditableTextView* _tmp3_;
char* _tmp4_;
- gboolean _tmp5_;
+ GtkTextBuffer* buf;
+ char* _tmp5_ = NULL;
+ char* _tmp6_;
+ gboolean _tmp7_;
self = (DdbCellRendererTextMultiline*) base;
g_return_val_if_fail (event != NULL, NULL);
g_return_val_if_fail (widget != NULL, NULL);
@@ -250,14 +259,24 @@ static GtkCellEditable* ddb_cell_renderer_text_multiline_real_start_editing (Gtk
result = GTK_CELL_EDITABLE (NULL);
return result;
}
- self->priv->entry = (_tmp1_ = g_object_ref_sink (ddb_cell_editable_text_view_new ()), _g_object_unref0 (self->priv->entry), _tmp1_);
- self->priv->entry->tree_path = (_tmp2_ = g_strdup (path), _g_free0 (self->priv->entry->tree_path), _tmp2_);
+ p = gtk_tree_path_new_from_string (path);
+ tv = _g_object_ref0 (GTK_TREE_VIEW (widget));
+ store = _g_object_ref0 (GTK_LIST_STORE (gtk_tree_view_get_model (tv)));
+ gtk_tree_model_get_iter ((GtkTreeModel*) store, &iter, p);
+ gtk_tree_model_get_value ((GtkTreeModel*) store, &iter, 3, &_tmp1_);
+ v = (_tmp2_ = _tmp1_, G_IS_VALUE (&v) ? (g_value_unset (&v), NULL) : NULL, _tmp2_);
+ mult = g_value_get_int (&v);
+ self->priv->entry = (_tmp3_ = g_object_ref_sink (ddb_cell_editable_text_view_new ()), _g_object_unref0 (self->priv->entry), _tmp3_);
+ if (mult != 0) {
+ g_object_set ((GtkCellRendererText*) self, "text", "", NULL);
+ }
+ self->priv->entry->tree_path = (_tmp4_ = g_strdup (path), _g_free0 (self->priv->entry->tree_path), _tmp4_);
buf = gtk_text_buffer_new (NULL);
- if ((_tmp5_ = (_tmp4_ = (g_object_get ((GtkCellRendererText*) self, "text", &_tmp3_, NULL), _tmp3_)) != NULL, _g_free0 (_tmp4_), _tmp5_)) {
- char* _tmp6_ = NULL;
- char* _tmp7_;
- gtk_text_buffer_set_text (buf, _tmp7_ = (g_object_get ((GtkCellRendererText*) self, "text", &_tmp6_, NULL), _tmp6_), -1);
- _g_free0 (_tmp7_);
+ if ((_tmp7_ = (_tmp6_ = (g_object_get ((GtkCellRendererText*) self, "text", &_tmp5_, NULL), _tmp5_)) != NULL, _g_free0 (_tmp6_), _tmp7_)) {
+ char* _tmp8_ = NULL;
+ char* _tmp9_;
+ gtk_text_buffer_set_text (buf, _tmp9_ = (g_object_get ((GtkCellRendererText*) self, "text", &_tmp8_, NULL), _tmp8_), -1);
+ _g_free0 (_tmp9_);
}
gtk_text_view_set_buffer ((GtkTextView*) self->priv->entry, buf);
g_signal_connect (self->priv->entry, "editing-done", (GCallback) ddb_cell_renderer_text_multiline_gtk_cell_renderer_text_editing_done, self);
@@ -266,6 +285,10 @@ static GtkCellEditable* ddb_cell_renderer_text_multiline_real_start_editing (Gtk
gtk_widget_show ((GtkWidget*) self->priv->entry);
result = GTK_CELL_EDITABLE (self->priv->entry);
_g_object_unref0 (buf);
+ G_IS_VALUE (&v) ? (g_value_unset (&v), NULL) : NULL;
+ _g_object_unref0 (store);
+ _g_object_unref0 (tv);
+ _gtk_tree_path_free0 (p);
return result;
}
diff --git a/plugins/gtkui/ddbcellrenderertextmultiline.h b/plugins/gtkui/ddbcellrenderertextmultiline.h
index 787beb50..2fec6b26 100644
--- a/plugins/gtkui/ddbcellrenderertextmultiline.h
+++ b/plugins/gtkui/ddbcellrenderertextmultiline.h
@@ -1,4 +1,4 @@
-/* ddbcellrenderertextmultiline.h generated by valac 0.10.0, the Vala compiler, do not modify */
+/* ddbcellrenderertextmultiline.h generated by valac 0.10.2, the Vala compiler, do not modify */
#ifndef __DDBCELLRENDERERTEXTMULTILINE_H__
diff --git a/plugins/gtkui/ddbcellrenderertextmultiline.vala b/plugins/gtkui/ddbcellrenderertextmultiline.vala
index 75e7bdc9..4587cff9 100644
--- a/plugins/gtkui/ddbcellrenderertextmultiline.vala
+++ b/plugins/gtkui/ddbcellrenderertextmultiline.vala
@@ -79,7 +79,21 @@ namespace Ddb {
if (!editable) {
return (Gtk.CellEditable)null;
}
+
+ Gtk.TreePath p = new Gtk.TreePath.from_string (path);
+ Gtk.TreeView tv = (Gtk.TreeView)widget;
+ Gtk.ListStore store = (Gtk.ListStore)tv.get_model();
+ Gtk.TreeIter iter;
+ store.get_iter (out iter, p);
+ GLib.Value v;
+ store.get_value (iter, 3, out v);
+ int mult = v.get_int ();
+
entry = new CellEditableTextView ();
+ if (mult != 0) {
+ text = "";
+ }
+
entry.tree_path = path;
Gtk.TextBuffer buf = new Gtk.TextBuffer (null);
if (text != null) {
diff --git a/plugins/gtkui/ddbequalizer.c b/plugins/gtkui/ddbequalizer.c
index 201277ad..7cd9ee4f 100644
--- a/plugins/gtkui/ddbequalizer.c
+++ b/plugins/gtkui/ddbequalizer.c
@@ -1,4 +1,4 @@
-/* ddbequalizer.c generated by valac 0.10.0, the Vala compiler
+/* ddbequalizer.c generated by valac 0.10.2, the Vala compiler
* generated from ddbequalizer.vala, do not modify */
/*
diff --git a/plugins/gtkui/ddbequalizer.h b/plugins/gtkui/ddbequalizer.h
index 19f98c23..2ce2ba5c 100644
--- a/plugins/gtkui/ddbequalizer.h
+++ b/plugins/gtkui/ddbequalizer.h
@@ -1,4 +1,4 @@
-/* ddbequalizer.h generated by valac 0.10.0, the Vala compiler, do not modify */
+/* ddbequalizer.h generated by valac 0.10.2, the Vala compiler, do not modify */
#ifndef __DDBEQUALIZER_H__
diff --git a/plugins/gtkui/ddblistview.c b/plugins/gtkui/ddblistview.c
index 89a27cff..479c03c8 100644
--- a/plugins/gtkui/ddblistview.c
+++ b/plugins/gtkui/ddblistview.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -88,20 +88,19 @@ static void ddb_listview_destroy(GtkObject *object);
// fwd decls
void
ddb_listview_free_groups (DdbListview *listview);
-static inline void
-draw_drawable (GdkDrawable *window, GdkGC *gc, GdkDrawable *drawable, int x1, int y1, int x2, int y2, int w, int h);
+
+//static inline void
+//draw_drawable (GdkDrawable *window, GdkGC *gc, GdkDrawable *drawable, int x1, int y1, int x2, int y2, int w, int h);
////// list functions ////
void
ddb_listview_list_render (DdbListview *ps, int x, int y, int w, int h);
void
-ddb_listview_list_expose (DdbListview *ps, int x, int y, int w, int h);
-void
ddb_listview_list_render_row_background (DdbListview *ps, DdbListviewIter it, int even, int cursor, int x, int y, int w, int h);
void
ddb_listview_list_render_row_foreground (DdbListview *ps, DdbListviewIter it, DdbListviewIter group_it, int even, int cursor, int group_y, int x, int y, int w, int h);
-void
-ddb_listview_list_render_row (DdbListview *ps, int row, DdbListviewIter it, int expose);
+//void
+//ddb_listview_list_render_row (DdbListview *ps, int row, DdbListviewIter it);
void
ddb_listview_list_track_dragdrop (DdbListview *ps, int y);
int
@@ -122,8 +121,6 @@ ddb_listview_get_row_pos (DdbListview *listview, int pos);
////// header functions ////
void
ddb_listview_header_render (DdbListview *ps);
-void
-ddb_listview_header_expose (DdbListview *ps, int x, int y, int w, int h);
////// column management functions ////
void
@@ -282,8 +279,9 @@ static void
ddb_listview_init(DdbListview *listview)
{
// init instance - create all subwidgets, and insert into table
+ draw_init_font (GTK_WIDGET(listview)->style);
- listview->rowheight = draw_get_font_size () + 12;
+ listview->rowheight = draw_get_listview_rowheight ();
listview->col_movepos = -1;
listview->drag_motion_y = -1;
@@ -470,18 +468,6 @@ ddb_listview_destroy(GtkObject *object)
gdk_cursor_unref (listview->cursor_drag);
listview->cursor_drag = NULL;
}
- if (listview->backbuf) {
- g_object_unref (listview->backbuf);
- listview->backbuf = NULL;
- }
- if (listview->backbuf_header) {
- g_object_unref (listview->backbuf_header);
- listview->backbuf_header = NULL;
- }
-
-// if (G_OBJECT_CLASS (ddb_listview_parent_class)) {
-// G_OBJECT_CLASS (ddb_listview_parent_class)->destroy (object);
-// }
}
void
@@ -492,7 +478,7 @@ ddb_listview_refresh (DdbListview *listview, uint32_t flags) {
if (height != listview->fullheight) {
flags |= DDB_REFRESH_VSCROLL;
}
- ddb_listview_list_render (listview, 0, 0, listview->list->allocation.width, listview->list->allocation.height);
+ gtk_widget_queue_draw (listview->list);
}
if (flags & DDB_REFRESH_VSCROLL) {
ddb_listview_list_setup_vscroll (listview);
@@ -501,13 +487,7 @@ ddb_listview_refresh (DdbListview *listview, uint32_t flags) {
ddb_listview_list_setup_hscroll (listview);
}
if (flags & DDB_REFRESH_COLUMNS) {
- ddb_listview_header_render (listview);
- }
- if (flags & DDB_EXPOSE_COLUMNS) {
- ddb_listview_header_expose (listview, 0, 0, listview->header->allocation.width, listview->header->allocation.height);
- }
- if (flags & DDB_EXPOSE_LIST) {
- ddb_listview_list_expose (listview, 0, 0, listview->list->allocation.width, listview->list->allocation.height);
+ gtk_widget_queue_draw (listview->header);
}
}
@@ -516,9 +496,9 @@ ddb_listview_list_realize (GtkWidget *widget,
gpointer user_data)
{
GtkTargetEntry entry = {
- .target = "STRING",
+ .target = "DDB_URI_LIST",
.flags = GTK_TARGET_SAME_APP,
- TARGET_SAMEWIDGET
+ .info = TARGET_SAMEWIDGET
};
// setup drag-drop target
gtk_drag_dest_set (widget, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, &entry, 1, GDK_ACTION_COPY | GDK_ACTION_MOVE);
@@ -534,7 +514,7 @@ ddb_listview_list_configure_event (GtkWidget *widget,
DdbListview *ps = DDB_LISTVIEW (g_object_get_data (G_OBJECT (widget), "owner"));
draw_init_font (widget->style);
- int height = draw_get_font_size () + 12;
+ int height = draw_get_listview_rowheight ();
if (height != ps->rowheight) {
ps->rowheight = height;
ddb_listview_build_groups (ps);
@@ -543,13 +523,7 @@ ddb_listview_list_configure_event (GtkWidget *widget,
ddb_listview_list_setup_vscroll (ps);
ddb_listview_list_setup_hscroll (ps);
widget = ps->list;
- if (ps->backbuf) {
- g_object_unref (ps->backbuf);
- ps->backbuf = NULL;
- }
- ps->backbuf = gdk_pixmap_new (widget->window, widget->allocation.width, widget->allocation.height, -1);
- ddb_listview_list_render (ps, 0, 0, widget->allocation.width, widget->allocation.height);
return FALSE;
}
@@ -608,9 +582,6 @@ ddb_listview_list_pickpoint_y (DdbListview *listview, int y, DdbListviewGroup **
void
ddb_listview_list_render (DdbListview *listview, int x, int y, int w, int h) {
- if (!listview->backbuf) {
- return;
- }
GtkWidget *treeview = theme_treeview;
if (treeview->style->depth == -1) {
return; // drawing was called too early
@@ -627,7 +598,7 @@ ddb_listview_list_render (DdbListview *listview, int x, int y, int w, int h) {
abs_idx += grp->num_items;
grp = grp->next;
}
- draw_begin ((uintptr_t)listview->backbuf);
+ draw_begin ((uintptr_t)listview->list->window);
int ii = 0;
while (grp && grp_y < y + h + listview->scrollpos) {
@@ -641,7 +612,7 @@ ddb_listview_list_render (DdbListview *listview, int x, int y, int w, int h) {
if (grp_y + listview->grouptitle_height >= y + listview->scrollpos && grp_y < y + h + listview->scrollpos) {
ddb_listview_list_render_row_background (listview, NULL, idx & 1, 0, -listview->hscrollpos, grp_y - listview->scrollpos, listview->totalwidth, listview->grouptitle_height);
if (listview->binding->draw_group_title && listview->grouptitle_height > 0) {
- listview->binding->draw_group_title (listview, listview->backbuf, it, -listview->hscrollpos, grp_y - listview->scrollpos, listview->totalwidth, listview->grouptitle_height);
+ listview->binding->draw_group_title (listview, listview->list->window, it, -listview->hscrollpos, grp_y - listview->scrollpos, listview->totalwidth, listview->grouptitle_height);
}
}
for (int i = 0; i < grp->num_items; i++) {
@@ -654,7 +625,7 @@ ddb_listview_list_render (DdbListview *listview, int x, int y, int w, int h) {
}
if (grp_y + listview->grouptitle_height + (i+1) * listview->rowheight >= y + listview->scrollpos
&& grp_y + listview->grouptitle_height + i * listview->rowheight < y + h + listview->scrollpos) {
- gdk_draw_rectangle (listview->backbuf, listview->list->style->bg_gc[GTK_STATE_NORMAL], TRUE, -listview->hscrollpos, grp_y + listview->grouptitle_height + i * listview->rowheight - listview->scrollpos, listview->totalwidth, listview->rowheight);
+ gdk_draw_rectangle (listview->list->window, listview->list->style->bg_gc[GTK_STATE_NORMAL], TRUE, -listview->hscrollpos, grp_y + listview->grouptitle_height + i * listview->rowheight - listview->scrollpos, listview->totalwidth, listview->rowheight);
ddb_listview_list_render_row_background (listview, it, (idx + 1 + i) & 1, (abs_idx+i) == listview->binding->cursor () ? 1 : 0, -listview->hscrollpos, grp_y + listview->grouptitle_height + i * listview->rowheight - listview->scrollpos, listview->totalwidth, listview->rowheight);
ddb_listview_list_render_row_foreground (listview, it, grp->head, (idx + 1 + i) & 1, (idx+i) == listview->binding->cursor () ? 1 : 0, i * listview->rowheight, -listview->hscrollpos, grp_y + listview->grouptitle_height + i * listview->rowheight - listview->scrollpos, listview->totalwidth, listview->rowheight);
}
@@ -675,13 +646,13 @@ ddb_listview_list_render (DdbListview *listview, int x, int y, int w, int h) {
if (filler > 0) {
int theming = !gtkui_override_listview_colors ();
if (theming) {
- gtk_paint_flat_box (treeview->style, listview->backbuf, GTK_STATE_NORMAL, GTK_SHADOW_NONE, NULL, treeview, "cell_even_ruled", x, grp_y - listview->scrollpos + listview->grouptitle_height + listview->rowheight * grp->num_items, w, filler);
+ gtk_paint_flat_box (treeview->style, listview->list->window, GTK_STATE_NORMAL, GTK_SHADOW_NONE, NULL, treeview, "cell_even_ruled", x, grp_y - listview->scrollpos + listview->grouptitle_height + listview->rowheight * grp->num_items, w, filler);
}
else {
GdkColor clr;
- GdkGC *gc = gdk_gc_new (listview->backbuf);
+ GdkGC *gc = gdk_gc_new (listview->list->window);
gdk_gc_set_rgb_fg_color (gc, (gtkui_get_listview_even_row_color (&clr), &clr));
- gdk_draw_rectangle (listview->backbuf, gc, TRUE, x, grp_y - listview->scrollpos + listview->grouptitle_height + listview->rowheight * grp->num_items, w, filler);
+ gdk_draw_rectangle (listview->list->window, gc, TRUE, x, grp_y - listview->scrollpos + listview->grouptitle_height + listview->rowheight * grp->num_items, w, filler);
g_object_unref (gc);
}
@@ -694,16 +665,16 @@ ddb_listview_list_render (DdbListview *listview, int x, int y, int w, int h) {
}
if (grp_y < y + h + listview->scrollpos) {
int hh = y + h - (grp_y - listview->scrollpos);
-// gdk_draw_rectangle (listview->backbuf, listview->list->style->bg_gc[GTK_STATE_NORMAL], TRUE, x, grp_y - listview->scrollpos, w, hh);
+// gdk_draw_rectangle (listview->list->window, listview->list->style->bg_gc[GTK_STATE_NORMAL], TRUE, x, grp_y - listview->scrollpos, w, hh);
int theming = !gtkui_override_listview_colors ();
if (theming) {
- gtk_paint_flat_box (treeview->style, listview->backbuf, GTK_STATE_NORMAL, GTK_SHADOW_NONE, NULL, treeview, "cell_even_ruled", x, grp_y - listview->scrollpos, w, hh);
+ gtk_paint_flat_box (treeview->style, listview->list->window, GTK_STATE_NORMAL, GTK_SHADOW_NONE, NULL, treeview, "cell_even_ruled", x, grp_y - listview->scrollpos, w, hh);
}
else {
GdkColor clr;
- GdkGC *gc = gdk_gc_new (listview->backbuf);
+ GdkGC *gc = gdk_gc_new (listview->list->window);
gdk_gc_set_rgb_fg_color (gc, (gtkui_get_listview_even_row_color (&clr), &clr));
- gdk_draw_rectangle (listview->backbuf, gc, TRUE, x, grp_y - listview->scrollpos, w, hh);
+ gdk_draw_rectangle (listview->list->window, gc, TRUE, x, grp_y - listview->scrollpos, w, hh);
g_object_unref (gc);
}
}
@@ -711,16 +682,6 @@ ddb_listview_list_render (DdbListview *listview, int x, int y, int w, int h) {
draw_end ();
}
-gboolean
-ddb_listview_list_expose_event (GtkWidget *widget,
- GdkEventExpose *event,
- gpointer user_data)
-{
- DdbListview *ps = DDB_LISTVIEW (g_object_get_data (G_OBJECT (widget), "owner"));
- ddb_listview_list_expose (ps, event->area.x, event->area.y, event->area.width, event->area.height);
- return FALSE;
-}
-
static void
ddb_listview_draw_dnd_marker (DdbListview *ps) {
if (ps->drag_motion_y < 0) {
@@ -740,15 +701,20 @@ ddb_listview_draw_dnd_marker (DdbListview *ps) {
}
-void
-ddb_listview_list_expose (DdbListview *listview, int x, int y, int w, int h) {
- GtkWidget *widget = listview->list;
- if (widget->window && listview->backbuf) {
- draw_drawable (widget->window, widget->style->black_gc, listview->backbuf, x, y, x, y, w, h);
+gboolean
+ddb_listview_list_expose_event (GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer user_data)
+{
+ DdbListview *ps = DDB_LISTVIEW (g_object_get_data (G_OBJECT (widget), "owner"));
+ widget = ps->list;
+ if (widget->window) {
+ ddb_listview_list_render (ps, event->area.x, event->area.y, event->area.width, event->area.height);
}
- if (listview->drag_motion_y >= 0 && listview->drag_motion_y-listview->scrollpos-3 < y+h && listview->drag_motion_y-listview->scrollpos+3 >= y) {
- ddb_listview_draw_dnd_marker (listview);
+ if (ps->drag_motion_y >= 0 && ps->drag_motion_y-ps->scrollpos-3 < event->area.y+event->area.height && ps->drag_motion_y-ps->scrollpos+3 >= event->area.y) {
+ ddb_listview_draw_dnd_marker (ps);
}
+ return FALSE;
}
gboolean
@@ -795,19 +761,23 @@ ddb_listview_vscroll_value_changed (GtkRange *widget,
if (di > 0) {
// scroll down
// copy scrolled part of buffer
- draw_drawable (ps->backbuf, widget->style->black_gc, ps->backbuf, 0, d, 0, 0, widget->allocation.width, widget->allocation.height-d);
+ gdk_draw_drawable (ps->list->window, widget->style->black_gc, ps->list->window, 0, d, 0, 0, widget->allocation.width, widget->allocation.height-d);
+// draw_drawable (ps->list->window, widget->style->black_gc, ps->list->window, 0, d, 0, 0, widget->allocation.width, widget->allocation.height-d);
// redraw other part
int start = height-d-1;
ps->scrollpos = newscroll;
- ddb_listview_list_render (ps, 0, start, ps->list->allocation.width, widget->allocation.height-start);
+ gtk_widget_queue_draw_area (ps->list, 0, start, ps->list->allocation.width, widget->allocation.height-start);
+// ddb_listview_list_render (ps, 0, start, ps->list->allocation.width, widget->allocation.height-start);
}
else {
// scroll up
// copy scrolled part of buffer
- draw_drawable (ps->backbuf, widget->style->black_gc, ps->backbuf, 0, 0, 0, d, widget->allocation.width, widget->allocation.height-d);
+ gdk_draw_drawable (ps->list->window, widget->style->black_gc, ps->list->window, 0, 0, 0, d, widget->allocation.width, widget->allocation.height-d);
+ //draw_drawable (ps->list->window, widget->style->black_gc, ps->list->window, 0, 0, 0, d, widget->allocation.width, widget->allocation.height-d);
// redraw other part
ps->scrollpos = newscroll;
- ddb_listview_list_render (ps, 0, 0, ps->list->allocation.width, d+1);
+ gtk_widget_queue_draw_area (ps->list, 0, 0, ps->list->allocation.width, d+1);
+ //ddb_listview_list_render (ps, 0, 0, ps->list->allocation.width, d+1);
}
}
else {
@@ -815,7 +785,8 @@ ddb_listview_vscroll_value_changed (GtkRange *widget,
ps->scrollpos = newscroll;
ddb_listview_list_render (ps, 0, 0, widget->allocation.width, widget->allocation.height);
}
- draw_drawable (widget->window, widget->style->black_gc, ps->backbuf, 0, 0, 0, 0, widget->allocation.width, widget->allocation.height);
+ gtk_widget_queue_draw (ps->list);
+// draw_drawable (widget->window, widget->style->black_gc, ps->list->window, 0, 0, 0, 0, widget->allocation.width, widget->allocation.height);
}
}
@@ -877,17 +848,6 @@ ddb_listview_list_drag_drop (GtkWidget *widget,
gpointer user_data)
{
return TRUE;
-#if 0
- if (drag_context->targets) {
- GdkAtom target_type = GDK_POINTER_TO_ATOM (g_list_nth_data (drag_context->targets, TARGET_SAMEWIDGET));
- if (!target_type) {
- return FALSE;
- }
-// gtk_drag_get_data (widget, drag_context, target_type, time);
- return TRUE;
- }
- return FALSE;
-#endif
}
@@ -942,6 +902,7 @@ ddb_listview_list_drag_data_received (GtkWidget *widget,
guint time,
gpointer user_data)
{
+ printf ("target_type: %d, format: %d\n", target_type, data->format);
DdbListview *ps = DDB_LISTVIEW (g_object_get_data (G_OBJECT (widget), "owner"));
ps->scroll_direction = 0; // interrupt autoscrolling, if on
ps->scroll_active = 0;
@@ -972,7 +933,7 @@ ddb_listview_list_drag_data_received (GtkWidget *widget,
UNREF (it);
}
}
- else if (target_type == 1) {
+ else if (target_type == 1 && data->format == 32) { // list of 32bit ints, DDB_URI_LIST target
uint32_t *d= (uint32_t *)ptr;
int plt = *d;
d++;
@@ -1013,17 +974,17 @@ ddb_listview_list_drag_leave (GtkWidget *widget,
}
// debug function for gdk_draw_drawable
-static inline void
-draw_drawable (GdkDrawable *window, GdkGC *gc, GdkDrawable *drawable, int x1, int y1, int x2, int y2, int w, int h) {
- gint width1, height1;
- gint width2, height2;
- gdk_drawable_get_size (window, &width1, &height1);
- gdk_drawable_get_size (drawable, &width2, &height2);
-// assert (y1 >= 0 && y1 + h < height2);
-// assert (y2 >= 0 && y2 + h < height1);
-// printf ("dd: %p %p %p %d %d %d %d %d %d\n", window, gc, drawable, x1, y1, x2, y2, w, h);
- gdk_draw_drawable (window, gc, drawable, x1, y1, x2, y2, w, h);
-}
+//static inline void
+//draw_drawable (GdkDrawable *window, GdkGC *gc, GdkDrawable *drawable, int x1, int y1, int x2, int y2, int w, int h) {
+// gint width1, height1;
+// gint width2, height2;
+// gdk_drawable_get_size (window, &width1, &height1);
+// gdk_drawable_get_size (drawable, &width2, &height2);
+//// assert (y1 >= 0 && y1 + h < height2);
+//// assert (y2 >= 0 && y2 + h < height1);
+//// printf ("dd: %p %p %p %d %d %d %d %d %d\n", window, gc, drawable, x1, y1, x2, y2, w, h);
+// gdk_draw_drawable (window, gc, drawable, x1, y1, x2, y2, w, h);
+//}
int
ddb_listview_get_vscroll_pos (DdbListview *listview) {
@@ -1117,8 +1078,7 @@ ddb_listview_list_setup_vscroll (DdbListview *ps) {
if (ps->fullheight <= ps->list->allocation.height) {
gtk_widget_hide (scroll);
ps->scrollpos = 0;
- ddb_listview_list_render (ps, 0, 0, list->allocation.width, list->allocation.height);
- ddb_listview_list_expose (ps, 0, 0, list->allocation.width, list->allocation.height);
+ gtk_widget_queue_draw (ps->list);
}
else {
gtk_widget_show (scroll);
@@ -1194,8 +1154,9 @@ ddb_listview_list_get_drawinfo (DdbListview *listview, int row, DdbListviewGroup
return -1;
}
+#if 0
void
-ddb_listview_list_render_row (DdbListview *listview, int row, DdbListviewIter it, int expose) {
+ddb_listview_list_render_row (DdbListview *listview, int row, DdbListviewIter it) {
DdbListviewGroup *grp;
int even;
int cursor;
@@ -1213,20 +1174,34 @@ ddb_listview_list_render_row (DdbListview *listview, int row, DdbListviewIter it
return;
}
- draw_begin ((uintptr_t)listview->backbuf);
+ draw_begin ((uintptr_t)listview->list->window);
ddb_listview_list_render_row_background (listview, it, even, cursor, x, y, w, h);
if (it) {
ddb_listview_list_render_row_foreground (listview, it, grp->head, even, cursor, group_y, x, y, w, h);
}
draw_end ();
- if (expose) {
- draw_drawable (listview->list->window, listview->list->style->black_gc, listview->backbuf, 0, y, 0, y, listview->list->allocation.width, h);
- }
}
+#endif
void
ddb_listview_draw_row (DdbListview *listview, int row, DdbListviewIter it) {
- ddb_listview_list_render_row (listview, row, it, 1);
+ DdbListviewGroup *grp;
+ int even;
+ int cursor;
+ int x, y, w, h;
+ int group_y;
+ if (ddb_listview_list_get_drawinfo (listview, row, &grp, &even, &cursor, &group_y, &x, &y, &w, &h) == -1) {
+ return;
+ }
+
+ if (y + h <= 0) {
+ return;
+ }
+
+ if (y > GTK_WIDGET (listview)->allocation.height) {
+ return;
+ }
+ gtk_widget_queue_draw_area (listview->list, 0, y, listview->list->allocation.width, h);
}
// coords passed are window-relative
@@ -1247,26 +1222,26 @@ ddb_listview_list_render_row_background (DdbListview *ps, DdbListviewIter it, in
if (theming || !sel) {
if (theming) {
// draw background for selection -- workaround for New Wave theme (translucency)
- gtk_paint_flat_box (treeview->style, ps->backbuf, GTK_STATE_NORMAL, GTK_SHADOW_NONE, NULL, treeview, even ? "cell_even_ruled" : "cell_odd_ruled", x, y, w, h);
+ gtk_paint_flat_box (treeview->style, ps->list->window, GTK_STATE_NORMAL, GTK_SHADOW_NONE, NULL, treeview, even ? "cell_even_ruled" : "cell_odd_ruled", x, y, w, h);
}
else {
GdkColor clr;
- GdkGC *gc = gdk_gc_new (ps->backbuf);
+ GdkGC *gc = gdk_gc_new (ps->list->window);
gdk_gc_set_rgb_fg_color (gc, even ? (gtkui_get_listview_even_row_color (&clr), &clr) : (gtkui_get_listview_odd_row_color (&clr), &clr));
- gdk_draw_rectangle (ps->backbuf, gc, TRUE, x, y, w, h);
+ gdk_draw_rectangle (ps->list->window, gc, TRUE, x, y, w, h);
g_object_unref (gc);
}
}
if (sel) {
if (theming) {
- gtk_paint_flat_box (treeview->style, ps->backbuf, GTK_STATE_SELECTED, GTK_SHADOW_NONE, NULL, treeview, even ? "cell_even_ruled" : "cell_odd_ruled", x, y, w, h);
+ gtk_paint_flat_box (treeview->style, ps->list->window, GTK_STATE_SELECTED, GTK_SHADOW_NONE, NULL, treeview, even ? "cell_even_ruled" : "cell_odd_ruled", x, y, w, h);
}
else {
GdkColor clr;
- GdkGC *gc = gdk_gc_new (ps->backbuf);
+ GdkGC *gc = gdk_gc_new (ps->list->window);
gdk_gc_set_rgb_fg_color (gc, (gtkui_get_listview_selection_color (&clr), &clr));
- gdk_draw_rectangle (ps->backbuf, gc, TRUE, x, y, w, h);
+ gdk_draw_rectangle (ps->list->window, gc, TRUE, x, y, w, h);
g_object_unref (gc);
}
}
@@ -1275,9 +1250,9 @@ ddb_listview_list_render_row_background (DdbListview *ps, DdbListviewIter it, in
// but we want it anyway
//treeview->style->fg_gc[GTK_STATE_NORMAL]
GdkColor clr;
- GdkGC *gc = gdk_gc_new (ps->backbuf);
+ GdkGC *gc = gdk_gc_new (ps->list->window);
gdk_gc_set_rgb_fg_color (gc, (gtkui_get_listview_cursor_color (&clr), &clr));
- gdk_draw_rectangle (ps->backbuf, gc, FALSE, x, y, w-1, h-1);
+ gdk_draw_rectangle (ps->list->window, gc, FALSE, x, y, w-1, h-1);
g_object_unref (gc);
}
}
@@ -1285,7 +1260,7 @@ ddb_listview_list_render_row_background (DdbListview *ps, DdbListviewIter it, in
void
ddb_listview_list_render_row_foreground (DdbListview *ps, DdbListviewIter it, DdbListviewIter group_it, int even, int cursor, int group_y, int x, int y, int w, int h) {
int width, height;
- draw_get_canvas_size ((uintptr_t)ps->backbuf, &width, &height);
+ draw_get_canvas_size ((uintptr_t)ps->list->window, &width, &height);
if (it && ps->binding->is_selected (it)) {
GdkColor *clr = &theme_treeview->style->fg[GTK_STATE_SELECTED];
float rgb[3] = { clr->red/65535.f, clr->green/65535.f, clr->blue/65535.f };
@@ -1300,7 +1275,7 @@ ddb_listview_list_render_row_foreground (DdbListview *ps, DdbListviewIter it, Dd
int cidx = 0;
for (c = ps->columns; c; c = c->next, cidx++) {
int cw = c->width;
- ps->binding->draw_column_data (ps, ps->backbuf, it, ps->grouptitle_height > 0 ? group_it : NULL, cidx, group_y, x, y, cw, h);
+ ps->binding->draw_column_data (ps, ps->list->window, it, ps->grouptitle_height > 0 ? group_it : NULL, cidx, group_y, x, y, cw, h);
x += cw;
}
}
@@ -1308,8 +1283,7 @@ ddb_listview_list_render_row_foreground (DdbListview *ps, DdbListviewIter it, Dd
void
ddb_listview_header_expose (DdbListview *ps, int x, int y, int w, int h) {
- GtkWidget *widget = ps->header;
- draw_drawable (widget->window, widget->style->black_gc, ps->backbuf_header, x, y, x, y, w, h);
+ ddb_listview_header_render (ps);
}
void
@@ -1347,7 +1321,7 @@ ddb_listview_select_single (DdbListview *ps, int sel) {
}
UNREF (it);
if (nchanged >= NUM_CHANGED_ROWS_BEFORE_FULL_REDRAW) {
- ddb_listview_refresh (ps, DDB_REFRESH_LIST | DDB_EXPOSE_LIST);
+ ddb_listview_refresh (ps, DDB_REFRESH_LIST);
ps->binding->selection_changed (it, -1); // that means "selection changed a lot, redraw everything"
}
ps->area_selection_start = sel;
@@ -1587,7 +1561,7 @@ ddb_listview_list_mouse1_released (DdbListview *ps, int state, int ex, int ey, d
#if 0
void
ddb_listview_list_dbg_draw_areasel (GtkWidget *widget, int x, int y) {
- // erase previous rect using 4 blits from ps->backbuffer
+ // erase previous rect using 4 blits from ps->list->windowfer
if (areaselect_dx != -1) {
int sx = min (areaselect_x, areaselect_dx);
int sy = min (areaselect_y, areaselect_dy);
@@ -1595,11 +1569,11 @@ ddb_listview_list_dbg_draw_areasel (GtkWidget *widget, int x, int y) {
int dy = max (areaselect_y, areaselect_dy);
int w = dx - sx + 1;
int h = dy - sy + 1;
- //draw_drawable (widget->window, widget->style->black_gc, ps->backbuf, sx, sy, sx, sy, dx - sx + 1, dy - sy + 1);
- draw_drawable (widget->window, widget->style->black_gc, ps->backbuf, sx, sy, sx, sy, w, 1);
- draw_drawable (widget->window, widget->style->black_gc, ps->backbuf, sx, sy, sx, sy, 1, h);
- draw_drawable (widget->window, widget->style->black_gc, ps->backbuf, sx, sy + h - 1, sx, sy + h - 1, w, 1);
- draw_drawable (widget->window, widget->style->black_gc, ps->backbuf, sx + w - 1, sy, sx + w - 1, sy, 1, h);
+ //draw_drawable (widget->window, widget->style->black_gc, ps->list->window, sx, sy, sx, sy, dx - sx + 1, dy - sy + 1);
+ draw_drawable (widget->window, widget->style->black_gc, ps->list->window, sx, sy, sx, sy, w, 1);
+ draw_drawable (widget->window, widget->style->black_gc, ps->list->window, sx, sy, sx, sy, 1, h);
+ draw_drawable (widget->window, widget->style->black_gc, ps->list->window, sx, sy + h - 1, sx, sy + h - 1, w, 1);
+ draw_drawable (widget->window, widget->style->black_gc, ps->list->window, sx + w - 1, sy, sx + w - 1, sy, 1, h);
}
areaselect_dx = x;
areaselect_dy = y;
@@ -1675,7 +1649,7 @@ ddb_listview_list_mousemove (DdbListview *ps, GdkEventMotion *ev, int ex, int ey
ps->dragwait = 0;
ps->drag_source_playlist = deadbeef->plt_get_curr ();
GtkTargetEntry entry = {
- .target = "STRING",
+ .target = "DDB_URI_LIST",
.flags = GTK_TARGET_SAME_WIDGET,
.info = TARGET_SAMEWIDGET
};
@@ -1778,7 +1752,7 @@ ddb_listview_list_mousemove (DdbListview *ps, GdkEventMotion *ev, int ex, int ey
}
UNREF (it);
if (nchanged >= NUM_CHANGED_ROWS_BEFORE_FULL_REDRAW) {
- ddb_listview_refresh (ps, DDB_REFRESH_LIST | DDB_EXPOSE_LIST);
+ ddb_listview_refresh (ps, DDB_REFRESH_LIST);
ps->binding->selection_changed (it, -1); // that means "selection changed a lot, redraw everything"
}
ps->area_selection_start = start;
@@ -1841,10 +1815,8 @@ ddb_listview_list_set_hscroll (DdbListview *ps, int newscroll) {
{
ps->hscrollpos = newscroll;
GtkWidget *widget = ps->list;
- ddb_listview_header_render (ps);
- ddb_listview_header_expose (ps, 0, 0, ps->header->allocation.width, ps->header->allocation.height);
- ddb_listview_list_render (ps, 0, 0, widget->allocation.width, widget->allocation.height);
- draw_drawable (widget->window, widget->style->black_gc, ps->backbuf, 0, 0, 0, 0, widget->allocation.width, widget->allocation.height);
+ gtk_widget_queue_draw (ps->header);
+ gtk_widget_queue_draw (ps->list);
}
}
@@ -1971,7 +1943,7 @@ ddb_listview_handle_keypress (DdbListview *ps, int keyval, int state) {
}
UNREF (it);
if (nchanged >= NUM_CHANGED_ROWS_BEFORE_FULL_REDRAW) {
- ddb_listview_refresh (ps, DDB_REFRESH_LIST | DDB_EXPOSE_LIST);
+ ddb_listview_refresh (ps, DDB_REFRESH_LIST);
ps->binding->selection_changed (it, -1); // that means "selection changed a lot, redraw everything"
}
}
@@ -2018,7 +1990,7 @@ ddb_listview_list_track_dragdrop (DdbListview *ps, int y) {
GtkWidget *widget = ps->list;
if (ps->drag_motion_y != -1) {
// erase previous track
- draw_drawable (widget->window, widget->style->black_gc, ps->backbuf, 0, ps->drag_motion_y-3-ps->scrollpos, 0, ps->drag_motion_y-ps->scrollpos-3, widget->allocation.width, 7);
+ gtk_widget_queue_draw_area (ps->list, 0, ps->drag_motion_y-ps->scrollpos-3, widget->allocation.width, 7);
}
if (y == -1) {
@@ -2077,7 +2049,7 @@ ddb_listview_list_drag_end (GtkWidget *widget,
gpointer user_data)
{
DdbListview *ps = DDB_LISTVIEW (g_object_get_data (G_OBJECT (widget), "owner"));
- ddb_listview_refresh (ps, DDB_REFRESH_LIST|DDB_EXPOSE_LIST);
+ ddb_listview_refresh (ps, DDB_REFRESH_LIST);
ps->scroll_direction = 0;
ps->scroll_pointer_y = -1;
}
@@ -2094,17 +2066,17 @@ ddb_listview_header_render (DdbListview *ps) {
// fill background and draw bottom line
#if !HEADERS_GTKTHEME
- GdkGC *gc = gdk_gc_new (ps->backbuf_header);
+ GdkGC *gc = gdk_gc_new (ps->header->window);
GdkColor clr;
gdk_gc_set_rgb_fg_color (gc, (gtkui_get_tabstrip_base_color (&clr), &clr));
- gdk_draw_rectangle (ps->backbuf_header, gc, TRUE, 0, 0, widget->allocation.width, widget->allocation.height);
+ gdk_draw_rectangle (ps->header->window, gc, TRUE, 0, 0, widget->allocation.width, widget->allocation.height);
gdk_gc_set_rgb_fg_color (gc, (gtkui_get_tabstrip_dark_color (&clr), &clr));
- gdk_draw_line (ps->backbuf_header, gc, 0, widget->allocation.height-1, widget->allocation.width, widget->allocation.height-1);
+ gdk_draw_line (ps->header->window, gc, 0, widget->allocation.height-1, widget->allocation.width, widget->allocation.height-1);
#else
- gtk_paint_box (theme_button->style, ps->backbuf_header, GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, widget, detail, -10, -10, widget->allocation.width+20, widget->allocation.height+20);
- gdk_draw_line (ps->backbuf_header, widget->style->mid_gc[GTK_STATE_NORMAL], 0, widget->allocation.height-1, widget->allocation.width, widget->allocation.height-1);
+ gtk_paint_box (theme_button->style, ps->header->window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, widget, detail, -10, -10, widget->allocation.width+20, widget->allocation.height+20);
+ gdk_draw_line (ps->header->window, widget->style->mid_gc[GTK_STATE_NORMAL], 0, widget->allocation.height-1, widget->allocation.width, widget->allocation.height-1);
#endif
- draw_begin ((uintptr_t)ps->backbuf_header);
+ draw_begin ((uintptr_t)ps->header->window);
x = -ps->hscrollpos;
DdbListviewColumn *c;
int need_draw_moving = 0;
@@ -2131,11 +2103,11 @@ ddb_listview_header_render (DdbListview *ps) {
if (w > 0) {
#if !HEADERS_GTKTHEME
gdk_gc_set_rgb_fg_color (gc, (gtkui_get_tabstrip_dark_color (&clr), &clr));
- gdk_draw_line (ps->backbuf_header, gc, xx+w - 2, 2, xx+w - 2, h-4);
+ gdk_draw_line (ps->header->window, gc, xx+w - 2, 2, xx+w - 2, h-4);
gdk_gc_set_rgb_fg_color (gc, (gtkui_get_tabstrip_light_color (&clr), &clr));
- gdk_draw_line (ps->backbuf_header, gc, xx+w - 1, 2, xx+w - 1, h-4);
+ gdk_draw_line (ps->header->window, gc, xx+w - 1, 2, xx+w - 1, h-4);
#else
- gtk_paint_vline (widget->style, ps->backbuf_header, GTK_STATE_NORMAL, NULL, widget, NULL, 2, h-4, xx+w - 2);
+ gtk_paint_vline (widget->style, ps->header->window, GTK_STATE_NORMAL, NULL, widget, NULL, 2, h-4, xx+w - 2);
#endif
GdkColor *gdkfg = &theme_button->style->fg[0];
float fg[3] = {(float)gdkfg->red/0xffff, (float)gdkfg->green/0xffff, (float)gdkfg->blue/0xffff};
@@ -2151,7 +2123,7 @@ ddb_listview_header_render (DdbListview *ps) {
}
if (sort) {
int dir = sort == 1 ? GTK_ARROW_DOWN : GTK_ARROW_UP;
- gtk_paint_arrow (widget->style, ps->backbuf_header, GTK_STATE_NORMAL, GTK_SHADOW_NONE, NULL, widget, NULL, dir, TRUE, xx + w-arrow_sz-5, widget->allocation.height/2-arrow_sz/2, arrow_sz, arrow_sz);
+ gtk_paint_arrow (widget->style, ps->header->window, GTK_STATE_NORMAL, GTK_SHADOW_NONE, NULL, widget, NULL, dir, TRUE, xx + w-arrow_sz-5, widget->allocation.height/2-arrow_sz/2, arrow_sz, arrow_sz);
}
}
else {
@@ -2177,14 +2149,14 @@ ddb_listview_header_render (DdbListview *ps) {
#endif
// draw empty slot
if (x < widget->allocation.width) {
- gtk_paint_box (theme_button->style, ps->backbuf_header, GTK_STATE_ACTIVE, GTK_SHADOW_ETCHED_IN, NULL, widget, "button", x, 0, w, h);
+ gtk_paint_box (theme_button->style, ps->header->window, GTK_STATE_ACTIVE, GTK_SHADOW_ETCHED_IN, NULL, widget, "button", x, 0, w, h);
}
x = ps->col_movepos - ps->hscrollpos;
if (x >= widget->allocation.width) {
break;
}
if (w > 0) {
- gtk_paint_box (theme_button->style, ps->backbuf_header, GTK_STATE_SELECTED, GTK_SHADOW_OUT, NULL, widget, "button", x, 0, w, h);
+ gtk_paint_box (theme_button->style, ps->header->window, GTK_STATE_SELECTED, GTK_SHADOW_OUT, NULL, widget, "button", x, 0, w, h);
GdkColor *gdkfg = &theme_button->style->fg[GTK_STATE_SELECTED];
float fg[3] = {(float)gdkfg->red/0xffff, (float)gdkfg->green/0xffff, (float)gdkfg->blue/0xffff};
draw_set_fg_color (fg);
@@ -2224,12 +2196,6 @@ ddb_listview_header_configure_event (GtkWidget *widget,
if (height != widget->allocation.height) {
gtk_widget_set_size_request (widget, -1, height);
}
- if (ps->backbuf_header) {
- g_object_unref (ps->backbuf_header);
- ps->backbuf_header = NULL;
- }
- ps->backbuf_header = gdk_pixmap_new (widget->window, widget->allocation.width, widget->allocation.height, -1);
- ddb_listview_header_render (ps);
return FALSE;
}
@@ -2268,7 +2234,9 @@ ddb_listview_header_motion_notify_event (GtkWidget *widget,
ev_x = event->x;
ev_y = event->y;
ev_state = event->state;
+#if GTK_CHECK_VERSION(2,12,0) && !defined(ULTRA_COMPATIBLE)
gdk_event_request_motions (event);
+#endif
if ((ev_state & GDK_BUTTON1_MASK) && ps->header_prepare) {
if (gtk_drag_check_threshold (widget, ev_x, ps->prev_header_x, 0, 0)) {
@@ -2304,13 +2272,11 @@ ddb_listview_header_motion_notify_event (GtkWidget *widget,
// colhdr_anim_swap (ps, c1, c2, x1, x2);
// force redraw of everything
// ddb_listview_list_setup_hscroll (ps);
- ddb_listview_list_render (ps, 0, 0, ps->list->allocation.width, ps->list->allocation.height);
- ddb_listview_list_expose (ps, 0, 0, ps->list->allocation.width, ps->list->allocation.height);
+ gtk_widget_queue_draw (ps->list);
}
else {
// only redraw that if not animating
- ddb_listview_header_render (ps);
- ddb_listview_header_expose (ps, 0, 0, ps->header->allocation.width, ps->header->allocation.height);
+ gtk_widget_queue_draw (ps->header);
}
}
else if (ps->header_sizing >= 0) {
@@ -2334,10 +2300,8 @@ ddb_listview_header_motion_notify_event (GtkWidget *widget,
ddb_listview_list_setup_vscroll (ps);
ddb_listview_list_setup_hscroll (ps);
ps->block_redraw_on_scroll = 0;
- ddb_listview_header_render (ps);
- ddb_listview_header_expose (ps, 0, 0, ps->header->allocation.width, ps->header->allocation.height);
- ddb_listview_list_render (ps, 0, 0, ps->list->allocation.width, ps->list->allocation.height);
- ddb_listview_list_expose (ps, 0, 0, ps->list->allocation.width, ps->list->allocation.height);
+ gtk_widget_queue_draw (ps->header);
+ gtk_widget_queue_draw (ps->list);
ps->binding->column_size_changed (ps, ps->header_sizing);
}
else {
@@ -2451,7 +2415,7 @@ ddb_listview_header_button_release_event (GtkWidget *widget,
else if (sort_order == 2) {
c->sort_order = 1;
}
- ps->binding->col_sort (i, c->sort_order, c->user_data);
+ ps->binding->col_sort (i, c->sort_order-1, c->user_data);
sorted = 1;
}
else {
@@ -2459,7 +2423,7 @@ ddb_listview_header_button_release_event (GtkWidget *widget,
}
x += w;
}
- ddb_listview_refresh (ps, DDB_REFRESH_LIST | DDB_REFRESH_COLUMNS | DDB_EXPOSE_LIST | DDB_EXPOSE_COLUMNS);
+ ddb_listview_refresh (ps, DDB_REFRESH_LIST | DDB_REFRESH_COLUMNS);
}
else {
ps->header_sizing = -1;
@@ -2478,7 +2442,7 @@ ddb_listview_header_button_release_event (GtkWidget *widget,
}
if (ps->header_dragging >= 0) {
ps->header_dragging = -1;
- ddb_listview_refresh (ps, DDB_REFRESH_LIST | DDB_REFRESH_COLUMNS | DDB_EXPOSE_LIST | DDB_EXPOSE_COLUMNS | DDB_REFRESH_HSCROLL);
+ ddb_listview_refresh (ps, DDB_REFRESH_LIST | DDB_REFRESH_COLUMNS | DDB_REFRESH_HSCROLL);
}
}
ps->binding->columns_changed (ps);
@@ -2630,7 +2594,9 @@ ddb_listview_motion_notify_event (GtkWidget *widget,
{
int x = event->x;
int y = event->y;
+#if GTK_CHECK_VERSION(2,12,0) && !defined(ULTRA_COMPATIBLE)
gdk_event_request_motions (event);
+#endif
DdbListview *ps = DDB_LISTVIEW (g_object_get_data (G_OBJECT (widget), "owner"));
ddb_listview_list_mousemove (ps, event, x, y);
return FALSE;
@@ -2959,6 +2925,5 @@ ddb_listview_clear_sort (DdbListview *listview) {
for (c = listview->columns; c; c = c->next) {
c->sort_order = 0;
}
- ddb_listview_header_render (listview);
- ddb_listview_header_expose (listview, 0, 0, listview->header->allocation.width, listview->header->allocation.height);
+ gtk_widget_queue_draw (listview->header);
}
diff --git a/plugins/gtkui/ddblistview.h b/plugins/gtkui/ddblistview.h
index 55333384..d0a7ceb9 100644
--- a/plugins/gtkui/ddblistview.h
+++ b/plugins/gtkui/ddblistview.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -103,8 +103,6 @@ struct _DdbListview {
GtkWidget *hscrollbar;
int totalwidth; // width of listview, including invisible (scrollable) part
- GdkPixmap *backbuf;
- GdkPixmap *backbuf_header;
const char *title; // unique id, used for config writing, etc
int lastpos[2]; // last mouse position (for list widget)
// current state
@@ -205,8 +203,6 @@ enum {
DDB_REFRESH_HSCROLL = 2,
DDB_REFRESH_VSCROLL = 4,
DDB_REFRESH_LIST = 8,
- DDB_EXPOSE_COLUMNS = 16,
- DDB_EXPOSE_LIST = 32,
};
void ddb_listview_refresh (DdbListview *listview, uint32_t flags);
diff --git a/plugins/gtkui/ddbseekbar.c b/plugins/gtkui/ddbseekbar.c
index 407b347c..1ad285a7 100644
--- a/plugins/gtkui/ddbseekbar.c
+++ b/plugins/gtkui/ddbseekbar.c
@@ -1,4 +1,4 @@
-/* ddbseekbar.c generated by valac 0.10.0, the Vala compiler
+/* ddbseekbar.c generated by valac 0.10.2, the Vala compiler
* generated from ddbseekbar.vala, do not modify */
/*
@@ -138,7 +138,7 @@ static gboolean ddb_seekbar_real_configure_event (GtkWidget* base, GdkEventConfi
DdbSeekbar* ddb_seekbar_construct (GType object_type) {
- DdbSeekbar * self;
+ DdbSeekbar * self = NULL;
self = (DdbSeekbar*) gtk_widget_new (object_type, NULL);
return self;
}
diff --git a/plugins/gtkui/ddbseekbar.h b/plugins/gtkui/ddbseekbar.h
index f501a00c..c975654e 100644
--- a/plugins/gtkui/ddbseekbar.h
+++ b/plugins/gtkui/ddbseekbar.h
@@ -1,4 +1,4 @@
-/* ddbseekbar.h generated by valac 0.10.0, the Vala compiler, do not modify */
+/* ddbseekbar.h generated by valac 0.10.2, the Vala compiler, do not modify */
#ifndef __DDBSEEKBAR_H__
diff --git a/plugins/gtkui/ddbtabstrip.c b/plugins/gtkui/ddbtabstrip.c
index ea7905c7..d6920a9f 100644
--- a/plugins/gtkui/ddbtabstrip.c
+++ b/plugins/gtkui/ddbtabstrip.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -43,7 +43,14 @@ extern GtkWidget *theme_button;
void
plt_get_title_wrapper (int plt, char *buffer, int len) {
- deadbeef->plt_get_title (plt, buffer, len);
+ if (plt == -1) {
+ strcpy (buffer, "");
+ return;
+ }
+ deadbeef->plt_lock ();
+ void *p = deadbeef->plt_get_handle (plt);
+ deadbeef->plt_get_title (p, buffer, len);
+ deadbeef->plt_unlock ();
char *end;
if (!g_utf8_validate (buffer, -1, (const gchar **)&end)) {
*end = 0;
@@ -135,6 +142,11 @@ ddb_tabstrip_size_allocate (GtkWidget *widget,
}
}
+
+gboolean
+on_tabstrip_scroll_event (GtkWidget *widget,
+ GdkEventScroll *event);
+
gboolean
on_tabstrip_button_press_event (GtkWidget *widget,
GdkEventButton *event);
@@ -213,6 +225,7 @@ ddb_tabstrip_class_init(DdbTabStripClass *class)
widget_class->button_release_event = on_tabstrip_button_release_event;
widget_class->configure_event = on_tabstrip_configure_event;
widget_class->motion_notify_event = on_tabstrip_motion_notify_event;
+ widget_class->scroll_event= on_tabstrip_scroll_event;
widget_class->drag_motion = on_tabstrip_drag_motion_event;
widget_class->drag_drop = on_tabstrip_drag_drop;
widget_class->drag_end = on_tabstrip_drag_end;
@@ -452,6 +465,32 @@ tabstrip_adjust_hscroll (DdbTabStrip *ts) {
}
void
+set_tab_text_color (int idx) {
+ if (idx == -1) {
+ return;
+ }
+ deadbeef->plt_lock ();
+ void *plt = deadbeef->plt_get_handle (idx);
+ const char *clr = deadbeef->plt_find_meta (plt, "gui.color");
+ int fallback = 1;
+ if (clr) {
+ int r, g, b;
+ if (3 == sscanf (clr, "%02x%02x%02x", &r, &g, &b)) {
+ fallback = 0;
+ float fg[3] = {(float)r/0xff, (float)g/0xff, (float)b/0xff};
+ draw_set_fg_color (fg);
+ }
+ }
+ if (fallback) {
+ GdkColor color;
+ gtkui_get_tabstrip_text_color (&color);
+ float fg[3] = {(float)color.red/0xffff, (float)color.green/0xffff, (float)color.blue/0xffff};
+ draw_set_fg_color (fg);
+ }
+ deadbeef->plt_unlock ();
+}
+
+void
tabstrip_render (DdbTabStrip *ts) {
GtkWidget *widget = GTK_WIDGET (ts);
GdkDrawable *backbuf = gtk_widget_get_window (widget);
@@ -514,9 +553,8 @@ tabstrip_render (DdbTabStrip *ts) {
ddb_tabstrip_draw_tab (widget, backbuf, idx == tab_selected, x, y, w, h);
char tab_title[100];
plt_get_title_wrapper (idx, tab_title, sizeof (tab_title));
- GdkColor *color = &widget->style->text[GTK_STATE_NORMAL];
- float fg[3] = {(float)color->red/0xffff, (float)color->green/0xffff, (float)color->blue/0xffff};
- draw_set_fg_color (fg);
+
+ set_tab_text_color (idx);
draw_text (x + text_left_padding, y + h/2 - draw_get_font_size()/2 + text_vert_offset, w, 0, tab_title);
}
x += w - tab_overlap_size;
@@ -541,9 +579,7 @@ tabstrip_render (DdbTabStrip *ts) {
ddb_tabstrip_draw_tab (widget, backbuf, 1, x, y, w, h);
char tab_title[100];
plt_get_title_wrapper (idx, tab_title, sizeof (tab_title));
- GdkColor *color = &widget->style->text[GTK_STATE_NORMAL];
- float fg[3] = {(float)color->red/0xffff, (float)color->green/0xffff, (float)color->blue/0xffff};
- draw_set_fg_color (fg);
+ set_tab_text_color (idx);
draw_text (x + text_left_padding, y + h/2 - draw_get_font_size()/2 + text_vert_offset, w, 0, tab_title);
}
else {
@@ -562,9 +598,7 @@ tabstrip_render (DdbTabStrip *ts) {
ddb_tabstrip_draw_tab (widget, backbuf, 1, x, y, w, h);
char tab_title[100];
plt_get_title_wrapper (idx, tab_title, sizeof (tab_title));
- GdkColor *color = &widget->style->text[GTK_STATE_NORMAL];
- float fg[3] = {(float)color->red/0xffff, (float)color->green/0xffff, (float)color->blue/0xffff};
- draw_set_fg_color (fg);
+ set_tab_text_color (idx);
draw_text (x + text_left_padding, y + h/2 - draw_get_font_size()/2 + text_vert_offset, w, 0, tab_title);
}
break;
@@ -621,17 +655,23 @@ void
on_rename_playlist1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
- GtkWidget *dlg = create_editplaylistdlg ();
+ GtkWidget *dlg = create_entrydialog ();
gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK);
gtk_window_set_title (GTK_WINDOW (dlg), _("Edit playlist"));
- GtkWidget *e = lookup_widget (dlg, "title");
+ GtkWidget *e;
+ e = lookup_widget (dlg, "title_label");
+ gtk_label_set_text (GTK_LABEL(e), _("Title:"));
+ e = lookup_widget (dlg, "title");
char t[100];
plt_get_title_wrapper (tab_clicked, t, sizeof (t));
gtk_entry_set_text (GTK_ENTRY (e), t);
int res = gtk_dialog_run (GTK_DIALOG (dlg));
if (res == GTK_RESPONSE_OK) {
const char *text = gtk_entry_get_text (GTK_ENTRY (e));
- deadbeef->plt_set_title (tab_clicked, text);
+ deadbeef->plt_lock ();
+ void *p = deadbeef->plt_get_handle (tab_clicked);
+ deadbeef->plt_set_title (p, text);
+ deadbeef->plt_unlock ();
}
gtk_widget_destroy (dlg);
}
@@ -643,6 +683,7 @@ on_remove_playlist1_activate (GtkMenuItem *menuitem,
{
if (tab_clicked != -1) {
deadbeef->plt_remove (tab_clicked);
+ playlist_refresh ();
int playlist = deadbeef->plt_get_curr ();
deadbeef->conf_set_int ("playlist.current", playlist);
}
@@ -739,8 +780,26 @@ tabstrip_scroll_cb (gpointer data) {
}
gboolean
-on_tabstrip_button_press_event (GtkWidget *widget,
- GdkEventButton *event)
+on_tabstrip_scroll_event(GtkWidget *widget,
+ GdkEventScroll *event)
+{
+ DdbTabStrip *ts = DDB_TABSTRIP (widget);
+
+ if(event->direction == GDK_SCROLL_UP)
+ {
+ tabstrip_scroll_left(ts);
+ }
+ else if (event->direction == GDK_SCROLL_DOWN)
+ {
+ tabstrip_scroll_right(ts);
+ }
+
+ return TRUE;
+}
+
+gboolean
+on_tabstrip_button_press_event(GtkWidget *widget,
+ GdkEventButton *event)
{
DdbTabStrip *ts = DDB_TABSTRIP (widget);
tab_clicked = get_tab_under_cursor (ts, event->x);
@@ -818,6 +877,7 @@ on_tabstrip_button_press_event (GtkWidget *widget,
else if (deadbeef->conf_get_int ("gtkui.mmb_delete_playlist", 1)) {
if (tab_clicked != -1) {
deadbeef->plt_remove (tab_clicked);
+ playlist_refresh ();
int playlist = deadbeef->plt_get_curr ();
deadbeef->conf_set_int ("playlist.current", playlist);
}
@@ -879,7 +939,9 @@ on_tabstrip_motion_notify_event (GtkWidget *widget,
ev_x = event->x;
ev_y = event->y;
ev_state = event->state;
+#if GTK_CHECK_VERSION(2,12,0) && !defined(ULTRA_COMPATIBLE)
gdk_event_request_motions (event);
+#endif
if ((ev_state & GDK_BUTTON1_MASK) && ts->prepare) {
if (gtk_drag_check_threshold (widget, ev_x, ts->prev_x, 0, 0)) {
ts->prepare = 0;
diff --git a/plugins/gtkui/ddbtabstrip.h b/plugins/gtkui/ddbtabstrip.h
index 7f530e2f..c68b95f1 100644
--- a/plugins/gtkui/ddbtabstrip.h
+++ b/plugins/gtkui/ddbtabstrip.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
diff --git a/plugins/gtkui/ddbvolumebar.c b/plugins/gtkui/ddbvolumebar.c
index 83389f7f..b0df2c9a 100644
--- a/plugins/gtkui/ddbvolumebar.c
+++ b/plugins/gtkui/ddbvolumebar.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
diff --git a/plugins/gtkui/ddbvolumebar.h b/plugins/gtkui/ddbvolumebar.h
index 530e556e..d2cfbe61 100644
--- a/plugins/gtkui/ddbvolumebar.h
+++ b/plugins/gtkui/ddbvolumebar.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
diff --git a/plugins/gtkui/deadbeef.glade b/plugins/gtkui/deadbeef.glade
index 4f38af30..0351668d 100644
--- a/plugins/gtkui/deadbeef.glade
+++ b/plugins/gtkui/deadbeef.glade
@@ -62,7 +62,7 @@
<accelerator key="O" modifiers="GDK_CONTROL_MASK" signal="activate"/>
<child internal-child="image">
- <widget class="GtkImage" id="image452">
+ <widget class="GtkImage" id="image512">
<property name="visible">True</property>
<property name="stock">gtk-open</property>
<property name="icon_size">1</property>
@@ -89,7 +89,7 @@
<signal name="activate" handler="on_add_files_activate" last_modification_time="Sat, 04 Jul 2009 13:04:01 GMT"/>
<child internal-child="image">
- <widget class="GtkImage" id="image453">
+ <widget class="GtkImage" id="image513">
<property name="visible">True</property>
<property name="stock">gtk-add</property>
<property name="icon_size">1</property>
@@ -110,7 +110,7 @@
<signal name="activate" handler="on_add_folders_activate" last_modification_time="Sun, 06 Sep 2009 17:51:40 GMT"/>
<child internal-child="image">
- <widget class="GtkImage" id="image454">
+ <widget class="GtkImage" id="image514">
<property name="visible">True</property>
<property name="stock">gtk-add</property>
<property name="icon_size">1</property>
@@ -190,7 +190,7 @@
<accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/>
<child internal-child="image">
- <widget class="GtkImage" id="image455">
+ <widget class="GtkImage" id="image515">
<property name="visible">True</property>
<property name="stock">gtk-quit</property>
<property name="icon_size">1</property>
@@ -224,7 +224,7 @@
<signal name="activate" handler="on_clear1_activate" last_modification_time="Sun, 06 Sep 2009 18:30:03 GMT"/>
<child internal-child="image">
- <widget class="GtkImage" id="image456">
+ <widget class="GtkImage" id="image516">
<property name="visible">True</property>
<property name="stock">gtk-clear</property>
<property name="icon_size">1</property>
@@ -283,7 +283,7 @@
<signal name="activate" handler="on_remove1_activate" last_modification_time="Sun, 06 Sep 2009 18:30:03 GMT"/>
<child internal-child="image">
- <widget class="GtkImage" id="image457">
+ <widget class="GtkImage" id="image517">
<property name="visible">True</property>
<property name="stock">gtk-remove</property>
<property name="icon_size">1</property>
@@ -320,6 +320,55 @@
</child>
<child>
+ <widget class="GtkMenuItem" id="sort_by1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Sort By</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="sort_by1_menu">
+
+ <child>
+ <widget class="GtkMenuItem" id="album1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Album</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_album1_activate" last_modification_time="Fri, 03 Dec 2010 21:03:21 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="artist1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Artist</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_artist1_activate" last_modification_time="Fri, 03 Dec 2010 21:03:21 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="date1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Date</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_date1_activate" last_modification_time="Fri, 03 Dec 2010 21:03:21 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="custom2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Custom</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_custom2_activate" last_modification_time="Fri, 03 Dec 2010 21:03:21 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
<widget class="GtkSeparatorMenuItem" id="separator5">
<property name="visible">True</property>
</widget>
@@ -422,7 +471,7 @@
<child>
<widget class="GtkRadioMenuItem" id="order_shuffle">
<property name="visible">True</property>
- <property name="label" translatable="yes">Shuffle</property>
+ <property name="label" translatable="yes">Shuffle tracks</property>
<property name="use_underline">True</property>
<property name="active">True</property>
<property name="group">order_linear</property>
@@ -431,6 +480,17 @@
</child>
<child>
+ <widget class="GtkRadioMenuItem" id="order_shuffle_albums">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Shuffle albums</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="group">order_linear</property>
+ <signal name="activate" handler="on_order_shuffle_albums_activate" last_modification_time="Sun, 12 Dec 2010 18:14:47 GMT"/>
+ </widget>
+ </child>
+
+ <child>
<widget class="GtkRadioMenuItem" id="order_random">
<property name="visible">True</property>
<property name="label" translatable="yes">Random</property>
@@ -558,7 +618,7 @@
<signal name="activate" handler="on_help1_activate" last_modification_time="Tue, 08 Sep 2009 17:32:06 GMT"/>
<child internal-child="image">
- <widget class="GtkImage" id="image458">
+ <widget class="GtkImage" id="image518">
<property name="visible">True</property>
<property name="stock">gtk-help</property>
<property name="icon_size">1</property>
@@ -618,7 +678,7 @@
<signal name="activate" handler="on_about1_activate" last_modification_time="Sat, 04 Jul 2009 12:57:58 GMT"/>
<child internal-child="image">
- <widget class="GtkImage" id="image459">
+ <widget class="GtkImage" id="image519">
<property name="visible">True</property>
<property name="stock">gtk-about</property>
<property name="icon_size">1</property>
@@ -639,7 +699,7 @@
<signal name="activate" handler="on_translators1_activate" last_modification_time="Sun, 19 Sep 2010 13:38:07 GMT"/>
<child internal-child="image">
- <widget class="GtkImage" id="image460">
+ <widget class="GtkImage" id="image520">
<property name="visible">True</property>
<property name="stock">gtk-about</property>
<property name="icon_size">1</property>
@@ -1177,10 +1237,10 @@
</child>
</widget>
-<widget class="GtkWindow" id="addprogress">
+<widget class="GtkWindow" id="progressdlg">
<property name="border_width">12</property>
<property name="visible">True</property>
- <property name="title" translatable="yes">Adding files...</property>
+ <property name="title">progressdlg</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
<property name="modal">True</property>
@@ -1193,7 +1253,6 @@
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="focus_on_map">True</property>
<property name="urgency_hint">False</property>
- <signal name="delete_event" handler="on_addprogress_delete_event" last_modification_time="Sun, 16 Aug 2009 17:20:03 GMT"/>
<child>
<widget class="GtkVBox" id="vbox6">
@@ -1252,14 +1311,13 @@
</child>
<child>
- <widget class="GtkButton" id="button3">
+ <widget class="GtkButton" id="cancelbtn">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-cancel</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
- <signal name="clicked" handler="on_progress_abort" last_modification_time="Mon, 25 Oct 2010 20:04:28 GMT"/>
</widget>
<packing>
<property name="padding">0</property>
@@ -1336,7 +1394,7 @@
<property name="visible">True</property>
<property name="title" translatable="yes">Track Properties</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="window_position">GTK_WIN_POS_MOUSE</property>
<property name="modal">False</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>
@@ -1349,6 +1407,8 @@
<property name="urgency_hint">False</property>
<signal name="key_press_event" handler="on_trackproperties_key_press_event" last_modification_time="Thu, 31 Dec 2009 13:46:40 GMT"/>
<signal name="delete_event" handler="on_trackproperties_delete_event" last_modification_time="Sat, 02 Jan 2010 21:38:32 GMT"/>
+ <signal name="configure_event" handler="on_trackproperties_configure_event" last_modification_time="Thu, 10 Mar 2011 11:06:48 GMT"/>
+ <signal name="window_state_event" handler="on_trackproperties_window_state_event" last_modification_time="Thu, 10 Mar 2011 11:08:02 GMT"/>
<child>
<widget class="GtkNotebook" id="notebook3">
@@ -1387,6 +1447,7 @@
<property name="fixed_height_mode">False</property>
<property name="hover_selection">False</property>
<property name="hover_expand">False</property>
+ <signal name="button_press_event" handler="on_metalist_button_press_event" last_modification_time="Sun, 27 Feb 2011 18:14:41 GMT"/>
</widget>
</child>
</widget>
@@ -1398,22 +1459,21 @@
</child>
<child>
- <widget class="GtkHButtonBox" id="hbuttonbox1">
+ <widget class="GtkHBox" id="hbox98">
<property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
- <widget class="GtkButton" id="write_tags">
+ <widget class="GtkButton" id="settings">
<property name="visible">True</property>
- <property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
- <signal name="clicked" handler="on_write_tags_clicked" last_modification_time="Sat, 27 Mar 2010 20:48:33 GMT"/>
+ <signal name="clicked" handler="on_tagwriter_settings_clicked" last_modification_time="Wed, 09 Mar 2011 20:01:45 GMT"/>
<child>
- <widget class="GtkAlignment" id="alignment11">
+ <widget class="GtkAlignment" id="alignment24">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
@@ -1425,15 +1485,15 @@
<property name="right_padding">0</property>
<child>
- <widget class="GtkHBox" id="hbox52">
+ <widget class="GtkHBox" id="hbox99">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">2</property>
<child>
- <widget class="GtkImage" id="image390">
+ <widget class="GtkImage" id="image522">
<property name="visible">True</property>
- <property name="stock">gtk-apply</property>
+ <property name="stock">gtk-preferences</property>
<property name="icon_size">4</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
@@ -1448,9 +1508,9 @@
</child>
<child>
- <widget class="GtkLabel" id="label88">
+ <widget class="GtkLabel" id="label123">
<property name="visible">True</property>
- <property name="label" translatable="yes">_Apply</property>
+ <property name="label" translatable="yes">Settings</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
@@ -1476,81 +1536,174 @@
</widget>
</child>
</widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
</child>
<child>
- <widget class="GtkButton" id="closebtn">
+ <widget class="GtkHButtonBox" id="hbuttonbox1">
<property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <signal name="clicked" handler="on_closebtn_clicked" last_modification_time="Thu, 01 Apr 2010 12:45:33 GMT"/>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <property name="spacing">0</property>
<child>
- <widget class="GtkAlignment" id="alignment12">
+ <widget class="GtkButton" id="write_tags">
<property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">0</property>
- <property name="yscale">0</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_write_tags_clicked" last_modification_time="Sat, 27 Mar 2010 20:48:33 GMT"/>
<child>
- <widget class="GtkHBox" id="hbox53">
+ <widget class="GtkAlignment" id="alignment11">
<property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">2</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
<child>
- <widget class="GtkImage" id="image391">
+ <widget class="GtkHBox" id="hbox52">
<property name="visible">True</property>
- <property name="stock">gtk-close</property>
- <property name="icon_size">4</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image390">
+ <property name="visible">True</property>
+ <property name="stock">gtk-apply</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label88">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Apply</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
</widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
</child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="closebtn">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_closebtn_clicked" last_modification_time="Thu, 01 Apr 2010 12:45:33 GMT"/>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment12">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
<child>
- <widget class="GtkLabel" id="label89">
+ <widget class="GtkHBox" id="hbox53">
<property name="visible">True</property>
- <property name="label" translatable="yes">_Close</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image391">
+ <property name="visible">True</property>
+ <property name="stock">gtk-close</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label89">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Close</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
</widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
</child>
</widget>
</child>
</widget>
</child>
</widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
</child>
</widget>
<packing>
@@ -1749,7 +1902,7 @@
<widget class="GtkDialog" id="editcolumndlg">
<property name="border_width">12</property>
<property name="visible">True</property>
- <property name="title" translatable="yes">editcolumndlg</property>
+ <property name="title">editcolumndlg</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">True</property>
@@ -2037,8 +2190,8 @@ Artist - Album
Artist
Album
Title
-Length
-Track
+Duration
+Track No
Band / Album Artist
Custom</property>
<property name="add_tearoffs">False</property>
@@ -2091,16 +2244,44 @@ Custom</property>
</child>
<child>
- <widget class="GtkEntry" id="format">
+ <widget class="GtkHBox" id="hbox74">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="editable">True</property>
- <property name="visibility">True</property>
- <property name="max_length">0</property>
- <property name="text" translatable="yes"></property>
- <property name="has_frame">True</property>
- <property name="invisible_char">â—</property>
- <property name="activates_default">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkEntry" id="format">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">â—</property>
+ <property name="activates_default">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="Custom" id="title_formatting_help_link">
+ <property name="visible">True</property>
+ <property name="creation_function">title_formatting_help_link_create</property>
+ <property name="int1">0</property>
+ <property name="int2">0</property>
+ <property name="last_modification_time">Fri, 03 Dec 2010 20:39:24 GMT</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
</widget>
<packing>
<property name="padding">0</property>
@@ -2168,38 +2349,6 @@ Right</property>
<property name="fill">False</property>
</packing>
</child>
-
- <child>
- <widget class="GtkLabel" id="label25">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Format conversions (start with %):
- [a]rtist, [t]itle, al[b]um, [B]and, [C]omposer
- track[n]umber, [N]totaltracks,
- [l]ength, [y]ear, [g]enre, [c]omment,
- copy[r]ight, [f]ilename, [F]ullPathname, [T]ags,
- [d]irectory, [D]irectoryWithPath
-Example: %a - %t [%l]</property>
- <property name="use_underline">False</property>
- <property name="use_markup">True</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">True</property>
- <property name="xalign">0.10000000149</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
</widget>
<packing>
<property name="padding">0</property>
@@ -2213,15 +2362,11 @@ Example: %a - %t [%l]</property>
<widget class="GtkDialog" id="prefwin">
<property name="border_width">12</property>
- <property name="width_request">630</property>
- <property name="height_request">400</property>
<property name="visible">True</property>
<property name="title" translatable="yes">Preferences</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="window_position">GTK_WIN_POS_CENTER</property>
<property name="modal">False</property>
- <property name="default_width">630</property>
- <property name="default_height">400</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>
<property name="decorated">True</property>
@@ -2232,6 +2377,9 @@ Example: %a - %t [%l]</property>
<property name="focus_on_map">True</property>
<property name="urgency_hint">False</property>
<property name="has_separator">True</property>
+ <signal name="configure_event" handler="on_prefwin_configure_event" last_modification_time="Thu, 10 Mar 2011 11:14:37 GMT"/>
+ <signal name="window_state_event" handler="on_prefwin_window_state_event" last_modification_time="Thu, 10 Mar 2011 11:14:42 GMT"/>
+ <signal name="realize" handler="on_prefwin_realize" last_modification_time="Thu, 10 Mar 2011 11:20:24 GMT"/>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox2">
@@ -2249,73 +2397,11 @@ Example: %a - %t [%l]</property>
<property name="visible">True</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="response_id">-7</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment14">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">0</property>
- <property name="yscale">0</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="GtkHBox" id="hbox55">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">2</property>
-
- <child>
- <widget class="GtkImage" id="image393">
- <property name="visible">True</property>
- <property name="stock">gtk-close</property>
- <property name="icon_size">4</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label91">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Close</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- </child>
</widget>
</child>
</widget>
@@ -2483,38 +2569,18 @@ Example: %a - %t [%l]</property>
<property name="spacing">8</property>
<child>
- <widget class="GtkCheckButton" id="pref_dynsamplerate">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Allow dynamic samplerate switching</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <signal name="clicked" handler="on_pref_dynsamplerate_clicked" last_modification_time="Tue, 26 Jan 2010 19:46:12 GMT"/>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox9">
+ <widget class="GtkHBox" id="hbox10">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">8</property>
<child>
- <widget class="GtkLabel" id="label6">
+ <widget class="GtkLabel" id="label8">
<property name="visible">True</property>
- <property name="label" translatable="yes">Samplerate conversion quality:</property>
+ <property name="label" translatable="yes">Replaygain mode:</property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_RIGHT</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0</property>
@@ -2534,16 +2600,15 @@ Example: %a - %t [%l]</property>
</child>
<child>
- <widget class="GtkComboBox" id="pref_src_quality">
+ <widget class="GtkComboBox" id="pref_replaygain_mode">
+ <property name="width_request">337</property>
<property name="visible">True</property>
- <property name="items">sinc_best_quality
-sinc_medium_quality
-sinc_fastest
-zero_order_hold
-linear</property>
+ <property name="items" translatable="yes">Disable
+Track
+Album</property>
<property name="add_tearoffs">False</property>
<property name="focus_on_click">True</property>
- <signal name="changed" handler="on_pref_src_quality_changed" last_modification_time="Sat, 10 Oct 2009 19:02:36 GMT"/>
+ <signal name="changed" handler="on_pref_replaygain_mode_changed" last_modification_time="Sat, 10 Oct 2009 19:22:23 GMT"/>
</widget>
<packing>
<property name="padding">0</property>
@@ -2560,21 +2625,41 @@ linear</property>
</child>
<child>
- <widget class="GtkHBox" id="hbox10">
+ <widget class="GtkCheckButton" id="pref_replaygain_scale">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Replaygain peak scale</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="clicked" handler="on_pref_replaygain_scale_clicked" last_modification_time="Sat, 10 Oct 2009 18:52:10 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox100">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">8</property>
<child>
- <widget class="GtkLabel" id="label8">
+ <widget class="GtkLabel" id="label124">
<property name="visible">True</property>
- <property name="label" translatable="yes">Replaygain mode:</property>
+ <property name="label" translatable="yes">Replaygain preamp:</property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
- <property name="xalign">0</property>
+ <property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
@@ -2591,15 +2676,41 @@ linear</property>
</child>
<child>
- <widget class="GtkComboBox" id="pref_replaygain_mode">
- <property name="width_request">337</property>
+ <widget class="GtkLabel" id="label125">
<property name="visible">True</property>
- <property name="items" translatable="yes">Disable
-Track
-Album</property>
- <property name="add_tearoffs">False</property>
- <property name="focus_on_click">True</property>
- <signal name="changed" handler="on_pref_replaygain_mode_changed" last_modification_time="Sat, 10 Oct 2009 19:22:23 GMT"/>
+ <property name="label" translatable="yes">-12 dB</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHScale" id="replaygain_preamp">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="draw_value">True</property>
+ <property name="value_pos">GTK_POS_BOTTOM</property>
+ <property name="digits">0</property>
+ <property name="update_policy">GTK_UPDATE_CONTINUOUS</property>
+ <property name="inverted">False</property>
+ <property name="adjustment">0 -12 12 0 0 0</property>
+ <signal name="value_changed" handler="on_replaygain_preamp_value_changed" last_modification_time="Sat, 12 Mar 2011 14:20:29 GMT"/>
</widget>
<packing>
<property name="padding">0</property>
@@ -2607,26 +2718,31 @@ Album</property>
<property name="fill">True</property>
</packing>
</child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkCheckButton" id="pref_replaygain_scale">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Replaygain peak scale</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <signal name="clicked" handler="on_pref_replaygain_scale_clicked" last_modification_time="Sat, 10 Oct 2009 18:52:10 GMT"/>
+ <child>
+ <widget class="GtkLabel" id="label126">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">+12 dB</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
</widget>
<packing>
<property name="padding">0</property>
@@ -2707,6 +2823,26 @@ Album</property>
<property name="fill">False</property>
</packing>
</child>
+
+ <child>
+ <widget class="GtkCheckButton" id="ignore_archives">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Don't add from archives when adding folders</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_ignore_archives_toggled" last_modification_time="Tue, 05 Apr 2011 20:41:18 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
</widget>
<packing>
<property name="tab_expand">False</property>
@@ -2738,6 +2874,283 @@ Album</property>
</child>
<child>
+ <widget class="GtkVBox" id="vbox29">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox80">
+ <property name="visible">True</property>
+ <property name="homogeneous">True</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkButton" id="dsp_add">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-add</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_dsp_add_clicked" last_modification_time="Wed, 29 Dec 2010 11:54:39 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="dsp_remove">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-remove</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_dsp_remove_clicked" last_modification_time="Wed, 29 Dec 2010 11:54:43 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="dsp_configure">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Configure</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_dsp_configure_clicked" last_modification_time="Wed, 29 Dec 2010 11:54:47 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox81">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow7">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="dsp_listview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox30">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkButton" id="dsp_up">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-go-up</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_dsp_up_clicked" last_modification_time="Wed, 29 Dec 2010 11:54:52 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="dsp_down">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-go-down</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_dsp_down_clicked" last_modification_time="Wed, 29 Dec 2010 11:54:55 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox86">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label114">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">DSP Chain Preset</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBoxEntry" id="dsp_preset">
+ <property name="visible">True</property>
+ <property name="add_tearoffs">False</property>
+ <property name="has_frame">True</property>
+ <property name="focus_on_click">True</property>
+ <signal name="changed" handler="on_dsp_preset_changed" last_modification_time="Wed, 05 Jan 2011 19:38:28 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="dsp_preset_save">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-save</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_dsp_preset_save_clicked" last_modification_time="Wed, 05 Jan 2011 19:38:10 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="dsp_preset_load">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Load</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_dsp_preset_load_clicked" last_modification_time="Wed, 05 Jan 2011 19:38:13 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label110">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">DSP</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
<widget class="GtkVBox" id="vbox9">
<property name="border_width">12</property>
<property name="visible">True</property>
@@ -2845,6 +3258,83 @@ Album</property>
</child>
<child>
+ <widget class="GtkCheckButton" id="auto_name_playlist_from_folder">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Auto-name playlists when adding a single folder</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_auto_name_playlist_from_folder_toggled" last_modification_time="Tue, 04 Jan 2011 20:49:15 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox102">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label129">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Interface refresh rate (times per second):</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHScale" id="gui_fps">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="draw_value">True</property>
+ <property name="value_pos">GTK_POS_RIGHT</property>
+ <property name="digits">0</property>
+ <property name="update_policy">GTK_UPDATE_CONTINUOUS</property>
+ <property name="inverted">False</property>
+ <property name="adjustment">10 1 30 0 0 0</property>
+ <signal name="value_changed" handler="on_gui_fps_value_changed" last_modification_time="Mon, 04 Apr 2011 20:11:49 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
<widget class="GtkHBox" id="hbox64">
<property name="visible">True</property>
<property name="homogeneous">False</property>
@@ -2961,7 +3451,55 @@ Album</property>
</child>
<child>
- <placeholder/>
+ <widget class="GtkHBox" id="hbox101">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label128">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">GUI Plugin (changing requires restart):</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="gui_plugin">
+ <property name="visible">True</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ <signal name="changed" handler="on_gui_plugin_changed" last_modification_time="Wed, 23 Mar 2011 20:30:20 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
</child>
</widget>
<packing>
@@ -3199,7 +3737,7 @@ Album</property>
<widget class="GtkTable" id="tabstrip_colors_group">
<property name="visible">True</property>
<property name="n_rows">2</property>
- <property name="n_columns">4</property>
+ <property name="n_columns">5</property>
<property name="homogeneous">True</property>
<property name="row_spacing">0</property>
<property name="column_spacing">8</property>
@@ -3387,6 +3925,52 @@ Album</property>
<property name="y_options"></property>
</packing>
</child>
+
+ <child>
+ <widget class="GtkLabel" id="label127">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Text</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="right_attach">5</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">expand</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="tabstrip_text">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ <signal name="color_set" handler="on_tabstrip_text_color_set" last_modification_time="Wed, 23 Mar 2011 20:09:34 GMT"/>
+ </widget>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="right_attach">5</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">expand</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
</widget>
<packing>
<property name="padding">0</property>
@@ -4148,705 +4732,6 @@ SOCKS5_HOSTNAME</property>
</child>
<child>
- <widget class="GtkVBox" id="vbox18">
- <property name="border_width">12</property>
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkFrame" id="frame5">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_NONE</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment3">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">1</property>
- <property name="yscale">1</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">12</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="GtkVBox" id="vbox19">
- <property name="border_width">12</property>
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child>
- <widget class="GtkHBox" id="hbox38">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child>
- <widget class="GtkCheckButton" id="write_id3v2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Write ID3v2</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_write_id3v2_toggled" last_modification_time="Tue, 30 Mar 2010 20:43:51 GMT"/>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="write_id3v1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Write ID3v1</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_write_id3v1_toggled" last_modification_time="Tue, 30 Mar 2010 20:43:55 GMT"/>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="write_apev2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Write APEv2</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_write_apev2_toggled" last_modification_time="Tue, 30 Mar 2010 20:43:59 GMT"/>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox40">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child>
- <widget class="GtkCheckButton" id="strip_id3v2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Strip ID3v2</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_strip_id3v2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:03 GMT"/>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="strip_id3v1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Strip ID3v1</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_strip_id3v1_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:07 GMT"/>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="strip_apev2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Strip APEv2</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_strip_apev2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:12 GMT"/>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox36">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child>
- <widget class="GtkLabel" id="label69">
- <property name="visible">True</property>
- <property name="label" translatable="yes">ID3v2 version</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkComboBox" id="id3v2_version">
- <property name="visible">True</property>
- <property name="items" translatable="yes">2.3 (Recommended)
-2.4</property>
- <property name="add_tearoffs">False</property>
- <property name="focus_on_click">True</property>
- <signal name="changed" handler="on_id3v2_version_changed" last_modification_time="Tue, 30 Mar 2010 20:44:27 GMT"/>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox39">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child>
- <widget class="GtkLabel" id="label71">
- <property name="visible">True</property>
- <property name="label" translatable="yes">ID3v1 character encoding (default is iso8859-1)</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkEntry" id="id3v1_encoding">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="editable">True</property>
- <property name="visibility">True</property>
- <property name="max_length">0</property>
- <property name="text" translatable="yes"></property>
- <property name="has_frame">True</property>
- <property name="invisible_char">â—</property>
- <property name="activates_default">False</property>
- <signal name="changed" handler="on_id3v1_encoding_changed" last_modification_time="Tue, 30 Mar 2010 20:44:34 GMT"/>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label68">
- <property name="visible">True</property>
- <property name="label">&lt;b&gt;MP3&lt;/b&gt;</property>
- <property name="use_underline">False</property>
- <property name="use_markup">True</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox41">
- <property name="visible">True</property>
- <property name="homogeneous">True</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkFrame" id="frame6">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_NONE</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment4">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">1</property>
- <property name="yscale">1</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">12</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="GtkVBox" id="vbox20">
- <property name="border_width">12</property>
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child>
- <widget class="GtkHBox" id="hbox37">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child>
- <widget class="GtkCheckButton" id="ape_write_id3v2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Write ID3v2.4</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_ape_write_id3v2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:42 GMT"/>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="ape_write_apev2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Write APEv2</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_ape_write_apev2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:46 GMT"/>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox45">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child>
- <widget class="GtkCheckButton" id="ape_strip_id3v2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Strip ID3v2</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_ape_strip_id3v2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:50 GMT"/>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="ape_strip_apev2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Strip APEv2</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_ape_strip_apev2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:54 GMT"/>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label70">
- <property name="visible">True</property>
- <property name="label">&lt;b&gt;APE&lt;/b&gt;</property>
- <property name="use_underline">False</property>
- <property name="use_markup">True</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkFrame" id="frame7">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_NONE</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment5">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">1</property>
- <property name="yscale">1</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">12</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="GtkVBox" id="vbox_wv">
- <property name="border_width">12</property>
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child>
- <widget class="GtkHBox" id="hbox44">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child>
- <widget class="GtkCheckButton" id="wv_write_apev2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Write APEv2</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_wv_write_apev2_toggled" last_modification_time="Tue, 06 Apr 2010 19:36:17 GMT"/>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="wv_write_id3v1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Write ID3v1</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_wv_write_id3v1_toggled" last_modification_time="Tue, 06 Apr 2010 19:36:13 GMT"/>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox43">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child>
- <widget class="GtkCheckButton" id="wv_strip_apev2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Strip APEv2</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_wv_strip_apev2_toggled" last_modification_time="Tue, 06 Apr 2010 19:40:53 GMT"/>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="wv_strip_id3v1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Strip ID3v1</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_wv_strip_id3v1_toggled" last_modification_time="Tue, 06 Apr 2010 19:40:57 GMT"/>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label79">
- <property name="visible">True</property>
- <property name="label">&lt;b&gt;WavPack&lt;/b&gt;</property>
- <property name="use_underline">False</property>
- <property name="use_markup">True</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="tab_expand">False</property>
- <property name="tab_fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label67">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Tag writer</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="type">tab</property>
- </packing>
- </child>
-
- <child>
<widget class="GtkHPaned" id="hpaned1">
<property name="border_width">12</property>
<property name="visible">True</property>
@@ -4892,249 +4777,138 @@ SOCKS5_HOSTNAME</property>
<property name="spacing">8</property>
<child>
- <widget class="GtkHBox" id="hbox16">
+ <widget class="GtkScrolledWindow" id="scrolledwindow8">
<property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child>
- <widget class="GtkLabel" id="label11">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Description:</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
<child>
- <widget class="GtkEntry" id="pref_plugin_descr">
+ <widget class="GtkTextView" id="plug_description">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">False</property>
- <property name="visibility">True</property>
- <property name="max_length">0</property>
+ <property name="overwrite">False</property>
+ <property name="accepts_tab">True</property>
+ <property name="justification">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap_mode">GTK_WRAP_NONE</property>
+ <property name="cursor_visible">False</property>
+ <property name="pixels_above_lines">0</property>
+ <property name="pixels_below_lines">0</property>
+ <property name="pixels_inside_wrap">0</property>
+ <property name="left_margin">0</property>
+ <property name="right_margin">0</property>
+ <property name="indent">0</property>
<property name="text" translatable="yes"></property>
- <property name="has_frame">True</property>
- <property name="invisible_char">â—</property>
- <property name="activates_default">False</property>
</widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
</packing>
</child>
<child>
- <widget class="GtkHBox" id="hbox17">
+ <widget class="GtkHBox" id="hbox20">
<property name="visible">True</property>
<property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child>
- <widget class="GtkLabel" id="label12">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Author(s):</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
+ <property name="spacing">0</property>
<child>
- <widget class="GtkEntry" id="pref_plugin_author">
+ <widget class="GtkButton" id="configure_plugin">
<property name="visible">True</property>
+ <property name="sensitive">False</property>
<property name="can_focus">True</property>
- <property name="editable">False</property>
- <property name="visibility">True</property>
- <property name="max_length">0</property>
- <property name="text" translatable="yes"></property>
- <property name="has_frame">True</property>
- <property name="invisible_char">â—</property>
- <property name="activates_default">False</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox18">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child>
- <widget class="GtkLabel" id="label13">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Email:</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_configure_plugin_clicked" last_modification_time="Tue, 01 Dec 2009 16:54:36 GMT"/>
- <child>
- <widget class="GtkEntry" id="pref_plugin_email">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="editable">False</property>
- <property name="visibility">True</property>
- <property name="max_length">0</property>
- <property name="text" translatable="yes"></property>
- <property name="has_frame">True</property>
- <property name="invisible_char">â—</property>
- <property name="activates_default">False</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
+ <child>
+ <widget class="GtkAlignment" id="alignment15">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
- <child>
- <widget class="GtkHBox" id="hbox19">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
+ <child>
+ <widget class="GtkHBox" id="hbox56">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
- <child>
- <widget class="GtkLabel" id="label14">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Website:</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
+ <child>
+ <widget class="GtkImage" id="image394">
+ <property name="visible">True</property>
+ <property name="stock">gtk-preferences</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
- <child>
- <widget class="GtkEntry" id="pref_plugin_website">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="editable">False</property>
- <property name="visibility">True</property>
- <property name="max_length">0</property>
- <property name="text" translatable="yes"></property>
- <property name="has_frame">True</property>
- <property name="invisible_char">â—</property>
- <property name="activates_default">False</property>
+ <child>
+ <widget class="GtkLabel" id="label92">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Configure</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
- <property name="fill">True</property>
+ <property name="fill">False</property>
</packing>
</child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox20">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
<child>
- <widget class="GtkButton" id="configure_plugin">
+ <widget class="GtkButton" id="plug_copyright">
<property name="visible">True</property>
+ <property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
- <signal name="clicked" handler="on_configure_plugin_clicked" last_modification_time="Tue, 01 Dec 2009 16:54:36 GMT"/>
+ <signal name="clicked" handler="on_plug_copyright_clicked" last_modification_time="Sun, 27 Feb 2011 10:24:22 GMT"/>
<child>
- <widget class="GtkAlignment" id="alignment15">
+ <widget class="GtkAlignment" id="alignment20">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
@@ -5146,15 +4920,15 @@ SOCKS5_HOSTNAME</property>
<property name="right_padding">0</property>
<child>
- <widget class="GtkHBox" id="hbox56">
+ <widget class="GtkHBox" id="hbox88">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">2</property>
<child>
- <widget class="GtkImage" id="image394">
+ <widget class="GtkImage" id="image521">
<property name="visible">True</property>
- <property name="stock">gtk-preferences</property>
+ <property name="stock">gtk-about</property>
<property name="icon_size">4</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
@@ -5169,9 +4943,9 @@ SOCKS5_HOSTNAME</property>
</child>
<child>
- <widget class="GtkLabel" id="label92">
+ <widget class="GtkLabel" id="label117">
<property name="visible">True</property>
- <property name="label" translatable="yes">Configure</property>
+ <property name="label" translatable="yes">Copyright</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
@@ -5203,6 +4977,21 @@ SOCKS5_HOSTNAME</property>
<property name="fill">False</property>
</packing>
</child>
+
+ <child>
+ <widget class="Custom" id="weblink">
+ <property name="visible">True</property>
+ <property name="creation_function">create_plugin_weblink</property>
+ <property name="int1">0</property>
+ <property name="int2">0</property>
+ <property name="last_modification_time">Sun, 27 Feb 2011 11:39:00 GMT</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
</widget>
<packing>
<property name="padding">0</property>
@@ -5256,10 +5045,10 @@ SOCKS5_HOSTNAME</property>
</child>
</widget>
-<widget class="GtkDialog" id="editplaylistdlg">
+<widget class="GtkDialog" id="entrydialog">
<property name="border_width">8</property>
<property name="visible">True</property>
- <property name="title" translatable="yes">editplaylistdlg</property>
+ <property name="title">EntryDialog</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">False</property>
@@ -5457,7 +5246,7 @@ SOCKS5_HOSTNAME</property>
<property name="spacing">8</property>
<child>
- <widget class="GtkLabel" id="label40">
+ <widget class="GtkLabel" id="title_label">
<property name="visible">True</property>
<property name="label" translatable="yes">Title:</property>
<property name="use_underline">False</property>
@@ -5991,16 +5780,44 @@ SOCKS5_HOSTNAME</property>
</child>
<child>
- <widget class="GtkEntry" id="format">
+ <widget class="GtkHBox" id="hbox75">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="editable">True</property>
- <property name="visibility">True</property>
- <property name="max_length">0</property>
- <property name="text" translatable="yes"></property>
- <property name="has_frame">True</property>
- <property name="invisible_char">â—</property>
- <property name="activates_default">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkEntry" id="format">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">â—</property>
+ <property name="activates_default">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="Custom" id="custom1">
+ <property name="visible">True</property>
+ <property name="creation_function">title_formatting_help_link_create</property>
+ <property name="int1">0</property>
+ <property name="int2">0</property>
+ <property name="last_modification_time">Fri, 03 Dec 2010 20:39:24 GMT</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
</widget>
<packing>
<property name="padding">0</property>
@@ -6015,30 +5832,347 @@ SOCKS5_HOSTNAME</property>
<property name="fill">False</property>
</packing>
</child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="sortbydlg">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Sort by...</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">True</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox8">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area7">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
<child>
- <widget class="GtkLabel" id="label82">
+ <widget class="GtkButton" id="cancelbutton5">
<property name="visible">True</property>
+ <property name="can_default">True</property>
<property name="can_focus">True</property>
- <property name="label" translatable="yes">Format conversions (start with %):
- [a]rtist, [t]itle, al[b]um, [B]and, [C]omposer
- track[n]umber, [N]totaltracks,
- [l]ength, [y]ear, [g]enre, [c]omment,
- copy[r]ight, [f]ilename, [T]ags
-Example: %a - %t [%l]</property>
- <property name="use_underline">False</property>
- <property name="use_markup">True</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">True</property>
- <property name="xalign">0.10000000149</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="okbutton5">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox28">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox76">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label108">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Format</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox77">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkEntry" id="sortfmt">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">â—</property>
+ <property name="activates_default">False</property>
+ <signal name="activate" handler="on_sortfmt_activate" last_modification_time="Fri, 03 Dec 2010 22:08:09 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="Custom" id="custom3">
+ <property name="visible">True</property>
+ <property name="creation_function">title_formatting_help_link_create</property>
+ <property name="int1">0</property>
+ <property name="int2">0</property>
+ <property name="last_modification_time">Fri, 03 Dec 2010 20:39:24 GMT</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox78">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label109">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Order</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="sortorder">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">Ascending
+Descending</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="select_dsp_plugin">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Select DSP Plugin</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">True</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox10">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area9">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="cancelbutton7">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="okbutton7">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox31">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox85">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label113">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Plugin</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="plugin">
+ <property name="visible">True</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
</widget>
<packing>
<property name="padding">0</property>
@@ -6057,4 +6191,733 @@ Example: %a - %t [%l]</property>
</child>
</widget>
+<widget class="GtkDialog" id="tagwritersettings">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Tag Writer Settings</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">True</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox11">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area10">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="closebutton2">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-7</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox32">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkFrame" id="frame8">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment21">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox33">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox89">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="write_id3v2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Write ID3v2</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_write_id3v2_toggled" last_modification_time="Tue, 30 Mar 2010 20:43:51 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="write_id3v1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Write ID3v1</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_write_id3v1_toggled" last_modification_time="Tue, 30 Mar 2010 20:43:55 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="write_apev2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Write APEv2</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_write_apev2_toggled" last_modification_time="Tue, 30 Mar 2010 20:43:59 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox90">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="strip_id3v2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Strip ID3v2</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_strip_id3v2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:03 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="strip_id3v1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Strip ID3v1</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_strip_id3v1_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:07 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="strip_apev2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Strip APEv2</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_strip_apev2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:12 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox91">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label118">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">ID3v2 version</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="id3v2_version">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">2.3 (Recommended)
+2.4</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ <signal name="changed" handler="on_id3v2_version_changed" last_modification_time="Tue, 30 Mar 2010 20:44:27 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox92">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkLabel" id="label119">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">ID3v1 character encoding (default is iso8859-1)</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="id3v1_encoding">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">â—</property>
+ <property name="activates_default">False</property>
+ <signal name="changed" handler="on_id3v1_encoding_changed" last_modification_time="Tue, 30 Mar 2010 20:44:34 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label120">
+ <property name="visible">True</property>
+ <property name="label">&lt;b&gt;MP3&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox93">
+ <property name="visible">True</property>
+ <property name="homogeneous">True</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkFrame" id="frame9">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment22">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox34">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox94">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="ape_write_id3v2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Write ID3v2.4</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_ape_write_id3v2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:42 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="ape_write_apev2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Write APEv2</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_ape_write_apev2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:46 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox95">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="ape_strip_id3v2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Strip ID3v2</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_ape_strip_id3v2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:50 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="ape_strip_apev2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Strip APEv2</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_ape_strip_apev2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:54 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label121">
+ <property name="visible">True</property>
+ <property name="label">&lt;b&gt;APE&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame10">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment23">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox35">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox96">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="wv_write_apev2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Write APEv2</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_wv_write_apev2_toggled" last_modification_time="Tue, 06 Apr 2010 19:36:17 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="wv_write_id3v1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Write ID3v1</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_wv_write_id3v1_toggled" last_modification_time="Tue, 06 Apr 2010 19:36:13 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox97">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="wv_strip_apev2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Strip APEv2</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_wv_strip_apev2_toggled" last_modification_time="Tue, 06 Apr 2010 19:40:53 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="wv_strip_id3v1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Strip ID3v1</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_wv_strip_id3v1_toggled" last_modification_time="Tue, 06 Apr 2010 19:40:57 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label122">
+ <property name="visible">True</property>
+ <property name="label">&lt;b&gt;WavPack&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
</glade-interface>
diff --git a/plugins/gtkui/deadbeef.gladep b/plugins/gtkui/deadbeef.gladep
index 88874320..d0428a88 100644
--- a/plugins/gtkui/deadbeef.gladep
+++ b/plugins/gtkui/deadbeef.gladep
@@ -7,5 +7,6 @@
<source_directory></source_directory>
<gnome_support>FALSE</gnome_support>
<output_main_file>FALSE</output_main_file>
+ <output_support_files>FALSE</output_support_files>
<output_build_files>FALSE</output_build_files>
</glade-project>
diff --git a/plugins/gtkui/drawing.h b/plugins/gtkui/drawing.h
index e8c7e99d..b73c9f97 100644
--- a/plugins/gtkui/drawing.h
+++ b/plugins/gtkui/drawing.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -97,6 +97,9 @@ void
gtkui_get_tabstrip_base_color (GdkColor *clr);
void
+gtkui_get_tabstrip_text_color (GdkColor *clr);
+
+void
gtkui_get_listview_even_row_color (GdkColor *clr);
void
@@ -126,4 +129,7 @@ gtkui_override_bar_colors (void);
int
gtkui_override_tabstrip_colors (void);
+int
+draw_get_listview_rowheight (void);
+
#endif // __DRAWING_H
diff --git a/plugins/gtkui/dspconfig.c b/plugins/gtkui/dspconfig.c
new file mode 100644
index 00000000..268f1b16
--- /dev/null
+++ b/plugins/gtkui/dspconfig.c
@@ -0,0 +1,482 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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 HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include "callbacks.h"
+#include "interface.h"
+#include "support.h"
+#include "deadbeef.h"
+#include "gtkui.h"
+#include "pluginconf.h"
+
+static ddb_dsp_context_t *chain;
+static GtkWidget *prefwin;
+
+static ddb_dsp_context_t *
+dsp_clone (ddb_dsp_context_t *from) {
+ ddb_dsp_context_t *dsp = from->plugin->open ();
+ char param[2000];
+ if (from->plugin->num_params) {
+ int n = from->plugin->num_params ();
+ for (int i = 0; i < n; i++) {
+ from->plugin->get_param (from, i, param, sizeof (param));
+ dsp->plugin->set_param (dsp, i, param);
+ }
+ }
+ dsp->enabled = from->enabled;
+ return dsp;
+}
+
+static void
+fill_dsp_chain (GtkListStore *mdl) {
+ ddb_dsp_context_t *dsp = chain;
+ while (dsp) {
+ GtkTreeIter iter;
+ gtk_list_store_append (mdl, &iter);
+ gtk_list_store_set (mdl, &iter, 0, dsp->plugin->plugin.name, -1);
+ dsp = dsp->next;
+ }
+}
+
+static int dirent_alphasort (const struct dirent **a, const struct dirent **b) {
+ return strcmp ((*a)->d_name, (*b)->d_name);
+}
+
+static int
+scandir_preset_filter (const struct dirent *ent) {
+ char *ext = strrchr (ent->d_name, '.');
+ if (ext && !strcasecmp (ext, ".txt")) {
+ return 1;
+ }
+ return 0;
+}
+
+void
+dsp_setup_init (GtkWidget *_prefwin) {
+ prefwin = _prefwin;
+ // copy current dsp chain
+ ddb_dsp_context_t *streamer_chain = deadbeef->streamer_get_dsp_chain ();
+
+ ddb_dsp_context_t *tail = NULL;
+ while (streamer_chain) {
+ ddb_dsp_context_t *new = dsp_clone (streamer_chain);
+ if (tail) {
+ tail->next = new;
+ tail = new;
+ }
+ else {
+ chain = tail = new;
+ }
+ streamer_chain = streamer_chain->next;
+ }
+
+ // fill dsp_listview
+ GtkWidget *listview = lookup_widget (prefwin, "dsp_listview");
+
+
+ GtkCellRenderer *title_cell = gtk_cell_renderer_text_new ();
+ GtkTreeViewColumn *col = gtk_tree_view_column_new_with_attributes (_("Plugin"), title_cell, "text", 0, NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (listview), GTK_TREE_VIEW_COLUMN (col));
+ GtkListStore *mdl = gtk_list_store_new (1, G_TYPE_STRING);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (listview), GTK_TREE_MODEL (mdl));
+
+ fill_dsp_chain (mdl);
+
+ // set last preset name
+ GtkWidget *combobox = lookup_widget (prefwin, "dsp_preset");
+ GtkWidget *entry = gtk_bin_get_child (GTK_BIN (combobox));
+ if (entry) {
+ deadbeef->conf_lock ();
+ gtk_entry_set_text (GTK_ENTRY (entry), deadbeef->conf_get_str_fast ("gtkui.conf_dsp_preset", ""));
+ deadbeef->conf_unlock ();
+ }
+
+ // fill list of presets
+ mdl = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (combobox)));
+ struct dirent **namelist = NULL;
+ char path[1024];
+ if (snprintf (path, sizeof (path), "%s/presets/dsp", deadbeef->get_config_dir ()) > 0) {
+ int n = scandir (path, &namelist, scandir_preset_filter, dirent_alphasort);
+ int i;
+ for (i = 0; i < n; i++) {
+ char title[100];
+ strcpy (title, namelist[i]->d_name);
+ char *e = strrchr (title, '.');
+ if (e) {
+ *e = 0;
+ }
+ GtkTreeIter iter;
+ gtk_list_store_append (mdl, &iter);
+ gtk_list_store_set (mdl, &iter, 0, title, -1);
+ free (namelist[i]);
+ }
+ free (namelist);
+ }
+}
+
+void
+dsp_setup_free (void) {
+ while (chain) {
+ ddb_dsp_context_t *next = chain->next;
+ chain->plugin->close (chain);
+ chain = next;
+ }
+ prefwin = NULL;
+}
+
+static void
+fill_dsp_plugin_list (GtkListStore *mdl) {
+ struct DB_dsp_s **dsp = deadbeef->plug_get_dsp_list ();
+ int i;
+ for (i = 0; dsp[i]; i++) {
+ GtkTreeIter iter;
+ gtk_list_store_append (mdl, &iter);
+ gtk_list_store_set (mdl, &iter, 0, dsp[i]->plugin.name, -1);
+ }
+}
+
+static void
+update_streamer (void) {
+ deadbeef->streamer_set_dsp_chain (chain);
+}
+
+void
+on_dsp_add_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *dlg = create_select_dsp_plugin ();
+ gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK);
+ gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (prefwin));
+ gtk_window_set_title (GTK_WINDOW (dlg), _("Add plugin to DSP chain"));
+
+ GtkComboBox *combo;
+ // fill encoder presets
+ combo = GTK_COMBO_BOX (lookup_widget (dlg, "plugin"));
+ GtkListStore *mdl = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
+ fill_dsp_plugin_list (mdl);
+ gtk_combo_box_set_active (combo, deadbeef->conf_get_int ("converter.last_selected_dsp", 0));
+
+ int r = gtk_dialog_run (GTK_DIALOG (dlg));
+ if (r == GTK_RESPONSE_OK) {
+ // create new instance of the selected plugin
+ int idx = gtk_combo_box_get_active (combo);
+ struct DB_dsp_s **dsp = deadbeef->plug_get_dsp_list ();
+ int i;
+ ddb_dsp_context_t *inst = NULL;
+ for (i = 0; dsp[i]; i++) {
+ if (i == idx) {
+ inst = dsp[i]->open ();
+ break;
+ }
+ }
+ if (inst) {
+ // append to DSP chain
+ ddb_dsp_context_t *tail = chain;
+ while (tail && tail->next) {
+ tail = tail->next;
+ }
+ if (tail) {
+ tail->next = inst;
+ }
+ else {
+ chain = inst;
+ }
+
+ // reinit list of instances
+ GtkWidget *list = lookup_widget (prefwin, "dsp_listview");
+ GtkListStore *mdl = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW(list)));
+ gtk_list_store_clear (mdl);
+ fill_dsp_chain (mdl);
+ update_streamer ();
+ }
+ else {
+ fprintf (stderr, "prefwin: failed to add DSP plugin to chain\n");
+ }
+ }
+ gtk_widget_destroy (dlg);
+}
+
+static int
+listview_get_index (GtkWidget *list) {
+ GtkTreePath *path;
+ GtkTreeViewColumn *col;
+ gtk_tree_view_get_cursor (GTK_TREE_VIEW (list), &path, &col);
+ if (!path || !col) {
+ // nothing selected
+ return - 1;
+ }
+ int *indices = gtk_tree_path_get_indices (path);
+ int idx = *indices;
+ g_free (indices);
+ return idx;
+}
+
+void
+on_dsp_remove_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *list = lookup_widget (prefwin, "dsp_listview");
+ int idx = listview_get_index (list);
+ if (idx == -1) {
+ return;
+ }
+
+ ddb_dsp_context_t *p = chain;
+ ddb_dsp_context_t *prev = NULL;
+ int i = idx;
+ while (p && i--) {
+ prev = p;
+ p = p->next;
+ }
+ if (p) {
+ if (prev) {
+ prev->next = p->next;
+ }
+ else {
+ chain = p->next;
+ }
+ p->plugin->close (p);
+ GtkListStore *mdl = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW(list)));
+ gtk_list_store_clear (mdl);
+ fill_dsp_chain (mdl);
+ GtkTreePath *path = gtk_tree_path_new_from_indices (idx, -1);
+ GtkTreeViewColumn *col;
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, col, FALSE);
+ gtk_tree_path_free (path);
+ update_streamer ();
+ }
+}
+
+static ddb_dsp_context_t *current_dsp_context = NULL;
+
+void
+dsp_ctx_set_param (const char *key, const char *value) {
+ current_dsp_context->plugin->set_param (current_dsp_context, atoi (key), value);
+}
+
+void
+dsp_ctx_get_param (const char *key, char *value, int len, const char *def) {
+ strncpy (value, def, len);
+ current_dsp_context->plugin->get_param (current_dsp_context, atoi (key), value, len);
+}
+
+int
+button_cb (int btn, void *ctx) {
+ if (btn == ddb_button_apply) {
+ update_streamer ();
+ }
+ return 1;
+}
+
+void
+on_dsp_configure_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *list = lookup_widget (prefwin, "dsp_listview");
+ GtkTreePath *path;
+ GtkTreeViewColumn *col;
+ gtk_tree_view_get_cursor (GTK_TREE_VIEW (list), &path, &col);
+ if (!path || !col) {
+ // nothing selected
+ return;
+ }
+ int *indices = gtk_tree_path_get_indices (path);
+ int idx = *indices;
+ g_free (indices);
+ if (idx == -1) {
+ return;
+ }
+ ddb_dsp_context_t *p = chain;
+ int i = idx;
+ while (p && i--) {
+ p = p->next;
+ }
+ if (!p || !p->plugin->configdialog) {
+ return;
+ }
+ current_dsp_context = p;
+ ddb_dialog_t conf = {
+ .title = p->plugin->plugin.name,
+ .layout = p->plugin->configdialog,
+ .set_param = dsp_ctx_set_param,
+ .get_param = dsp_ctx_get_param,
+ };
+ int response = gtkui_run_dialog (prefwin, &conf, 0, button_cb, NULL);
+ if (response == ddb_button_ok) {
+ update_streamer ();
+ }
+ current_dsp_context = NULL;
+}
+
+static int
+swap_items (GtkWidget *list, int idx) {
+ ddb_dsp_context_t *prev = NULL;
+ ddb_dsp_context_t *p = chain;
+
+ int n = idx;
+ while (n > 0 && p) {
+ prev = p;
+ p = p->next;
+ n--;
+ }
+
+ if (!p || !p->next) {
+ return -1;
+ }
+
+ ddb_dsp_context_t *moved = p->next;
+
+ if (!moved) {
+ return -1;
+ }
+
+ ddb_dsp_context_t *last = moved ? moved->next : NULL;
+
+ if (prev) {
+ p->next = last;
+ prev->next = moved;
+ moved->next = p;
+ }
+ else {
+ p->next = last;
+ chain = moved;
+ moved->next = p;
+ }
+ GtkListStore *mdl = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW(list)));
+ gtk_list_store_clear (mdl);
+ fill_dsp_chain (mdl);
+ return 0;
+}
+
+
+void
+on_dsp_up_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *list = lookup_widget (prefwin, "dsp_listview");
+ int idx = listview_get_index (list);
+ if (idx <= 0) {
+ return;
+ }
+
+ if (-1 == swap_items (list, idx-1)) {
+ return;
+ }
+ GtkTreePath *path = gtk_tree_path_new_from_indices (idx-1, -1);
+ GtkTreeViewColumn *col;
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, col, FALSE);
+ gtk_tree_path_free (path);
+ update_streamer ();
+}
+
+
+void
+on_dsp_down_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *list = lookup_widget (prefwin, "dsp_listview");
+ int idx = listview_get_index (list);
+ if (idx == -1) {
+ return;
+ }
+
+ if (-1 == swap_items (list, idx)) {
+ return;
+ }
+ GtkTreePath *path = gtk_tree_path_new_from_indices (idx+1, -1);
+ GtkTreeViewColumn *col;
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, col, FALSE);
+ gtk_tree_path_free (path);
+ update_streamer ();
+}
+
+void
+on_dsp_preset_changed (GtkComboBox *combobox,
+ gpointer user_data)
+{
+ GtkWidget *entry = gtk_bin_get_child (GTK_BIN (combobox));
+ if (entry) {
+ deadbeef->conf_set_str ("gtkui.conf_dsp_preset", gtk_entry_get_text (GTK_ENTRY (entry)));
+ }
+}
+
+
+void
+on_dsp_preset_save_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ const char *confdir = deadbeef->get_config_dir ();
+ char path[1024];
+ if (snprintf (path, sizeof (path), "%s/presets", confdir) < 0) {
+ return;
+ }
+ mkdir (path, 0755);
+ if (snprintf (path, sizeof (path), "%s/presets/dsp", confdir) < 0) {
+ return;
+ }
+ GtkWidget *combobox = lookup_widget (prefwin, "dsp_preset");
+ GtkWidget *entry = gtk_bin_get_child (GTK_BIN (combobox));
+ if (!entry) {
+ return;
+ }
+
+ const char *text = gtk_entry_get_text (GTK_ENTRY (entry));
+ mkdir (path, 0755);
+ if (snprintf (path, sizeof (path), "%s/presets/dsp/%s.txt", confdir, text) < 0) {
+ return;
+ }
+ deadbeef->dsp_preset_save (path, chain);
+}
+
+
+void
+on_dsp_preset_load_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *combobox = lookup_widget (prefwin, "dsp_preset");
+ GtkWidget *entry = gtk_bin_get_child (GTK_BIN (combobox));
+ if (entry) {
+ const char *text = gtk_entry_get_text (GTK_ENTRY (entry));
+ char path[PATH_MAX];
+ if (snprintf (path, sizeof (path), "%s/presets/dsp/%s.txt", deadbeef->get_config_dir (), text) > 0) {
+ ddb_dsp_context_t *new_chain = NULL;
+ int res = deadbeef->dsp_preset_load (path, &new_chain);
+ if (!res) {
+ deadbeef->dsp_preset_free (chain);
+ chain = new_chain;
+ GtkWidget *list = lookup_widget (prefwin, "dsp_listview");
+ GtkListStore *mdl = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW(list)));
+ gtk_list_store_clear (mdl);
+ fill_dsp_chain (mdl);
+ update_streamer ();
+ }
+ }
+ }
+}
+
diff --git a/plugins/supereq/supereq.h b/plugins/gtkui/dspconfig.h
index 32298ef1..6b7f5310 100644
--- a/plugins/supereq/supereq.h
+++ b/plugins/gtkui/dspconfig.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -16,16 +16,14 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#ifndef __DSPCONFIG_H
+#define __DSPCONFIG_H
-#ifndef __SUPEREQ_H
-#define __SUPEREQ_H
+void
+dsp_setup_init (GtkWidget *prefwin);
-typedef struct DB_supereq_dsp_s {
- DB_dsp_t dsp;
- float (*get_band) (int band);
- void (*set_band) (int band, float value);
- float (*get_preamp) (void);
- void (*set_preamp) (float value);
-} DB_supereq_dsp_t;
+void
+dsp_setup_free (void);
#endif
+
diff --git a/plugins/gtkui/eq.c b/plugins/gtkui/eq.c
index 93f92af5..bfb77703 100644
--- a/plugins/gtkui/eq.c
+++ b/plugins/gtkui/eq.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -22,7 +22,6 @@
#include <stdlib.h>
#include "gtkui.h"
#include "support.h"
-#include "../supereq/supereq.h"
#include "ddbequalizer.h"
static GtkWidget *eqcont;
@@ -40,46 +39,66 @@ amp_to_db (float amp) {
return 20*log10 (amp);
}
-DB_supereq_dsp_t *
-get_supereq_plugin (void) {
- DB_dsp_t **plugs = deadbeef->plug_get_dsp_list ();
- for (int i = 0; plugs[i]; i++) {
- if (plugs[i]->plugin.id && !strcmp (plugs[i]->plugin.id, "supereq")) {
- return (DB_supereq_dsp_t *)plugs[i];
+ddb_dsp_context_t *
+get_supereq (void) {
+ ddb_dsp_context_t *dsp = deadbeef->streamer_get_dsp_chain ();
+ while (dsp) {
+ if (!strcmp (dsp->plugin->plugin.id, "supereq")) {
+ return dsp;
}
+ dsp = dsp->next;
}
+
return NULL;
}
+static void
+set_param (ddb_dsp_context_t *eq, int i, float v) {
+ char fv[100];
+ snprintf (fv, sizeof (fv), "%f", v);
+ eq->plugin->set_param (eq, i, fv);
+}
+
void
eq_value_changed (DdbEqualizer *widget)
{
- DB_supereq_dsp_t *eq = get_supereq_plugin ();
- for (int i = 0; i < 18; i++) {
- eq->set_band (i, db_to_amp (ddb_equalizer_get_band (widget, i)));
+ ddb_dsp_context_t *eq = get_supereq ();
+ if (eq) {
+ for (int i = 0; i < 18; i++) {
+ set_param (eq, i+1, ddb_equalizer_get_band (widget, i));
+ }
+ set_param (eq, 0, ddb_equalizer_get_preamp (widget));
}
- eq->set_preamp (db_to_amp (ddb_equalizer_get_preamp (widget)));
}
void
on_enable_toggled (GtkToggleButton *togglebutton,
gpointer user_data) {
- DB_supereq_dsp_t *eq = get_supereq_plugin ();
- eq->dsp.enable (gtk_toggle_button_get_active (togglebutton));
+ ddb_dsp_context_t *eq = get_supereq ();
+ if (eq) {
+ int enabled = gtk_toggle_button_get_active (togglebutton) ? 1 : 0;
+ eq->enabled = enabled;
+ deadbeef->streamer_dsp_refresh ();
+ }
}
void
on_zero_all_clicked (GtkButton *button,
gpointer user_data) {
if (eqwin) {
- DB_supereq_dsp_t *eq = get_supereq_plugin ();
- eq->set_preamp (1);
- ddb_equalizer_set_preamp (DDB_EQUALIZER (eqwin), 0);
- for (int i = 0; i < 18; i++) {
- ddb_equalizer_set_band (DDB_EQUALIZER (eqwin), i, 0);
- eq->set_band (i, 1);
+ ddb_dsp_context_t *eq = get_supereq ();
+ if (eq) {
+ ddb_equalizer_set_preamp (DDB_EQUALIZER (eqwin), 0);
+ set_param (eq, 0, 0);
+ for (int i = 0; i < 18; i++) {
+ // set gui
+ ddb_equalizer_set_band (DDB_EQUALIZER (eqwin), i, 0);
+
+ // set dsp
+ set_param (eq, i+1, 0);
+ }
+ gdk_window_invalidate_rect (eqwin->window, NULL, FALSE);
}
- gdk_window_invalidate_rect (eqwin->window, NULL, FALSE);
}
}
@@ -87,10 +106,12 @@ void
on_zero_preamp_clicked (GtkButton *button,
gpointer user_data) {
if (eqwin) {
- DB_supereq_dsp_t *eq = get_supereq_plugin ();
- eq->set_preamp (1);
- ddb_equalizer_set_preamp (DDB_EQUALIZER (eqwin), 0);
- gdk_window_invalidate_rect (eqwin->window, NULL, FALSE);
+ ddb_dsp_context_t *eq = get_supereq ();
+ if (eq) {
+ set_param (eq, 0, 0);
+ ddb_equalizer_set_preamp (DDB_EQUALIZER (eqwin), 0);
+ gdk_window_invalidate_rect (eqwin->window, NULL, FALSE);
+ }
}
}
@@ -98,17 +119,19 @@ void
on_zero_bands_clicked (GtkButton *button,
gpointer user_data) {
if (eqwin) {
- DB_supereq_dsp_t *eq = get_supereq_plugin ();
- for (int i = 0; i < 18; i++) {
- ddb_equalizer_set_band (DDB_EQUALIZER (eqwin), i, 0);
- eq->set_band (i, 1);
+ ddb_dsp_context_t *eq = get_supereq ();
+ if (eq) {
+ for (int i = 0; i < 18; i++) {
+ ddb_equalizer_set_band (DDB_EQUALIZER (eqwin), i, 0);
+ set_param (eq, i+1, 0);
+ }
+ gdk_window_invalidate_rect (eqwin->window, NULL, FALSE);
}
- gdk_window_invalidate_rect (eqwin->window, NULL, FALSE);
}
}
void
-on_save_preset_clicked (GtkButton *button,
+on_save_preset_clicked (GtkMenuItem *menuitem,
gpointer user_data) {
GtkWidget *dlg = gtk_file_chooser_dialog_new (_("Save DeaDBeeF EQ Preset"), GTK_WINDOW (mainwin), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL);
@@ -130,11 +153,19 @@ on_save_preset_clicked (GtkButton *button,
if (fname) {
FILE *fp = fopen (fname, "w+b");
if (fp) {
- DB_supereq_dsp_t *eq = get_supereq_plugin ();
- for (int i = 0; i < 18; i++) {
- fprintf (fp, "%f\n", amp_to_db (eq->get_band (i)));
+ ddb_dsp_context_t *eq = get_supereq ();
+ if (eq) {
+ char fv[100];
+ float v;
+ for (int i = 0; i < 18; i++) {
+ eq->plugin->get_param (eq, i+1, fv, sizeof (fv));
+ v = atof (fv);
+ fprintf (fp, "%f\n", v);
+ }
+ eq->plugin->get_param (eq, 0, fv, sizeof (fv));
+ v = atof (fv);
+ fprintf (fp, "%f\n", v);
}
- fprintf (fp, "%f\n", amp_to_db (eq->get_preamp ()));
fclose (fp);
}
g_free (fname);
@@ -146,7 +177,7 @@ on_save_preset_clicked (GtkButton *button,
}
void
-on_load_preset_clicked (GtkButton *button,
+on_load_preset_clicked (GtkMenuItem *menuitem,
gpointer user_data) {
GtkWidget *dlg = gtk_file_chooser_dialog_new (_("Load DeaDBeeF EQ Preset..."), GTK_WINDOW (mainwin), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
@@ -158,7 +189,9 @@ on_load_preset_clicked (GtkButton *button,
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), FALSE);
// restore folder
- gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str ("filechooser.lastdir", ""));
+ deadbeef->conf_lock ();
+ gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str_fast ("filechooser.lastdir", ""));
+ deadbeef->conf_unlock ();
int response = gtk_dialog_run (GTK_DIALOG (dlg));
// store folder
gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
@@ -186,13 +219,13 @@ on_load_preset_clicked (GtkButton *button,
fclose (fp);
if (i == 19) {
// apply and save config
- DB_supereq_dsp_t *eq = get_supereq_plugin ();
+ ddb_dsp_context_t *eq = get_supereq ();
if (eq) {
- eq->set_preamp (db_to_amp (vals[18]));
+ set_param (eq, 0, vals[18]);
ddb_equalizer_set_preamp (DDB_EQUALIZER (eqwin), vals[18]);
for (int i = 0; i < 18; i++) {
ddb_equalizer_set_band (DDB_EQUALIZER (eqwin), i, vals[i]);
- eq->set_band (i, db_to_amp (vals[i]));
+ set_param (eq, i+1, vals[i]);
}
gdk_window_invalidate_rect (eqwin->window, NULL, FALSE);
deadbeef->conf_save ();
@@ -221,7 +254,10 @@ on_import_fb2k_preset_clicked (GtkButton *button,
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), FALSE);
// restore folder
- gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str ("filechooser.lastdir", ""));
+ deadbeef->conf_lock ();
+ gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str_fast ("filechooser.lastdir", ""));
+ deadbeef->conf_unlock ();
+
int response = gtk_dialog_run (GTK_DIALOG (dlg));
// store folder
gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
@@ -249,13 +285,13 @@ on_import_fb2k_preset_clicked (GtkButton *button,
fclose (fp);
if (i == 18) {
// apply and save config
- DB_supereq_dsp_t *eq = get_supereq_plugin ();
+ ddb_dsp_context_t *eq = get_supereq ();
if (eq) {
- eq->set_preamp (1);
+ set_param (eq, 0, 0);
ddb_equalizer_set_preamp (DDB_EQUALIZER (eqwin), 0);
for (int i = 0; i < 18; i++) {
- ddb_equalizer_set_band (DDB_EQUALIZER (eqwin), i, vals[i]);
- eq->set_band (i, db_to_amp (vals[i]));
+ ddb_equalizer_set_band (DDB_EQUALIZER (eqwin), i, amp_to_db (vals[i]));
+ set_param (eq, i+1, amp_to_db (vals[i]));
}
gdk_window_invalidate_rect (eqwin->window, NULL, FALSE);
deadbeef->conf_save ();
@@ -272,11 +308,40 @@ on_import_fb2k_preset_clicked (GtkButton *button,
}
void
+on_presets_clicked (GtkButton *button,
+ gpointer user_data) {
+ GtkWidget *menu = gtk_menu_new ();
+ GtkWidget *menuitem;
+
+ menuitem = gtk_menu_item_new_with_mnemonic (_("Save Preset"));
+ gtk_widget_show (menuitem);
+ gtk_container_add (GTK_CONTAINER (menu), menuitem);
+
+ g_signal_connect ((gpointer) menuitem, "activate",
+ G_CALLBACK (on_save_preset_clicked),
+ NULL);
+
+ menuitem = gtk_menu_item_new_with_mnemonic (_("Load Preset"));
+ gtk_widget_show (menuitem);
+ gtk_container_add (GTK_CONTAINER (menu), menuitem);
+
+ g_signal_connect ((gpointer) menuitem, "activate",
+ G_CALLBACK (on_load_preset_clicked),
+ NULL);
+
+ menuitem = gtk_menu_item_new_with_mnemonic (_("Import Foobar2000 Preset"));
+ gtk_widget_show (menuitem);
+ gtk_container_add (GTK_CONTAINER (menu), menuitem);
+
+ g_signal_connect ((gpointer) menuitem, "activate",
+ G_CALLBACK (on_import_fb2k_preset_clicked),
+ NULL);
+
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
+}
+
+void
eq_window_show (void) {
- DB_supereq_dsp_t *eq = get_supereq_plugin ();
- if (!eq) {
- return;
- }
if (!eqcont) {
eqcont = gtk_vbox_new (FALSE, 8);
GtkWidget *parent= lookup_widget (mainwin, "plugins_bottom_vbox");
@@ -292,7 +357,8 @@ eq_window_show (void) {
eqenablebtn = button = gtk_check_button_new_with_label (_("Enable"));
gtk_widget_show (button);
gtk_box_pack_start (GTK_BOX (buttons), button, FALSE, FALSE, 0);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (eqenablebtn), deadbeef->conf_get_int ("supereq.enable", 0));
+ ddb_dsp_context_t *eq = get_supereq ();
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (eqenablebtn), eq ? eq->enabled : 0);
g_signal_connect ((gpointer) button, "toggled",
G_CALLBACK (on_enable_toggled),
NULL);
@@ -318,37 +384,29 @@ eq_window_show (void) {
G_CALLBACK (on_zero_bands_clicked),
NULL);
- button = gtk_button_new_with_label (_("Save Preset"));
+ button = gtk_button_new_with_label (_("Presets"));
gtk_widget_show (button);
gtk_box_pack_start (GTK_BOX (buttons), button, FALSE, FALSE, 0);
g_signal_connect ((gpointer) button, "clicked",
- G_CALLBACK (on_save_preset_clicked),
- NULL);
-
- button = gtk_button_new_with_label (_("Load Preset"));
- gtk_widget_show (button);
- gtk_box_pack_start (GTK_BOX (buttons), button, FALSE, FALSE, 0);
- g_signal_connect ((gpointer) button, "clicked",
- G_CALLBACK (on_load_preset_clicked),
- NULL);
-
- button = gtk_button_new_with_label (_("Import Foobar2000 Preset"));
- gtk_widget_show (button);
- gtk_box_pack_start (GTK_BOX (buttons), button, FALSE, FALSE, 0);
- g_signal_connect ((gpointer) button, "clicked",
- G_CALLBACK (on_import_fb2k_preset_clicked),
+ G_CALLBACK (on_presets_clicked),
NULL);
eqwin = GTK_WIDGET (ddb_equalizer_new());
g_signal_connect (eqwin, "on_changed", G_CALLBACK (eq_value_changed), 0);
gtk_widget_set_size_request (eqwin, -1, 200);
-
- ddb_equalizer_set_preamp (DDB_EQUALIZER (eqwin), amp_to_db (eq->get_preamp ()));
- for (int i = 0; i < 18; i++) {
- if (eq) {
- float val = eq->get_band (i);
- ddb_equalizer_set_band (DDB_EQUALIZER (eqwin), i, amp_to_db (val));
+ if (eq) {
+ char fv[100];
+ float v;
+ eq->plugin->get_param (eq, 0, fv, sizeof (fv));
+ v = atof (fv);
+ ddb_equalizer_set_preamp (DDB_EQUALIZER (eqwin), v);
+ for (int i = 0; i < 18; i++) {
+ if (eq) {
+ eq->plugin->get_param (eq, i+1, fv, sizeof (fv));
+ v = atof (fv);
+ ddb_equalizer_set_band (DDB_EQUALIZER (eqwin), i, v);
+ }
}
}
diff --git a/plugins/gtkui/eq.h b/plugins/gtkui/eq.h
index 9e54916e..570cd935 100644
--- a/plugins/gtkui/eq.h
+++ b/plugins/gtkui/eq.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -29,8 +29,8 @@ eq_window_hide (void);
void
eq_window_destroy (void);
-struct DB_supereq_dsp_s *
-get_supereq_plugin (void);
+ddb_dsp_context_t *
+get_supereq (void);
void
eq_redraw (void);
diff --git a/plugins/gtkui/fileman.c b/plugins/gtkui/fileman.c
index 3f58bb09..d33764c0 100644
--- a/plugins/gtkui/fileman.c
+++ b/plugins/gtkui/fileman.c
@@ -2,6 +2,7 @@
#include <gtk/gtk.h>
#include <stdlib.h>
#include <ctype.h>
+#include <string.h>
#include "gtkui.h"
#include "ddblistview.h"
#include "progress.h"
@@ -9,10 +10,8 @@
void
gtkpl_add_dir (DdbListview *ps, char *folder) {
- g_idle_add (gtkui_progress_show_idle, NULL);
gtkui_original_pl_add_dir (folder, gtkui_add_file_info_cb, NULL);
g_free (folder);
- g_idle_add (gtkui_progress_hide_idle, NULL);
}
static void
@@ -23,10 +22,30 @@ gtkpl_adddir_cb (gpointer data, gpointer userdata) {
void
gtkpl_add_dirs (GSList *lst) {
- g_idle_add (gtkui_progress_show_idle, NULL);
+ deadbeef->plt_lock ();
+ deadbeef->pl_add_files_begin (deadbeef->plt_get_curr ());
+ if (g_slist_length (lst) == 1
+ && deadbeef->conf_get_int ("gtkui.name_playlist_from_folder", 0)) {
+ int plt = deadbeef->plt_get_curr ();
+ if (plt != -1) {
+ void *p = deadbeef->plt_get_handle (plt);
+ char t[1000];
+ if (!deadbeef->plt_get_title (p, t, sizeof (t))) {
+ char *def = _("New Playlist");
+ if (!strncmp (t, def, strlen (def))) {
+ const char *folder = strrchr ((char*)lst->data, '/');
+ if (!folder) {
+ folder = lst->data;
+ }
+ deadbeef->plt_set_title (p, folder+1);
+ }
+ }
+ }
+ }
+ deadbeef->plt_unlock ();
g_slist_foreach(lst, gtkpl_adddir_cb, NULL);
g_slist_free (lst);
- g_idle_add (gtkui_progress_hide_idle, NULL);
+ deadbeef->pl_add_files_end ();
}
static void
@@ -37,10 +56,10 @@ gtkpl_addfile_cb (gpointer data, gpointer userdata) {
void
gtkpl_add_files (GSList *lst) {
- g_idle_add (gtkui_progress_show_idle, NULL);
+ deadbeef->pl_add_files_begin (deadbeef->plt_get_curr ());
g_slist_foreach(lst, gtkpl_addfile_cb, NULL);
g_slist_free (lst);
- g_idle_add (gtkui_progress_hide_idle, NULL);
+ deadbeef->pl_add_files_end ();
}
static void
@@ -51,7 +70,8 @@ add_dirs_worker (void *data) {
void
gtkui_add_dirs (GSList *lst) {
- deadbeef->thread_start (add_dirs_worker, lst);
+ intptr_t tid = deadbeef->thread_start (add_dirs_worker, lst);
+ deadbeef->thread_detach (tid);
}
static void
@@ -62,7 +82,9 @@ add_files_worker (void *data) {
void
gtkui_add_files (struct _GSList *lst) {
- deadbeef->thread_start (add_files_worker, lst);
+ deadbeef->pl_add_files_begin (deadbeef->plt_get_curr ());
+ intptr_t tid = deadbeef->thread_start (add_files_worker, lst);
+ deadbeef->thread_detach (tid);
}
static void
@@ -73,14 +95,16 @@ open_files_worker (void *data) {
extern GtkWidget *mainwin;
DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
ddb_listview_set_cursor (pl, 0);
- deadbeef->sendmessage (M_PLAYSONG, 0, 1, 0);
+ deadbeef->sendmessage (M_PLAY_CURRENT, 0, 1, 0);
}
void
gtkui_open_files (struct _GSList *lst) {
deadbeef->pl_clear ();
playlist_refresh ();
- deadbeef->thread_start (open_files_worker, lst);
+
+ intptr_t tid = deadbeef->thread_start (open_files_worker, lst);
+ deadbeef->thread_detach (tid);
}
void
@@ -140,7 +164,7 @@ set_dnd_cursor_idle (gpointer data) {
void
gtkpl_add_fm_dropped_files (DB_playItem_t *drop_before, char *ptr, int length) {
DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- g_idle_add (gtkui_progress_show_idle, NULL);
+ deadbeef->pl_add_files_begin (deadbeef->plt_get_curr ());
DdbListviewIter first = NULL;
DdbListviewIter after = NULL;
@@ -188,7 +212,7 @@ gtkpl_add_fm_dropped_files (DB_playItem_t *drop_before, char *ptr, int length) {
}
free (ptr);
- g_idle_add (gtkui_progress_hide_idle, NULL);
+ deadbeef->pl_add_files_end ();
g_idle_add (set_dnd_cursor_idle, first);
}
@@ -222,5 +246,6 @@ gtkui_receive_fm_drop (DB_playItem_t *before, char *mem, int length) {
}
data->drop_before = before;
// since it happens in separate thread, we need to addref
- deadbeef->thread_start (fmdrop_worker, data);
+ intptr_t tid = deadbeef->thread_start (fmdrop_worker, data);
+ deadbeef->thread_detach (tid);
}
diff --git a/plugins/gtkui/gdkdrawing.c b/plugins/gtkui/gdkdrawing.c
index c7c2339b..cb795ccb 100644
--- a/plugins/gtkui/gdkdrawing.c
+++ b/plugins/gtkui/gdkdrawing.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -197,6 +197,7 @@ static GdkColor gtkui_tabstrip_dark_color;
static GdkColor gtkui_tabstrip_mid_color;
static GdkColor gtkui_tabstrip_light_color;
static GdkColor gtkui_tabstrip_base_color;
+static GdkColor gtkui_tabstrip_text_color;
static GdkColor gtkui_listview_even_row_color;
static GdkColor gtkui_listview_odd_row_color;
@@ -226,6 +227,7 @@ gtkui_override_tabstrip_colors (void) {
void
gtkui_init_theme_colors (void) {
+ deadbeef->conf_lock ();
override_listview_colors= deadbeef->conf_get_int ("gtkui.override_listview_colors", 0);
override_bar_colors = deadbeef->conf_get_int ("gtkui.override_bar_colors", 0);
override_tabstrip_colors = deadbeef->conf_get_int ("gtkui.override_tabstrip_colors", 0);
@@ -241,11 +243,11 @@ gtkui_init_theme_colors (void) {
}
else {
snprintf (color_text, sizeof (color_text), "%hd %hd %hd", style->base[GTK_STATE_SELECTED].red, style->base[GTK_STATE_SELECTED].green, style->base[GTK_STATE_SELECTED].blue);
- clr = deadbeef->conf_get_str ("gtkui.color.bar_foreground", color_text);
+ clr = deadbeef->conf_get_str_fast ("gtkui.color.bar_foreground", color_text);
sscanf (clr, "%hd %hd %hd", &gtkui_bar_foreground_color.red, &gtkui_bar_foreground_color.green, &gtkui_bar_foreground_color.blue);
snprintf (color_text, sizeof (color_text), "%hd %hd %hd", style->fg[GTK_STATE_NORMAL].red, style->fg[GTK_STATE_NORMAL].green, style->fg[GTK_STATE_NORMAL].blue);
- clr = deadbeef->conf_get_str ("gtkui.color.bar_background", color_text);
+ clr = deadbeef->conf_get_str_fast ("gtkui.color.bar_background", color_text);
sscanf (clr, "%hd %hd %hd", &gtkui_bar_background_color.red, &gtkui_bar_background_color.green, &gtkui_bar_background_color.blue);
}
@@ -255,23 +257,28 @@ gtkui_init_theme_colors (void) {
memcpy (&gtkui_tabstrip_mid_color, &style->mid[GTK_STATE_NORMAL], sizeof (GdkColor));
memcpy (&gtkui_tabstrip_light_color, &style->light[GTK_STATE_NORMAL], sizeof (GdkColor));
memcpy (&gtkui_tabstrip_base_color, &style->bg[GTK_STATE_NORMAL], sizeof (GdkColor));
+ memcpy (&gtkui_tabstrip_text_color, &style->text[GTK_STATE_NORMAL], sizeof (GdkColor));
}
else {
snprintf (color_text, sizeof (color_text), "%hd %hd %hd", style->dark[GTK_STATE_NORMAL].red, style->dark[GTK_STATE_NORMAL].green, style->dark[GTK_STATE_NORMAL].blue);
- clr = deadbeef->conf_get_str ("gtkui.color.tabstrip_dark", color_text);
+ clr = deadbeef->conf_get_str_fast ("gtkui.color.tabstrip_dark", color_text);
sscanf (clr, "%hd %hd %hd", &gtkui_tabstrip_dark_color.red, &gtkui_tabstrip_dark_color.green, &gtkui_tabstrip_dark_color.blue);
snprintf (color_text, sizeof (color_text), "%hd %hd %hd", style->mid[GTK_STATE_NORMAL].red, style->mid[GTK_STATE_NORMAL].green, style->mid[GTK_STATE_NORMAL].blue);
- clr = deadbeef->conf_get_str ("gtkui.color.tabstrip_mid", color_text);
+ clr = deadbeef->conf_get_str_fast ("gtkui.color.tabstrip_mid", color_text);
sscanf (clr, "%hd %hd %hd", &gtkui_tabstrip_mid_color.red, &gtkui_tabstrip_mid_color.green, &gtkui_tabstrip_mid_color.blue);
snprintf (color_text, sizeof (color_text), "%hd %hd %hd", style->light[GTK_STATE_NORMAL].red, style->light[GTK_STATE_NORMAL].green, style->light[GTK_STATE_NORMAL].blue);
- clr = deadbeef->conf_get_str ("gtkui.color.tabstrip_light", color_text);
+ clr = deadbeef->conf_get_str_fast ("gtkui.color.tabstrip_light", color_text);
sscanf (clr, "%hd %hd %hd", &gtkui_tabstrip_light_color.red, &gtkui_tabstrip_light_color.green, &gtkui_tabstrip_light_color.blue);
snprintf (color_text, sizeof (color_text), "%hd %hd %hd", style->bg[GTK_STATE_NORMAL].red, style->bg[GTK_STATE_NORMAL].green, style->bg[GTK_STATE_NORMAL].blue);
- clr = deadbeef->conf_get_str ("gtkui.color.tabstrip_base", color_text);
+ clr = deadbeef->conf_get_str_fast ("gtkui.color.tabstrip_base", color_text);
sscanf (clr, "%hd %hd %hd", &gtkui_tabstrip_base_color.red, &gtkui_tabstrip_base_color.green, &gtkui_tabstrip_base_color.blue);
+
+ snprintf (color_text, sizeof (color_text), "%hd %hd %hd", style->text[GTK_STATE_NORMAL].red, style->text[GTK_STATE_NORMAL].green, style->text[GTK_STATE_NORMAL].blue);
+ clr = deadbeef->conf_get_str_fast ("gtkui.color.tabstrip_text", color_text);
+ sscanf (clr, "%hd %hd %hd", &gtkui_tabstrip_text_color.red, &gtkui_tabstrip_text_color.green, &gtkui_tabstrip_text_color.blue);
}
if (!override_listview_colors) {
@@ -284,29 +291,30 @@ gtkui_init_theme_colors (void) {
}
else {
snprintf (color_text, sizeof (color_text), "%hd %hd %hd", style->light[GTK_STATE_NORMAL].red, style->light[GTK_STATE_NORMAL].green, style->light[GTK_STATE_NORMAL].blue);
- clr = deadbeef->conf_get_str ("gtkui.color.listview_even_row", color_text);
+ clr = deadbeef->conf_get_str_fast ("gtkui.color.listview_even_row", color_text);
sscanf (clr, "%hd %hd %hd", &gtkui_listview_even_row_color.red, &gtkui_listview_even_row_color.green, &gtkui_listview_even_row_color.blue);
snprintf (color_text, sizeof (color_text), "%hd %hd %hd", style->mid[GTK_STATE_NORMAL].red, style->mid[GTK_STATE_NORMAL].green, style->mid[GTK_STATE_NORMAL].blue);
- clr = deadbeef->conf_get_str ("gtkui.color.listview_odd_row", color_text);
+ clr = deadbeef->conf_get_str_fast ("gtkui.color.listview_odd_row", color_text);
sscanf (clr, "%hd %hd %hd", &gtkui_listview_odd_row_color.red, &gtkui_listview_odd_row_color.green, &gtkui_listview_odd_row_color.blue);
snprintf (color_text, sizeof (color_text), "%hd %hd %hd", style->mid[GTK_STATE_NORMAL].red, style->mid[GTK_STATE_NORMAL].green, style->mid[GTK_STATE_NORMAL].blue);
- clr = deadbeef->conf_get_str ("gtkui.color.listview_selection", color_text);
+ clr = deadbeef->conf_get_str_fast ("gtkui.color.listview_selection", color_text);
sscanf (clr, "%hd %hd %hd", &gtkui_listview_selection_color.red, &gtkui_listview_selection_color.green, &gtkui_listview_selection_color.blue);
snprintf (color_text, sizeof (color_text), "%hd %hd %hd", style->fg[GTK_STATE_NORMAL].red, style->fg[GTK_STATE_NORMAL].green, style->fg[GTK_STATE_NORMAL].blue);
- clr = deadbeef->conf_get_str ("gtkui.color.listview_text", color_text);
+ clr = deadbeef->conf_get_str_fast ("gtkui.color.listview_text", color_text);
sscanf (clr, "%hd %hd %hd", &gtkui_listview_text_color.red, &gtkui_listview_text_color.green, &gtkui_listview_text_color.blue);
snprintf (color_text, sizeof (color_text), "%hd %hd %hd", style->fg[GTK_STATE_SELECTED].red, style->fg[GTK_STATE_SELECTED].green, style->fg[GTK_STATE_SELECTED].blue);
- clr = deadbeef->conf_get_str ("gtkui.color.listview_selected_text", color_text);
+ clr = deadbeef->conf_get_str_fast ("gtkui.color.listview_selected_text", color_text);
sscanf (clr, "%hd %hd %hd", &gtkui_listview_selected_text_color.red, &gtkui_listview_selected_text_color.green, &gtkui_listview_selected_text_color.blue);
snprintf (color_text, sizeof (color_text), "%hd %hd %hd", style->fg[GTK_STATE_SELECTED].red, style->fg[GTK_STATE_SELECTED].green, style->fg[GTK_STATE_SELECTED].blue);
- clr = deadbeef->conf_get_str ("gtkui.color.listview_cursor", color_text);
+ clr = deadbeef->conf_get_str_fast ("gtkui.color.listview_cursor", color_text);
sscanf (clr, "%hd %hd %hd", &gtkui_listview_cursor_color.red, &gtkui_listview_cursor_color.green, &gtkui_listview_cursor_color.blue);
}
+ deadbeef->conf_unlock ();
}
void
@@ -340,6 +348,11 @@ gtkui_get_tabstrip_base_color (GdkColor *clr) {
}
void
+gtkui_get_tabstrip_text_color (GdkColor *clr) {
+ memcpy (clr, &gtkui_tabstrip_text_color, sizeof (GdkColor));
+}
+
+void
gtkui_get_listview_even_row_color (GdkColor *clr) {
memcpy (clr, &gtkui_listview_even_row_color, sizeof (GdkColor));
}
@@ -368,3 +381,16 @@ void
gtkui_get_listview_cursor_color (GdkColor *clr) {
memcpy (clr, &gtkui_listview_cursor_color, sizeof (GdkColor));
}
+
+int
+draw_get_listview_rowheight (void) {
+ PangoFontDescription *font_desc = font_style->font_desc;
+ PangoFontMetrics *metrics = pango_context_get_metrics (pangoctx,
+ font_desc,
+ pango_context_get_language (pangoctx));
+ int row_height = (pango_font_metrics_get_ascent (metrics) +
+ pango_font_metrics_get_descent (metrics));
+ pango_font_metrics_unref (metrics);
+ return PANGO_PIXELS(row_height)+6;
+}
+
diff --git a/plugins/gtkui/gtkui.c b/plugins/gtkui/gtkui.c
index 35da1527..6b34e1e9 100644
--- a/plugins/gtkui/gtkui.c
+++ b/plugins/gtkui/gtkui.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -44,11 +44,14 @@
#include "ddbtabstrip.h"
#include "eq.h"
#include "actions.h"
+#include "pluginconf.h"
+#include "gtkui_api.h"
+#include "wingeom.h"
-//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
-#define trace(fmt,...)
+#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+//#define trace(fmt,...)
-static DB_gui_t plugin;
+static ddb_gtkui_t plugin;
DB_functions_t *deadbeef;
static intptr_t gtk_tid;
@@ -116,6 +119,7 @@ update_songinfo (gpointer ctx) {
if (!gtk_widget_get_visible (mainwin) || iconified) {
return FALSE;
}
+ DB_output_t *output = deadbeef->get_output ();
char sbtext_new[512] = "-";
float songpos = last_songpos;
@@ -141,7 +145,7 @@ update_songinfo (gpointer ctx) {
float duration = track ? deadbeef->pl_get_item_duration (track) : -1;
- if (deadbeef->get_output ()->state () == OUTPUT_STATE_STOPPED || !track || !c) {
+ if (!output || (output->state () == OUTPUT_STATE_STOPPED || !track || !c)) {
snprintf (sbtext_new, sizeof (sbtext_new), _("Stopped | %d tracks | %s total playtime"), deadbeef->pl_getcount (PL_MAIN), totaltime_str);
songpos = 0;
}
@@ -154,15 +158,15 @@ update_songinfo (gpointer ctx) {
const char *mode;
char temp[20];
- if (c->channels <= 2) {
- mode = c->channels == 1 ? _("Mono") : _("Stereo");
+ if (c->fmt.channels <= 2) {
+ mode = c->fmt.channels == 1 ? _("Mono") : _("Stereo");
}
else {
- snprintf (temp, sizeof (temp), "%dch Multichannel", c->channels);
+ snprintf (temp, sizeof (temp), "%dch Multichannel", c->fmt.channels);
mode = temp;
}
- int samplerate = c->samplerate;
- int bitspersample = c->bps;
+ int samplerate = c->fmt.samplerate;
+ int bitspersample = c->fmt.bps;
songpos = playpos;
// codec_unlock ();
@@ -187,7 +191,11 @@ update_songinfo (gpointer ctx) {
}
}
const char *spaused = deadbeef->get_output ()->state () == OUTPUT_STATE_PAUSED ? _("Paused | ") : "";
- snprintf (sbtext_new, sizeof (sbtext_new), _("%s%s %s| %dHz | %d bit | %s | %d:%02d / %s | %d tracks | %s total playtime"), spaused, track->filetype ? track->filetype:"-", sbitrate, samplerate, bitspersample, mode, minpos, secpos, t, deadbeef->pl_getcount (PL_MAIN), totaltime_str);
+ const char *filetype = deadbeef->pl_find_meta (track, ":FILETYPE");
+ if (!filetype) {
+ filetype = "-";
+ }
+ snprintf (sbtext_new, sizeof (sbtext_new), _("%s%s %s| %dHz | %d bit | %s | %d:%02d / %s | %d tracks | %s total playtime"), spaused, filetype, sbitrate, samplerate, bitspersample, mode, minpos, secpos, t, deadbeef->pl_getcount (PL_MAIN), totaltime_str);
}
if (strcmp (sbtext_new, sb_text)) {
@@ -223,7 +231,7 @@ update_songinfo (gpointer ctx) {
void
set_tray_tooltip (const char *text) {
if (trayicon) {
-#if (GTK_MINOR_VERSION < 16)
+#if !GTK_CHECK_VERSION(2,16,0) || defined(ULTRA_COMPATIBLE)
gtk_status_icon_set_tooltip (trayicon, text);
#else
gtk_status_icon_set_tooltip_text (trayicon, text);
@@ -274,15 +282,7 @@ mainwin_toggle_visible (void) {
gtk_widget_hide (mainwin);
}
else {
- int x = deadbeef->conf_get_int ("mainwin.geometry.x", 40);
- int y = deadbeef->conf_get_int ("mainwin.geometry.y", 40);
- int w = deadbeef->conf_get_int ("mainwin.geometry.w", 500);
- int h = deadbeef->conf_get_int ("mainwin.geometry.h", 300);
- gtk_window_move (GTK_WINDOW (mainwin), x, y);
- gtk_window_resize (GTK_WINDOW (mainwin), w, h);
- if (deadbeef->conf_get_int ("mainwin.geometry.maximized", 0)) {
- gtk_window_maximize (GTK_WINDOW (mainwin));
- }
+ wingeom_restore (mainwin, "mainwin", 40, 40, 500, 300, 0);
if (iconified) {
gtk_window_deiconify (GTK_WINDOW(mainwin));
}
@@ -292,7 +292,7 @@ mainwin_toggle_visible (void) {
}
}
-#if GTK_MINOR_VERSION<=14
+#if !GTK_CHECK_VERSION(2,14,0) || defined(ULTRA_COMPATIBLE)
gboolean
on_trayicon_activate (GtkWidget *widget,
@@ -314,7 +314,7 @@ on_trayicon_button_press_event (GtkWidget *widget,
mainwin_toggle_visible ();
}
else if (event->button == 2) {
- deadbeef->sendmessage (M_PAUSESONG, 0, 0, 0);
+ deadbeef->sendmessage (M_TOGGLE_PAUSE, 0, 0, 0);
}
return FALSE;
}
@@ -398,13 +398,13 @@ gtkui_set_titlebar (DB_playItem_t *it) {
else {
deadbeef->pl_item_ref (it);
}
+ char fmt[500];
char str[600];
- const char *fmt;
if (it) {
- fmt = deadbeef->conf_get_str ("gtkui.titlebar_playing", "%a - %t - DeaDBeeF-%V");
+ deadbeef->conf_get_str ("gtkui.titlebar_playing", "%a - %t - DeaDBeeF-%V", fmt, sizeof (fmt));
}
else {
- fmt = deadbeef->conf_get_str ("gtkui.titlebar_stopped", "DeaDBeeF-%V");
+ deadbeef->conf_get_str ("gtkui.titlebar_stopped", "DeaDBeeF-%V", fmt, sizeof (fmt));
}
deadbeef->pl_format_title (it, -1, str, sizeof (str), -1, fmt);
gtk_window_set_title (GTK_WINDOW (mainwin), str);
@@ -478,7 +478,7 @@ gtkui_on_paused (DB_event_state_t *ev, uintptr_t data) {
void
playlist_refresh (void) {
DdbListview *ps = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (ps, DDB_REFRESH_LIST | DDB_REFRESH_VSCROLL | DDB_EXPOSE_LIST);
+ ddb_listview_refresh (ps, DDB_REFRESH_LIST | DDB_REFRESH_VSCROLL);
search_refresh ();
}
@@ -532,11 +532,11 @@ gtkui_on_playlistswitch (DB_event_t *ev, uintptr_t data) {
return 0;
}
-static int
-gtkui_on_frameupdate (DB_event_t *ev, uintptr_t data) {
- g_idle_add (update_songinfo, NULL);
+static gboolean
+gtkui_on_frameupdate (gpointer data) {
+ update_songinfo (NULL);
- return 0;
+ return TRUE;
}
static gboolean
@@ -571,7 +571,9 @@ gtkui_update_status_icon (gpointer unused) {
// system tray icon
traymenu = create_traymenu ();
- const char *icon_name = deadbeef->conf_get_str ("gtkui.custom_tray_icon", TRAY_ICON);
+ char tmp[1000];
+ const char *icon_name = tmp;
+ deadbeef->conf_get_str ("gtkui.custom_tray_icon", TRAY_ICON, tmp, sizeof (tmp));
GtkIconTheme *theme = gtk_icon_theme_get_default();
if (!gtk_icon_theme_has_icon(theme, icon_name))
@@ -583,12 +585,19 @@ gtkui_update_status_icon (gpointer unused) {
icon_name = icon_is_builtin ? "deadbeef" : icon_name;
}
- trayicon = gtk_status_icon_new_from_icon_name(icon_name);
+ if (!gtk_icon_theme_has_icon(theme, icon_name)) {
+ char iconpath[1024];
+ snprintf (iconpath, sizeof (iconpath), "%s/deadbeef.png", deadbeef->get_prefix ());
+ trayicon = gtk_status_icon_new_from_file(iconpath);
+ }
+ else {
+ trayicon = gtk_status_icon_new_from_icon_name(icon_name);
+ }
if (hide_tray_icon) {
g_object_set (trayicon, "visible", FALSE, NULL);
}
-#if GTK_MINOR_VERSION <= 14
+#if !GTK_CHECK_VERSION(2,14,0) || defined(ULTRA_COMPATIBLE)
g_signal_connect ((gpointer)trayicon, "activate", G_CALLBACK (on_trayicon_activate), NULL);
#else
g_signal_connect ((gpointer)trayicon, "scroll_event", G_CALLBACK (on_trayicon_scroll_event), NULL);
@@ -614,7 +623,7 @@ gtkui_on_configchanged (DB_event_t *ev, uintptr_t data) {
const char *w;
// order
- const char *orderwidgets[3] = { "order_linear", "order_shuffle", "order_random" };
+ const char *orderwidgets[4] = { "order_linear", "order_shuffle", "order_random", "order_shuffle_albums" };
w = orderwidgets[deadbeef->conf_get_int ("playback.order", PLAYBACK_ORDER_LINEAR)];
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (lookup_widget (mainwin, w)), TRUE);
@@ -663,13 +672,31 @@ save_playlist_as (void) {
gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dlg), TRUE);
gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dlg), "untitled.dbpl");
// restore folder
- gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str ("filechooser.playlist.lastdir", ""));
+ deadbeef->conf_lock ();
+ gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str_fast ("filechooser.playlist.lastdir", ""));
+ deadbeef->conf_unlock ();
GtkFileFilter* flt;
flt = gtk_file_filter_new ();
gtk_file_filter_set_name (flt, _("DeaDBeeF playlist files (*.dbpl)"));
gtk_file_filter_add_pattern (flt, "*.dbpl");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
+ DB_playlist_t **plug = deadbeef->plug_get_playlist_list ();
+ for (int i = 0; plug[i]; i++) {
+ if (plug[i]->extensions && plug[i]->load) {
+ const char **exts = plug[i]->extensions;
+ if (exts && plug[i]->save) {
+ for (int e = 0; exts[e]; e++) {
+ char s[100];
+ flt = gtk_file_filter_new ();
+ gtk_file_filter_set_name (flt, exts[e]);
+ snprintf (s, sizeof (s), "*.%s", exts[e]);
+ gtk_file_filter_add_pattern (flt, s);
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
+ }
+ }
+ }
+ }
int res = gtk_dialog_run (GTK_DIALOG (dlg));
// store folder
@@ -716,6 +743,29 @@ on_playlist_save_as_activate (GtkMenuItem *menuitem,
save_playlist_as ();
}
+static gboolean
+playlist_filter_func (const GtkFileFilterInfo *filter_info, gpointer data) {
+ // get ext
+ const char *p = strrchr (filter_info->filename, '.');
+ if (!p) {
+ return FALSE;
+ }
+ p++;
+ DB_playlist_t **plug = deadbeef->plug_get_playlist_list ();
+ for (int i = 0; plug[i]; i++) {
+ if (plug[i]->extensions && plug[i]->load) {
+ const char **exts = plug[i]->extensions;
+ if (exts) {
+ for (int e = 0; exts[e]; e++) {
+ if (!strcasecmp (exts[e], p)) {
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+ return FALSE;
+}
void
on_playlist_load_activate (GtkMenuItem *menuitem,
@@ -724,13 +774,21 @@ on_playlist_load_activate (GtkMenuItem *menuitem,
GtkWidget *dlg = gtk_file_chooser_dialog_new (_("Load Playlist"), GTK_WINDOW (mainwin), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
// restore folder
- gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str ("filechooser.playlist.lastdir", ""));
+ deadbeef->conf_lock ();
+ gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str_fast ("filechooser.playlist.lastdir", ""));
+ deadbeef->conf_unlock ();
GtkFileFilter* flt;
flt = gtk_file_filter_new ();
- gtk_file_filter_set_name (flt, _("DeaDBeeF playlist files (*.dbpl)"));
+ gtk_file_filter_set_name (flt, "Supported playlist formats");
+ gtk_file_filter_add_custom (flt, GTK_FILE_FILTER_FILENAME, playlist_filter_func, NULL, NULL);
gtk_file_filter_add_pattern (flt, "*.dbpl");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
+ gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dlg), flt);
+ flt = gtk_file_filter_new ();
+ gtk_file_filter_set_name (flt, _("Other files (*)"));
+ gtk_file_filter_add_pattern (flt, "*");
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
int res = gtk_dialog_run (GTK_DIALOG (dlg));
// store folder
@@ -767,7 +825,9 @@ on_add_location_activate (GtkMenuItem *menuitem,
if (entry) {
const char *text = gtk_entry_get_text (entry);
if (text) {
+ deadbeef->pl_add_files_begin (deadbeef->plt_get_curr ());
deadbeef->pl_add_file (text, NULL, NULL);
+ deadbeef->pl_add_files_end ();
playlist_refresh ();
}
}
@@ -867,13 +927,16 @@ gtkui_add_new_playlist (void) {
else {
snprintf (name, sizeof (name), _("New Playlist (%d)"), idx);
}
+ deadbeef->plt_lock ();
for (i = 0; i < cnt; i++) {
char t[100];
- deadbeef->plt_get_title (i, t, sizeof (t));
+ void *plt = deadbeef->plt_get_handle (i);
+ deadbeef->plt_get_title (plt, t, sizeof (t));
if (!strcasecmp (t, name)) {
break;
}
}
+ deadbeef->plt_unlock ();
if (i == cnt) {
return deadbeef->plt_add (cnt, name);
}
@@ -895,12 +958,34 @@ tabstrip_redraw (void) {
}
static int gtk_initialized = 0;
+static gint refresh_timeout = 0;
+
+void
+gtkui_setup_gui_refresh (void) {
+ int fps = deadbeef->conf_get_int ("gtkui.refresh_rate", 10);
+ if (fps < 1) {
+ fps = 1;
+ }
+ else if (fps > 30) {
+ fps = 30;
+ }
+
+ int tm = 1000/fps;
+
+ if (refresh_timeout) {
+ g_source_remove (refresh_timeout);
+ refresh_timeout = 0;
+ }
+
+ refresh_timeout = g_timeout_add (tm, gtkui_on_frameupdate, NULL);
+}
void
gtkui_thread (void *ctx) {
// let's start some gtk
g_thread_init (NULL);
- add_pixmap_directory (PREFIX "/share/deadbeef/pixmaps");
+// add_pixmap_directory (PREFIX "/share/deadbeef/pixmaps");
+ add_pixmap_directory (deadbeef->get_pixmap_dir ());
gdk_threads_init ();
gdk_threads_enter ();
@@ -918,19 +1003,15 @@ gtkui_thread (void *ctx) {
mainwin = create_mainwin ();
gtkpl_init ();
+#if PORTABLE
+ char iconpath[1024];
+ snprintf (iconpath, sizeof (iconpath), "%s/deadbeef.png", deadbeef->get_prefix ());
+ gtk_window_set_icon_from_file (GTK_WINDOW (mainwin), iconpath, NULL);
+#else
gtk_window_set_icon_name (GTK_WINDOW (mainwin), "deadbeef");
+#endif
- {
- int x = deadbeef->conf_get_int ("mainwin.geometry.x", 40);
- int y = deadbeef->conf_get_int ("mainwin.geometry.y", 40);
- int w = deadbeef->conf_get_int ("mainwin.geometry.w", 500);
- int h = deadbeef->conf_get_int ("mainwin.geometry.h", 300);
- gtk_window_move (GTK_WINDOW (mainwin), x, y);
- gtk_window_resize (GTK_WINDOW (mainwin), w, h);
- if (deadbeef->conf_get_int ("mainwin.geometry.maximized", 0)) {
- gtk_window_maximize (GTK_WINDOW (mainwin));
- }
- }
+ wingeom_restore (mainwin, "mainwin", 40, 40, 500, 300, 0);
gtkui_on_configchanged (NULL, 0);
gtkui_init_theme_colors ();
@@ -984,14 +1065,17 @@ gtkui_thread (void *ctx) {
deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_TRACKINFOCHANGED, DB_CALLBACK (gtkui_on_trackinfochanged), 0);
deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_PAUSED, DB_CALLBACK (gtkui_on_paused), 0);
deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_PLAYLISTCHANGED, DB_CALLBACK (gtkui_on_playlistchanged), 0);
- deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_FRAMEUPDATE, DB_CALLBACK (gtkui_on_frameupdate), 0);
deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_VOLUMECHANGED, DB_CALLBACK (gtkui_on_volumechanged), 0);
deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_CONFIGCHANGED, DB_CALLBACK (gtkui_on_configchanged), 0);
deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_OUTPUTCHANGED, DB_CALLBACK (gtkui_on_outputchanged), 0);
deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_PLAYLISTSWITCH, DB_CALLBACK (gtkui_on_playlistswitch), 0);
+ gtkui_setup_gui_refresh ();
+
+ char fmt[500];
char str[600];
- deadbeef->pl_format_title (NULL, -1, str, sizeof (str), -1, deadbeef->conf_get_str ("gtkui.titlebar_stopped", "DeaDBeeF-%V"));
+ deadbeef->conf_get_str ("gtkui.titlebar_stopped", "DeaDBeeF-%V", fmt, sizeof (fmt));
+ deadbeef->pl_format_title (NULL, -1, str, sizeof (str), -1, fmt);
gtk_window_set_title (GTK_WINDOW (mainwin), str);
gtk_initialized = 1;
@@ -1024,7 +1108,7 @@ gtkui_set_progress_text_idle (gpointer data) {
gboolean
gtkui_progress_hide_idle (gpointer data) {
progress_hide ();
- deadbeef->sendmessage (M_PLAYLISTREFRESH, 0, 0, 0);
+ deadbeef->sendmessage (M_PLAYLIST_REFRESH, 0, 0, 0);
//playlist_refresh ();
return FALSE;
}
@@ -1034,13 +1118,13 @@ gtkui_add_file_info_cb (DB_playItem_t *it, void *data) {
if (progress_is_aborted ()) {
return -1;
}
- g_idle_add (gtkui_set_progress_text_idle, it->fname);
+ g_idle_add (gtkui_set_progress_text_idle, (gpointer)deadbeef->pl_find_meta (it, ":URI"));
return 0;
}
int (*gtkui_original_pl_add_dir) (const char *dirname, int (*cb)(DB_playItem_t *it, void *data), void *user_data);
int (*gtkui_original_pl_add_file) (const char *fname, int (*cb)(DB_playItem_t *it, void *data), void *user_data);
-void (*gtkui_original_pl_add_files_begin) (void);
+void (*gtkui_original_pl_add_files_begin) (int plt);
void (*gtkui_original_pl_add_files_end) (void);
int
@@ -1056,9 +1140,9 @@ gtkui_pl_add_file (const char *filename, int (*cb)(DB_playItem_t *it, void *data
}
void
-gtkui_pl_add_files_begin (void) {
+gtkui_pl_add_files_begin (int plt) {
g_idle_add (gtkui_progress_show_idle, NULL);
- gtkui_original_pl_add_files_begin ();
+ gtkui_original_pl_add_files_begin (plt);
}
void
@@ -1093,6 +1177,8 @@ gtkui_playlist_set_curr (int playlist) {
static int
gtkui_start (void) {
+ fprintf (stderr, "gtkui plugin compiled for gtk version: %d.%d.%d\n", GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION);
+
// gtk must be running in separate thread
gtk_initialized = 0;
gtk_tid = deadbeef->thread_start (gtkui_thread, NULL);
@@ -1117,11 +1203,13 @@ gtkui_start (void) {
return 0;
}
+static DB_plugin_t *supereq_plugin;
+
gboolean
gtkui_connect_cb (void *none) {
// equalizer
GtkWidget *eq_mi = lookup_widget (mainwin, "view_eq");
- if (!get_supereq_plugin ()) {
+ if (!supereq_plugin) {
gtk_widget_hide (GTK_WIDGET (eq_mi));
}
else {
@@ -1138,17 +1226,19 @@ gtkui_connect_cb (void *none) {
DB_plugin_t **plugins = deadbeef->plug_get_list ();
for (int i = 0; plugins[i]; i++) {
DB_plugin_t *p = plugins[i];
- if (p->id && !strcmp (p->id, "cover_loader")) {
+ if (p->id && !strcmp (p->id, "artwork")) {
trace ("gtkui: found cover-art loader plugin\n");
coverart_plugin = (DB_artwork_plugin_t *)p;
break;
}
}
+ gtkui_playlist_changed ();
return FALSE;
}
static int
gtkui_connect (void) {
+ supereq_plugin = deadbeef->plug_get_for_id ("supereq");
// need to do it in gtk thread
g_idle_add (gtkui_connect_cb, NULL);
@@ -1174,7 +1264,6 @@ gtkui_stop (void) {
deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_TRACKINFOCHANGED, DB_CALLBACK (gtkui_on_trackinfochanged), 0);
deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_PAUSED, DB_CALLBACK (gtkui_on_paused), 0);
deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_PLAYLISTCHANGED, DB_CALLBACK (gtkui_on_playlistchanged), 0);
- deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_FRAMEUPDATE, DB_CALLBACK (gtkui_on_frameupdate), 0);
deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_VOLUMECHANGED, DB_CALLBACK (gtkui_on_volumechanged), 0);
deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_CONFIGCHANGED, DB_CALLBACK (gtkui_on_configchanged), 0);
deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_OUTPUTCHANGED, DB_CALLBACK (gtkui_on_outputchanged), 0);
@@ -1190,8 +1279,13 @@ gtkui_stop (void) {
return 0;
}
+GtkWidget *
+gtkui_get_mainwin (void) {
+ return mainwin;
+}
+
DB_plugin_t *
-gtkui_load (DB_functions_t *api) {
+ddb_gui_GTK2_load (DB_functions_t *api) {
deadbeef = api;
return DB_PLUGIN (&plugin);
}
@@ -1205,19 +1299,37 @@ static const char settings_dlg[] =
;
// define plugin interface
-static DB_gui_t plugin = {
- DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
- .plugin.nostop = 1,
- .plugin.type = DB_PLUGIN_MISC,
- .plugin.name = "Standard GTK2 user interface",
- .plugin.descr = "Default DeaDBeeF GUI",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
- .plugin.website = "http://deadbeef.sf.net",
- .plugin.start = gtkui_start,
- .plugin.stop = gtkui_stop,
- .plugin.connect = gtkui_connect,
- .plugin.configdialog = settings_dlg,
+static ddb_gtkui_t plugin = {
+ .gui.plugin.api_vmajor = DB_API_VERSION_MAJOR,
+ .gui.plugin.api_vminor = DB_API_VERSION_MINOR,
+ .gui.plugin.version_major = 1,
+ .gui.plugin.version_minor = 0,
+ .gui.plugin.type = DB_PLUGIN_MISC,
+ .gui.plugin.id = "gtkui",
+ .gui.plugin.name = "Standard GTK2 user interface",
+ .gui.plugin.descr = "Default DeaDBeeF GUI",
+ .gui.plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
+ .gui.plugin.website = "http://deadbeef.sf.net",
+ .gui.plugin.start = gtkui_start,
+ .gui.plugin.stop = gtkui_stop,
+ .gui.plugin.connect = gtkui_connect,
+ .gui.plugin.configdialog = settings_dlg,
+ .gui.run_dialog = gtkui_run_dialog_root,
+ .get_mainwin = gtkui_get_mainwin,
};
diff --git a/plugins/gtkui/gtkui.h b/plugins/gtkui/gtkui.h
index 53db09af..4074ddb2 100644
--- a/plugins/gtkui/gtkui.h
+++ b/plugins/gtkui/gtkui.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -25,12 +25,20 @@
#include <gtk/gtk.h>
+#ifdef HAVE_CONFIG_H
+#include "../../config.h"
+#endif
+
+#if defined(ULTRA_COMPATIBLE)
+#warning compiling for compatibility with gtk <2.14
+#endif
+
// workaround to make older gtk compatible with vala codegen
-#if !GTK_CHECK_VERSION(2,14,0)
+#if !GTK_CHECK_VERSION(2,14,0) || defined(ULTRA_COMPATIBLE)
#define gtk_widget_get_window(widget) ((widget)->window)
#endif
-#if !GTK_CHECK_VERSION(2,18,0)
+#if !GTK_CHECK_VERSION(2,18,0) || defined(ULTRA_COMPATIBLE)
#define gtk_widget_set_has_window(widget, has_window) \
if (has_window) GTK_WIDGET_UNSET_FLAGS (widget, GTK_NO_WINDOW); \
else GTK_WIDGET_SET_FLAGS (widget, GTK_NO_WINDOW);
@@ -39,7 +47,7 @@
#define gtk_widget_get_has_window(widget) (!GTK_WIDGET_NO_WINDOW(widget))
#endif
-#if !GTK_CHECK_VERSION(2,20,0)
+#if !GTK_CHECK_VERSION(2,20,0) || defined(ULTRA_COMPATIBLE)
#define gtk_widget_get_realized(widget) (GTK_WIDGET_REALIZED(widget))
#endif
@@ -66,11 +74,6 @@ gtkui_open_files (struct _GSList *lst);
void
gtkui_receive_fm_drop (DB_playItem_t *before, char *mem, int length);
-// plugin configuration dialogs
-
-void
-plugin_configure (GtkWidget *parentwin, DB_plugin_t *p);
-
void
preferences_fill_soundcards (void);
@@ -160,4 +163,7 @@ gtkui_focus_on_playing_track (void);
void
gtkui_playlist_set_curr (int playlist);
+void
+gtkui_setup_gui_refresh ();
+
#endif
diff --git a/plugins/gtkui/gtkui_api.h b/plugins/gtkui/gtkui_api.h
new file mode 100644
index 00000000..596aeb17
--- /dev/null
+++ b/plugins/gtkui/gtkui_api.h
@@ -0,0 +1,28 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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.
+*/
+
+#ifndef __GTKUI_API_H
+#define __GTKUI_API_H
+
+typedef struct {
+ DB_gui_t gui;
+ GtkWidget * (*get_mainwin) (void);
+} ddb_gtkui_t;
+
+#endif
diff --git a/plugins/gtkui/interface.c b/plugins/gtkui/interface.c
index 1b255c52..5d3dde1a 100644
--- a/plugins/gtkui/interface.c
+++ b/plugins/gtkui/interface.c
@@ -35,12 +35,12 @@ create_mainwin (void)
GtkWidget *File;
GtkWidget *File_menu;
GtkWidget *open;
- GtkWidget *image452;
+ GtkWidget *image512;
GtkWidget *separator2;
GtkWidget *add_files;
- GtkWidget *image453;
+ GtkWidget *image513;
GtkWidget *add_folders;
- GtkWidget *image454;
+ GtkWidget *image514;
GtkWidget *add_location1;
GtkWidget *separatormenuitem1;
GtkWidget *new_playlist1;
@@ -49,20 +49,26 @@ create_mainwin (void)
GtkWidget *playlist_save_as;
GtkWidget *separator8;
GtkWidget *quit;
- GtkWidget *image455;
+ GtkWidget *image515;
GtkWidget *Edit;
GtkWidget *Edit_menu;
GtkWidget *clear1;
- GtkWidget *image456;
+ GtkWidget *image516;
GtkWidget *select_all1;
GtkWidget *deselect_all1;
GtkWidget *invert_selection1;
GtkWidget *Selection;
GtkWidget *Selection_menu;
GtkWidget *remove1;
- GtkWidget *image457;
+ GtkWidget *image517;
GtkWidget *crop1;
GtkWidget *find1;
+ GtkWidget *sort_by1;
+ GtkWidget *sort_by1_menu;
+ GtkWidget *album1;
+ GtkWidget *artist1;
+ GtkWidget *date1;
+ GtkWidget *custom2;
GtkWidget *separator5;
GtkWidget *preferences;
GtkWidget *View;
@@ -78,6 +84,7 @@ create_mainwin (void)
GSList *order_linear_group = NULL;
GtkWidget *order_linear;
GtkWidget *order_shuffle;
+ GtkWidget *order_shuffle_albums;
GtkWidget *order_random;
GtkWidget *Looping;
GtkWidget *Looping_menu;
@@ -93,16 +100,16 @@ create_mainwin (void)
GtkWidget *Help;
GtkWidget *Help_menu;
GtkWidget *help1;
- GtkWidget *image458;
+ GtkWidget *image518;
GtkWidget *changelog1;
GtkWidget *separator10;
GtkWidget *gpl1;
GtkWidget *lgpl1;
GtkWidget *separator9;
GtkWidget *about1;
- GtkWidget *image459;
+ GtkWidget *image519;
GtkWidget *translators1;
- GtkWidget *image460;
+ GtkWidget *image520;
GtkWidget *hbox2;
GtkWidget *hbox3;
GtkWidget *stopbtn;
@@ -153,9 +160,9 @@ create_mainwin (void)
GDK_O, (GdkModifierType) GDK_CONTROL_MASK,
GTK_ACCEL_VISIBLE);
- image452 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image452);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (open), image452);
+ image512 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image512);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (open), image512);
separator2 = gtk_separator_menu_item_new ();
gtk_widget_show (separator2);
@@ -166,17 +173,17 @@ create_mainwin (void)
gtk_widget_show (add_files);
gtk_container_add (GTK_CONTAINER (File_menu), add_files);
- image453 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image453);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_files), image453);
+ image513 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image513);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_files), image513);
add_folders = gtk_image_menu_item_new_with_mnemonic (_("Add folder(s)"));
gtk_widget_show (add_folders);
gtk_container_add (GTK_CONTAINER (File_menu), add_folders);
- image454 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image454);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_folders), image454);
+ image514 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image514);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_folders), image514);
add_location1 = gtk_menu_item_new_with_mnemonic (_("Add location"));
gtk_widget_show (add_location1);
@@ -218,9 +225,9 @@ create_mainwin (void)
GDK_Q, (GdkModifierType) GDK_CONTROL_MASK,
GTK_ACCEL_VISIBLE);
- image455 = gtk_image_new_from_stock ("gtk-quit", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image455);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (quit), image455);
+ image515 = gtk_image_new_from_stock ("gtk-quit", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image515);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (quit), image515);
Edit = gtk_menu_item_new_with_mnemonic (_("_Edit"));
gtk_widget_show (Edit);
@@ -233,9 +240,9 @@ create_mainwin (void)
gtk_widget_show (clear1);
gtk_container_add (GTK_CONTAINER (Edit_menu), clear1);
- image456 = gtk_image_new_from_stock ("gtk-clear", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image456);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (clear1), image456);
+ image516 = gtk_image_new_from_stock ("gtk-clear", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image516);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (clear1), image516);
select_all1 = gtk_menu_item_new_with_mnemonic (_("Select all"));
gtk_widget_show (select_all1);
@@ -266,9 +273,9 @@ create_mainwin (void)
gtk_widget_show (remove1);
gtk_container_add (GTK_CONTAINER (Selection_menu), remove1);
- image457 = gtk_image_new_from_stock ("gtk-remove", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image457);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (remove1), image457);
+ image517 = gtk_image_new_from_stock ("gtk-remove", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image517);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (remove1), image517);
crop1 = gtk_menu_item_new_with_mnemonic (_("Crop"));
gtk_widget_show (crop1);
@@ -281,6 +288,29 @@ create_mainwin (void)
GDK_F, (GdkModifierType) GDK_CONTROL_MASK,
GTK_ACCEL_VISIBLE);
+ sort_by1 = gtk_menu_item_new_with_mnemonic (_("Sort By"));
+ gtk_widget_show (sort_by1);
+ gtk_container_add (GTK_CONTAINER (Edit_menu), sort_by1);
+
+ sort_by1_menu = gtk_menu_new ();
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (sort_by1), sort_by1_menu);
+
+ album1 = gtk_menu_item_new_with_mnemonic (_("Album"));
+ gtk_widget_show (album1);
+ gtk_container_add (GTK_CONTAINER (sort_by1_menu), album1);
+
+ artist1 = gtk_menu_item_new_with_mnemonic (_("Artist"));
+ gtk_widget_show (artist1);
+ gtk_container_add (GTK_CONTAINER (sort_by1_menu), artist1);
+
+ date1 = gtk_menu_item_new_with_mnemonic (_("Date"));
+ gtk_widget_show (date1);
+ gtk_container_add (GTK_CONTAINER (sort_by1_menu), date1);
+
+ custom2 = gtk_menu_item_new_with_mnemonic (_("Custom"));
+ gtk_widget_show (custom2);
+ gtk_container_add (GTK_CONTAINER (sort_by1_menu), custom2);
+
separator5 = gtk_separator_menu_item_new ();
gtk_widget_show (separator5);
gtk_container_add (GTK_CONTAINER (Edit_menu), separator5);
@@ -333,12 +363,18 @@ create_mainwin (void)
gtk_container_add (GTK_CONTAINER (Order_menu), order_linear);
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (order_linear), TRUE);
- order_shuffle = gtk_radio_menu_item_new_with_mnemonic (order_linear_group, _("Shuffle"));
+ order_shuffle = gtk_radio_menu_item_new_with_mnemonic (order_linear_group, _("Shuffle tracks"));
order_linear_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (order_shuffle));
gtk_widget_show (order_shuffle);
gtk_container_add (GTK_CONTAINER (Order_menu), order_shuffle);
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (order_shuffle), TRUE);
+ order_shuffle_albums = gtk_radio_menu_item_new_with_mnemonic (order_linear_group, _("Shuffle albums"));
+ order_linear_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (order_shuffle_albums));
+ gtk_widget_show (order_shuffle_albums);
+ gtk_container_add (GTK_CONTAINER (Order_menu), order_shuffle_albums);
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (order_shuffle_albums), TRUE);
+
order_random = gtk_radio_menu_item_new_with_mnemonic (order_linear_group, _("Random"));
order_linear_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (order_random));
gtk_widget_show (order_random);
@@ -409,9 +445,9 @@ create_mainwin (void)
gtk_widget_show (help1);
gtk_container_add (GTK_CONTAINER (Help_menu), help1);
- image458 = gtk_image_new_from_stock ("gtk-help", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image458);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (help1), image458);
+ image518 = gtk_image_new_from_stock ("gtk-help", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image518);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (help1), image518);
changelog1 = gtk_menu_item_new_with_mnemonic (_("_ChangeLog"));
gtk_widget_show (changelog1);
@@ -439,17 +475,17 @@ create_mainwin (void)
gtk_widget_show (about1);
gtk_container_add (GTK_CONTAINER (Help_menu), about1);
- image459 = gtk_image_new_from_stock ("gtk-about", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image459);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (about1), image459);
+ image519 = gtk_image_new_from_stock ("gtk-about", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image519);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (about1), image519);
translators1 = gtk_image_menu_item_new_with_mnemonic (_("_Translators"));
gtk_widget_show (translators1);
gtk_container_add (GTK_CONTAINER (Help_menu), translators1);
- image460 = gtk_image_new_from_stock ("gtk-about", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image460);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (translators1), image460);
+ image520 = gtk_image_new_from_stock ("gtk-about", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image520);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (translators1), image520);
hbox2 = gtk_hbox_new (FALSE, 0);
gtk_widget_show (hbox2);
@@ -645,6 +681,18 @@ create_mainwin (void)
g_signal_connect ((gpointer) find1, "activate",
G_CALLBACK (on_find_activate),
NULL);
+ g_signal_connect ((gpointer) album1, "activate",
+ G_CALLBACK (on_album1_activate),
+ NULL);
+ g_signal_connect ((gpointer) artist1, "activate",
+ G_CALLBACK (on_artist1_activate),
+ NULL);
+ g_signal_connect ((gpointer) date1, "activate",
+ G_CALLBACK (on_date1_activate),
+ NULL);
+ g_signal_connect ((gpointer) custom2, "activate",
+ G_CALLBACK (on_custom2_activate),
+ NULL);
g_signal_connect ((gpointer) preferences, "activate",
G_CALLBACK (on_preferences_activate),
NULL);
@@ -666,6 +714,9 @@ create_mainwin (void)
g_signal_connect ((gpointer) order_shuffle, "activate",
G_CALLBACK (on_order_shuffle_activate),
NULL);
+ g_signal_connect ((gpointer) order_shuffle_albums, "activate",
+ G_CALLBACK (on_order_shuffle_albums_activate),
+ NULL);
g_signal_connect ((gpointer) order_random, "activate",
G_CALLBACK (on_order_random_activate),
NULL);
@@ -731,12 +782,12 @@ create_mainwin (void)
GLADE_HOOKUP_OBJECT (mainwin, File, "File");
GLADE_HOOKUP_OBJECT (mainwin, File_menu, "File_menu");
GLADE_HOOKUP_OBJECT (mainwin, open, "open");
- GLADE_HOOKUP_OBJECT (mainwin, image452, "image452");
+ GLADE_HOOKUP_OBJECT (mainwin, image512, "image512");
GLADE_HOOKUP_OBJECT (mainwin, separator2, "separator2");
GLADE_HOOKUP_OBJECT (mainwin, add_files, "add_files");
- GLADE_HOOKUP_OBJECT (mainwin, image453, "image453");
+ GLADE_HOOKUP_OBJECT (mainwin, image513, "image513");
GLADE_HOOKUP_OBJECT (mainwin, add_folders, "add_folders");
- GLADE_HOOKUP_OBJECT (mainwin, image454, "image454");
+ GLADE_HOOKUP_OBJECT (mainwin, image514, "image514");
GLADE_HOOKUP_OBJECT (mainwin, add_location1, "add_location1");
GLADE_HOOKUP_OBJECT (mainwin, separatormenuitem1, "separatormenuitem1");
GLADE_HOOKUP_OBJECT (mainwin, new_playlist1, "new_playlist1");
@@ -745,20 +796,26 @@ create_mainwin (void)
GLADE_HOOKUP_OBJECT (mainwin, playlist_save_as, "playlist_save_as");
GLADE_HOOKUP_OBJECT (mainwin, separator8, "separator8");
GLADE_HOOKUP_OBJECT (mainwin, quit, "quit");
- GLADE_HOOKUP_OBJECT (mainwin, image455, "image455");
+ GLADE_HOOKUP_OBJECT (mainwin, image515, "image515");
GLADE_HOOKUP_OBJECT (mainwin, Edit, "Edit");
GLADE_HOOKUP_OBJECT (mainwin, Edit_menu, "Edit_menu");
GLADE_HOOKUP_OBJECT (mainwin, clear1, "clear1");
- GLADE_HOOKUP_OBJECT (mainwin, image456, "image456");
+ GLADE_HOOKUP_OBJECT (mainwin, image516, "image516");
GLADE_HOOKUP_OBJECT (mainwin, select_all1, "select_all1");
GLADE_HOOKUP_OBJECT (mainwin, deselect_all1, "deselect_all1");
GLADE_HOOKUP_OBJECT (mainwin, invert_selection1, "invert_selection1");
GLADE_HOOKUP_OBJECT (mainwin, Selection, "Selection");
GLADE_HOOKUP_OBJECT (mainwin, Selection_menu, "Selection_menu");
GLADE_HOOKUP_OBJECT (mainwin, remove1, "remove1");
- GLADE_HOOKUP_OBJECT (mainwin, image457, "image457");
+ GLADE_HOOKUP_OBJECT (mainwin, image517, "image517");
GLADE_HOOKUP_OBJECT (mainwin, crop1, "crop1");
GLADE_HOOKUP_OBJECT (mainwin, find1, "find1");
+ GLADE_HOOKUP_OBJECT (mainwin, sort_by1, "sort_by1");
+ GLADE_HOOKUP_OBJECT (mainwin, sort_by1_menu, "sort_by1_menu");
+ GLADE_HOOKUP_OBJECT (mainwin, album1, "album1");
+ GLADE_HOOKUP_OBJECT (mainwin, artist1, "artist1");
+ GLADE_HOOKUP_OBJECT (mainwin, date1, "date1");
+ GLADE_HOOKUP_OBJECT (mainwin, custom2, "custom2");
GLADE_HOOKUP_OBJECT (mainwin, separator5, "separator5");
GLADE_HOOKUP_OBJECT (mainwin, preferences, "preferences");
GLADE_HOOKUP_OBJECT (mainwin, View, "View");
@@ -773,6 +830,7 @@ create_mainwin (void)
GLADE_HOOKUP_OBJECT (mainwin, Order_menu, "Order_menu");
GLADE_HOOKUP_OBJECT (mainwin, order_linear, "order_linear");
GLADE_HOOKUP_OBJECT (mainwin, order_shuffle, "order_shuffle");
+ GLADE_HOOKUP_OBJECT (mainwin, order_shuffle_albums, "order_shuffle_albums");
GLADE_HOOKUP_OBJECT (mainwin, order_random, "order_random");
GLADE_HOOKUP_OBJECT (mainwin, Looping, "Looping");
GLADE_HOOKUP_OBJECT (mainwin, Looping_menu, "Looping_menu");
@@ -787,16 +845,16 @@ create_mainwin (void)
GLADE_HOOKUP_OBJECT (mainwin, Help, "Help");
GLADE_HOOKUP_OBJECT (mainwin, Help_menu, "Help_menu");
GLADE_HOOKUP_OBJECT (mainwin, help1, "help1");
- GLADE_HOOKUP_OBJECT (mainwin, image458, "image458");
+ GLADE_HOOKUP_OBJECT (mainwin, image518, "image518");
GLADE_HOOKUP_OBJECT (mainwin, changelog1, "changelog1");
GLADE_HOOKUP_OBJECT (mainwin, separator10, "separator10");
GLADE_HOOKUP_OBJECT (mainwin, gpl1, "gpl1");
GLADE_HOOKUP_OBJECT (mainwin, lgpl1, "lgpl1");
GLADE_HOOKUP_OBJECT (mainwin, separator9, "separator9");
GLADE_HOOKUP_OBJECT (mainwin, about1, "about1");
- GLADE_HOOKUP_OBJECT (mainwin, image459, "image459");
+ GLADE_HOOKUP_OBJECT (mainwin, image519, "image519");
GLADE_HOOKUP_OBJECT (mainwin, translators1, "translators1");
- GLADE_HOOKUP_OBJECT (mainwin, image460, "image460");
+ GLADE_HOOKUP_OBJECT (mainwin, image520, "image520");
GLADE_HOOKUP_OBJECT (mainwin, hbox2, "hbox2");
GLADE_HOOKUP_OBJECT (mainwin, hbox3, "hbox3");
GLADE_HOOKUP_OBJECT (mainwin, stopbtn, "stopbtn");
@@ -1027,26 +1085,26 @@ create_traymenu (void)
}
GtkWidget*
-create_addprogress (void)
+create_progressdlg (void)
{
- GtkWidget *addprogress;
+ GtkWidget *progressdlg;
GtkWidget *vbox6;
GtkWidget *progresstitle;
GtkWidget *hbox7;
GtkWidget *label22;
- GtkWidget *button3;
+ GtkWidget *cancelbtn;
- addprogress = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- gtk_container_set_border_width (GTK_CONTAINER (addprogress), 12);
- gtk_window_set_title (GTK_WINDOW (addprogress), _("Adding files..."));
- gtk_window_set_position (GTK_WINDOW (addprogress), GTK_WIN_POS_CENTER_ON_PARENT);
- gtk_window_set_modal (GTK_WINDOW (addprogress), TRUE);
- gtk_window_set_skip_taskbar_hint (GTK_WINDOW (addprogress), TRUE);
- gtk_window_set_skip_pager_hint (GTK_WINDOW (addprogress), TRUE);
+ progressdlg = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_container_set_border_width (GTK_CONTAINER (progressdlg), 12);
+ gtk_window_set_title (GTK_WINDOW (progressdlg), "progressdlg");
+ gtk_window_set_position (GTK_WINDOW (progressdlg), GTK_WIN_POS_CENTER_ON_PARENT);
+ gtk_window_set_modal (GTK_WINDOW (progressdlg), TRUE);
+ gtk_window_set_skip_taskbar_hint (GTK_WINDOW (progressdlg), TRUE);
+ gtk_window_set_skip_pager_hint (GTK_WINDOW (progressdlg), TRUE);
vbox6 = gtk_vbox_new (FALSE, 8);
gtk_widget_show (vbox6);
- gtk_container_add (GTK_CONTAINER (addprogress), vbox6);
+ gtk_container_add (GTK_CONTAINER (progressdlg), vbox6);
progresstitle = gtk_entry_new ();
gtk_widget_show (progresstitle);
@@ -1064,26 +1122,19 @@ create_addprogress (void)
gtk_widget_show (label22);
gtk_box_pack_start (GTK_BOX (hbox7), label22, TRUE, FALSE, 0);
- button3 = gtk_button_new_from_stock ("gtk-cancel");
- gtk_widget_show (button3);
- gtk_box_pack_start (GTK_BOX (hbox7), button3, FALSE, FALSE, 0);
-
- g_signal_connect ((gpointer) addprogress, "delete_event",
- G_CALLBACK (on_addprogress_delete_event),
- NULL);
- g_signal_connect ((gpointer) button3, "clicked",
- G_CALLBACK (on_progress_abort),
- NULL);
+ cancelbtn = gtk_button_new_from_stock ("gtk-cancel");
+ gtk_widget_show (cancelbtn);
+ gtk_box_pack_start (GTK_BOX (hbox7), cancelbtn, FALSE, FALSE, 0);
/* Store pointers to all widgets, for use by lookup_widget(). */
- GLADE_HOOKUP_OBJECT_NO_REF (addprogress, addprogress, "addprogress");
- GLADE_HOOKUP_OBJECT (addprogress, vbox6, "vbox6");
- GLADE_HOOKUP_OBJECT (addprogress, progresstitle, "progresstitle");
- GLADE_HOOKUP_OBJECT (addprogress, hbox7, "hbox7");
- GLADE_HOOKUP_OBJECT (addprogress, label22, "label22");
- GLADE_HOOKUP_OBJECT (addprogress, button3, "button3");
-
- return addprogress;
+ GLADE_HOOKUP_OBJECT_NO_REF (progressdlg, progressdlg, "progressdlg");
+ GLADE_HOOKUP_OBJECT (progressdlg, vbox6, "vbox6");
+ GLADE_HOOKUP_OBJECT (progressdlg, progresstitle, "progresstitle");
+ GLADE_HOOKUP_OBJECT (progressdlg, hbox7, "hbox7");
+ GLADE_HOOKUP_OBJECT (progressdlg, label22, "label22");
+ GLADE_HOOKUP_OBJECT (progressdlg, cancelbtn, "cancelbtn");
+
+ return progressdlg;
}
GtkWidget*
@@ -1135,6 +1186,12 @@ create_trackproperties (void)
GtkWidget *vbox16;
GtkWidget *scrolledwindow5;
GtkWidget *metalist;
+ GtkWidget *hbox98;
+ GtkWidget *settings;
+ GtkWidget *alignment24;
+ GtkWidget *hbox99;
+ GtkWidget *image522;
+ GtkWidget *label123;
GtkWidget *hbuttonbox1;
GtkWidget *write_tags;
GtkWidget *alignment11;
@@ -1161,6 +1218,7 @@ create_trackproperties (void)
trackproperties = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_set_size_request (trackproperties, 400, 400);
gtk_window_set_title (GTK_WINDOW (trackproperties), _("Track Properties"));
+ gtk_window_set_position (GTK_WINDOW (trackproperties), GTK_WIN_POS_MOUSE);
gtk_window_set_skip_taskbar_hint (GTK_WINDOW (trackproperties), TRUE);
gtk_window_set_skip_pager_hint (GTK_WINDOW (trackproperties), TRUE);
@@ -1184,9 +1242,33 @@ create_trackproperties (void)
gtk_container_add (GTK_CONTAINER (scrolledwindow5), metalist);
gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (metalist), TRUE);
+ hbox98 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (hbox98);
+ gtk_box_pack_start (GTK_BOX (vbox16), hbox98, FALSE, FALSE, 0);
+
+ settings = gtk_button_new ();
+ gtk_widget_show (settings);
+ gtk_box_pack_start (GTK_BOX (hbox98), settings, FALSE, FALSE, 0);
+
+ alignment24 = gtk_alignment_new (0.5, 0.5, 0, 0);
+ gtk_widget_show (alignment24);
+ gtk_container_add (GTK_CONTAINER (settings), alignment24);
+
+ hbox99 = gtk_hbox_new (FALSE, 2);
+ gtk_widget_show (hbox99);
+ gtk_container_add (GTK_CONTAINER (alignment24), hbox99);
+
+ image522 = gtk_image_new_from_stock ("gtk-preferences", GTK_ICON_SIZE_BUTTON);
+ gtk_widget_show (image522);
+ gtk_box_pack_start (GTK_BOX (hbox99), image522, FALSE, FALSE, 0);
+
+ label123 = gtk_label_new_with_mnemonic (_("Settings"));
+ gtk_widget_show (label123);
+ gtk_box_pack_start (GTK_BOX (hbox99), label123, FALSE, FALSE, 0);
+
hbuttonbox1 = gtk_hbutton_box_new ();
gtk_widget_show (hbuttonbox1);
- gtk_box_pack_start (GTK_BOX (vbox16), hbuttonbox1, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox98), hbuttonbox1, TRUE, TRUE, 0);
gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_END);
write_tags = gtk_button_new ();
@@ -1287,6 +1369,18 @@ create_trackproperties (void)
g_signal_connect ((gpointer) trackproperties, "delete_event",
G_CALLBACK (on_trackproperties_delete_event),
NULL);
+ g_signal_connect ((gpointer) trackproperties, "configure_event",
+ G_CALLBACK (on_trackproperties_configure_event),
+ NULL);
+ g_signal_connect ((gpointer) trackproperties, "window_state_event",
+ G_CALLBACK (on_trackproperties_window_state_event),
+ NULL);
+ g_signal_connect ((gpointer) metalist, "button_press_event",
+ G_CALLBACK (on_metalist_button_press_event),
+ NULL);
+ g_signal_connect ((gpointer) settings, "clicked",
+ G_CALLBACK (on_tagwriter_settings_clicked),
+ NULL);
g_signal_connect ((gpointer) write_tags, "clicked",
G_CALLBACK (on_write_tags_clicked),
NULL);
@@ -1303,6 +1397,12 @@ create_trackproperties (void)
GLADE_HOOKUP_OBJECT (trackproperties, vbox16, "vbox16");
GLADE_HOOKUP_OBJECT (trackproperties, scrolledwindow5, "scrolledwindow5");
GLADE_HOOKUP_OBJECT (trackproperties, metalist, "metalist");
+ GLADE_HOOKUP_OBJECT (trackproperties, hbox98, "hbox98");
+ GLADE_HOOKUP_OBJECT (trackproperties, settings, "settings");
+ GLADE_HOOKUP_OBJECT (trackproperties, alignment24, "alignment24");
+ GLADE_HOOKUP_OBJECT (trackproperties, hbox99, "hbox99");
+ GLADE_HOOKUP_OBJECT (trackproperties, image522, "image522");
+ GLADE_HOOKUP_OBJECT (trackproperties, label123, "label123");
GLADE_HOOKUP_OBJECT (trackproperties, hbuttonbox1, "hbuttonbox1");
GLADE_HOOKUP_OBJECT (trackproperties, write_tags, "write_tags");
GLADE_HOOKUP_OBJECT (trackproperties, alignment11, "alignment11");
@@ -1343,11 +1443,12 @@ create_editcolumndlg (void)
GtkWidget *id;
GtkWidget *hbox31;
GtkWidget *fmtlabel;
+ GtkWidget *hbox74;
GtkWidget *format;
+ GtkWidget *title_formatting_help_link;
GtkWidget *hbox32;
GtkWidget *label38;
GtkWidget *align;
- GtkWidget *label25;
GtkWidget *dialog_action_area1;
GtkWidget *cancelbutton1;
GtkWidget *alignment9;
@@ -1362,7 +1463,7 @@ create_editcolumndlg (void)
editcolumndlg = gtk_dialog_new ();
gtk_container_set_border_width (GTK_CONTAINER (editcolumndlg), 12);
- gtk_window_set_title (GTK_WINDOW (editcolumndlg), _("editcolumndlg"));
+ gtk_window_set_title (GTK_WINDOW (editcolumndlg), "editcolumndlg");
gtk_window_set_modal (GTK_WINDOW (editcolumndlg), TRUE);
gtk_window_set_type_hint (GTK_WINDOW (editcolumndlg), GDK_WINDOW_TYPE_HINT_DIALOG);
@@ -1408,8 +1509,8 @@ create_editcolumndlg (void)
gtk_combo_box_append_text (GTK_COMBO_BOX (id), _("Artist"));
gtk_combo_box_append_text (GTK_COMBO_BOX (id), _("Album"));
gtk_combo_box_append_text (GTK_COMBO_BOX (id), _("Title"));
- gtk_combo_box_append_text (GTK_COMBO_BOX (id), _("Length"));
- gtk_combo_box_append_text (GTK_COMBO_BOX (id), _("Track"));
+ gtk_combo_box_append_text (GTK_COMBO_BOX (id), _("Duration"));
+ gtk_combo_box_append_text (GTK_COMBO_BOX (id), _("Track No"));
gtk_combo_box_append_text (GTK_COMBO_BOX (id), _("Band / Album Artist"));
gtk_combo_box_append_text (GTK_COMBO_BOX (id), _("Custom"));
@@ -1422,12 +1523,22 @@ create_editcolumndlg (void)
gtk_box_pack_start (GTK_BOX (hbox31), fmtlabel, FALSE, FALSE, 0);
gtk_misc_set_alignment (GTK_MISC (fmtlabel), 0, 0.5);
+ hbox74 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (hbox74);
+ gtk_box_pack_start (GTK_BOX (hbox31), hbox74, TRUE, TRUE, 0);
+
format = gtk_entry_new ();
gtk_widget_show (format);
- gtk_box_pack_start (GTK_BOX (hbox31), format, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox74), format, TRUE, TRUE, 0);
gtk_entry_set_invisible_char (GTK_ENTRY (format), 9679);
gtk_entry_set_activates_default (GTK_ENTRY (format), TRUE);
+ title_formatting_help_link = title_formatting_help_link_create ("title_formatting_help_link", "", "", 0, 0);
+ gtk_widget_show (title_formatting_help_link);
+ gtk_box_pack_start (GTK_BOX (hbox74), title_formatting_help_link, TRUE, TRUE, 0);
+ GTK_WIDGET_UNSET_FLAGS (title_formatting_help_link, GTK_CAN_FOCUS);
+ GTK_WIDGET_UNSET_FLAGS (title_formatting_help_link, GTK_CAN_DEFAULT);
+
hbox32 = gtk_hbox_new (FALSE, 8);
gtk_widget_show (hbox32);
gtk_box_pack_start (GTK_BOX (vbox14), hbox32, FALSE, FALSE, 0);
@@ -1443,14 +1554,6 @@ create_editcolumndlg (void)
gtk_combo_box_append_text (GTK_COMBO_BOX (align), _("Left"));
gtk_combo_box_append_text (GTK_COMBO_BOX (align), _("Right"));
- label25 = gtk_label_new (_("Format conversions (start with %):\n [a]rtist, [t]itle, al[b]um, [B]and, [C]omposer\n track[n]umber, [N]totaltracks,\n [l]ength, [y]ear, [g]enre, [c]omment,\n copy[r]ight, [f]ilename, [F]ullPathname, [T]ags,\n [d]irectory, [D]irectoryWithPath\nExample: %a - %t [%l]"));
- gtk_widget_show (label25);
- gtk_box_pack_start (GTK_BOX (vbox14), label25, TRUE, TRUE, 0);
- GTK_WIDGET_SET_FLAGS (label25, GTK_CAN_FOCUS);
- gtk_label_set_use_markup (GTK_LABEL (label25), TRUE);
- gtk_label_set_selectable (GTK_LABEL (label25), TRUE);
- gtk_misc_set_alignment (GTK_MISC (label25), 0.1, 0.5);
-
dialog_action_area1 = GTK_DIALOG (editcolumndlg)->action_area;
gtk_widget_show (dialog_action_area1);
gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END);
@@ -1513,11 +1616,12 @@ create_editcolumndlg (void)
GLADE_HOOKUP_OBJECT (editcolumndlg, id, "id");
GLADE_HOOKUP_OBJECT (editcolumndlg, hbox31, "hbox31");
GLADE_HOOKUP_OBJECT (editcolumndlg, fmtlabel, "fmtlabel");
+ GLADE_HOOKUP_OBJECT (editcolumndlg, hbox74, "hbox74");
GLADE_HOOKUP_OBJECT (editcolumndlg, format, "format");
+ GLADE_HOOKUP_OBJECT (editcolumndlg, title_formatting_help_link, "title_formatting_help_link");
GLADE_HOOKUP_OBJECT (editcolumndlg, hbox32, "hbox32");
GLADE_HOOKUP_OBJECT (editcolumndlg, label38, "label38");
GLADE_HOOKUP_OBJECT (editcolumndlg, align, "align");
- GLADE_HOOKUP_OBJECT (editcolumndlg, label25, "label25");
GLADE_HOOKUP_OBJECT_NO_REF (editcolumndlg, dialog_action_area1, "dialog_action_area1");
GLADE_HOOKUP_OBJECT (editcolumndlg, cancelbutton1, "cancelbutton1");
GLADE_HOOKUP_OBJECT (editcolumndlg, alignment9, "alignment9");
@@ -1548,31 +1652,57 @@ create_prefwin (void)
GtkWidget *pref_soundcard;
GtkWidget *Sound;
GtkWidget *vbox8;
- GtkWidget *pref_dynsamplerate;
- GtkWidget *hbox9;
- GtkWidget *label6;
- GtkWidget *pref_src_quality;
GtkWidget *hbox10;
GtkWidget *label8;
GtkWidget *pref_replaygain_mode;
GtkWidget *pref_replaygain_scale;
+ GtkWidget *hbox100;
+ GtkWidget *label124;
+ GtkWidget *label125;
+ GtkWidget *replaygain_preamp;
+ GtkWidget *label126;
GtkWidget *hbox66;
GtkWidget *cli_add_to_playlist;
GtkWidget *cli_playlist_name;
GtkWidget *resume_last_session;
+ GtkWidget *ignore_archives;
GtkWidget *label39;
+ GtkWidget *vbox29;
+ GtkWidget *hbox80;
+ GtkWidget *dsp_add;
+ GtkWidget *dsp_remove;
+ GtkWidget *dsp_configure;
+ GtkWidget *hbox81;
+ GtkWidget *scrolledwindow7;
+ GtkWidget *dsp_listview;
+ GtkWidget *vbox30;
+ GtkWidget *dsp_up;
+ GtkWidget *dsp_down;
+ GtkWidget *hbox86;
+ GtkWidget *label114;
+ GtkWidget *dsp_preset;
+ GtkWidget *dsp_preset_save;
+ GtkWidget *dsp_preset_load;
+ GtkWidget *label110;
GtkWidget *vbox9;
GtkWidget *pref_close_send_to_tray;
GtkWidget *mmb_delete_playlist;
GtkWidget *hide_tray_icon;
GtkWidget *embolden_current;
GtkWidget *hide_delete_from_disk;
+ GtkWidget *auto_name_playlist_from_folder;
+ GtkWidget *hbox102;
+ GtkWidget *label129;
+ GtkWidget *gui_fps;
GtkWidget *hbox64;
GtkWidget *label101;
GtkWidget *titlebar_format_playing;
GtkWidget *hbox65;
GtkWidget *label102;
GtkWidget *titlebar_format_stopped;
+ GtkWidget *hbox101;
+ GtkWidget *label128;
+ GtkWidget *gui_plugin;
GtkWidget *label2;
GtkWidget *notebook4;
GtkWidget *vbox21;
@@ -1594,6 +1724,8 @@ create_prefwin (void)
GtkWidget *tabstrip_dark;
GtkWidget *tabstrip_base;
GtkWidget *label76;
+ GtkWidget *label127;
+ GtkWidget *tabstrip_text;
GtkWidget *label74;
GtkWidget *vbox23;
GtkWidget *override_listview_colors;
@@ -1630,82 +1762,32 @@ create_prefwin (void)
GtkWidget *label98;
GtkWidget *proxypassword;
GtkWidget *label16;
- GtkWidget *vbox18;
- GtkWidget *frame5;
- GtkWidget *alignment3;
- GtkWidget *vbox19;
- GtkWidget *hbox38;
- GtkWidget *write_id3v2;
- GtkWidget *write_id3v1;
- GtkWidget *write_apev2;
- GtkWidget *hbox40;
- GtkWidget *strip_id3v2;
- GtkWidget *strip_id3v1;
- GtkWidget *strip_apev2;
- GtkWidget *hbox36;
- GtkWidget *label69;
- GtkWidget *id3v2_version;
- GtkWidget *hbox39;
- GtkWidget *label71;
- GtkWidget *id3v1_encoding;
- GtkWidget *label68;
- GtkWidget *hbox41;
- GtkWidget *frame6;
- GtkWidget *alignment4;
- GtkWidget *vbox20;
- GtkWidget *hbox37;
- GtkWidget *ape_write_id3v2;
- GtkWidget *ape_write_apev2;
- GtkWidget *hbox45;
- GtkWidget *ape_strip_id3v2;
- GtkWidget *ape_strip_apev2;
- GtkWidget *label70;
- GtkWidget *frame7;
- GtkWidget *alignment5;
- GtkWidget *vbox_wv;
- GtkWidget *hbox44;
- GtkWidget *wv_write_apev2;
- GtkWidget *wv_write_id3v1;
- GtkWidget *hbox43;
- GtkWidget *wv_strip_apev2;
- GtkWidget *wv_strip_id3v1;
- GtkWidget *label79;
- GtkWidget *label67;
GtkWidget *hpaned1;
GtkWidget *scrolledwindow2;
GtkWidget *pref_pluginlist;
GtkWidget *vbox12;
- GtkWidget *hbox16;
- GtkWidget *label11;
- GtkWidget *pref_plugin_descr;
- GtkWidget *hbox17;
- GtkWidget *label12;
- GtkWidget *pref_plugin_author;
- GtkWidget *hbox18;
- GtkWidget *label13;
- GtkWidget *pref_plugin_email;
- GtkWidget *hbox19;
- GtkWidget *label14;
- GtkWidget *pref_plugin_website;
+ GtkWidget *scrolledwindow8;
+ GtkWidget *plug_description;
GtkWidget *hbox20;
GtkWidget *configure_plugin;
GtkWidget *alignment15;
GtkWidget *hbox56;
GtkWidget *image394;
GtkWidget *label92;
+ GtkWidget *plug_copyright;
+ GtkWidget *alignment20;
+ GtkWidget *hbox88;
+ GtkWidget *image521;
+ GtkWidget *label117;
+ GtkWidget *weblink;
GtkWidget *label3;
GtkWidget *dialog_action_area2;
GtkWidget *closebutton1;
- GtkWidget *alignment14;
- GtkWidget *hbox55;
- GtkWidget *image393;
- GtkWidget *label91;
prefwin = gtk_dialog_new ();
- gtk_widget_set_size_request (prefwin, 630, 400);
gtk_container_set_border_width (GTK_CONTAINER (prefwin), 12);
gtk_window_set_title (GTK_WINDOW (prefwin), _("Preferences"));
- gtk_window_set_default_size (GTK_WINDOW (prefwin), 630, 400);
+ gtk_window_set_position (GTK_WINDOW (prefwin), GTK_WIN_POS_CENTER);
gtk_window_set_type_hint (GTK_WINDOW (prefwin), GDK_WINDOW_TYPE_HINT_DIALOG);
dialog_vbox2 = GTK_DIALOG (prefwin)->vbox;
@@ -1756,29 +1838,6 @@ create_prefwin (void)
gtk_container_add (GTK_CONTAINER (notebook), vbox8);
gtk_container_set_border_width (GTK_CONTAINER (vbox8), 12);
- pref_dynsamplerate = gtk_check_button_new_with_mnemonic (_("Allow dynamic samplerate switching"));
- gtk_widget_show (pref_dynsamplerate);
- gtk_box_pack_start (GTK_BOX (vbox8), pref_dynsamplerate, FALSE, FALSE, 0);
-
- hbox9 = gtk_hbox_new (FALSE, 8);
- gtk_widget_show (hbox9);
- gtk_box_pack_start (GTK_BOX (vbox8), hbox9, FALSE, FALSE, 0);
-
- label6 = gtk_label_new (_("Samplerate conversion quality:"));
- gtk_widget_show (label6);
- gtk_box_pack_start (GTK_BOX (hbox9), label6, FALSE, FALSE, 0);
- gtk_label_set_justify (GTK_LABEL (label6), GTK_JUSTIFY_RIGHT);
- gtk_misc_set_alignment (GTK_MISC (label6), 0, 0.5);
-
- pref_src_quality = gtk_combo_box_new_text ();
- gtk_widget_show (pref_src_quality);
- gtk_box_pack_start (GTK_BOX (hbox9), pref_src_quality, TRUE, TRUE, 0);
- gtk_combo_box_append_text (GTK_COMBO_BOX (pref_src_quality), "sinc_best_quality");
- gtk_combo_box_append_text (GTK_COMBO_BOX (pref_src_quality), "sinc_medium_quality");
- gtk_combo_box_append_text (GTK_COMBO_BOX (pref_src_quality), "sinc_fastest");
- gtk_combo_box_append_text (GTK_COMBO_BOX (pref_src_quality), "zero_order_hold");
- gtk_combo_box_append_text (GTK_COMBO_BOX (pref_src_quality), "linear");
-
hbox10 = gtk_hbox_new (FALSE, 8);
gtk_widget_show (hbox10);
gtk_box_pack_start (GTK_BOX (vbox8), hbox10, FALSE, FALSE, 0);
@@ -1800,6 +1859,28 @@ create_prefwin (void)
gtk_widget_show (pref_replaygain_scale);
gtk_box_pack_start (GTK_BOX (vbox8), pref_replaygain_scale, FALSE, FALSE, 0);
+ hbox100 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox100);
+ gtk_box_pack_start (GTK_BOX (vbox8), hbox100, FALSE, FALSE, 0);
+
+ label124 = gtk_label_new (_("Replaygain preamp:"));
+ gtk_widget_show (label124);
+ gtk_box_pack_start (GTK_BOX (hbox100), label124, FALSE, FALSE, 0);
+
+ label125 = gtk_label_new (_("-12 dB"));
+ gtk_widget_show (label125);
+ gtk_box_pack_start (GTK_BOX (hbox100), label125, FALSE, FALSE, 0);
+
+ replaygain_preamp = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, -12, 12, 0, 0, 0)));
+ gtk_widget_show (replaygain_preamp);
+ gtk_box_pack_start (GTK_BOX (hbox100), replaygain_preamp, TRUE, TRUE, 0);
+ gtk_scale_set_value_pos (GTK_SCALE (replaygain_preamp), GTK_POS_BOTTOM);
+ gtk_scale_set_digits (GTK_SCALE (replaygain_preamp), 0);
+
+ label126 = gtk_label_new (_("+12 dB"));
+ gtk_widget_show (label126);
+ gtk_box_pack_start (GTK_BOX (hbox100), label126, FALSE, FALSE, 0);
+
hbox66 = gtk_hbox_new (FALSE, 8);
gtk_widget_show (hbox66);
gtk_box_pack_start (GTK_BOX (vbox8), hbox66, FALSE, FALSE, 0);
@@ -1817,10 +1898,86 @@ create_prefwin (void)
gtk_widget_show (resume_last_session);
gtk_box_pack_start (GTK_BOX (vbox8), resume_last_session, FALSE, FALSE, 0);
+ ignore_archives = gtk_check_button_new_with_mnemonic (_("Don't add from archives when adding folders"));
+ gtk_widget_show (ignore_archives);
+ gtk_box_pack_start (GTK_BOX (vbox8), ignore_archives, FALSE, FALSE, 0);
+
label39 = gtk_label_new (_("Playback"));
gtk_widget_show (label39);
gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 1), label39);
+ vbox29 = gtk_vbox_new (FALSE, 8);
+ gtk_widget_show (vbox29);
+ gtk_container_add (GTK_CONTAINER (notebook), vbox29);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox29), 12);
+
+ hbox80 = gtk_hbox_new (TRUE, 8);
+ gtk_widget_show (hbox80);
+ gtk_box_pack_start (GTK_BOX (vbox29), hbox80, FALSE, TRUE, 0);
+
+ dsp_add = gtk_button_new_from_stock ("gtk-add");
+ gtk_widget_show (dsp_add);
+ gtk_box_pack_start (GTK_BOX (hbox80), dsp_add, FALSE, TRUE, 0);
+
+ dsp_remove = gtk_button_new_from_stock ("gtk-remove");
+ gtk_widget_show (dsp_remove);
+ gtk_box_pack_start (GTK_BOX (hbox80), dsp_remove, FALSE, TRUE, 0);
+
+ dsp_configure = gtk_button_new_with_mnemonic (_("Configure"));
+ gtk_widget_show (dsp_configure);
+ gtk_box_pack_start (GTK_BOX (hbox80), dsp_configure, FALSE, TRUE, 0);
+
+ hbox81 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox81);
+ gtk_box_pack_start (GTK_BOX (vbox29), hbox81, TRUE, TRUE, 0);
+
+ scrolledwindow7 = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_show (scrolledwindow7);
+ gtk_box_pack_start (GTK_BOX (hbox81), scrolledwindow7, TRUE, TRUE, 0);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow7), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow7), GTK_SHADOW_IN);
+
+ dsp_listview = gtk_tree_view_new ();
+ gtk_widget_show (dsp_listview);
+ gtk_container_add (GTK_CONTAINER (scrolledwindow7), dsp_listview);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (dsp_listview), FALSE);
+
+ vbox30 = gtk_vbox_new (FALSE, 8);
+ gtk_widget_show (vbox30);
+ gtk_box_pack_start (GTK_BOX (hbox81), vbox30, FALSE, TRUE, 0);
+
+ dsp_up = gtk_button_new_from_stock ("gtk-go-up");
+ gtk_widget_show (dsp_up);
+ gtk_box_pack_start (GTK_BOX (vbox30), dsp_up, FALSE, FALSE, 0);
+
+ dsp_down = gtk_button_new_from_stock ("gtk-go-down");
+ gtk_widget_show (dsp_down);
+ gtk_box_pack_start (GTK_BOX (vbox30), dsp_down, FALSE, FALSE, 0);
+
+ hbox86 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox86);
+ gtk_box_pack_start (GTK_BOX (vbox29), hbox86, FALSE, TRUE, 0);
+
+ label114 = gtk_label_new (_("DSP Chain Preset"));
+ gtk_widget_show (label114);
+ gtk_box_pack_start (GTK_BOX (hbox86), label114, FALSE, FALSE, 0);
+
+ dsp_preset = gtk_combo_box_entry_new_text ();
+ gtk_widget_show (dsp_preset);
+ gtk_box_pack_start (GTK_BOX (hbox86), dsp_preset, FALSE, TRUE, 0);
+
+ dsp_preset_save = gtk_button_new_from_stock ("gtk-save");
+ gtk_widget_show (dsp_preset_save);
+ gtk_box_pack_start (GTK_BOX (hbox86), dsp_preset_save, FALSE, FALSE, 0);
+
+ dsp_preset_load = gtk_button_new_with_mnemonic (_("_Load"));
+ gtk_widget_show (dsp_preset_load);
+ gtk_box_pack_start (GTK_BOX (hbox86), dsp_preset_load, FALSE, FALSE, 0);
+
+ label110 = gtk_label_new (_("DSP"));
+ gtk_widget_show (label110);
+ gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 2), label110);
+
vbox9 = gtk_vbox_new (FALSE, 8);
gtk_widget_show (vbox9);
gtk_container_add (GTK_CONTAINER (notebook), vbox9);
@@ -1846,6 +2003,24 @@ create_prefwin (void)
gtk_widget_show (hide_delete_from_disk);
gtk_box_pack_start (GTK_BOX (vbox9), hide_delete_from_disk, FALSE, FALSE, 0);
+ auto_name_playlist_from_folder = gtk_check_button_new_with_mnemonic (_("Auto-name playlists when adding a single folder"));
+ gtk_widget_show (auto_name_playlist_from_folder);
+ gtk_box_pack_start (GTK_BOX (vbox9), auto_name_playlist_from_folder, FALSE, FALSE, 0);
+
+ hbox102 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox102);
+ gtk_box_pack_start (GTK_BOX (vbox9), hbox102, FALSE, FALSE, 0);
+
+ label129 = gtk_label_new (_("Interface refresh rate (times per second):"));
+ gtk_widget_show (label129);
+ gtk_box_pack_start (GTK_BOX (hbox102), label129, FALSE, FALSE, 0);
+
+ gui_fps = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (10, 1, 30, 0, 0, 0)));
+ gtk_widget_show (gui_fps);
+ gtk_box_pack_start (GTK_BOX (hbox102), gui_fps, TRUE, TRUE, 0);
+ gtk_scale_set_value_pos (GTK_SCALE (gui_fps), GTK_POS_RIGHT);
+ gtk_scale_set_digits (GTK_SCALE (gui_fps), 0);
+
hbox64 = gtk_hbox_new (FALSE, 8);
gtk_widget_show (hbox64);
gtk_box_pack_start (GTK_BOX (vbox9), hbox64, FALSE, FALSE, 0);
@@ -1874,9 +2049,21 @@ create_prefwin (void)
gtk_box_pack_start (GTK_BOX (hbox65), titlebar_format_stopped, TRUE, TRUE, 0);
gtk_entry_set_invisible_char (GTK_ENTRY (titlebar_format_stopped), 8226);
+ hbox101 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox101);
+ gtk_box_pack_start (GTK_BOX (vbox9), hbox101, FALSE, FALSE, 0);
+
+ label128 = gtk_label_new (_("GUI Plugin (changing requires restart):"));
+ gtk_widget_show (label128);
+ gtk_box_pack_start (GTK_BOX (hbox101), label128, FALSE, FALSE, 0);
+
+ gui_plugin = gtk_combo_box_new_text ();
+ gtk_widget_show (gui_plugin);
+ gtk_box_pack_start (GTK_BOX (hbox101), gui_plugin, TRUE, TRUE, 0);
+
label2 = gtk_label_new (_("GUI"));
gtk_widget_show (label2);
- gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 2), label2);
+ gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 3), label2);
notebook4 = gtk_notebook_new ();
gtk_widget_show (notebook4);
@@ -1937,7 +2124,7 @@ create_prefwin (void)
gtk_widget_show (override_tabstrip_colors);
gtk_box_pack_start (GTK_BOX (vbox22), override_tabstrip_colors, FALSE, FALSE, 0);
- tabstrip_colors_group = gtk_table_new (2, 4, TRUE);
+ tabstrip_colors_group = gtk_table_new (2, 5, TRUE);
gtk_widget_show (tabstrip_colors_group);
gtk_box_pack_start (GTK_BOX (vbox22), tabstrip_colors_group, TRUE, TRUE, 0);
gtk_table_set_col_spacings (GTK_TABLE (tabstrip_colors_group), 8);
@@ -1994,6 +2181,19 @@ create_prefwin (void)
(GtkAttachOptions) (0), 0, 0);
gtk_misc_set_alignment (GTK_MISC (label76), 0, 0.5);
+ label127 = gtk_label_new (_("Text"));
+ gtk_widget_show (label127);
+ gtk_table_attach (GTK_TABLE (tabstrip_colors_group), label127, 4, 5, 0, 1,
+ (GtkAttachOptions) (GTK_EXPAND),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (label127), 0, 0.5);
+
+ tabstrip_text = gtk_color_button_new ();
+ gtk_widget_show (tabstrip_text);
+ gtk_table_attach (GTK_TABLE (tabstrip_colors_group), tabstrip_text, 4, 5, 1, 2,
+ (GtkAttachOptions) (GTK_EXPAND),
+ (GtkAttachOptions) (0), 0, 0);
+
label74 = gtk_label_new (_("Tab strip colors"));
gtk_widget_show (label74);
gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook4), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook4), 1), label74);
@@ -2096,7 +2296,7 @@ create_prefwin (void)
label100 = gtk_label_new (_("Colors"));
gtk_widget_show (label100);
- gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 3), label100);
+ gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 4), label100);
vbox11 = gtk_vbox_new (FALSE, 8);
gtk_widget_show (vbox11);
@@ -2183,187 +2383,7 @@ create_prefwin (void)
label16 = gtk_label_new (_("Network"));
gtk_widget_show (label16);
- gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 4), label16);
-
- vbox18 = gtk_vbox_new (FALSE, 0);
- gtk_widget_show (vbox18);
- gtk_container_add (GTK_CONTAINER (notebook), vbox18);
- gtk_container_set_border_width (GTK_CONTAINER (vbox18), 12);
-
- frame5 = gtk_frame_new (NULL);
- gtk_widget_show (frame5);
- gtk_box_pack_start (GTK_BOX (vbox18), frame5, FALSE, TRUE, 0);
- gtk_frame_set_shadow_type (GTK_FRAME (frame5), GTK_SHADOW_NONE);
-
- alignment3 = gtk_alignment_new (0.5, 0.5, 1, 1);
- gtk_widget_show (alignment3);
- gtk_container_add (GTK_CONTAINER (frame5), alignment3);
- gtk_alignment_set_padding (GTK_ALIGNMENT (alignment3), 0, 0, 12, 0);
-
- vbox19 = gtk_vbox_new (FALSE, 8);
- gtk_widget_show (vbox19);
- gtk_container_add (GTK_CONTAINER (alignment3), vbox19);
- gtk_container_set_border_width (GTK_CONTAINER (vbox19), 12);
-
- hbox38 = gtk_hbox_new (FALSE, 8);
- gtk_widget_show (hbox38);
- gtk_box_pack_start (GTK_BOX (vbox19), hbox38, FALSE, FALSE, 0);
-
- write_id3v2 = gtk_check_button_new_with_mnemonic (_("Write ID3v2"));
- gtk_widget_show (write_id3v2);
- gtk_box_pack_start (GTK_BOX (hbox38), write_id3v2, FALSE, FALSE, 0);
-
- write_id3v1 = gtk_check_button_new_with_mnemonic (_("Write ID3v1"));
- gtk_widget_show (write_id3v1);
- gtk_box_pack_start (GTK_BOX (hbox38), write_id3v1, FALSE, FALSE, 0);
-
- write_apev2 = gtk_check_button_new_with_mnemonic (_("Write APEv2"));
- gtk_widget_show (write_apev2);
- gtk_box_pack_start (GTK_BOX (hbox38), write_apev2, FALSE, FALSE, 0);
-
- hbox40 = gtk_hbox_new (FALSE, 8);
- gtk_widget_show (hbox40);
- gtk_box_pack_start (GTK_BOX (vbox19), hbox40, FALSE, FALSE, 0);
-
- strip_id3v2 = gtk_check_button_new_with_mnemonic (_("Strip ID3v2"));
- gtk_widget_show (strip_id3v2);
- gtk_box_pack_start (GTK_BOX (hbox40), strip_id3v2, FALSE, FALSE, 0);
-
- strip_id3v1 = gtk_check_button_new_with_mnemonic (_("Strip ID3v1"));
- gtk_widget_show (strip_id3v1);
- gtk_box_pack_start (GTK_BOX (hbox40), strip_id3v1, FALSE, FALSE, 0);
-
- strip_apev2 = gtk_check_button_new_with_mnemonic (_("Strip APEv2"));
- gtk_widget_show (strip_apev2);
- gtk_box_pack_start (GTK_BOX (hbox40), strip_apev2, FALSE, FALSE, 0);
-
- hbox36 = gtk_hbox_new (FALSE, 8);
- gtk_widget_show (hbox36);
- gtk_box_pack_start (GTK_BOX (vbox19), hbox36, TRUE, TRUE, 0);
-
- label69 = gtk_label_new (_("ID3v2 version"));
- gtk_widget_show (label69);
- gtk_box_pack_start (GTK_BOX (hbox36), label69, FALSE, FALSE, 0);
-
- id3v2_version = gtk_combo_box_new_text ();
- gtk_widget_show (id3v2_version);
- gtk_box_pack_start (GTK_BOX (hbox36), id3v2_version, TRUE, TRUE, 0);
- gtk_combo_box_append_text (GTK_COMBO_BOX (id3v2_version), _("2.3 (Recommended)"));
- gtk_combo_box_append_text (GTK_COMBO_BOX (id3v2_version), _("2.4"));
-
- hbox39 = gtk_hbox_new (FALSE, 8);
- gtk_widget_show (hbox39);
- gtk_box_pack_start (GTK_BOX (vbox19), hbox39, TRUE, TRUE, 0);
-
- label71 = gtk_label_new (_("ID3v1 character encoding (default is iso8859-1)"));
- gtk_widget_show (label71);
- gtk_box_pack_start (GTK_BOX (hbox39), label71, FALSE, FALSE, 0);
-
- id3v1_encoding = gtk_entry_new ();
- gtk_widget_show (id3v1_encoding);
- gtk_box_pack_start (GTK_BOX (hbox39), id3v1_encoding, TRUE, TRUE, 0);
- gtk_entry_set_invisible_char (GTK_ENTRY (id3v1_encoding), 9679);
-
- label68 = gtk_label_new ("<b>MP3</b>");
- gtk_widget_show (label68);
- gtk_frame_set_label_widget (GTK_FRAME (frame5), label68);
- gtk_label_set_use_markup (GTK_LABEL (label68), TRUE);
-
- hbox41 = gtk_hbox_new (TRUE, 0);
- gtk_widget_show (hbox41);
- gtk_box_pack_start (GTK_BOX (vbox18), hbox41, FALSE, TRUE, 0);
-
- frame6 = gtk_frame_new (NULL);
- gtk_widget_show (frame6);
- gtk_box_pack_start (GTK_BOX (hbox41), frame6, TRUE, TRUE, 0);
- gtk_frame_set_shadow_type (GTK_FRAME (frame6), GTK_SHADOW_NONE);
-
- alignment4 = gtk_alignment_new (0.5, 0.5, 1, 1);
- gtk_widget_show (alignment4);
- gtk_container_add (GTK_CONTAINER (frame6), alignment4);
- gtk_alignment_set_padding (GTK_ALIGNMENT (alignment4), 0, 0, 12, 0);
-
- vbox20 = gtk_vbox_new (FALSE, 8);
- gtk_widget_show (vbox20);
- gtk_container_add (GTK_CONTAINER (alignment4), vbox20);
- gtk_container_set_border_width (GTK_CONTAINER (vbox20), 12);
-
- hbox37 = gtk_hbox_new (FALSE, 8);
- gtk_widget_show (hbox37);
- gtk_box_pack_start (GTK_BOX (vbox20), hbox37, TRUE, TRUE, 0);
-
- ape_write_id3v2 = gtk_check_button_new_with_mnemonic (_("Write ID3v2.4"));
- gtk_widget_show (ape_write_id3v2);
- gtk_box_pack_start (GTK_BOX (hbox37), ape_write_id3v2, FALSE, FALSE, 0);
-
- ape_write_apev2 = gtk_check_button_new_with_mnemonic (_("Write APEv2"));
- gtk_widget_show (ape_write_apev2);
- gtk_box_pack_start (GTK_BOX (hbox37), ape_write_apev2, FALSE, FALSE, 0);
-
- hbox45 = gtk_hbox_new (FALSE, 8);
- gtk_widget_show (hbox45);
- gtk_box_pack_start (GTK_BOX (vbox20), hbox45, TRUE, TRUE, 0);
-
- ape_strip_id3v2 = gtk_check_button_new_with_mnemonic (_("Strip ID3v2"));
- gtk_widget_show (ape_strip_id3v2);
- gtk_box_pack_start (GTK_BOX (hbox45), ape_strip_id3v2, FALSE, FALSE, 0);
-
- ape_strip_apev2 = gtk_check_button_new_with_mnemonic (_("Strip APEv2"));
- gtk_widget_show (ape_strip_apev2);
- gtk_box_pack_start (GTK_BOX (hbox45), ape_strip_apev2, FALSE, FALSE, 0);
-
- label70 = gtk_label_new ("<b>APE</b>");
- gtk_widget_show (label70);
- gtk_frame_set_label_widget (GTK_FRAME (frame6), label70);
- gtk_label_set_use_markup (GTK_LABEL (label70), TRUE);
-
- frame7 = gtk_frame_new (NULL);
- gtk_widget_show (frame7);
- gtk_box_pack_start (GTK_BOX (hbox41), frame7, TRUE, TRUE, 0);
- gtk_frame_set_shadow_type (GTK_FRAME (frame7), GTK_SHADOW_NONE);
-
- alignment5 = gtk_alignment_new (0.5, 0.5, 1, 1);
- gtk_widget_show (alignment5);
- gtk_container_add (GTK_CONTAINER (frame7), alignment5);
- gtk_alignment_set_padding (GTK_ALIGNMENT (alignment5), 0, 0, 12, 0);
-
- vbox_wv = gtk_vbox_new (FALSE, 8);
- gtk_widget_show (vbox_wv);
- gtk_container_add (GTK_CONTAINER (alignment5), vbox_wv);
- gtk_container_set_border_width (GTK_CONTAINER (vbox_wv), 12);
-
- hbox44 = gtk_hbox_new (FALSE, 8);
- gtk_widget_show (hbox44);
- gtk_box_pack_start (GTK_BOX (vbox_wv), hbox44, FALSE, FALSE, 0);
-
- wv_write_apev2 = gtk_check_button_new_with_mnemonic (_("Write APEv2"));
- gtk_widget_show (wv_write_apev2);
- gtk_box_pack_start (GTK_BOX (hbox44), wv_write_apev2, FALSE, FALSE, 0);
-
- wv_write_id3v1 = gtk_check_button_new_with_mnemonic (_("Write ID3v1"));
- gtk_widget_show (wv_write_id3v1);
- gtk_box_pack_start (GTK_BOX (hbox44), wv_write_id3v1, FALSE, FALSE, 0);
-
- hbox43 = gtk_hbox_new (FALSE, 8);
- gtk_widget_show (hbox43);
- gtk_box_pack_start (GTK_BOX (vbox_wv), hbox43, FALSE, FALSE, 0);
-
- wv_strip_apev2 = gtk_check_button_new_with_mnemonic (_("Strip APEv2"));
- gtk_widget_show (wv_strip_apev2);
- gtk_box_pack_start (GTK_BOX (hbox43), wv_strip_apev2, FALSE, FALSE, 0);
-
- wv_strip_id3v1 = gtk_check_button_new_with_mnemonic (_("Strip ID3v1"));
- gtk_widget_show (wv_strip_id3v1);
- gtk_box_pack_start (GTK_BOX (hbox43), wv_strip_id3v1, FALSE, FALSE, 0);
-
- label79 = gtk_label_new ("<b>WavPack</b>");
- gtk_widget_show (label79);
- gtk_frame_set_label_widget (GTK_FRAME (frame7), label79);
- gtk_label_set_use_markup (GTK_LABEL (label79), TRUE);
-
- label67 = gtk_label_new (_("Tag writer"));
- gtk_widget_show (label67);
- gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 5), label67);
+ gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 5), label16);
hpaned1 = gtk_hpaned_new ();
gtk_widget_show (hpaned1);
@@ -2388,65 +2408,17 @@ create_prefwin (void)
gtk_paned_pack2 (GTK_PANED (hpaned1), vbox12, TRUE, TRUE);
gtk_container_set_border_width (GTK_CONTAINER (vbox12), 12);
- hbox16 = gtk_hbox_new (FALSE, 8);
- gtk_widget_show (hbox16);
- gtk_box_pack_start (GTK_BOX (vbox12), hbox16, FALSE, FALSE, 0);
-
- label11 = gtk_label_new (_("Description:"));
- gtk_widget_show (label11);
- gtk_box_pack_start (GTK_BOX (hbox16), label11, FALSE, FALSE, 0);
- gtk_misc_set_alignment (GTK_MISC (label11), 0, 0.5);
-
- pref_plugin_descr = gtk_entry_new ();
- gtk_widget_show (pref_plugin_descr);
- gtk_box_pack_start (GTK_BOX (hbox16), pref_plugin_descr, TRUE, TRUE, 0);
- gtk_editable_set_editable (GTK_EDITABLE (pref_plugin_descr), FALSE);
- gtk_entry_set_invisible_char (GTK_ENTRY (pref_plugin_descr), 9679);
-
- hbox17 = gtk_hbox_new (FALSE, 8);
- gtk_widget_show (hbox17);
- gtk_box_pack_start (GTK_BOX (vbox12), hbox17, FALSE, FALSE, 0);
-
- label12 = gtk_label_new (_("Author(s):"));
- gtk_widget_show (label12);
- gtk_box_pack_start (GTK_BOX (hbox17), label12, FALSE, FALSE, 0);
- gtk_misc_set_alignment (GTK_MISC (label12), 0, 0.5);
-
- pref_plugin_author = gtk_entry_new ();
- gtk_widget_show (pref_plugin_author);
- gtk_box_pack_start (GTK_BOX (hbox17), pref_plugin_author, TRUE, TRUE, 0);
- gtk_editable_set_editable (GTK_EDITABLE (pref_plugin_author), FALSE);
- gtk_entry_set_invisible_char (GTK_ENTRY (pref_plugin_author), 9679);
-
- hbox18 = gtk_hbox_new (FALSE, 8);
- gtk_widget_show (hbox18);
- gtk_box_pack_start (GTK_BOX (vbox12), hbox18, FALSE, FALSE, 0);
-
- label13 = gtk_label_new (_("Email:"));
- gtk_widget_show (label13);
- gtk_box_pack_start (GTK_BOX (hbox18), label13, FALSE, FALSE, 0);
- gtk_misc_set_alignment (GTK_MISC (label13), 0, 0.5);
-
- pref_plugin_email = gtk_entry_new ();
- gtk_widget_show (pref_plugin_email);
- gtk_box_pack_start (GTK_BOX (hbox18), pref_plugin_email, TRUE, TRUE, 0);
- gtk_editable_set_editable (GTK_EDITABLE (pref_plugin_email), FALSE);
- gtk_entry_set_invisible_char (GTK_ENTRY (pref_plugin_email), 9679);
-
- hbox19 = gtk_hbox_new (FALSE, 8);
- gtk_widget_show (hbox19);
- gtk_box_pack_start (GTK_BOX (vbox12), hbox19, FALSE, FALSE, 0);
-
- label14 = gtk_label_new (_("Website:"));
- gtk_widget_show (label14);
- gtk_box_pack_start (GTK_BOX (hbox19), label14, FALSE, FALSE, 0);
- gtk_misc_set_alignment (GTK_MISC (label14), 0, 0.5);
-
- pref_plugin_website = gtk_entry_new ();
- gtk_widget_show (pref_plugin_website);
- gtk_box_pack_start (GTK_BOX (hbox19), pref_plugin_website, TRUE, TRUE, 0);
- gtk_editable_set_editable (GTK_EDITABLE (pref_plugin_website), FALSE);
- gtk_entry_set_invisible_char (GTK_ENTRY (pref_plugin_website), 9679);
+ scrolledwindow8 = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_show (scrolledwindow8);
+ gtk_box_pack_start (GTK_BOX (vbox12), scrolledwindow8, TRUE, TRUE, 0);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow8), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow8), GTK_SHADOW_IN);
+
+ plug_description = gtk_text_view_new ();
+ gtk_widget_show (plug_description);
+ gtk_container_add (GTK_CONTAINER (scrolledwindow8), plug_description);
+ gtk_text_view_set_editable (GTK_TEXT_VIEW (plug_description), FALSE);
+ gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (plug_description), FALSE);
hbox20 = gtk_hbox_new (FALSE, 0);
gtk_widget_show (hbox20);
@@ -2455,6 +2427,7 @@ create_prefwin (void)
configure_plugin = gtk_button_new ();
gtk_widget_show (configure_plugin);
gtk_box_pack_start (GTK_BOX (hbox20), configure_plugin, TRUE, FALSE, 0);
+ gtk_widget_set_sensitive (configure_plugin, FALSE);
alignment15 = gtk_alignment_new (0.5, 0.5, 0, 0);
gtk_widget_show (alignment15);
@@ -2472,6 +2445,33 @@ create_prefwin (void)
gtk_widget_show (label92);
gtk_box_pack_start (GTK_BOX (hbox56), label92, FALSE, FALSE, 0);
+ plug_copyright = gtk_button_new ();
+ gtk_widget_show (plug_copyright);
+ gtk_box_pack_start (GTK_BOX (hbox20), plug_copyright, TRUE, FALSE, 0);
+ gtk_widget_set_sensitive (plug_copyright, FALSE);
+
+ alignment20 = gtk_alignment_new (0.5, 0.5, 0, 0);
+ gtk_widget_show (alignment20);
+ gtk_container_add (GTK_CONTAINER (plug_copyright), alignment20);
+
+ hbox88 = gtk_hbox_new (FALSE, 2);
+ gtk_widget_show (hbox88);
+ gtk_container_add (GTK_CONTAINER (alignment20), hbox88);
+
+ image521 = gtk_image_new_from_stock ("gtk-about", GTK_ICON_SIZE_BUTTON);
+ gtk_widget_show (image521);
+ gtk_box_pack_start (GTK_BOX (hbox88), image521, FALSE, FALSE, 0);
+
+ label117 = gtk_label_new_with_mnemonic (_("Copyright"));
+ gtk_widget_show (label117);
+ gtk_box_pack_start (GTK_BOX (hbox88), label117, FALSE, FALSE, 0);
+
+ weblink = create_plugin_weblink ("weblink", "", "", 0, 0);
+ gtk_widget_show (weblink);
+ gtk_box_pack_start (GTK_BOX (hbox20), weblink, TRUE, FALSE, 0);
+ GTK_WIDGET_UNSET_FLAGS (weblink, GTK_CAN_FOCUS);
+ GTK_WIDGET_UNSET_FLAGS (weblink, GTK_CAN_DEFAULT);
+
label3 = gtk_label_new (_("Plugins"));
gtk_widget_show (label3);
gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 6), label3);
@@ -2481,32 +2481,19 @@ create_prefwin (void)
gtk_widget_show (dialog_action_area2);
gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area2), GTK_BUTTONBOX_END);
- closebutton1 = gtk_button_new ();
+ closebutton1 = gtk_button_new_from_stock ("gtk-close");
gtk_widget_show (closebutton1);
gtk_dialog_add_action_widget (GTK_DIALOG (prefwin), closebutton1, GTK_RESPONSE_CLOSE);
GTK_WIDGET_SET_FLAGS (closebutton1, GTK_CAN_DEFAULT);
- alignment14 = gtk_alignment_new (0.5, 0.5, 0, 0);
- gtk_widget_show (alignment14);
- gtk_container_add (GTK_CONTAINER (closebutton1), alignment14);
-
- hbox55 = gtk_hbox_new (FALSE, 2);
- gtk_widget_show (hbox55);
- gtk_container_add (GTK_CONTAINER (alignment14), hbox55);
-
- image393 = gtk_image_new_from_stock ("gtk-close", GTK_ICON_SIZE_BUTTON);
- gtk_widget_show (image393);
- gtk_box_pack_start (GTK_BOX (hbox55), image393, FALSE, FALSE, 0);
-
- label91 = gtk_label_new_with_mnemonic (_("_Close"));
- gtk_widget_show (label91);
- gtk_box_pack_start (GTK_BOX (hbox55), label91, FALSE, FALSE, 0);
-
- g_signal_connect ((gpointer) pref_dynsamplerate, "clicked",
- G_CALLBACK (on_pref_dynsamplerate_clicked),
+ g_signal_connect ((gpointer) prefwin, "configure_event",
+ G_CALLBACK (on_prefwin_configure_event),
NULL);
- g_signal_connect ((gpointer) pref_src_quality, "changed",
- G_CALLBACK (on_pref_src_quality_changed),
+ g_signal_connect ((gpointer) prefwin, "window_state_event",
+ G_CALLBACK (on_prefwin_window_state_event),
+ NULL);
+ g_signal_connect ((gpointer) prefwin, "realize",
+ G_CALLBACK (on_prefwin_realize),
NULL);
g_signal_connect ((gpointer) pref_replaygain_mode, "changed",
G_CALLBACK (on_pref_replaygain_mode_changed),
@@ -2514,6 +2501,9 @@ create_prefwin (void)
g_signal_connect ((gpointer) pref_replaygain_scale, "clicked",
G_CALLBACK (on_pref_replaygain_scale_clicked),
NULL);
+ g_signal_connect ((gpointer) replaygain_preamp, "value_changed",
+ G_CALLBACK (on_replaygain_preamp_value_changed),
+ NULL);
g_signal_connect ((gpointer) cli_add_to_playlist, "toggled",
G_CALLBACK (on_cli_add_to_playlist_toggled),
NULL);
@@ -2523,6 +2513,33 @@ create_prefwin (void)
g_signal_connect ((gpointer) resume_last_session, "toggled",
G_CALLBACK (on_resume_last_session_toggled),
NULL);
+ g_signal_connect ((gpointer) ignore_archives, "toggled",
+ G_CALLBACK (on_ignore_archives_toggled),
+ NULL);
+ g_signal_connect ((gpointer) dsp_add, "clicked",
+ G_CALLBACK (on_dsp_add_clicked),
+ NULL);
+ g_signal_connect ((gpointer) dsp_remove, "clicked",
+ G_CALLBACK (on_dsp_remove_clicked),
+ NULL);
+ g_signal_connect ((gpointer) dsp_configure, "clicked",
+ G_CALLBACK (on_dsp_configure_clicked),
+ NULL);
+ g_signal_connect ((gpointer) dsp_up, "clicked",
+ G_CALLBACK (on_dsp_up_clicked),
+ NULL);
+ g_signal_connect ((gpointer) dsp_down, "clicked",
+ G_CALLBACK (on_dsp_down_clicked),
+ NULL);
+ g_signal_connect ((gpointer) dsp_preset, "changed",
+ G_CALLBACK (on_dsp_preset_changed),
+ NULL);
+ g_signal_connect ((gpointer) dsp_preset_save, "clicked",
+ G_CALLBACK (on_dsp_preset_save_clicked),
+ NULL);
+ g_signal_connect ((gpointer) dsp_preset_load, "clicked",
+ G_CALLBACK (on_dsp_preset_load_clicked),
+ NULL);
g_signal_connect ((gpointer) pref_close_send_to_tray, "clicked",
G_CALLBACK (on_pref_close_send_to_tray_clicked),
NULL);
@@ -2538,12 +2555,21 @@ create_prefwin (void)
g_signal_connect ((gpointer) hide_delete_from_disk, "toggled",
G_CALLBACK (on_hide_delete_from_disk_toggled),
NULL);
+ g_signal_connect ((gpointer) auto_name_playlist_from_folder, "toggled",
+ G_CALLBACK (on_auto_name_playlist_from_folder_toggled),
+ NULL);
+ g_signal_connect ((gpointer) gui_fps, "value_changed",
+ G_CALLBACK (on_gui_fps_value_changed),
+ NULL);
g_signal_connect ((gpointer) titlebar_format_playing, "changed",
G_CALLBACK (on_titlebar_format_playing_changed),
NULL);
g_signal_connect ((gpointer) titlebar_format_stopped, "changed",
G_CALLBACK (on_titlebar_format_stopped_changed),
NULL);
+ g_signal_connect ((gpointer) gui_plugin, "changed",
+ G_CALLBACK (on_gui_plugin_changed),
+ NULL);
g_signal_connect ((gpointer) override_bar_colors, "toggled",
G_CALLBACK (on_override_bar_colors_toggled),
NULL);
@@ -2568,6 +2594,9 @@ create_prefwin (void)
g_signal_connect ((gpointer) tabstrip_base, "color_set",
G_CALLBACK (on_tabstrip_base_color_set),
NULL);
+ g_signal_connect ((gpointer) tabstrip_text, "color_set",
+ G_CALLBACK (on_tabstrip_text_color_set),
+ NULL);
g_signal_connect ((gpointer) override_listview_colors, "toggled",
G_CALLBACK (on_override_listview_colors_toggled),
NULL);
@@ -2607,60 +2636,15 @@ create_prefwin (void)
g_signal_connect ((gpointer) proxypassword, "changed",
G_CALLBACK (on_proxypassword_changed),
NULL);
- g_signal_connect ((gpointer) write_id3v2, "toggled",
- G_CALLBACK (on_write_id3v2_toggled),
- NULL);
- g_signal_connect ((gpointer) write_id3v1, "toggled",
- G_CALLBACK (on_write_id3v1_toggled),
- NULL);
- g_signal_connect ((gpointer) write_apev2, "toggled",
- G_CALLBACK (on_write_apev2_toggled),
- NULL);
- g_signal_connect ((gpointer) strip_id3v2, "toggled",
- G_CALLBACK (on_strip_id3v2_toggled),
- NULL);
- g_signal_connect ((gpointer) strip_id3v1, "toggled",
- G_CALLBACK (on_strip_id3v1_toggled),
- NULL);
- g_signal_connect ((gpointer) strip_apev2, "toggled",
- G_CALLBACK (on_strip_apev2_toggled),
- NULL);
- g_signal_connect ((gpointer) id3v2_version, "changed",
- G_CALLBACK (on_id3v2_version_changed),
- NULL);
- g_signal_connect ((gpointer) id3v1_encoding, "changed",
- G_CALLBACK (on_id3v1_encoding_changed),
- NULL);
- g_signal_connect ((gpointer) ape_write_id3v2, "toggled",
- G_CALLBACK (on_ape_write_id3v2_toggled),
- NULL);
- g_signal_connect ((gpointer) ape_write_apev2, "toggled",
- G_CALLBACK (on_ape_write_apev2_toggled),
- NULL);
- g_signal_connect ((gpointer) ape_strip_id3v2, "toggled",
- G_CALLBACK (on_ape_strip_id3v2_toggled),
- NULL);
- g_signal_connect ((gpointer) ape_strip_apev2, "toggled",
- G_CALLBACK (on_ape_strip_apev2_toggled),
- NULL);
- g_signal_connect ((gpointer) wv_write_apev2, "toggled",
- G_CALLBACK (on_wv_write_apev2_toggled),
- NULL);
- g_signal_connect ((gpointer) wv_write_id3v1, "toggled",
- G_CALLBACK (on_wv_write_id3v1_toggled),
- NULL);
- g_signal_connect ((gpointer) wv_strip_apev2, "toggled",
- G_CALLBACK (on_wv_strip_apev2_toggled),
- NULL);
- g_signal_connect ((gpointer) wv_strip_id3v1, "toggled",
- G_CALLBACK (on_wv_strip_id3v1_toggled),
- NULL);
g_signal_connect ((gpointer) pref_pluginlist, "cursor_changed",
G_CALLBACK (on_pref_pluginlist_cursor_changed),
NULL);
g_signal_connect ((gpointer) configure_plugin, "clicked",
G_CALLBACK (on_configure_plugin_clicked),
NULL);
+ g_signal_connect ((gpointer) plug_copyright, "clicked",
+ G_CALLBACK (on_plug_copyright_clicked),
+ NULL);
/* Store pointers to all widgets, for use by lookup_widget(). */
GLADE_HOOKUP_OBJECT_NO_REF (prefwin, prefwin, "prefwin");
@@ -2675,31 +2659,57 @@ create_prefwin (void)
GLADE_HOOKUP_OBJECT (prefwin, pref_soundcard, "pref_soundcard");
GLADE_HOOKUP_OBJECT (prefwin, Sound, "Sound");
GLADE_HOOKUP_OBJECT (prefwin, vbox8, "vbox8");
- GLADE_HOOKUP_OBJECT (prefwin, pref_dynsamplerate, "pref_dynsamplerate");
- GLADE_HOOKUP_OBJECT (prefwin, hbox9, "hbox9");
- GLADE_HOOKUP_OBJECT (prefwin, label6, "label6");
- GLADE_HOOKUP_OBJECT (prefwin, pref_src_quality, "pref_src_quality");
GLADE_HOOKUP_OBJECT (prefwin, hbox10, "hbox10");
GLADE_HOOKUP_OBJECT (prefwin, label8, "label8");
GLADE_HOOKUP_OBJECT (prefwin, pref_replaygain_mode, "pref_replaygain_mode");
GLADE_HOOKUP_OBJECT (prefwin, pref_replaygain_scale, "pref_replaygain_scale");
+ GLADE_HOOKUP_OBJECT (prefwin, hbox100, "hbox100");
+ GLADE_HOOKUP_OBJECT (prefwin, label124, "label124");
+ GLADE_HOOKUP_OBJECT (prefwin, label125, "label125");
+ GLADE_HOOKUP_OBJECT (prefwin, replaygain_preamp, "replaygain_preamp");
+ GLADE_HOOKUP_OBJECT (prefwin, label126, "label126");
GLADE_HOOKUP_OBJECT (prefwin, hbox66, "hbox66");
GLADE_HOOKUP_OBJECT (prefwin, cli_add_to_playlist, "cli_add_to_playlist");
GLADE_HOOKUP_OBJECT (prefwin, cli_playlist_name, "cli_playlist_name");
GLADE_HOOKUP_OBJECT (prefwin, resume_last_session, "resume_last_session");
+ GLADE_HOOKUP_OBJECT (prefwin, ignore_archives, "ignore_archives");
GLADE_HOOKUP_OBJECT (prefwin, label39, "label39");
+ GLADE_HOOKUP_OBJECT (prefwin, vbox29, "vbox29");
+ GLADE_HOOKUP_OBJECT (prefwin, hbox80, "hbox80");
+ GLADE_HOOKUP_OBJECT (prefwin, dsp_add, "dsp_add");
+ GLADE_HOOKUP_OBJECT (prefwin, dsp_remove, "dsp_remove");
+ GLADE_HOOKUP_OBJECT (prefwin, dsp_configure, "dsp_configure");
+ GLADE_HOOKUP_OBJECT (prefwin, hbox81, "hbox81");
+ GLADE_HOOKUP_OBJECT (prefwin, scrolledwindow7, "scrolledwindow7");
+ GLADE_HOOKUP_OBJECT (prefwin, dsp_listview, "dsp_listview");
+ GLADE_HOOKUP_OBJECT (prefwin, vbox30, "vbox30");
+ GLADE_HOOKUP_OBJECT (prefwin, dsp_up, "dsp_up");
+ GLADE_HOOKUP_OBJECT (prefwin, dsp_down, "dsp_down");
+ GLADE_HOOKUP_OBJECT (prefwin, hbox86, "hbox86");
+ GLADE_HOOKUP_OBJECT (prefwin, label114, "label114");
+ GLADE_HOOKUP_OBJECT (prefwin, dsp_preset, "dsp_preset");
+ GLADE_HOOKUP_OBJECT (prefwin, dsp_preset_save, "dsp_preset_save");
+ GLADE_HOOKUP_OBJECT (prefwin, dsp_preset_load, "dsp_preset_load");
+ GLADE_HOOKUP_OBJECT (prefwin, label110, "label110");
GLADE_HOOKUP_OBJECT (prefwin, vbox9, "vbox9");
GLADE_HOOKUP_OBJECT (prefwin, pref_close_send_to_tray, "pref_close_send_to_tray");
GLADE_HOOKUP_OBJECT (prefwin, mmb_delete_playlist, "mmb_delete_playlist");
GLADE_HOOKUP_OBJECT (prefwin, hide_tray_icon, "hide_tray_icon");
GLADE_HOOKUP_OBJECT (prefwin, embolden_current, "embolden_current");
GLADE_HOOKUP_OBJECT (prefwin, hide_delete_from_disk, "hide_delete_from_disk");
+ GLADE_HOOKUP_OBJECT (prefwin, auto_name_playlist_from_folder, "auto_name_playlist_from_folder");
+ GLADE_HOOKUP_OBJECT (prefwin, hbox102, "hbox102");
+ GLADE_HOOKUP_OBJECT (prefwin, label129, "label129");
+ GLADE_HOOKUP_OBJECT (prefwin, gui_fps, "gui_fps");
GLADE_HOOKUP_OBJECT (prefwin, hbox64, "hbox64");
GLADE_HOOKUP_OBJECT (prefwin, label101, "label101");
GLADE_HOOKUP_OBJECT (prefwin, titlebar_format_playing, "titlebar_format_playing");
GLADE_HOOKUP_OBJECT (prefwin, hbox65, "hbox65");
GLADE_HOOKUP_OBJECT (prefwin, label102, "label102");
GLADE_HOOKUP_OBJECT (prefwin, titlebar_format_stopped, "titlebar_format_stopped");
+ GLADE_HOOKUP_OBJECT (prefwin, hbox101, "hbox101");
+ GLADE_HOOKUP_OBJECT (prefwin, label128, "label128");
+ GLADE_HOOKUP_OBJECT (prefwin, gui_plugin, "gui_plugin");
GLADE_HOOKUP_OBJECT (prefwin, label2, "label2");
GLADE_HOOKUP_OBJECT (prefwin, notebook4, "notebook4");
GLADE_HOOKUP_OBJECT (prefwin, vbox21, "vbox21");
@@ -2721,6 +2731,8 @@ create_prefwin (void)
GLADE_HOOKUP_OBJECT (prefwin, tabstrip_dark, "tabstrip_dark");
GLADE_HOOKUP_OBJECT (prefwin, tabstrip_base, "tabstrip_base");
GLADE_HOOKUP_OBJECT (prefwin, label76, "label76");
+ GLADE_HOOKUP_OBJECT (prefwin, label127, "label127");
+ GLADE_HOOKUP_OBJECT (prefwin, tabstrip_text, "tabstrip_text");
GLADE_HOOKUP_OBJECT (prefwin, label74, "label74");
GLADE_HOOKUP_OBJECT (prefwin, vbox23, "vbox23");
GLADE_HOOKUP_OBJECT (prefwin, override_listview_colors, "override_listview_colors");
@@ -2757,88 +2769,39 @@ create_prefwin (void)
GLADE_HOOKUP_OBJECT (prefwin, label98, "label98");
GLADE_HOOKUP_OBJECT (prefwin, proxypassword, "proxypassword");
GLADE_HOOKUP_OBJECT (prefwin, label16, "label16");
- GLADE_HOOKUP_OBJECT (prefwin, vbox18, "vbox18");
- GLADE_HOOKUP_OBJECT (prefwin, frame5, "frame5");
- GLADE_HOOKUP_OBJECT (prefwin, alignment3, "alignment3");
- GLADE_HOOKUP_OBJECT (prefwin, vbox19, "vbox19");
- GLADE_HOOKUP_OBJECT (prefwin, hbox38, "hbox38");
- GLADE_HOOKUP_OBJECT (prefwin, write_id3v2, "write_id3v2");
- GLADE_HOOKUP_OBJECT (prefwin, write_id3v1, "write_id3v1");
- GLADE_HOOKUP_OBJECT (prefwin, write_apev2, "write_apev2");
- GLADE_HOOKUP_OBJECT (prefwin, hbox40, "hbox40");
- GLADE_HOOKUP_OBJECT (prefwin, strip_id3v2, "strip_id3v2");
- GLADE_HOOKUP_OBJECT (prefwin, strip_id3v1, "strip_id3v1");
- GLADE_HOOKUP_OBJECT (prefwin, strip_apev2, "strip_apev2");
- GLADE_HOOKUP_OBJECT (prefwin, hbox36, "hbox36");
- GLADE_HOOKUP_OBJECT (prefwin, label69, "label69");
- GLADE_HOOKUP_OBJECT (prefwin, id3v2_version, "id3v2_version");
- GLADE_HOOKUP_OBJECT (prefwin, hbox39, "hbox39");
- GLADE_HOOKUP_OBJECT (prefwin, label71, "label71");
- GLADE_HOOKUP_OBJECT (prefwin, id3v1_encoding, "id3v1_encoding");
- GLADE_HOOKUP_OBJECT (prefwin, label68, "label68");
- GLADE_HOOKUP_OBJECT (prefwin, hbox41, "hbox41");
- GLADE_HOOKUP_OBJECT (prefwin, frame6, "frame6");
- GLADE_HOOKUP_OBJECT (prefwin, alignment4, "alignment4");
- GLADE_HOOKUP_OBJECT (prefwin, vbox20, "vbox20");
- GLADE_HOOKUP_OBJECT (prefwin, hbox37, "hbox37");
- GLADE_HOOKUP_OBJECT (prefwin, ape_write_id3v2, "ape_write_id3v2");
- GLADE_HOOKUP_OBJECT (prefwin, ape_write_apev2, "ape_write_apev2");
- GLADE_HOOKUP_OBJECT (prefwin, hbox45, "hbox45");
- GLADE_HOOKUP_OBJECT (prefwin, ape_strip_id3v2, "ape_strip_id3v2");
- GLADE_HOOKUP_OBJECT (prefwin, ape_strip_apev2, "ape_strip_apev2");
- GLADE_HOOKUP_OBJECT (prefwin, label70, "label70");
- GLADE_HOOKUP_OBJECT (prefwin, frame7, "frame7");
- GLADE_HOOKUP_OBJECT (prefwin, alignment5, "alignment5");
- GLADE_HOOKUP_OBJECT (prefwin, vbox_wv, "vbox_wv");
- GLADE_HOOKUP_OBJECT (prefwin, hbox44, "hbox44");
- GLADE_HOOKUP_OBJECT (prefwin, wv_write_apev2, "wv_write_apev2");
- GLADE_HOOKUP_OBJECT (prefwin, wv_write_id3v1, "wv_write_id3v1");
- GLADE_HOOKUP_OBJECT (prefwin, hbox43, "hbox43");
- GLADE_HOOKUP_OBJECT (prefwin, wv_strip_apev2, "wv_strip_apev2");
- GLADE_HOOKUP_OBJECT (prefwin, wv_strip_id3v1, "wv_strip_id3v1");
- GLADE_HOOKUP_OBJECT (prefwin, label79, "label79");
- GLADE_HOOKUP_OBJECT (prefwin, label67, "label67");
GLADE_HOOKUP_OBJECT (prefwin, hpaned1, "hpaned1");
GLADE_HOOKUP_OBJECT (prefwin, scrolledwindow2, "scrolledwindow2");
GLADE_HOOKUP_OBJECT (prefwin, pref_pluginlist, "pref_pluginlist");
GLADE_HOOKUP_OBJECT (prefwin, vbox12, "vbox12");
- GLADE_HOOKUP_OBJECT (prefwin, hbox16, "hbox16");
- GLADE_HOOKUP_OBJECT (prefwin, label11, "label11");
- GLADE_HOOKUP_OBJECT (prefwin, pref_plugin_descr, "pref_plugin_descr");
- GLADE_HOOKUP_OBJECT (prefwin, hbox17, "hbox17");
- GLADE_HOOKUP_OBJECT (prefwin, label12, "label12");
- GLADE_HOOKUP_OBJECT (prefwin, pref_plugin_author, "pref_plugin_author");
- GLADE_HOOKUP_OBJECT (prefwin, hbox18, "hbox18");
- GLADE_HOOKUP_OBJECT (prefwin, label13, "label13");
- GLADE_HOOKUP_OBJECT (prefwin, pref_plugin_email, "pref_plugin_email");
- GLADE_HOOKUP_OBJECT (prefwin, hbox19, "hbox19");
- GLADE_HOOKUP_OBJECT (prefwin, label14, "label14");
- GLADE_HOOKUP_OBJECT (prefwin, pref_plugin_website, "pref_plugin_website");
+ GLADE_HOOKUP_OBJECT (prefwin, scrolledwindow8, "scrolledwindow8");
+ GLADE_HOOKUP_OBJECT (prefwin, plug_description, "plug_description");
GLADE_HOOKUP_OBJECT (prefwin, hbox20, "hbox20");
GLADE_HOOKUP_OBJECT (prefwin, configure_plugin, "configure_plugin");
GLADE_HOOKUP_OBJECT (prefwin, alignment15, "alignment15");
GLADE_HOOKUP_OBJECT (prefwin, hbox56, "hbox56");
GLADE_HOOKUP_OBJECT (prefwin, image394, "image394");
GLADE_HOOKUP_OBJECT (prefwin, label92, "label92");
+ GLADE_HOOKUP_OBJECT (prefwin, plug_copyright, "plug_copyright");
+ GLADE_HOOKUP_OBJECT (prefwin, alignment20, "alignment20");
+ GLADE_HOOKUP_OBJECT (prefwin, hbox88, "hbox88");
+ GLADE_HOOKUP_OBJECT (prefwin, image521, "image521");
+ GLADE_HOOKUP_OBJECT (prefwin, label117, "label117");
+ GLADE_HOOKUP_OBJECT (prefwin, weblink, "weblink");
GLADE_HOOKUP_OBJECT (prefwin, label3, "label3");
GLADE_HOOKUP_OBJECT_NO_REF (prefwin, dialog_action_area2, "dialog_action_area2");
GLADE_HOOKUP_OBJECT (prefwin, closebutton1, "closebutton1");
- GLADE_HOOKUP_OBJECT (prefwin, alignment14, "alignment14");
- GLADE_HOOKUP_OBJECT (prefwin, hbox55, "hbox55");
- GLADE_HOOKUP_OBJECT (prefwin, image393, "image393");
- GLADE_HOOKUP_OBJECT (prefwin, label91, "label91");
return prefwin;
}
GtkWidget*
-create_editplaylistdlg (void)
+create_entrydialog (void)
{
- GtkWidget *editplaylistdlg;
+ GtkWidget *entrydialog;
GtkWidget *dialog_vbox3;
GtkWidget *vbox15;
GtkWidget *hbox33;
- GtkWidget *label40;
+ GtkWidget *title_label;
GtkWidget *title;
GtkWidget *dialog_action_area3;
GtkWidget *cancelbutton2;
@@ -2852,13 +2815,13 @@ create_editplaylistdlg (void)
GtkWidget *image395;
GtkWidget *label93;
- editplaylistdlg = gtk_dialog_new ();
- gtk_container_set_border_width (GTK_CONTAINER (editplaylistdlg), 8);
- gtk_window_set_title (GTK_WINDOW (editplaylistdlg), _("editplaylistdlg"));
- gtk_window_set_destroy_with_parent (GTK_WINDOW (editplaylistdlg), TRUE);
- gtk_window_set_type_hint (GTK_WINDOW (editplaylistdlg), GDK_WINDOW_TYPE_HINT_DIALOG);
+ entrydialog = gtk_dialog_new ();
+ gtk_container_set_border_width (GTK_CONTAINER (entrydialog), 8);
+ gtk_window_set_title (GTK_WINDOW (entrydialog), "EntryDialog");
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (entrydialog), TRUE);
+ gtk_window_set_type_hint (GTK_WINDOW (entrydialog), GDK_WINDOW_TYPE_HINT_DIALOG);
- dialog_vbox3 = GTK_DIALOG (editplaylistdlg)->vbox;
+ dialog_vbox3 = GTK_DIALOG (entrydialog)->vbox;
gtk_widget_show (dialog_vbox3);
vbox15 = gtk_vbox_new (FALSE, 0);
@@ -2870,9 +2833,9 @@ create_editplaylistdlg (void)
gtk_widget_show (hbox33);
gtk_box_pack_start (GTK_BOX (vbox15), hbox33, TRUE, TRUE, 0);
- label40 = gtk_label_new (_("Title:"));
- gtk_widget_show (label40);
- gtk_box_pack_start (GTK_BOX (hbox33), label40, FALSE, FALSE, 0);
+ title_label = gtk_label_new (_("Title:"));
+ gtk_widget_show (title_label);
+ gtk_box_pack_start (GTK_BOX (hbox33), title_label, FALSE, FALSE, 0);
title = gtk_entry_new ();
gtk_widget_show (title);
@@ -2880,13 +2843,13 @@ create_editplaylistdlg (void)
gtk_entry_set_invisible_char (GTK_ENTRY (title), 8226);
gtk_entry_set_activates_default (GTK_ENTRY (title), TRUE);
- dialog_action_area3 = GTK_DIALOG (editplaylistdlg)->action_area;
+ dialog_action_area3 = GTK_DIALOG (entrydialog)->action_area;
gtk_widget_show (dialog_action_area3);
gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area3), GTK_BUTTONBOX_END);
cancelbutton2 = gtk_button_new ();
gtk_widget_show (cancelbutton2);
- gtk_dialog_add_action_widget (GTK_DIALOG (editplaylistdlg), cancelbutton2, GTK_RESPONSE_CANCEL);
+ gtk_dialog_add_action_widget (GTK_DIALOG (entrydialog), cancelbutton2, GTK_RESPONSE_CANCEL);
GTK_WIDGET_SET_FLAGS (cancelbutton2, GTK_CAN_DEFAULT);
alignment17 = gtk_alignment_new (0.5, 0.5, 0, 0);
@@ -2907,7 +2870,7 @@ create_editplaylistdlg (void)
okbutton2 = gtk_button_new ();
gtk_widget_show (okbutton2);
- gtk_dialog_add_action_widget (GTK_DIALOG (editplaylistdlg), okbutton2, GTK_RESPONSE_OK);
+ gtk_dialog_add_action_widget (GTK_DIALOG (entrydialog), okbutton2, GTK_RESPONSE_OK);
GTK_WIDGET_SET_FLAGS (okbutton2, GTK_CAN_DEFAULT);
alignment16 = gtk_alignment_new (0.5, 0.5, 0, 0);
@@ -2927,25 +2890,25 @@ create_editplaylistdlg (void)
gtk_box_pack_start (GTK_BOX (hbox57), label93, FALSE, FALSE, 0);
/* Store pointers to all widgets, for use by lookup_widget(). */
- GLADE_HOOKUP_OBJECT_NO_REF (editplaylistdlg, editplaylistdlg, "editplaylistdlg");
- GLADE_HOOKUP_OBJECT_NO_REF (editplaylistdlg, dialog_vbox3, "dialog_vbox3");
- GLADE_HOOKUP_OBJECT (editplaylistdlg, vbox15, "vbox15");
- GLADE_HOOKUP_OBJECT (editplaylistdlg, hbox33, "hbox33");
- GLADE_HOOKUP_OBJECT (editplaylistdlg, label40, "label40");
- GLADE_HOOKUP_OBJECT (editplaylistdlg, title, "title");
- GLADE_HOOKUP_OBJECT_NO_REF (editplaylistdlg, dialog_action_area3, "dialog_action_area3");
- GLADE_HOOKUP_OBJECT (editplaylistdlg, cancelbutton2, "cancelbutton2");
- GLADE_HOOKUP_OBJECT (editplaylistdlg, alignment17, "alignment17");
- GLADE_HOOKUP_OBJECT (editplaylistdlg, hbox58, "hbox58");
- GLADE_HOOKUP_OBJECT (editplaylistdlg, image396, "image396");
- GLADE_HOOKUP_OBJECT (editplaylistdlg, label94, "label94");
- GLADE_HOOKUP_OBJECT (editplaylistdlg, okbutton2, "okbutton2");
- GLADE_HOOKUP_OBJECT (editplaylistdlg, alignment16, "alignment16");
- GLADE_HOOKUP_OBJECT (editplaylistdlg, hbox57, "hbox57");
- GLADE_HOOKUP_OBJECT (editplaylistdlg, image395, "image395");
- GLADE_HOOKUP_OBJECT (editplaylistdlg, label93, "label93");
-
- return editplaylistdlg;
+ GLADE_HOOKUP_OBJECT_NO_REF (entrydialog, entrydialog, "entrydialog");
+ GLADE_HOOKUP_OBJECT_NO_REF (entrydialog, dialog_vbox3, "dialog_vbox3");
+ GLADE_HOOKUP_OBJECT (entrydialog, vbox15, "vbox15");
+ GLADE_HOOKUP_OBJECT (entrydialog, hbox33, "hbox33");
+ GLADE_HOOKUP_OBJECT (entrydialog, title_label, "title_label");
+ GLADE_HOOKUP_OBJECT (entrydialog, title, "title");
+ GLADE_HOOKUP_OBJECT_NO_REF (entrydialog, dialog_action_area3, "dialog_action_area3");
+ GLADE_HOOKUP_OBJECT (entrydialog, cancelbutton2, "cancelbutton2");
+ GLADE_HOOKUP_OBJECT (entrydialog, alignment17, "alignment17");
+ GLADE_HOOKUP_OBJECT (entrydialog, hbox58, "hbox58");
+ GLADE_HOOKUP_OBJECT (entrydialog, image396, "image396");
+ GLADE_HOOKUP_OBJECT (entrydialog, label94, "label94");
+ GLADE_HOOKUP_OBJECT (entrydialog, okbutton2, "okbutton2");
+ GLADE_HOOKUP_OBJECT (entrydialog, alignment16, "alignment16");
+ GLADE_HOOKUP_OBJECT (entrydialog, hbox57, "hbox57");
+ GLADE_HOOKUP_OBJECT (entrydialog, image395, "image395");
+ GLADE_HOOKUP_OBJECT (entrydialog, label93, "label93");
+
+ return entrydialog;
}
GtkWidget*
@@ -3067,8 +3030,9 @@ create_groupbydlg (void)
GtkWidget *vbox25;
GtkWidget *hbox46;
GtkWidget *label81;
+ GtkWidget *hbox75;
GtkWidget *format;
- GtkWidget *label82;
+ GtkWidget *custom1;
GtkWidget *dialog_action_area4;
GtkWidget *cancelbutton4;
GtkWidget *alignment7;
@@ -3101,19 +3065,21 @@ create_groupbydlg (void)
gtk_widget_show (label81);
gtk_box_pack_start (GTK_BOX (hbox46), label81, FALSE, FALSE, 0);
+ hbox75 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (hbox75);
+ gtk_box_pack_start (GTK_BOX (hbox46), hbox75, TRUE, TRUE, 0);
+
format = gtk_entry_new ();
gtk_widget_show (format);
- gtk_box_pack_start (GTK_BOX (hbox46), format, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox75), format, TRUE, TRUE, 0);
gtk_entry_set_invisible_char (GTK_ENTRY (format), 9679);
gtk_entry_set_activates_default (GTK_ENTRY (format), TRUE);
- label82 = gtk_label_new (_("Format conversions (start with %):\n [a]rtist, [t]itle, al[b]um, [B]and, [C]omposer\n track[n]umber, [N]totaltracks,\n [l]ength, [y]ear, [g]enre, [c]omment,\n copy[r]ight, [f]ilename, [T]ags\nExample: %a - %t [%l]"));
- gtk_widget_show (label82);
- gtk_box_pack_start (GTK_BOX (vbox25), label82, FALSE, FALSE, 0);
- GTK_WIDGET_SET_FLAGS (label82, GTK_CAN_FOCUS);
- gtk_label_set_use_markup (GTK_LABEL (label82), TRUE);
- gtk_label_set_selectable (GTK_LABEL (label82), TRUE);
- gtk_misc_set_alignment (GTK_MISC (label82), 0.1, 0.5);
+ custom1 = title_formatting_help_link_create ("custom1", "", "", 0, 0);
+ gtk_widget_show (custom1);
+ gtk_box_pack_start (GTK_BOX (hbox75), custom1, TRUE, TRUE, 0);
+ GTK_WIDGET_UNSET_FLAGS (custom1, GTK_CAN_FOCUS);
+ GTK_WIDGET_UNSET_FLAGS (custom1, GTK_CAN_DEFAULT);
dialog_action_area4 = GTK_DIALOG (groupbydlg)->action_area;
gtk_widget_show (dialog_action_area4);
@@ -3167,8 +3133,9 @@ create_groupbydlg (void)
GLADE_HOOKUP_OBJECT (groupbydlg, vbox25, "vbox25");
GLADE_HOOKUP_OBJECT (groupbydlg, hbox46, "hbox46");
GLADE_HOOKUP_OBJECT (groupbydlg, label81, "label81");
+ GLADE_HOOKUP_OBJECT (groupbydlg, hbox75, "hbox75");
GLADE_HOOKUP_OBJECT (groupbydlg, format, "format");
- GLADE_HOOKUP_OBJECT (groupbydlg, label82, "label82");
+ GLADE_HOOKUP_OBJECT (groupbydlg, custom1, "custom1");
GLADE_HOOKUP_OBJECT_NO_REF (groupbydlg, dialog_action_area4, "dialog_action_area4");
GLADE_HOOKUP_OBJECT (groupbydlg, cancelbutton4, "cancelbutton4");
GLADE_HOOKUP_OBJECT (groupbydlg, alignment7, "alignment7");
@@ -3184,3 +3151,514 @@ create_groupbydlg (void)
return groupbydlg;
}
+GtkWidget*
+create_sortbydlg (void)
+{
+ GtkWidget *sortbydlg;
+ GtkWidget *dialog_vbox8;
+ GtkWidget *vbox28;
+ GtkWidget *hbox76;
+ GtkWidget *label108;
+ GtkWidget *hbox77;
+ GtkWidget *sortfmt;
+ GtkWidget *custom3;
+ GtkWidget *hbox78;
+ GtkWidget *label109;
+ GtkWidget *sortorder;
+ GtkWidget *dialog_action_area7;
+ GtkWidget *cancelbutton5;
+ GtkWidget *okbutton5;
+
+ sortbydlg = gtk_dialog_new ();
+ gtk_window_set_title (GTK_WINDOW (sortbydlg), _("Sort by..."));
+ gtk_window_set_modal (GTK_WINDOW (sortbydlg), TRUE);
+ gtk_window_set_type_hint (GTK_WINDOW (sortbydlg), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+ dialog_vbox8 = GTK_DIALOG (sortbydlg)->vbox;
+ gtk_widget_show (dialog_vbox8);
+
+ vbox28 = gtk_vbox_new (FALSE, 8);
+ gtk_widget_show (vbox28);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox8), vbox28, FALSE, FALSE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox28), 12);
+
+ hbox76 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox76);
+ gtk_box_pack_start (GTK_BOX (vbox28), hbox76, FALSE, TRUE, 0);
+
+ label108 = gtk_label_new (_("Format"));
+ gtk_widget_show (label108);
+ gtk_box_pack_start (GTK_BOX (hbox76), label108, FALSE, FALSE, 0);
+
+ hbox77 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (hbox77);
+ gtk_box_pack_start (GTK_BOX (hbox76), hbox77, TRUE, TRUE, 0);
+
+ sortfmt = gtk_entry_new ();
+ gtk_widget_show (sortfmt);
+ gtk_box_pack_start (GTK_BOX (hbox77), sortfmt, TRUE, TRUE, 0);
+ gtk_entry_set_invisible_char (GTK_ENTRY (sortfmt), 9679);
+
+ custom3 = title_formatting_help_link_create ("custom3", "", "", 0, 0);
+ gtk_widget_show (custom3);
+ gtk_box_pack_start (GTK_BOX (hbox77), custom3, TRUE, TRUE, 0);
+ GTK_WIDGET_UNSET_FLAGS (custom3, GTK_CAN_FOCUS);
+ GTK_WIDGET_UNSET_FLAGS (custom3, GTK_CAN_DEFAULT);
+
+ hbox78 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox78);
+ gtk_box_pack_start (GTK_BOX (vbox28), hbox78, TRUE, TRUE, 0);
+
+ label109 = gtk_label_new (_("Order"));
+ gtk_widget_show (label109);
+ gtk_box_pack_start (GTK_BOX (hbox78), label109, FALSE, FALSE, 0);
+
+ sortorder = gtk_combo_box_new_text ();
+ gtk_widget_show (sortorder);
+ gtk_box_pack_start (GTK_BOX (hbox78), sortorder, TRUE, TRUE, 0);
+ gtk_combo_box_append_text (GTK_COMBO_BOX (sortorder), _("Ascending"));
+ gtk_combo_box_append_text (GTK_COMBO_BOX (sortorder), _("Descending"));
+
+ dialog_action_area7 = GTK_DIALOG (sortbydlg)->action_area;
+ gtk_widget_show (dialog_action_area7);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area7), GTK_BUTTONBOX_END);
+
+ cancelbutton5 = gtk_button_new_from_stock ("gtk-cancel");
+ gtk_widget_show (cancelbutton5);
+ gtk_dialog_add_action_widget (GTK_DIALOG (sortbydlg), cancelbutton5, GTK_RESPONSE_CANCEL);
+ GTK_WIDGET_SET_FLAGS (cancelbutton5, GTK_CAN_DEFAULT);
+
+ okbutton5 = gtk_button_new_from_stock ("gtk-ok");
+ gtk_widget_show (okbutton5);
+ gtk_dialog_add_action_widget (GTK_DIALOG (sortbydlg), okbutton5, GTK_RESPONSE_OK);
+ GTK_WIDGET_SET_FLAGS (okbutton5, GTK_CAN_DEFAULT);
+
+ g_signal_connect ((gpointer) sortfmt, "activate",
+ G_CALLBACK (on_sortfmt_activate),
+ NULL);
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT_NO_REF (sortbydlg, sortbydlg, "sortbydlg");
+ GLADE_HOOKUP_OBJECT_NO_REF (sortbydlg, dialog_vbox8, "dialog_vbox8");
+ GLADE_HOOKUP_OBJECT (sortbydlg, vbox28, "vbox28");
+ GLADE_HOOKUP_OBJECT (sortbydlg, hbox76, "hbox76");
+ GLADE_HOOKUP_OBJECT (sortbydlg, label108, "label108");
+ GLADE_HOOKUP_OBJECT (sortbydlg, hbox77, "hbox77");
+ GLADE_HOOKUP_OBJECT (sortbydlg, sortfmt, "sortfmt");
+ GLADE_HOOKUP_OBJECT (sortbydlg, custom3, "custom3");
+ GLADE_HOOKUP_OBJECT (sortbydlg, hbox78, "hbox78");
+ GLADE_HOOKUP_OBJECT (sortbydlg, label109, "label109");
+ GLADE_HOOKUP_OBJECT (sortbydlg, sortorder, "sortorder");
+ GLADE_HOOKUP_OBJECT_NO_REF (sortbydlg, dialog_action_area7, "dialog_action_area7");
+ GLADE_HOOKUP_OBJECT (sortbydlg, cancelbutton5, "cancelbutton5");
+ GLADE_HOOKUP_OBJECT (sortbydlg, okbutton5, "okbutton5");
+
+ return sortbydlg;
+}
+
+GtkWidget*
+create_select_dsp_plugin (void)
+{
+ GtkWidget *select_dsp_plugin;
+ GtkWidget *dialog_vbox10;
+ GtkWidget *vbox31;
+ GtkWidget *hbox85;
+ GtkWidget *label113;
+ GtkWidget *plugin;
+ GtkWidget *dialog_action_area9;
+ GtkWidget *cancelbutton7;
+ GtkWidget *okbutton7;
+
+ select_dsp_plugin = gtk_dialog_new ();
+ gtk_window_set_title (GTK_WINDOW (select_dsp_plugin), _("Select DSP Plugin"));
+ gtk_window_set_modal (GTK_WINDOW (select_dsp_plugin), TRUE);
+ gtk_window_set_type_hint (GTK_WINDOW (select_dsp_plugin), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+ dialog_vbox10 = GTK_DIALOG (select_dsp_plugin)->vbox;
+ gtk_widget_show (dialog_vbox10);
+
+ vbox31 = gtk_vbox_new (FALSE, 8);
+ gtk_widget_show (vbox31);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox10), vbox31, TRUE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox31), 12);
+
+ hbox85 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox85);
+ gtk_box_pack_start (GTK_BOX (vbox31), hbox85, FALSE, FALSE, 0);
+
+ label113 = gtk_label_new (_("Plugin"));
+ gtk_widget_show (label113);
+ gtk_box_pack_start (GTK_BOX (hbox85), label113, FALSE, FALSE, 0);
+
+ plugin = gtk_combo_box_new_text ();
+ gtk_widget_show (plugin);
+ gtk_box_pack_start (GTK_BOX (hbox85), plugin, TRUE, TRUE, 0);
+
+ dialog_action_area9 = GTK_DIALOG (select_dsp_plugin)->action_area;
+ gtk_widget_show (dialog_action_area9);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area9), GTK_BUTTONBOX_END);
+
+ cancelbutton7 = gtk_button_new_from_stock ("gtk-cancel");
+ gtk_widget_show (cancelbutton7);
+ gtk_dialog_add_action_widget (GTK_DIALOG (select_dsp_plugin), cancelbutton7, GTK_RESPONSE_CANCEL);
+ GTK_WIDGET_SET_FLAGS (cancelbutton7, GTK_CAN_DEFAULT);
+
+ okbutton7 = gtk_button_new_from_stock ("gtk-ok");
+ gtk_widget_show (okbutton7);
+ gtk_dialog_add_action_widget (GTK_DIALOG (select_dsp_plugin), okbutton7, GTK_RESPONSE_OK);
+ GTK_WIDGET_SET_FLAGS (okbutton7, GTK_CAN_DEFAULT);
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT_NO_REF (select_dsp_plugin, select_dsp_plugin, "select_dsp_plugin");
+ GLADE_HOOKUP_OBJECT_NO_REF (select_dsp_plugin, dialog_vbox10, "dialog_vbox10");
+ GLADE_HOOKUP_OBJECT (select_dsp_plugin, vbox31, "vbox31");
+ GLADE_HOOKUP_OBJECT (select_dsp_plugin, hbox85, "hbox85");
+ GLADE_HOOKUP_OBJECT (select_dsp_plugin, label113, "label113");
+ GLADE_HOOKUP_OBJECT (select_dsp_plugin, plugin, "plugin");
+ GLADE_HOOKUP_OBJECT_NO_REF (select_dsp_plugin, dialog_action_area9, "dialog_action_area9");
+ GLADE_HOOKUP_OBJECT (select_dsp_plugin, cancelbutton7, "cancelbutton7");
+ GLADE_HOOKUP_OBJECT (select_dsp_plugin, okbutton7, "okbutton7");
+
+ return select_dsp_plugin;
+}
+
+GtkWidget*
+create_tagwritersettings (void)
+{
+ GtkWidget *tagwritersettings;
+ GtkWidget *dialog_vbox11;
+ GtkWidget *vbox32;
+ GtkWidget *frame8;
+ GtkWidget *alignment21;
+ GtkWidget *vbox33;
+ GtkWidget *hbox89;
+ GtkWidget *write_id3v2;
+ GtkWidget *write_id3v1;
+ GtkWidget *write_apev2;
+ GtkWidget *hbox90;
+ GtkWidget *strip_id3v2;
+ GtkWidget *strip_id3v1;
+ GtkWidget *strip_apev2;
+ GtkWidget *hbox91;
+ GtkWidget *label118;
+ GtkWidget *id3v2_version;
+ GtkWidget *hbox92;
+ GtkWidget *label119;
+ GtkWidget *id3v1_encoding;
+ GtkWidget *label120;
+ GtkWidget *hbox93;
+ GtkWidget *frame9;
+ GtkWidget *alignment22;
+ GtkWidget *vbox34;
+ GtkWidget *hbox94;
+ GtkWidget *ape_write_id3v2;
+ GtkWidget *ape_write_apev2;
+ GtkWidget *hbox95;
+ GtkWidget *ape_strip_id3v2;
+ GtkWidget *ape_strip_apev2;
+ GtkWidget *label121;
+ GtkWidget *frame10;
+ GtkWidget *alignment23;
+ GtkWidget *vbox35;
+ GtkWidget *hbox96;
+ GtkWidget *wv_write_apev2;
+ GtkWidget *wv_write_id3v1;
+ GtkWidget *hbox97;
+ GtkWidget *wv_strip_apev2;
+ GtkWidget *wv_strip_id3v1;
+ GtkWidget *label122;
+ GtkWidget *dialog_action_area10;
+ GtkWidget *closebutton2;
+
+ tagwritersettings = gtk_dialog_new ();
+ gtk_container_set_border_width (GTK_CONTAINER (tagwritersettings), 12);
+ gtk_window_set_title (GTK_WINDOW (tagwritersettings), _("Tag Writer Settings"));
+ gtk_window_set_modal (GTK_WINDOW (tagwritersettings), TRUE);
+ gtk_window_set_type_hint (GTK_WINDOW (tagwritersettings), GDK_WINDOW_TYPE_HINT_DIALOG);
+ gtk_dialog_set_has_separator (GTK_DIALOG (tagwritersettings), FALSE);
+
+ dialog_vbox11 = GTK_DIALOG (tagwritersettings)->vbox;
+ gtk_widget_show (dialog_vbox11);
+
+ vbox32 = gtk_vbox_new (FALSE, 0);
+ gtk_widget_show (vbox32);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox11), vbox32, TRUE, TRUE, 0);
+
+ frame8 = gtk_frame_new (NULL);
+ gtk_widget_show (frame8);
+ gtk_box_pack_start (GTK_BOX (vbox32), frame8, FALSE, TRUE, 0);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame8), GTK_SHADOW_NONE);
+
+ alignment21 = gtk_alignment_new (0.5, 0.5, 1, 1);
+ gtk_widget_show (alignment21);
+ gtk_container_add (GTK_CONTAINER (frame8), alignment21);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment21), 0, 0, 12, 0);
+
+ vbox33 = gtk_vbox_new (FALSE, 8);
+ gtk_widget_show (vbox33);
+ gtk_container_add (GTK_CONTAINER (alignment21), vbox33);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox33), 12);
+
+ hbox89 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox89);
+ gtk_box_pack_start (GTK_BOX (vbox33), hbox89, FALSE, FALSE, 0);
+
+ write_id3v2 = gtk_check_button_new_with_mnemonic (_("Write ID3v2"));
+ gtk_widget_show (write_id3v2);
+ gtk_box_pack_start (GTK_BOX (hbox89), write_id3v2, FALSE, FALSE, 0);
+
+ write_id3v1 = gtk_check_button_new_with_mnemonic (_("Write ID3v1"));
+ gtk_widget_show (write_id3v1);
+ gtk_box_pack_start (GTK_BOX (hbox89), write_id3v1, FALSE, FALSE, 0);
+
+ write_apev2 = gtk_check_button_new_with_mnemonic (_("Write APEv2"));
+ gtk_widget_show (write_apev2);
+ gtk_box_pack_start (GTK_BOX (hbox89), write_apev2, FALSE, FALSE, 0);
+
+ hbox90 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox90);
+ gtk_box_pack_start (GTK_BOX (vbox33), hbox90, FALSE, FALSE, 0);
+
+ strip_id3v2 = gtk_check_button_new_with_mnemonic (_("Strip ID3v2"));
+ gtk_widget_show (strip_id3v2);
+ gtk_box_pack_start (GTK_BOX (hbox90), strip_id3v2, FALSE, FALSE, 0);
+
+ strip_id3v1 = gtk_check_button_new_with_mnemonic (_("Strip ID3v1"));
+ gtk_widget_show (strip_id3v1);
+ gtk_box_pack_start (GTK_BOX (hbox90), strip_id3v1, FALSE, FALSE, 0);
+
+ strip_apev2 = gtk_check_button_new_with_mnemonic (_("Strip APEv2"));
+ gtk_widget_show (strip_apev2);
+ gtk_box_pack_start (GTK_BOX (hbox90), strip_apev2, FALSE, FALSE, 0);
+
+ hbox91 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox91);
+ gtk_box_pack_start (GTK_BOX (vbox33), hbox91, TRUE, TRUE, 0);
+
+ label118 = gtk_label_new (_("ID3v2 version"));
+ gtk_widget_show (label118);
+ gtk_box_pack_start (GTK_BOX (hbox91), label118, FALSE, FALSE, 0);
+
+ id3v2_version = gtk_combo_box_new_text ();
+ gtk_widget_show (id3v2_version);
+ gtk_box_pack_start (GTK_BOX (hbox91), id3v2_version, TRUE, TRUE, 0);
+ gtk_combo_box_append_text (GTK_COMBO_BOX (id3v2_version), _("2.3 (Recommended)"));
+ gtk_combo_box_append_text (GTK_COMBO_BOX (id3v2_version), _("2.4"));
+
+ hbox92 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox92);
+ gtk_box_pack_start (GTK_BOX (vbox33), hbox92, TRUE, TRUE, 0);
+
+ label119 = gtk_label_new (_("ID3v1 character encoding (default is iso8859-1)"));
+ gtk_widget_show (label119);
+ gtk_box_pack_start (GTK_BOX (hbox92), label119, FALSE, FALSE, 0);
+
+ id3v1_encoding = gtk_entry_new ();
+ gtk_widget_show (id3v1_encoding);
+ gtk_box_pack_start (GTK_BOX (hbox92), id3v1_encoding, TRUE, TRUE, 0);
+ gtk_entry_set_invisible_char (GTK_ENTRY (id3v1_encoding), 9679);
+
+ label120 = gtk_label_new ("<b>MP3</b>");
+ gtk_widget_show (label120);
+ gtk_frame_set_label_widget (GTK_FRAME (frame8), label120);
+ gtk_label_set_use_markup (GTK_LABEL (label120), TRUE);
+
+ hbox93 = gtk_hbox_new (TRUE, 0);
+ gtk_widget_show (hbox93);
+ gtk_box_pack_start (GTK_BOX (vbox32), hbox93, FALSE, TRUE, 0);
+
+ frame9 = gtk_frame_new (NULL);
+ gtk_widget_show (frame9);
+ gtk_box_pack_start (GTK_BOX (hbox93), frame9, TRUE, TRUE, 0);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame9), GTK_SHADOW_NONE);
+
+ alignment22 = gtk_alignment_new (0.5, 0.5, 1, 1);
+ gtk_widget_show (alignment22);
+ gtk_container_add (GTK_CONTAINER (frame9), alignment22);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment22), 0, 0, 12, 0);
+
+ vbox34 = gtk_vbox_new (FALSE, 8);
+ gtk_widget_show (vbox34);
+ gtk_container_add (GTK_CONTAINER (alignment22), vbox34);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox34), 12);
+
+ hbox94 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox94);
+ gtk_box_pack_start (GTK_BOX (vbox34), hbox94, TRUE, TRUE, 0);
+
+ ape_write_id3v2 = gtk_check_button_new_with_mnemonic (_("Write ID3v2.4"));
+ gtk_widget_show (ape_write_id3v2);
+ gtk_box_pack_start (GTK_BOX (hbox94), ape_write_id3v2, FALSE, FALSE, 0);
+
+ ape_write_apev2 = gtk_check_button_new_with_mnemonic (_("Write APEv2"));
+ gtk_widget_show (ape_write_apev2);
+ gtk_box_pack_start (GTK_BOX (hbox94), ape_write_apev2, FALSE, FALSE, 0);
+
+ hbox95 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox95);
+ gtk_box_pack_start (GTK_BOX (vbox34), hbox95, TRUE, TRUE, 0);
+
+ ape_strip_id3v2 = gtk_check_button_new_with_mnemonic (_("Strip ID3v2"));
+ gtk_widget_show (ape_strip_id3v2);
+ gtk_box_pack_start (GTK_BOX (hbox95), ape_strip_id3v2, FALSE, FALSE, 0);
+
+ ape_strip_apev2 = gtk_check_button_new_with_mnemonic (_("Strip APEv2"));
+ gtk_widget_show (ape_strip_apev2);
+ gtk_box_pack_start (GTK_BOX (hbox95), ape_strip_apev2, FALSE, FALSE, 0);
+
+ label121 = gtk_label_new ("<b>APE</b>");
+ gtk_widget_show (label121);
+ gtk_frame_set_label_widget (GTK_FRAME (frame9), label121);
+ gtk_label_set_use_markup (GTK_LABEL (label121), TRUE);
+
+ frame10 = gtk_frame_new (NULL);
+ gtk_widget_show (frame10);
+ gtk_box_pack_start (GTK_BOX (hbox93), frame10, TRUE, TRUE, 0);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame10), GTK_SHADOW_NONE);
+
+ alignment23 = gtk_alignment_new (0.5, 0.5, 1, 1);
+ gtk_widget_show (alignment23);
+ gtk_container_add (GTK_CONTAINER (frame10), alignment23);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment23), 0, 0, 12, 0);
+
+ vbox35 = gtk_vbox_new (FALSE, 8);
+ gtk_widget_show (vbox35);
+ gtk_container_add (GTK_CONTAINER (alignment23), vbox35);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox35), 12);
+
+ hbox96 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox96);
+ gtk_box_pack_start (GTK_BOX (vbox35), hbox96, FALSE, FALSE, 0);
+
+ wv_write_apev2 = gtk_check_button_new_with_mnemonic (_("Write APEv2"));
+ gtk_widget_show (wv_write_apev2);
+ gtk_box_pack_start (GTK_BOX (hbox96), wv_write_apev2, FALSE, FALSE, 0);
+
+ wv_write_id3v1 = gtk_check_button_new_with_mnemonic (_("Write ID3v1"));
+ gtk_widget_show (wv_write_id3v1);
+ gtk_box_pack_start (GTK_BOX (hbox96), wv_write_id3v1, FALSE, FALSE, 0);
+
+ hbox97 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox97);
+ gtk_box_pack_start (GTK_BOX (vbox35), hbox97, FALSE, FALSE, 0);
+
+ wv_strip_apev2 = gtk_check_button_new_with_mnemonic (_("Strip APEv2"));
+ gtk_widget_show (wv_strip_apev2);
+ gtk_box_pack_start (GTK_BOX (hbox97), wv_strip_apev2, FALSE, FALSE, 0);
+
+ wv_strip_id3v1 = gtk_check_button_new_with_mnemonic (_("Strip ID3v1"));
+ gtk_widget_show (wv_strip_id3v1);
+ gtk_box_pack_start (GTK_BOX (hbox97), wv_strip_id3v1, FALSE, FALSE, 0);
+
+ label122 = gtk_label_new ("<b>WavPack</b>");
+ gtk_widget_show (label122);
+ gtk_frame_set_label_widget (GTK_FRAME (frame10), label122);
+ gtk_label_set_use_markup (GTK_LABEL (label122), TRUE);
+
+ dialog_action_area10 = GTK_DIALOG (tagwritersettings)->action_area;
+ gtk_widget_show (dialog_action_area10);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area10), GTK_BUTTONBOX_END);
+
+ closebutton2 = gtk_button_new_from_stock ("gtk-close");
+ gtk_widget_show (closebutton2);
+ gtk_dialog_add_action_widget (GTK_DIALOG (tagwritersettings), closebutton2, GTK_RESPONSE_CLOSE);
+ GTK_WIDGET_SET_FLAGS (closebutton2, GTK_CAN_DEFAULT);
+
+ g_signal_connect ((gpointer) write_id3v2, "toggled",
+ G_CALLBACK (on_write_id3v2_toggled),
+ NULL);
+ g_signal_connect ((gpointer) write_id3v1, "toggled",
+ G_CALLBACK (on_write_id3v1_toggled),
+ NULL);
+ g_signal_connect ((gpointer) write_apev2, "toggled",
+ G_CALLBACK (on_write_apev2_toggled),
+ NULL);
+ g_signal_connect ((gpointer) strip_id3v2, "toggled",
+ G_CALLBACK (on_strip_id3v2_toggled),
+ NULL);
+ g_signal_connect ((gpointer) strip_id3v1, "toggled",
+ G_CALLBACK (on_strip_id3v1_toggled),
+ NULL);
+ g_signal_connect ((gpointer) strip_apev2, "toggled",
+ G_CALLBACK (on_strip_apev2_toggled),
+ NULL);
+ g_signal_connect ((gpointer) id3v2_version, "changed",
+ G_CALLBACK (on_id3v2_version_changed),
+ NULL);
+ g_signal_connect ((gpointer) id3v1_encoding, "changed",
+ G_CALLBACK (on_id3v1_encoding_changed),
+ NULL);
+ g_signal_connect ((gpointer) ape_write_id3v2, "toggled",
+ G_CALLBACK (on_ape_write_id3v2_toggled),
+ NULL);
+ g_signal_connect ((gpointer) ape_write_apev2, "toggled",
+ G_CALLBACK (on_ape_write_apev2_toggled),
+ NULL);
+ g_signal_connect ((gpointer) ape_strip_id3v2, "toggled",
+ G_CALLBACK (on_ape_strip_id3v2_toggled),
+ NULL);
+ g_signal_connect ((gpointer) ape_strip_apev2, "toggled",
+ G_CALLBACK (on_ape_strip_apev2_toggled),
+ NULL);
+ g_signal_connect ((gpointer) wv_write_apev2, "toggled",
+ G_CALLBACK (on_wv_write_apev2_toggled),
+ NULL);
+ g_signal_connect ((gpointer) wv_write_id3v1, "toggled",
+ G_CALLBACK (on_wv_write_id3v1_toggled),
+ NULL);
+ g_signal_connect ((gpointer) wv_strip_apev2, "toggled",
+ G_CALLBACK (on_wv_strip_apev2_toggled),
+ NULL);
+ g_signal_connect ((gpointer) wv_strip_id3v1, "toggled",
+ G_CALLBACK (on_wv_strip_id3v1_toggled),
+ NULL);
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT_NO_REF (tagwritersettings, tagwritersettings, "tagwritersettings");
+ GLADE_HOOKUP_OBJECT_NO_REF (tagwritersettings, dialog_vbox11, "dialog_vbox11");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, vbox32, "vbox32");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, frame8, "frame8");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, alignment21, "alignment21");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, vbox33, "vbox33");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, hbox89, "hbox89");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, write_id3v2, "write_id3v2");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, write_id3v1, "write_id3v1");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, write_apev2, "write_apev2");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, hbox90, "hbox90");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, strip_id3v2, "strip_id3v2");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, strip_id3v1, "strip_id3v1");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, strip_apev2, "strip_apev2");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, hbox91, "hbox91");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, label118, "label118");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, id3v2_version, "id3v2_version");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, hbox92, "hbox92");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, label119, "label119");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, id3v1_encoding, "id3v1_encoding");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, label120, "label120");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, hbox93, "hbox93");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, frame9, "frame9");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, alignment22, "alignment22");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, vbox34, "vbox34");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, hbox94, "hbox94");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, ape_write_id3v2, "ape_write_id3v2");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, ape_write_apev2, "ape_write_apev2");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, hbox95, "hbox95");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, ape_strip_id3v2, "ape_strip_id3v2");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, ape_strip_apev2, "ape_strip_apev2");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, label121, "label121");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, frame10, "frame10");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, alignment23, "alignment23");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, vbox35, "vbox35");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, hbox96, "hbox96");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, wv_write_apev2, "wv_write_apev2");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, wv_write_id3v1, "wv_write_id3v1");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, hbox97, "hbox97");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, wv_strip_apev2, "wv_strip_apev2");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, wv_strip_id3v1, "wv_strip_id3v1");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, label122, "label122");
+ GLADE_HOOKUP_OBJECT_NO_REF (tagwritersettings, dialog_action_area10, "dialog_action_area10");
+ GLADE_HOOKUP_OBJECT (tagwritersettings, closebutton2, "closebutton2");
+
+ return tagwritersettings;
+}
+
diff --git a/plugins/gtkui/interface.h b/plugins/gtkui/interface.h
index 5c4b5923..d27c75e6 100644
--- a/plugins/gtkui/interface.h
+++ b/plugins/gtkui/interface.h
@@ -5,11 +5,14 @@
GtkWidget* create_mainwin (void);
GtkWidget* create_searchwin (void);
GtkWidget* create_traymenu (void);
-GtkWidget* create_addprogress (void);
+GtkWidget* create_progressdlg (void);
GtkWidget* create_helpwindow (void);
GtkWidget* create_trackproperties (void);
GtkWidget* create_editcolumndlg (void);
GtkWidget* create_prefwin (void);
-GtkWidget* create_editplaylistdlg (void);
+GtkWidget* create_entrydialog (void);
GtkWidget* create_addlocationdlg (void);
GtkWidget* create_groupbydlg (void);
+GtkWidget* create_sortbydlg (void);
+GtkWidget* create_select_dsp_plugin (void);
+GtkWidget* create_tagwritersettings (void);
diff --git a/plugins/gtkui/mainplaylist.c b/plugins/gtkui/mainplaylist.c
index 2df3bd0e..340cbfb3 100644
--- a/plugins/gtkui/mainplaylist.c
+++ b/plugins/gtkui/mainplaylist.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -127,9 +127,9 @@ gboolean
playlist_tooltip_handler (GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, gpointer unused)
{
GtkWidget *pl = lookup_widget (mainwin, "playlist");
- DB_playItem_t *item = (DB_playItem_t *)ddb_listview_get_iter_from_coord (DDB_LISTVIEW (pl), 0, y);
- if (item && item->fname) {
- gtk_tooltip_set_text (tooltip, item->fname);
+ DB_playItem_t *it = (DB_playItem_t *)ddb_listview_get_iter_from_coord (DDB_LISTVIEW (pl), 0, y);
+ if (it) {
+ gtk_tooltip_set_text (tooltip, deadbeef->pl_find_meta (it, ":URI"));
return TRUE;
}
return FALSE;
@@ -143,13 +143,13 @@ main_col_sort (int col, int sort_order, void *user_data) {
deadbeef->pl_sort (PL_MAIN, c->id, c->format, sort_order-1);
}
void main_handle_doubleclick (DdbListview *listview, DdbListviewIter iter, int idx) {
- deadbeef->sendmessage (M_PLAYSONGNUM, 0, idx, 0);
+ deadbeef->sendmessage (M_PLAY_NUM, 0, idx, 0);
}
void main_selection_changed (DdbListviewIter it, int idx) {
DdbListview *search = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist"));
if (idx == -1) {
- ddb_listview_refresh (search, DDB_REFRESH_LIST | DDB_EXPOSE_LIST);
+ ddb_listview_refresh (search, DDB_REFRESH_LIST);
}
else {
ddb_listview_draw_row (search, search_get_idx ((DB_playItem_t *)it), it);
@@ -173,8 +173,8 @@ void main_draw_group_title (DdbListview *listview, GdkDrawable *drawable, DdbLis
draw_set_fg_color (rgb);
}
int ew, eh;
- draw_text (x + 5, y + height/2 - draw_get_font_size ()/2 - 2, width-10, 0, str);
draw_get_text_extents (str, -1, &ew, &eh);
+ draw_text (x + 5, y + height/2 - draw_get_font_size ()/2 - 2, ew+5, 0, str);
draw_line (x + 5 + ew + 3, y+height/2, x + width, y+height/2);
}
}
@@ -305,7 +305,7 @@ main_playlist_init (GtkWidget *widget) {
add_column_helper (listview, _("Playing"), 50, DB_COLUMN_PLAYING, NULL, 0);
add_column_helper (listview, _("Artist / Album"), 150, -1, "%a - %b", 0);
add_column_helper (listview, _("Track No"), 50, -1, "%n", 1);
- add_column_helper (listview, _("Title / Track Artist"), 150, -1, "%t", 0);
+ add_column_helper (listview, _("Title"), 150, -1, "%t", 0);
add_column_helper (listview, _("Duration"), 50, -1, "%l", 0);
}
else {
@@ -325,7 +325,9 @@ main_playlist_init (GtkWidget *widget) {
g_object_set_property (G_OBJECT (widget), "has-tooltip", &value);
g_signal_connect (G_OBJECT (widget), "query-tooltip", G_CALLBACK (playlist_tooltip_handler), NULL);
}
- strncpy (group_by_str, deadbeef->conf_get_str ("playlist.group_by", ""), sizeof (group_by_str));
+ deadbeef->conf_lock ();
+ strncpy (group_by_str, deadbeef->conf_get_str_fast ("playlist.group_by", ""), sizeof (group_by_str));
+ deadbeef->conf_unlock ();
group_by_str[sizeof (group_by_str)-1] = 0;
}
@@ -337,7 +339,7 @@ void
main_refresh (void) {
if (mainwin && gtk_widget_get_visible (mainwin)) {
DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (pl, DDB_REFRESH_VSCROLL | DDB_REFRESH_LIST | DDB_EXPOSE_LIST);
+ ddb_listview_refresh (pl, DDB_REFRESH_VSCROLL | DDB_REFRESH_LIST);
}
}
diff --git a/plugins/gtkui/mainplaylist.h b/plugins/gtkui/mainplaylist.h
index af266c4a..b17ef63d 100644
--- a/plugins/gtkui/mainplaylist.h
+++ b/plugins/gtkui/mainplaylist.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
diff --git a/plugins/gtkui/parser.c b/plugins/gtkui/parser.c
index 96558c9e..6ee81f9a 100644
--- a/plugins/gtkui/parser.c
+++ b/plugins/gtkui/parser.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
diff --git a/plugins/gtkui/parser.h b/plugins/gtkui/parser.h
index b5d48a04..ac411577 100644
--- a/plugins/gtkui/parser.h
+++ b/plugins/gtkui/parser.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
diff --git a/plugins/gtkui/plcommon.c b/plugins/gtkui/plcommon.c
index beff39bb..216b7122 100644
--- a/plugins/gtkui/plcommon.c
+++ b/plugins/gtkui/plcommon.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -120,7 +120,7 @@ void draw_column_data (DdbListview *listview, GdkDrawable *drawable, DdbListview
if (!album || !*album) {
album = deadbeef->pl_find_meta (group_it, "title");
}
- GdkPixbuf *pixbuf = get_cover_art (((DB_playItem_t *)group_it)->fname, artist, album, art_width);
+ GdkPixbuf *pixbuf = get_cover_art (deadbeef->pl_find_meta (((DB_playItem_t *)group_it), ":URI"), artist, album, art_width);
if (pixbuf) {
int pw = gdk_pixbuf_get_width (pixbuf);
int ph = gdk_pixbuf_get_height (pixbuf);
@@ -181,10 +181,10 @@ void draw_column_data (DdbListview *listview, GdkDrawable *drawable, DdbListview
draw_init_font_bold ();
}
if (calign_right) {
- draw_text (x+5, y + height/2 - draw_get_font_size ()/2 - 2, cwidth-10, 1, text);
+ draw_text (x+5, y + (height-1)/2 - draw_get_font_size ()/2, cwidth-10, 1, text);
}
else {
- draw_text (x + 5, y + height/2 - draw_get_font_size ()/2 - 2, cwidth-10, 0, text);
+ draw_text (x + 5, y + (height-1)/2 - draw_get_font_size ()/2, cwidth-10, 0, text);
}
if (gtkui_embolden_current_track && it && it == playing_track) {
draw_init_font_normal ();
@@ -238,14 +238,15 @@ main_reload_metadata_activate
DdbListview *ps = DDB_LISTVIEW (g_object_get_data (G_OBJECT (menuitem), "ps"));
DB_playItem_t *it = deadbeef->pl_get_first (PL_MAIN);
while (it) {
- if (deadbeef->pl_is_selected (it) && deadbeef->is_local_file (it->fname) && it->decoder_id) {
+ const char *decoder_id = deadbeef->pl_find_meta (it, ":DECODER");
+ if (deadbeef->pl_is_selected (it) && deadbeef->is_local_file (deadbeef->pl_find_meta (it, ":URI")) && decoder_id) {
uint32_t f = deadbeef->pl_get_item_flags (it);
if (!(f & DDB_IS_SUBTRACK)) {
f &= ~DDB_TAG_MASK;
deadbeef->pl_set_item_flags (it, f);
DB_decoder_t **decoders = deadbeef->plug_get_decoder_list ();
for (int i = 0; decoders[i]; i++) {
- if (!strcmp (decoders[i]->plugin.id, it->decoder_id)) {
+ if (!strcmp (decoders[i]->plugin.id, decoder_id)) {
if (decoders[i]->read_metadata) {
decoders[i]->read_metadata (it);
}
@@ -266,13 +267,7 @@ void
main_properties_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
- DB_playItem_t *it = deadbeef->pl_get_for_idx_and_iter (clicked_idx, PL_MAIN);
- if (!it) {
- fprintf (stderr, "attempt to view properties of non-existing item\n");
- return;
- }
- show_track_properties_dlg (it);
- deadbeef->pl_item_unref (it);
+ show_track_properties_dlg ();
}
void
@@ -337,8 +332,8 @@ on_remove_from_disk_activate (GtkMenuItem *menuitem,
DB_playItem_t *it = deadbeef->pl_get_first (PL_MAIN);
while (it) {
- if (deadbeef->pl_is_selected (it) && deadbeef->is_local_file (it->fname)) {
- unlink (it->fname);
+ if (deadbeef->pl_is_selected (it) && deadbeef->is_local_file (deadbeef->pl_find_meta (it, ":URI"))) {
+ unlink (deadbeef->pl_find_meta (it, ":URI"));
}
DB_playItem_t *next = deadbeef->pl_get_next (it, PL_MAIN);
deadbeef->pl_item_unref (it);
@@ -460,6 +455,7 @@ list_context_menu (DdbListview *listview, DdbListviewIter it, int idx) {
DB_plugin_t **plugins = deadbeef->plug_get_list();
int i;
+ int added_entries = 0;
for (i = 0; plugins[i]; i++)
{
if (!plugins[i]->get_actions)
@@ -474,6 +470,7 @@ list_context_menu (DdbListview *listview, DdbListviewIter it, int idx) {
if (action->flags & DB_ACTION_COMMON)
continue;
count++;
+ added_entries++;
GtkWidget *actionitem;
actionitem = gtk_menu_item_new_with_mnemonic (_(action->title));
gtk_widget_show (actionitem);
@@ -492,13 +489,14 @@ list_context_menu (DdbListview *listview, DdbListviewIter it, int idx) {
gtk_widget_set_sensitive (GTK_WIDGET (actionitem), FALSE);
}
}
- if (count > 0)
- {
- separator8 = gtk_separator_menu_item_new ();
- gtk_widget_show (separator8);
- gtk_container_add (GTK_CONTAINER (playlist_menu), separator8);
- gtk_widget_set_sensitive (separator8, FALSE);
- }
+ }
+
+ if (added_entries > 0)
+ {
+ separator8 = gtk_separator_menu_item_new ();
+ gtk_widget_show (separator8);
+ gtk_container_add (GTK_CONTAINER (playlist_menu), separator8);
+ gtk_widget_set_sensitive (separator8, FALSE);
}
properties1 = gtk_menu_item_new_with_mnemonic (_("Properties"));
@@ -733,7 +731,7 @@ on_add_column_activate (GtkMenuItem *menuitem,
int align = gtk_combo_box_get_active (GTK_COMBO_BOX (lookup_widget (dlg, "align")));
ddb_listview_column_insert (last_playlist, active_column, title, 100, align, inf->id == DB_COLUMN_ALBUM_ART ? 100 : 0, inf);
- ddb_listview_refresh (last_playlist, DDB_REFRESH_COLUMNS | DDB_REFRESH_LIST | DDB_REFRESH_HSCROLL | DDB_EXPOSE_LIST | DDB_EXPOSE_COLUMNS);
+ ddb_listview_refresh (last_playlist, DDB_REFRESH_COLUMNS | DDB_REFRESH_LIST | DDB_REFRESH_HSCROLL);
}
gtk_widget_destroy (dlg);
}
@@ -808,7 +806,7 @@ on_edit_column_activate (GtkMenuItem *menuitem,
init_column (inf, id, format);
ddb_listview_column_set_info (last_playlist, active_column, title, width, align, inf->id == DB_COLUMN_ALBUM_ART ? width : 0, inf);
- ddb_listview_refresh (last_playlist, DDB_REFRESH_COLUMNS | DDB_REFRESH_LIST | DDB_EXPOSE_LIST | DDB_EXPOSE_COLUMNS);
+ ddb_listview_refresh (last_playlist, DDB_REFRESH_COLUMNS | DDB_REFRESH_LIST);
}
gtk_widget_destroy (dlg);
}
@@ -822,7 +820,7 @@ on_remove_column_activate (GtkMenuItem *menuitem,
return;
ddb_listview_column_remove (last_playlist, active_column);
- ddb_listview_refresh (last_playlist, DDB_REFRESH_COLUMNS | DDB_REFRESH_LIST | DDB_REFRESH_HSCROLL | DDB_EXPOSE_LIST | DDB_EXPOSE_COLUMNS);
+ ddb_listview_refresh (last_playlist, DDB_REFRESH_COLUMNS | DDB_REFRESH_LIST | DDB_REFRESH_HSCROLL);
}
GtkWidget*
diff --git a/plugins/gtkui/plcommon.h b/plugins/gtkui/plcommon.h
index 8332cfcb..6a3114c1 100644
--- a/plugins/gtkui/plcommon.h
+++ b/plugins/gtkui/plcommon.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
diff --git a/plugins/gtkui/pluginconf.c b/plugins/gtkui/pluginconf.c
index 601f72e8..c7c73ae8 100644
--- a/plugins/gtkui/pluginconf.c
+++ b/plugins/gtkui/pluginconf.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -30,6 +30,7 @@
#include "gtkui.h"
#include "parser.h"
#include "support.h"
+#include "pluginconf.h"
//#define trace(...) { fprintf (stderr, __VA_ARGS__); }
#define trace(fmt,...)
@@ -42,14 +43,16 @@ on_prop_browse_file (GtkButton *button, gpointer user_data) {
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), FALSE);
// restore folder
- gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str ("filechooser.lastdir", ""));
+ deadbeef->conf_lock ();
+ gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str_fast ("filechooser.lastdir", ""));
+ deadbeef->conf_unlock ();
int response = gtk_dialog_run (GTK_DIALOG (dlg));
// store folder
gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
if (folder) {
deadbeef->conf_set_str ("filechooser.lastdir", folder);
g_free (folder);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
}
if (response == GTK_RESPONSE_OK) {
gchar *file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
@@ -65,14 +68,14 @@ on_prop_browse_file (GtkButton *button, gpointer user_data) {
}
}
-static void apply_conf (GtkWidget *w, DB_plugin_t *p) {
+static void apply_conf (GtkWidget *w, ddb_dialog_t *conf) {
// parse script
char token[MAX_TOKEN];
- const char *script = p->configdialog;
+ const char *script = conf->layout;
parser_line = 1;
while (script = gettoken (script, token)) {
if (strcmp (token, "property")) {
- fprintf (stderr, "invalid token while loading plugin %s config dialog: %s at line %d\n", p->name, token, parser_line);
+ fprintf (stderr, "invalid token while loading plugin %s config dialog: %s at line %d\n", conf->title, token, parser_line);
break;
}
char labeltext[MAX_TOKEN];
@@ -85,8 +88,34 @@ static void apply_conf (GtkWidget *w, DB_plugin_t *p) {
if (!script) {
break;
}
+
+ // skip containers
+ if (!strncmp (type, "hbox[", 5) || !strncmp (type, "vbox[", 5)) {
+ // skip to ;
+ char semicolon[MAX_TOKEN];
+ while (script = gettoken_warn_eof (script, semicolon)) {
+ if (!strcmp (semicolon, ";")) {
+ break;
+ }
+ }
+ continue;
+ }
+
+ // ignore layout options
char key[MAX_TOKEN];
- script = gettoken_warn_eof (script, key);
+ const char *skiptokens[] = { "vert", NULL };
+ for (;;) {
+ script = gettoken_warn_eof (script, key);
+ int i = 0;
+ for (i = 0; skiptokens[i]; i++) {
+ if (!strcmp (key, skiptokens[i])) {
+ break;
+ }
+ }
+ if (!skiptokens[i]) {
+ break;
+ }
+ }
if (!script) {
break;
}
@@ -95,39 +124,66 @@ static void apply_conf (GtkWidget *w, DB_plugin_t *p) {
if (!script) {
break;
}
- script = gettoken_warn_eof (script, token);
- if (!script) {
- break;
- }
- if (strcmp (token, ";")) {
- fprintf (stderr, "expected `;' while loading plugin %s config dialog: %s at line %d\n", p->name, token, parser_line);
- break;
- }
// fetch data
GtkWidget *widget = lookup_widget (w, key);
if (widget) {
if (!strcmp (type, "entry") || !strcmp (type, "password")) {
- deadbeef->conf_set_str (key, gtk_entry_get_text (GTK_ENTRY (widget)));
+ conf->set_param (key, gtk_entry_get_text (GTK_ENTRY (widget)));
}
else if (!strcmp (type, "file")) {
if (deadbeef->conf_get_int ("gtkui.pluginconf.use_filechooser_button", 0)) {
// filechooser
- deadbeef->conf_set_str (key, gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget)));
+ conf->set_param (key, gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget)));
}
else {
- deadbeef->conf_set_str (key, gtk_entry_get_text (GTK_ENTRY (widget)));
+ conf->set_param (key, gtk_entry_get_text (GTK_ENTRY (widget)));
}
}
else if (!strcmp (type, "checkbox")) {
- deadbeef->conf_set_int (key, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)));
+ conf->set_param (key, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? "1" : "0");
+ }
+ else if (!strncmp (type, "hscale[", 7) || !strncmp (type, "vscale[", 7)) {
+ char s[20];
+ snprintf (s, sizeof (s), "%f", gtk_range_get_value (GTK_RANGE (widget)));
+ conf->set_param (key, s);
}
- else if (!strncmp (type, "hscale[", 7)) {
- deadbeef->conf_set_float (key, gtk_range_get_value (GTK_RANGE (widget)));
+ else if (!strncmp (type, "spinbtn[", 8)) {
+ char s[20];
+ snprintf (s, sizeof (s), "%f", (float)gtk_spin_button_get_value (GTK_SPIN_BUTTON (widget)));
+ conf->set_param (key, s);
+ }
+ else if (!strncmp (type, "select[", 7)) {
+ int n;
+ if (1 != sscanf (type+6, "[%d]", &n)) {
+ break;
+ }
+ for (int i = 0; i < n; i++) {
+ char value[MAX_TOKEN];
+ script = gettoken_warn_eof (script, value);
+ if (!script) {
+ break;
+ }
+ }
+ if (!script) {
+ break;
+ }
+ char s[20];
+ snprintf (s, sizeof (s), "%d", gtk_combo_box_get_active (GTK_COMBO_BOX (widget)));
+ conf->set_param (key, s);
}
}
+
+ script = gettoken_warn_eof (script, token);
+ if (!script) {
+ break;
+ }
+ if (strcmp (token, ";")) {
+ fprintf (stderr, "expected `;' while loading plugin %s config dialog: %s at line %d\n", conf->title, token, parser_line);
+ break;
+ }
}
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
}
static void
@@ -135,22 +191,69 @@ prop_changed (GtkWidget *editable, gpointer user_data) {
gtk_dialog_set_response_sensitive (GTK_DIALOG (user_data), GTK_RESPONSE_APPLY, TRUE);
}
-void
-plugin_configure (GtkWidget *parentwin, DB_plugin_t *p) {
+int
+ddb_button_from_gtk_response (int response) {
+ switch (response) {
+ case GTK_RESPONSE_OK:
+ return ddb_button_ok;
+ case GTK_RESPONSE_CANCEL:
+ return ddb_button_cancel;
+ case GTK_RESPONSE_CLOSE:
+ return ddb_button_close;
+ case GTK_RESPONSE_APPLY:
+ return ddb_button_apply;
+ case GTK_RESPONSE_YES:
+ return ddb_button_yes;
+ case GTK_RESPONSE_NO:
+ return ddb_button_no;
+ }
+ return -1;
+}
+
+int
+gtkui_run_dialog (GtkWidget *parentwin, ddb_dialog_t *conf, uint32_t buttons, int (*callback)(int button, void *ctx), void *ctx) {
// create window
char title[200];
- snprintf (title, sizeof (title), _("Setup %s"), p->name);
- GtkWidget *win = gtk_dialog_new_with_buttons (title, GTK_WINDOW (parentwin), GTK_DIALOG_MODAL, GTK_STOCK_APPLY, GTK_RESPONSE_APPLY, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
- gtk_dialog_set_default_response (GTK_DIALOG (win), GTK_RESPONSE_OK);
+ snprintf (title, sizeof (title), _("Configure %s"), conf->title);
+ GtkWidget *win;
+ if (!buttons) {
+ win = gtk_dialog_new_with_buttons (title, GTK_WINDOW (parentwin), GTK_DIALOG_MODAL, GTK_STOCK_APPLY, GTK_RESPONSE_APPLY, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+ gtk_dialog_set_default_response (GTK_DIALOG (win), GTK_RESPONSE_OK);
+ }
+ else {
+ win = gtk_dialog_new_with_buttons (title, GTK_WINDOW (parentwin), GTK_DIALOG_MODAL, NULL);
+ if (buttons & (1<<ddb_button_ok)) {
+ gtk_dialog_add_button (GTK_DIALOG (win), GTK_STOCK_OK, GTK_RESPONSE_OK);
+ }
+ if (buttons & (1<<ddb_button_cancel)) {
+ gtk_dialog_add_button (GTK_DIALOG (win), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+ }
+ if (buttons & (1<<ddb_button_close)) {
+ gtk_dialog_add_button (GTK_DIALOG (win), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
+ }
+ if (buttons & (1<<ddb_button_apply)) {
+ gtk_dialog_add_button (GTK_DIALOG (win), GTK_STOCK_APPLY, GTK_RESPONSE_APPLY);
+ }
+ if (buttons & (1<<ddb_button_yes)) {
+ gtk_dialog_add_button (GTK_DIALOG (win), GTK_STOCK_YES, GTK_RESPONSE_YES);
+ }
+ if (buttons & (1<<ddb_button_no)) {
+ gtk_dialog_add_button (GTK_DIALOG (win), GTK_STOCK_NO, GTK_RESPONSE_NO);
+ }
+ }
gtk_window_set_type_hint (GTK_WINDOW (win), GDK_WINDOW_TYPE_HINT_DIALOG);
gtk_container_set_border_width (GTK_CONTAINER(win), 12);
gtk_window_set_title (GTK_WINDOW (win), title);
gtk_window_set_modal (GTK_WINDOW (win), TRUE);
gtk_window_set_transient_for (GTK_WINDOW (win), GTK_WINDOW (parentwin));
- GtkWidget *vbox;
- vbox = GTK_DIALOG (win)->vbox;
- gtk_box_set_spacing (GTK_BOX (vbox), 8);
+
+ GtkWidget *widgets[100] = {NULL};
+ int pack[100] = {0};
+ int ncurr = 0;
+
+ widgets[ncurr] = GTK_DIALOG (win)->vbox;
+ gtk_box_set_spacing (GTK_BOX (widgets[ncurr]), 8);
GtkWidget *action_area = GTK_DIALOG (win)->action_area;
gtk_widget_show (action_area);
gtk_button_box_set_layout (GTK_BUTTON_BOX (action_area), GTK_BUTTONBOX_END);
@@ -158,11 +261,11 @@ plugin_configure (GtkWidget *parentwin, DB_plugin_t *p) {
// parse script
char token[MAX_TOKEN];
- const char *script = p->configdialog;
+ const char *script = conf->layout;
parser_line = 1;
while (script = gettoken (script, token)) {
if (strcmp (token, "property")) {
- fprintf (stderr, "invalid token while loading plugin %s config dialog: %s at line %d\n", p->name, token, parser_line);
+ fprintf (stderr, "invalid token while loading plugin %s config dialog: %s at line %d\n", conf->title, token, parser_line);
break;
}
char labeltext[MAX_TOKEN];
@@ -170,34 +273,100 @@ plugin_configure (GtkWidget *parentwin, DB_plugin_t *p) {
if (!script) {
break;
}
+
+ if (ncurr > 0) {
+ pack[ncurr]--;
+ if (pack[ncurr] < 0) {
+ ncurr--;
+ }
+ }
+
char type[MAX_TOKEN];
script = gettoken_warn_eof (script, type);
if (!script) {
break;
}
+
+ if (!strncmp (type, "hbox[", 5) || !strncmp (type, "vbox[", 5)) {
+ ncurr++;
+ int n = 0;
+ if (1 != sscanf (type+4, "[%d]", &n)) {
+ break;
+ }
+ pack[ncurr] = n;
+
+ int vert = 0;
+ int hmg = FALSE;
+ int fill = FALSE;
+ int expand = FALSE;
+ int border = 0;
+ int spacing = 8;
+ int height = 100;
+
+ char param[MAX_TOKEN];
+ for (;;) {
+ script = gettoken_warn_eof (script, param);
+ if (!script) {
+ break;
+ }
+ if (!strcmp (param, ";")) {
+ break;
+ }
+ else if (!strcmp (param, "hmg")) {
+ hmg = TRUE;
+ }
+ else if (!strcmp (param, "fill")) {
+ fill = TRUE;
+ }
+ else if (!strcmp (param, "expand")) {
+ expand = TRUE;
+ }
+ else if (!strncmp (param, "border=", 7)) {
+ border = atoi (param+7);
+ }
+ else if (!strncmp (param, "spacing=", 8)) {
+ spacing = atoi (param+8);
+ }
+ else if (!strncmp (param, "height=", 7)) {
+ height = atoi (param+7);
+ }
+ }
+
+ widgets[ncurr] = vert ? gtk_vbox_new (TRUE, spacing) : gtk_hbox_new (TRUE, spacing);
+ gtk_widget_set_size_request (widgets[ncurr], -1, height);
+ gtk_widget_show (widgets[ncurr]);
+ gtk_box_pack_start (GTK_BOX(widgets[ncurr-1]), widgets[ncurr], fill, expand, border);
+ continue;
+ }
+
+ int vertical = 0;
+
char key[MAX_TOKEN];
- script = gettoken_warn_eof (script, key);
- if (!script) {
- break;
+ for (;;) {
+ script = gettoken_warn_eof (script, key);
+ if (!script) {
+ break;
+ }
+ if (!strcmp (key, "vert")) {
+ vertical = 1;
+ }
+ else {
+ break;
+ }
}
+
char def[MAX_TOKEN];
script = gettoken_warn_eof (script, def);
if (!script) {
break;
}
- script = gettoken_warn_eof (script, token);
- if (!script) {
- break;
- }
- if (strcmp (token, ";")) {
- fprintf (stderr, "expected `;' while loading plugin %s config dialog: %s at line %d\n", p->name, token, parser_line);
- break;
- }
// add to dialog
GtkWidget *label = NULL;
GtkWidget *prop = NULL;
GtkWidget *cont = NULL;
+ char value[1000];
+ conf->get_param (key, value, sizeof (value), def);
if (!strcmp (type, "entry") || !strcmp (type, "password")) {
label = gtk_label_new (_(labeltext));
gtk_widget_show (label);
@@ -205,13 +374,17 @@ plugin_configure (GtkWidget *parentwin, DB_plugin_t *p) {
gtk_entry_set_activates_default (GTK_ENTRY (prop), TRUE);
g_signal_connect (G_OBJECT (prop), "changed", G_CALLBACK (prop_changed), win);
gtk_widget_show (prop);
- gtk_entry_set_text (GTK_ENTRY (prop), deadbeef->conf_get_str (key, def));
+ gtk_entry_set_text (GTK_ENTRY (prop), value);
+
+ if (!strcmp (type, "password")) {
+ gtk_entry_set_visibility (GTK_ENTRY (prop), FALSE);
+ }
}
else if (!strcmp (type, "checkbox")) {
prop = gtk_check_button_new_with_label (_(labeltext));
g_signal_connect (G_OBJECT (prop), "toggled", G_CALLBACK (prop_changed), win);
gtk_widget_show (prop);
- int val = deadbeef->conf_get_int (key, atoi (def));
+ int val = atoi (value);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (prop), val);
}
else if (!strcmp (type, "file")) {
@@ -220,7 +393,7 @@ plugin_configure (GtkWidget *parentwin, DB_plugin_t *p) {
if (deadbeef->conf_get_int ("gtkui.pluginconf.use_filechooser_button", 0)) {
prop = gtk_file_chooser_button_new (_(labeltext), GTK_FILE_CHOOSER_ACTION_OPEN);
gtk_widget_show (prop);
- gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (prop), deadbeef->conf_get_str (key, def));
+ gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (prop), value);
g_signal_connect (G_OBJECT (prop), "file-set", G_CALLBACK (prop_changed), win);
}
else {
@@ -231,7 +404,7 @@ plugin_configure (GtkWidget *parentwin, DB_plugin_t *p) {
g_signal_connect (G_OBJECT (prop), "changed", G_CALLBACK (prop_changed), win);
gtk_widget_show (prop);
gtk_editable_set_editable (GTK_EDITABLE (prop), FALSE);
- gtk_entry_set_text (GTK_ENTRY (prop), deadbeef->conf_get_str (key, def));
+ gtk_entry_set_text (GTK_ENTRY (prop), value);
gtk_box_pack_start (GTK_BOX (cont), prop, TRUE, TRUE, 0);
GtkWidget *btn = gtk_button_new_with_label ("…");
gtk_widget_show (btn);
@@ -239,36 +412,88 @@ plugin_configure (GtkWidget *parentwin, DB_plugin_t *p) {
g_signal_connect (G_OBJECT (btn), "clicked", G_CALLBACK (on_prop_browse_file), prop);
}
}
- else if (!strncmp (type, "hscale[", 7)) {
+ else if (!strncmp (type, "select[", 7)) {
+ int n;
+ if (1 != sscanf (type+6, "[%d]", &n)) {
+ break;
+ }
+
+ label = gtk_label_new (_(labeltext));
+ gtk_widget_show (label);
+
+ prop = gtk_combo_box_new_text ();
+ gtk_widget_show (prop);
+
+ for (int i = 0; i < n; i++) {
+ char entry[MAX_TOKEN];
+ script = gettoken_warn_eof (script, entry);
+ if (!script) {
+ break;
+ }
+
+ gtk_combo_box_append_text (GTK_COMBO_BOX (prop), entry);
+ }
+ if (!script) {
+ break;
+ }
+ gtk_combo_box_set_active (GTK_COMBO_BOX (prop), atoi (value));
+ g_signal_connect ((gpointer) prop, "changed",
+ G_CALLBACK (prop_changed),
+ win);
+ }
+ else if (!strncmp (type, "hscale[", 7) || !strncmp (type, "vscale[", 7) || !strncmp (type, "spinbtn[", 8)) {
float min, max, step;
- if (3 != sscanf (type+6, "[%f,%f,%f]", &min, &max, &step)) {
- min = 0;
- max = 100;
- step = 1;
+ const char *args;
+ if (type[0] == 's') {
+ args = type + 7;
}
+ else {
+ args = type + 6;
+ }
+ if (3 != sscanf (args, "[%f,%f,%f]", &min, &max, &step)) {
+ break;
+ }
+ int invert = 0;
if (min >= max) {
float tmp = min;
min = max;
max = tmp;
- break;
+ invert = 1;
}
if (step <= 0) {
step = 1;
}
- prop = gtk_hscale_new_with_range (min, max, step);
+ if (type[0] == 's') {
+ prop = gtk_spin_button_new_with_range (min, max, step);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (prop), atof (value));
+ }
+ else {
+ prop = type[0] == 'h' ? gtk_hscale_new_with_range (min, max, step) : gtk_vscale_new_with_range (min, max, step);
+ if (invert) {
+ gtk_range_set_inverted (GTK_RANGE (prop), TRUE);
+ }
+ gtk_range_set_value (GTK_RANGE (prop), (gdouble)atof (value));
+ gtk_scale_set_value_pos (GTK_SCALE (prop), GTK_POS_RIGHT);
+ }
label = gtk_label_new (_(labeltext));
gtk_widget_show (label);
g_signal_connect (G_OBJECT (prop), "value-changed", G_CALLBACK (prop_changed), win);
gtk_widget_show (prop);
- gtk_range_set_value (GTK_RANGE (prop), (gdouble)deadbeef->conf_get_float (key, (float)*def));
- gtk_scale_set_value_pos (GTK_SCALE (prop), GTK_POS_RIGHT);
}
- if (!strcmp (type, "password")) {
- gtk_entry_set_visibility (GTK_ENTRY (prop), FALSE);
+
+ script = gettoken_warn_eof (script, token);
+ if (!script) {
+ break;
+ }
+ if (strcmp (token, ";")) {
+ fprintf (stderr, "expected `;' while loading plugin %s config dialog: %s at line %d\n", conf->title, token, parser_line);
+ break;
}
+
+
if (label && prop) {
GtkWidget *hbox = NULL;
- hbox = gtk_hbox_new (FALSE, 8);
+ hbox = vertical ? gtk_vbox_new (FALSE, 8) : gtk_hbox_new (FALSE, 8);
gtk_widget_show (hbox);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), cont ? cont : prop, TRUE, TRUE, 0);
@@ -281,7 +506,7 @@ plugin_configure (GtkWidget *parentwin, DB_plugin_t *p) {
g_object_set_data (G_OBJECT (win), key, prop);
}
if (cont) {
- gtk_box_pack_start (GTK_BOX (vbox), cont, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (widgets[ncurr]), cont, FALSE, FALSE, 0);
}
}
@@ -290,10 +515,21 @@ plugin_configure (GtkWidget *parentwin, DB_plugin_t *p) {
gtk_dialog_set_response_sensitive (GTK_DIALOG (win), GTK_RESPONSE_APPLY, FALSE);
response = gtk_dialog_run (GTK_DIALOG (win));
if (response == GTK_RESPONSE_APPLY || response == GTK_RESPONSE_OK) {
- apply_conf (win, p);
+ apply_conf (win, conf);
+ }
+ if (callback) {
+ int btn = ddb_button_from_gtk_response (response);
+ if (!callback (btn, ctx)) {
+ break;
+ }
}
} while (response == GTK_RESPONSE_APPLY);
gtk_widget_destroy (win);
+ int btn = ddb_button_from_gtk_response (response);
+ return btn;
}
-
+int
+gtkui_run_dialog_root (ddb_dialog_t *conf, uint32_t buttons, int (*callback)(int button, void *ctx), void *ctx) {
+ return gtkui_run_dialog (mainwin, conf, buttons, callback, ctx);
+}
diff --git a/plugins/gtkui/pluginconf.h b/plugins/gtkui/pluginconf.h
new file mode 100644
index 00000000..102691aa
--- /dev/null
+++ b/plugins/gtkui/pluginconf.h
@@ -0,0 +1,28 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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.
+*/
+#ifndef __PLUGINCONF_H
+#define __PLUGINCONF_H
+
+int
+gtkui_run_dialog (GtkWidget *parentwin, ddb_dialog_t *conf, uint32_t buttons, int (*callback)(int button, void *ctx), void *ctx);
+
+int
+gtkui_run_dialog_root (ddb_dialog_t *conf, uint32_t buttons, int (*callback)(int button, void *ctx), void *ctx);
+
+#endif
diff --git a/plugins/gtkui/prefwin.c b/plugins/gtkui/prefwin.c
index 4e1c42b0..9883fc96 100644
--- a/plugins/gtkui/prefwin.c
+++ b/plugins/gtkui/prefwin.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -34,6 +34,9 @@
#include "support.h"
#include "eq.h"
#include "ddblistview.h"
+#include "pluginconf.h"
+#include "dspconfig.h"
+#include "wingeom.h"
#define GLADE_HOOKUP_OBJECT(component,widget,name) \
g_object_set_data_full (G_OBJECT (component), name, \
@@ -56,9 +59,11 @@ gtk_enum_sound_callback (const char *name, const char *desc, void *userdata) {
GtkComboBox *combobox = GTK_COMBO_BOX (userdata);
gtk_combo_box_append_text (combobox, desc);
- if (!strcmp (deadbeef->conf_get_str ("alsa_soundcard", "default"), name)) {
+ deadbeef->conf_lock ();
+ if (!strcmp (deadbeef->conf_get_str_fast ("alsa_soundcard", "default"), name)) {
gtk_combo_box_set_active (combobox, num_alsa_devices);
}
+ deadbeef->conf_unlock ();
strncpy (alsa_device_names[num_alsa_devices], name, 63);
alsa_device_names[num_alsa_devices][63] = 0;
@@ -66,40 +71,23 @@ gtk_enum_sound_callback (const char *name, const char *desc, void *userdata) {
}
void
-on_plugin_active_toggled (GtkCellRendererToggle *cell_renderer, gchar *path, GtkTreeModel *model) {
- GtkTreePath *p = gtk_tree_path_new_from_string (path);
- if (p) {
- int *indices = gtk_tree_path_get_indices (p);
- //gtk_tree_path_free (p); // wtf?? gtk crashes on this
- if (indices) {
- DB_plugin_t **plugins = deadbeef->plug_get_list ();
- DB_plugin_t *plug = plugins[*indices];
- gboolean state;
- GtkTreeIter iter;
- gtk_tree_model_get_iter (model, &iter, p);
- gtk_tree_model_get (model, &iter, 0, &state, -1);
- if (!deadbeef->plug_activate (plug, !state)) {
- gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, !state, -1);
- }
- }
- g_free (indices);
- }
-}
-
-void
preferences_fill_soundcards (void) {
if (!prefwin) {
return;
}
- const char *s = deadbeef->conf_get_str ("alsa_soundcard", "default");
GtkComboBox *combobox = GTK_COMBO_BOX (lookup_widget (prefwin, "pref_soundcard"));
GtkTreeModel *mdl = gtk_combo_box_get_model (combobox);
gtk_list_store_clear (GTK_LIST_STORE (mdl));
gtk_combo_box_append_text (combobox, _("Default Audio Device"));
+
+ deadbeef->conf_lock ();
+ const char *s = deadbeef->conf_get_str_fast ("alsa_soundcard", "default");
if (!strcmp (s, "default")) {
gtk_combo_box_set_active (combobox, 0);
}
+ deadbeef->conf_unlock ();
+
num_alsa_devices = 1;
strcpy (alsa_device_names[0], "default");
if (deadbeef->get_output ()->enum_soundcards) {
@@ -269,6 +257,7 @@ prefwin_init_theme_colors (void) {
gtk_color_button_set_color (GTK_COLOR_BUTTON (lookup_widget (prefwin, "tabstrip_mid")), (gtkui_get_tabstrip_mid_color (&clr), &clr));
gtk_color_button_set_color (GTK_COLOR_BUTTON (lookup_widget (prefwin, "tabstrip_light")), (gtkui_get_tabstrip_light_color (&clr), &clr));
gtk_color_button_set_color (GTK_COLOR_BUTTON (lookup_widget (prefwin, "tabstrip_base")), (gtkui_get_tabstrip_base_color (&clr), &clr));
+ gtk_color_button_set_color (GTK_COLOR_BUTTON (lookup_widget (prefwin, "tabstrip_text")), (gtkui_get_tabstrip_text_color (&clr), &clr));
gtk_color_button_set_color (GTK_COLOR_BUTTON (lookup_widget (prefwin, "listview_even_row")), (gtkui_get_listview_even_row_color (&clr), &clr));
gtk_color_button_set_color (GTK_COLOR_BUTTON (lookup_widget (prefwin, "listview_odd_row")), (gtkui_get_listview_odd_row_color (&clr), &clr));
gtk_color_button_set_color (GTK_COLOR_BUTTON (lookup_widget (prefwin, "listview_selected_row")), (gtkui_get_listview_selection_color (&clr), &clr));
@@ -472,15 +461,16 @@ on_preferences_activate (GtkMenuItem *menuitem,
if (prefwin) {
return;
}
+ deadbeef->conf_lock ();
GtkWidget *w = prefwin = create_prefwin ();
gtk_window_set_transient_for (GTK_WINDOW (w), GTK_WINDOW (mainwin));
GtkComboBox *combobox = NULL;
// output plugin selection
- const char *outplugname = deadbeef->conf_get_str ("output_plugin", _("ALSA output plugin"));
combobox = GTK_COMBO_BOX (lookup_widget (w, "pref_output_plugin"));
+ const char *outplugname = deadbeef->conf_get_str_fast ("output_plugin", "ALSA output plugin");
DB_output_t **out_plugs = deadbeef->plug_get_output_list ();
for (int i = 0; out_plugs[i]; i++) {
gtk_combo_box_append_text (combobox, out_plugs[i]->plugin.name);
@@ -500,13 +490,6 @@ on_preferences_activate (GtkMenuItem *menuitem,
G_CALLBACK (on_pref_soundcard_changed),
NULL);
- // alsa resampling
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (w, "pref_dynsamplerate")), deadbeef->conf_get_int ("playback.dynsamplerate", 0));
-
- // src_quality
- combobox = GTK_COMBO_BOX (lookup_widget (w, "pref_src_quality"));
- gtk_combo_box_set_active (combobox, deadbeef->conf_get_int ("src_quality", 2));
-
// replaygain_mode
combobox = GTK_COMBO_BOX (lookup_widget (w, "pref_replaygain_mode"));
gtk_combo_box_set_active (combobox, deadbeef->conf_get_int ("replaygain_mode", 0));
@@ -514,6 +497,12 @@ on_preferences_activate (GtkMenuItem *menuitem,
// replaygain_scale
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (w, "pref_replaygain_scale")), deadbeef->conf_get_int ("replaygain_scale", 1));
+ // replaygain_preamp
+ gtk_range_set_value (GTK_RANGE (lookup_widget (w, "replaygain_preamp")), deadbeef->conf_get_int ("replaygain_preamp", 0));
+
+ // dsp
+ dsp_setup_init (prefwin);
+
// close_send_to_tray
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (w, "pref_close_send_to_tray")), deadbeef->conf_get_int ("close_send_to_tray", 0));
@@ -529,19 +518,38 @@ on_preferences_activate (GtkMenuItem *menuitem,
// hide_delete_from_disk
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (w, "hide_delete_from_disk")), deadbeef->conf_get_int ("gtkui.hide_remove_from_disk", 0));
+ // auto-rename playlist from folder name
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (w, "auto_name_playlist_from_folder")), deadbeef->conf_get_int ("gtkui.name_playlist_from_folder", 0));
+
+ // refresh rate
+ int val = deadbeef->conf_get_int ("gtkui.refresh_rate", 10);
+ gtk_range_set_value (GTK_RANGE (lookup_widget (w, "gui_fps")), val);
+
+ // add from archives
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (w, "ignore_archives")), deadbeef->conf_get_int ("ignore_archives", 1));
// titlebar text
- gtk_entry_set_text (GTK_ENTRY (lookup_widget (w, "titlebar_format_playing")), deadbeef->conf_get_str ("gtkui.titlebar_playing", "%a - %t - DeaDBeeF-%V"));
- gtk_entry_set_text (GTK_ENTRY (lookup_widget (w, "titlebar_format_stopped")), deadbeef->conf_get_str ("gtkui.titlebar_stopped", "DeaDBeeF-%V"));
+ gtk_entry_set_text (GTK_ENTRY (lookup_widget (w, "titlebar_format_playing")), deadbeef->conf_get_str_fast ("gtkui.titlebar_playing", "%a - %t - DeaDBeeF-%V"));
+ gtk_entry_set_text (GTK_ENTRY (lookup_widget (w, "titlebar_format_stopped")), deadbeef->conf_get_str_fast ("gtkui.titlebar_stopped", "DeaDBeeF-%V"));
// cli playlist
int active = deadbeef->conf_get_int ("cli_add_to_specific_playlist", 1);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "cli_add_to_playlist")), active);
gtk_widget_set_sensitive (lookup_widget (prefwin, "cli_playlist_name"), active);
- gtk_entry_set_text (GTK_ENTRY (lookup_widget (prefwin, "cli_playlist_name")), deadbeef->conf_get_str ("cli_add_playlist_name", "Default"));
+ gtk_entry_set_text (GTK_ENTRY (lookup_widget (prefwin, "cli_playlist_name")), deadbeef->conf_get_str_fast ("cli_add_playlist_name", "Default"));
// resume last session
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (w, "resume_last_session")), deadbeef->conf_get_int ("resume_last_session", 0));
+ // fill gui plugin list
+ combobox = GTK_COMBO_BOX (lookup_widget (w, "gui_plugin"));
+ const char **names = deadbeef->plug_get_gui_names ();
+ for (int i = 0; names[i]; i++) {
+ gtk_combo_box_append_text (combobox, names[i]);
+ if (!strcmp (names[i], deadbeef->conf_get_str_fast ("gui_plugin", "GTK2"))) {
+ gtk_combo_box_set_active (combobox, i);
+ }
+ }
+
// override bar colors
int override = deadbeef->conf_get_int ("gtkui.override_bar_colors", 0);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "override_bar_colors")), override);
@@ -562,10 +570,10 @@ on_preferences_activate (GtkMenuItem *menuitem,
// network
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (w, "pref_network_enableproxy")), deadbeef->conf_get_int ("network.proxy", 0));
- gtk_entry_set_text (GTK_ENTRY (lookup_widget (w, "pref_network_proxyaddress")), deadbeef->conf_get_str ("network.proxy.address", ""));
- gtk_entry_set_text (GTK_ENTRY (lookup_widget (w, "pref_network_proxyport")), deadbeef->conf_get_str ("network.proxy.port", "8080"));
+ gtk_entry_set_text (GTK_ENTRY (lookup_widget (w, "pref_network_proxyaddress")), deadbeef->conf_get_str_fast ("network.proxy.address", ""));
+ gtk_entry_set_text (GTK_ENTRY (lookup_widget (w, "pref_network_proxyport")), deadbeef->conf_get_str_fast ("network.proxy.port", "8080"));
combobox = GTK_COMBO_BOX (lookup_widget (w, "pref_network_proxytype"));
- const char *type = deadbeef->conf_get_str ("network.proxy.type", "HTTP");
+ const char *type = deadbeef->conf_get_str_fast ("network.proxy.type", "HTTP");
if (!strcasecmp (type, "HTTP")) {
gtk_combo_box_set_active (combobox, 0);
}
@@ -584,8 +592,8 @@ on_preferences_activate (GtkMenuItem *menuitem,
else if (!strcasecmp (type, "SOCKS5_HOSTNAME")) {
gtk_combo_box_set_active (combobox, 5);
}
- gtk_entry_set_text (GTK_ENTRY (lookup_widget (w, "proxyuser")), deadbeef->conf_get_str ("network.proxy.username", ""));
- gtk_entry_set_text (GTK_ENTRY (lookup_widget (w, "proxypassword")), deadbeef->conf_get_str ("network.proxy.password", ""));
+ gtk_entry_set_text (GTK_ENTRY (lookup_widget (w, "proxyuser")), deadbeef->conf_get_str_fast ("network.proxy.username", ""));
+ gtk_entry_set_text (GTK_ENTRY (lookup_widget (w, "proxypassword")), deadbeef->conf_get_str_fast ("network.proxy.password", ""));
// list of plugins
GtkTreeView *tree = GTK_TREE_VIEW (lookup_widget (w, "pref_pluginlist"));
@@ -622,7 +630,6 @@ on_preferences_activate (GtkMenuItem *menuitem,
gtk_tree_view_set_model (tree, GTK_TREE_MODEL (store));
gtk_widget_set_sensitive (lookup_widget (prefwin, "configure_plugin"), FALSE);
-// gtk_widget_show (w);
// hotkeys
DB_plugin_t *hotkeys = deadbeef->plug_get_for_id ("hotkeys");
@@ -630,42 +637,9 @@ on_preferences_activate (GtkMenuItem *menuitem,
prefwin_add_hotkeys_tab (prefwin);
}
- // tag writer
- int strip_id3v2 = deadbeef->conf_get_int ("mp3.strip_id3v2", 0);
- int strip_id3v1 = deadbeef->conf_get_int ("mp3.strip_id3v1", 0);
- int strip_apev2 = deadbeef->conf_get_int ("mp3.strip_apev2", 0);
- int write_id3v2 = deadbeef->conf_get_int ("mp3.write_id3v2", 1);
- int write_id3v1 = deadbeef->conf_get_int ("mp3.write_id3v1", 1);
- int write_apev2 = deadbeef->conf_get_int ("mp3.write_apev2", 0);
- int id3v2_version = deadbeef->conf_get_int ("mp3.id3v2_version", 3);
- const char *id3v1_encoding = deadbeef->conf_get_str ("mp3.id3v1_encoding", "iso8859-1");
- int ape_strip_id3v2 = deadbeef->conf_get_int ("ape.strip_id3v2", 0);
- int ape_strip_apev2 = deadbeef->conf_get_int ("ape.strip_apev2", 0);
- int ape_write_id3v2 = deadbeef->conf_get_int ("ape.write_id3v2", 0);
- int ape_write_apev2 = deadbeef->conf_get_int ("ape.write_apev2", 1);
- int wv_strip_apev2 = deadbeef->conf_get_int ("wv.strip_apev2", 0);
- int wv_strip_id3v1 = deadbeef->conf_get_int ("wv.strip_id3v1", 0);
- int wv_write_apev2 = deadbeef->conf_get_int ("wv.write_apev2", 1);
- int wv_write_id3v1 = deadbeef->conf_get_int ("wv.write_id3v1", 0);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "strip_id3v2")), strip_id3v2);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "strip_id3v1")), strip_id3v1);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "strip_apev2")), strip_apev2);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "write_id3v2")), write_id3v2);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "write_id3v1")), write_id3v1);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "write_apev2")), write_apev2);
- gtk_combo_box_set_active (GTK_COMBO_BOX (lookup_widget (prefwin, "id3v2_version")), id3v2_version != 4 ? 0 : 1);
- gtk_entry_set_text (GTK_ENTRY (lookup_widget (prefwin, "id3v1_encoding")), id3v1_encoding);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "ape_strip_id3v2")), ape_strip_id3v2);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "ape_strip_apev2")), ape_strip_apev2);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "ape_write_apev2")), ape_write_apev2);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "ape_write_id3v2")), ape_write_id3v2);
-
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "wv_strip_id3v1")), wv_strip_id3v1);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "wv_strip_apev2")), wv_strip_apev2);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "wv_write_apev2")), wv_write_apev2);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "wv_write_id3v1")), wv_write_id3v1);
-
+ deadbeef->conf_unlock ();
gtk_dialog_run (GTK_DIALOG (prefwin));
+ dsp_setup_free ();
gtk_widget_destroy (prefwin);
deadbeef->conf_save ();
prefwin = NULL;
@@ -678,11 +652,13 @@ on_pref_soundcard_changed (GtkComboBox *combobox,
{
int active = gtk_combo_box_get_active (combobox);
if (active >= 0 && active < num_alsa_devices) {
- const char *soundcard = deadbeef->conf_get_str ("alsa_soundcard", "default");
+ deadbeef->conf_lock ();
+ const char *soundcard = deadbeef->conf_get_str_fast ("alsa_soundcard", "default");
if (strcmp (soundcard, alsa_device_names[active])) {
deadbeef->conf_set_str ("alsa_soundcard", alsa_device_names[active]);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
}
+ deadbeef->conf_unlock ();
}
}
@@ -690,13 +666,14 @@ void
on_pref_output_plugin_changed (GtkComboBox *combobox,
gpointer user_data)
{
- const char *outplugname = deadbeef->conf_get_str ("output_plugin", _("ALSA output plugin"));
int active = gtk_combo_box_get_active (combobox);
DB_output_t **out_plugs = deadbeef->plug_get_output_list ();
DB_output_t *prev = NULL;
DB_output_t *new = NULL;
+ deadbeef->conf_lock ();
+ const char *outplugname = deadbeef->conf_get_str_fast ("output_plugin", "ALSA output plugin");
for (int i = 0; out_plugs[i]; i++) {
if (!strcmp (out_plugs[i]->plugin.name, outplugname)) {
prev = out_plugs[i];
@@ -705,6 +682,7 @@ on_pref_output_plugin_changed (GtkComboBox *combobox,
new = out_plugs[i];
}
}
+ deadbeef->conf_unlock ();
if (!new) {
fprintf (stderr, "failed to find output plugin selected in preferences window\n");
@@ -718,32 +696,12 @@ on_pref_output_plugin_changed (GtkComboBox *combobox,
}
void
-on_pref_dynsamplerate_clicked (GtkButton *button,
- gpointer user_data)
-{
- int active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
- deadbeef->conf_set_int ("playback.dynsamplerate", active);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
-}
-
-
-void
-on_pref_src_quality_changed (GtkComboBox *combobox,
- gpointer user_data)
-{
- int active = gtk_combo_box_get_active (combobox);
- deadbeef->conf_set_int ("src_quality", active == -1 ? 2 : active);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
-}
-
-
-void
on_pref_replaygain_mode_changed (GtkComboBox *combobox,
gpointer user_data)
{
int active = gtk_combo_box_get_active (combobox);
deadbeef->conf_set_int ("replaygain_mode", active == -1 ? 0 : active);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
}
void
@@ -752,7 +710,16 @@ on_pref_replaygain_scale_clicked (GtkButton *button,
{
int active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
deadbeef->conf_set_int ("replaygain_scale", active);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
+}
+
+void
+on_replaygain_preamp_value_changed (GtkRange *range,
+ gpointer user_data)
+{
+ float val = gtk_range_get_value (range);
+ deadbeef->conf_set_float ("replaygain_preamp", val);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
}
@@ -762,7 +729,7 @@ on_pref_close_send_to_tray_clicked (GtkButton *button,
{
int active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
deadbeef->conf_set_int ("close_send_to_tray", active);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
}
void
@@ -771,7 +738,7 @@ on_hide_tray_icon_toggled (GtkToggleButton *togglebutton,
{
int active = gtk_toggle_button_get_active (togglebutton);
deadbeef->conf_set_int ("gtkui.hide_tray_icon", active);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
}
void
@@ -797,21 +764,45 @@ on_pref_pluginlist_cursor_changed (GtkTreeView *treeview,
DB_plugin_t *p = plugins[*indices];
g_free (indices);
assert (p);
- GtkWidget *w = prefwin;//GTK_WIDGET (gtk_widget_get_parent_window (GTK_WIDGET (treeview)));
+ GtkWidget *w = prefwin;
assert (w);
- GtkEntry *e = GTK_ENTRY (lookup_widget (w, "pref_plugin_descr"));
- gtk_entry_set_text (e, p->descr ? p->descr : "");
- e = GTK_ENTRY (lookup_widget (w, "pref_plugin_author"));
- gtk_entry_set_text (e, p->author ? p->author : "");
- e = GTK_ENTRY (lookup_widget (w, "pref_plugin_email"));
- gtk_entry_set_text (e, p->email ? p->email : "");
- e = GTK_ENTRY (lookup_widget (w, "pref_plugin_website"));
- gtk_entry_set_text (e, p->website ? p->website : "");
+ if (p->descr) {
+ GtkTextView *tv = GTK_TEXT_VIEW (lookup_widget (w, "plug_description"));
+
+ GtkTextBuffer *buffer = gtk_text_buffer_new (NULL);
+
+ gtk_text_buffer_set_text (buffer, p->descr, strlen(p->descr));
+ gtk_text_view_set_buffer (GTK_TEXT_VIEW (tv), buffer);
+ g_object_unref (buffer);
+ }
+
+ GtkWidget *link = lookup_widget (w, "weblink");
+ if (p->website) {
+ gtk_link_button_set_uri (GTK_LINK_BUTTON(link), p->website);
+ gtk_widget_set_sensitive (link, TRUE);
+ }
+ else {
+ gtk_link_button_set_uri (GTK_LINK_BUTTON(link), "");
+ gtk_widget_set_sensitive (link, FALSE);
+ }
+
+ GtkWidget *cpr = lookup_widget (w, "plug_copyright");
+ if (p->copyright) {
+ gtk_widget_set_sensitive (cpr, TRUE);
+ }
+ else {
+ gtk_widget_set_sensitive (cpr, FALSE);
+ }
gtk_widget_set_sensitive (lookup_widget (prefwin, "configure_plugin"), p->configdialog ? TRUE : FALSE);
}
void
+gtkui_conf_get_str (const char *key, char *value, int len, const char *def) {
+ deadbeef->conf_get_str (key, def, value, len);
+}
+
+void
on_configure_plugin_clicked (GtkButton *button,
gpointer user_data)
{
@@ -828,7 +819,13 @@ on_configure_plugin_clicked (GtkButton *button,
DB_plugin_t **plugins = deadbeef->plug_get_list ();
DB_plugin_t *p = plugins[*indices];
if (p->configdialog) {
- plugin_configure (prefwin, p);
+ ddb_dialog_t conf = {
+ .title = p->name,
+ .layout = p->configdialog,
+ .set_param = deadbeef->conf_set_str,
+ .get_param = gtkui_conf_get_str,
+ };
+ gtkui_run_dialog (prefwin, &conf, 0, NULL, NULL);
}
}
@@ -837,10 +834,10 @@ redraw_headers (void) {
DdbListview *playlist = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
DdbListview *search = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist"));
if (playlist) {
- ddb_listview_refresh (playlist, DDB_REFRESH_COLUMNS | DDB_EXPOSE_COLUMNS);
+ ddb_listview_refresh (playlist, DDB_REFRESH_COLUMNS);
}
if (search) {
- ddb_listview_refresh (search, DDB_REFRESH_COLUMNS | DDB_EXPOSE_COLUMNS);
+ ddb_listview_refresh (search, DDB_REFRESH_COLUMNS);
}
}
@@ -853,7 +850,7 @@ on_tabstrip_light_color_set (GtkColorButton *colorbutton,
char str[100];
snprintf (str, sizeof (str), "%d %d %d", clr.red, clr.green, clr.blue);
deadbeef->conf_set_str ("gtkui.color.tabstrip_light", str);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
redraw_headers ();
tabstrip_redraw ();
@@ -869,7 +866,7 @@ on_tabstrip_mid_color_set (GtkColorButton *colorbutton,
char str[100];
snprintf (str, sizeof (str), "%d %d %d", clr.red, clr.green, clr.blue);
deadbeef->conf_set_str ("gtkui.color.tabstrip_mid", str);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
redraw_headers ();
tabstrip_redraw ();
@@ -885,7 +882,7 @@ on_tabstrip_dark_color_set (GtkColorButton *colorbutton,
char str[100];
snprintf (str, sizeof (str), "%d %d %d", clr.red, clr.green, clr.blue);
deadbeef->conf_set_str ("gtkui.color.tabstrip_dark", str);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
redraw_headers ();
tabstrip_redraw ();
@@ -900,12 +897,26 @@ on_tabstrip_base_color_set (GtkColorButton *colorbutton,
char str[100];
snprintf (str, sizeof (str), "%d %d %d", clr.red, clr.green, clr.blue);
deadbeef->conf_set_str ("gtkui.color.tabstrip_base", str);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
redraw_headers ();
tabstrip_redraw ();
}
+void
+on_tabstrip_text_color_set (GtkColorButton *colorbutton,
+ gpointer user_data)
+{
+ GdkColor clr;
+ gtk_color_button_get_color (colorbutton, &clr);
+ char str[100];
+ snprintf (str, sizeof (str), "%d %d %d", clr.red, clr.green, clr.blue);
+ deadbeef->conf_set_str ("gtkui.color.tabstrip_text", str);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
+ gtkui_init_theme_colors ();
+ redraw_headers ();
+ tabstrip_redraw ();
+}
void
on_bar_foreground_color_set (GtkColorButton *colorbutton,
@@ -916,7 +927,7 @@ on_bar_foreground_color_set (GtkColorButton *colorbutton,
char str[100];
snprintf (str, sizeof (str), "%d %d %d", clr.red, clr.green, clr.blue);
deadbeef->conf_set_str ("gtkui.color.bar_foreground", str);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
seekbar_redraw ();
volumebar_redraw ();
@@ -933,7 +944,7 @@ on_bar_background_color_set (GtkColorButton *colorbutton,
char str[100];
snprintf (str, sizeof (str), "%d %d %d", clr.red, clr.green, clr.blue);
deadbeef->conf_set_str ("gtkui.color.bar_background", str);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
seekbar_redraw ();
volumebar_redraw ();
@@ -947,7 +958,7 @@ on_override_listview_colors_toggled (GtkToggleButton *togglebutton,
int active = gtk_toggle_button_get_active (togglebutton);
deadbeef->conf_set_int ("gtkui.override_listview_colors", active);
gtk_widget_set_sensitive (lookup_widget (prefwin, "listview_colors_group"), active);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
prefwin_init_theme_colors ();
playlist_refresh ();
@@ -963,7 +974,7 @@ on_listview_even_row_color_set (GtkColorButton *colorbutton,
char str[100];
snprintf (str, sizeof (str), "%d %d %d", clr.red, clr.green, clr.blue);
deadbeef->conf_set_str ("gtkui.color.listview_even_row", str);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
playlist_refresh ();
}
@@ -977,7 +988,7 @@ on_listview_odd_row_color_set (GtkColorButton *colorbutton,
char str[100];
snprintf (str, sizeof (str), "%d %d %d", clr.red, clr.green, clr.blue);
deadbeef->conf_set_str ("gtkui.color.listview_odd_row", str);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
playlist_refresh ();
}
@@ -991,7 +1002,7 @@ on_listview_selected_row_color_set (GtkColorButton *colorbutton,
char str[100];
snprintf (str, sizeof (str), "%d %d %d", clr.red, clr.green, clr.blue);
deadbeef->conf_set_str ("gtkui.color.listview_selection", str);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
playlist_refresh ();
}
@@ -1005,7 +1016,7 @@ on_listview_text_color_set (GtkColorButton *colorbutton,
char str[100];
snprintf (str, sizeof (str), "%d %d %d", clr.red, clr.green, clr.blue);
deadbeef->conf_set_str ("gtkui.color.listview_text", str);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
playlist_refresh ();
}
@@ -1020,7 +1031,7 @@ on_listview_selected_text_color_set (GtkColorButton *colorbutton,
char str[100];
snprintf (str, sizeof (str), "%d %d %d", clr.red, clr.green, clr.blue);
deadbeef->conf_set_str ("gtkui.color.listview_selected_text", str);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
playlist_refresh ();
}
@@ -1034,7 +1045,7 @@ on_listview_cursor_color_set (GtkColorButton *colorbutton,
char str[100];
snprintf (str, sizeof (str), "%d %d %d", clr.red, clr.green, clr.blue);
deadbeef->conf_set_str ("gtkui.color.listview_cursor", str);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
playlist_refresh ();
}
@@ -1047,7 +1058,7 @@ on_override_bar_colors_toggled (GtkToggleButton *togglebutton,
int active = gtk_toggle_button_get_active (togglebutton);
deadbeef->conf_set_int ("gtkui.override_bar_colors", active);
gtk_widget_set_sensitive (lookup_widget (prefwin, "bar_colors_group"), active);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
prefwin_init_theme_colors ();
seekbar_redraw ();
@@ -1062,7 +1073,7 @@ on_override_tabstrip_colors_toggled (GtkToggleButton *togglebutton,
int active = gtk_toggle_button_get_active (togglebutton);
deadbeef->conf_set_int ("gtkui.override_tabstrip_colors", active);
gtk_widget_set_sensitive (lookup_widget (prefwin, "tabstrip_colors_group"), active);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
prefwin_init_theme_colors ();
redraw_headers ();
@@ -1070,137 +1081,6 @@ on_override_tabstrip_colors_toggled (GtkToggleButton *togglebutton,
}
void
-on_write_id3v2_toggled (GtkToggleButton *togglebutton,
- gpointer user_data)
-{
- deadbeef->conf_set_int ("mp3.write_id3v2", gtk_toggle_button_get_active (togglebutton));
-}
-
-
-void
-on_write_id3v1_toggled (GtkToggleButton *togglebutton,
- gpointer user_data)
-{
- deadbeef->conf_set_int ("mp3.write_id3v1", gtk_toggle_button_get_active (togglebutton));
-}
-
-
-void
-on_write_apev2_toggled (GtkToggleButton *togglebutton,
- gpointer user_data)
-{
- deadbeef->conf_set_int ("mp3.write_apev2", gtk_toggle_button_get_active (togglebutton));
-}
-
-
-void
-on_strip_id3v2_toggled (GtkToggleButton *togglebutton,
- gpointer user_data)
-{
- deadbeef->conf_set_int ("mp3.strip_id3v2", gtk_toggle_button_get_active (togglebutton));
-}
-
-
-void
-on_strip_id3v1_toggled (GtkToggleButton *togglebutton,
- gpointer user_data)
-{
- deadbeef->conf_set_int ("mp3.strip_id3v1", gtk_toggle_button_get_active (togglebutton));
-}
-
-
-void
-on_strip_apev2_toggled (GtkToggleButton *togglebutton,
- gpointer user_data)
-{
- deadbeef->conf_set_int ("mp3.strip_apev2", gtk_toggle_button_get_active (togglebutton));
-}
-
-
-void
-on_id3v2_version_changed (GtkComboBox *combobox,
- gpointer user_data)
-{
- int version = 3;
- int active = gtk_combo_box_get_active (combobox);
- if (active == 1) {
- version = 4;
- }
- deadbeef->conf_set_int ("mp3.id3v2_version", version);
-}
-
-
-void
-on_id3v1_encoding_changed (GtkEditable *editable,
- gpointer user_data)
-{
- deadbeef->conf_set_str ("mp3.id3v1_encoding", gtk_entry_get_text (GTK_ENTRY (editable)));
-}
-
-
-void
-on_ape_write_id3v2_toggled (GtkToggleButton *togglebutton,
- gpointer user_data)
-{
- deadbeef->conf_set_int ("ape.write_id3v2", gtk_toggle_button_get_active (togglebutton));
-}
-
-
-void
-on_ape_write_apev2_toggled (GtkToggleButton *togglebutton,
- gpointer user_data)
-{
- deadbeef->conf_set_int ("ape.write_apev2", gtk_toggle_button_get_active (togglebutton));
-}
-
-
-void
-on_ape_strip_id3v2_toggled (GtkToggleButton *togglebutton,
- gpointer user_data)
-{
- deadbeef->conf_set_int ("ape.strip_id3v2", gtk_toggle_button_get_active (togglebutton));
-}
-
-
-void
-on_ape_strip_apev2_toggled (GtkToggleButton *togglebutton,
- gpointer user_data)
-{
- deadbeef->conf_set_int ("ape.strip_apev2", gtk_toggle_button_get_active (togglebutton));
-}
-
-
-void
-on_wv_write_apev2_toggled (GtkToggleButton *togglebutton,
- gpointer user_data)
-{
- deadbeef->conf_set_int ("wv.write_apev2", gtk_toggle_button_get_active (togglebutton));
-}
-
-
-void
-on_wv_write_id3v1_toggled (GtkToggleButton *togglebutton,
- gpointer user_data)
-{
- deadbeef->conf_set_int ("wv.write_id3v1", gtk_toggle_button_get_active (togglebutton));
-}
-
-void
-on_wv_strip_apev2_toggled (GtkToggleButton *togglebutton,
- gpointer user_data)
-{
- deadbeef->conf_set_int ("wv.strip_apev2", gtk_toggle_button_get_active (togglebutton));
-}
-
-
-void
-on_wv_strip_id3v1_toggled (GtkToggleButton *togglebutton,
- gpointer user_data)
-{
- deadbeef->conf_set_int ("wv.strip_id3v1", gtk_toggle_button_get_active (togglebutton));
-}
-
-void
on_pref_network_proxyaddress_changed (GtkEditable *editable,
gpointer user_data)
{
@@ -1344,3 +1224,115 @@ on_resume_last_session_toggled (GtkToggleButton *togglebutton,
deadbeef->conf_set_int ("resume_last_session", active);
}
+
+void
+on_auto_name_playlist_from_folder_toggled
+ (GtkToggleButton *togglebutton,
+ gpointer user_data)
+{
+ int active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (togglebutton));
+ deadbeef->conf_set_int ("gtkui.name_playlist_from_folder", active);
+}
+
+void
+on_info_window_delete (GtkWidget *widget, GtkTextDirection previous_direction, GtkWidget **pwindow);
+
+static void
+show_copyright_window (const char *text, const char *title, GtkWidget **pwindow) {
+ if (*pwindow) {
+ return;
+ }
+ GtkWidget *widget = *pwindow = create_helpwindow ();
+ g_object_set_data (G_OBJECT (widget), "pointer", pwindow);
+ g_signal_connect (widget, "delete_event", G_CALLBACK (on_info_window_delete), pwindow);
+ gtk_window_set_title (GTK_WINDOW (widget), title);
+ gtk_window_set_transient_for (GTK_WINDOW (widget), GTK_WINDOW (prefwin));
+ GtkWidget *txt = lookup_widget (widget, "helptext");
+ GtkTextBuffer *buffer = gtk_text_buffer_new (NULL);
+
+ gtk_text_buffer_set_text (buffer, text, strlen(text));
+ gtk_text_view_set_buffer (GTK_TEXT_VIEW (txt), buffer);
+ g_object_unref (buffer);
+ gtk_widget_show (widget);
+}
+
+static GtkWidget *copyright_window;
+
+void
+on_plug_copyright_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GtkTreeView *treeview = GTK_TREE_VIEW(lookup_widget (prefwin, "pref_pluginlist"));
+ GtkTreePath *path;
+ GtkTreeViewColumn *col;
+ gtk_tree_view_get_cursor (treeview, &path, &col);
+ if (!path || !col) {
+ // reset
+ return;
+ }
+ int *indices = gtk_tree_path_get_indices (path);
+ DB_plugin_t **plugins = deadbeef->plug_get_list ();
+ DB_plugin_t *p = plugins[*indices];
+ g_free (indices);
+ assert (p);
+
+ if (p->copyright) {
+ show_copyright_window (p->copyright, "Copyright", &copyright_window);
+ }
+}
+
+gboolean
+on_prefwin_configure_event (GtkWidget *widget,
+ GdkEventConfigure *event,
+ gpointer user_data)
+{
+ wingeom_save (widget, "prefwin");
+ return FALSE;
+}
+
+
+gboolean
+on_prefwin_window_state_event (GtkWidget *widget,
+ GdkEventWindowState *event,
+ gpointer user_data)
+{
+ wingeom_save_max (event, widget, "prefwin");
+ return FALSE;
+}
+
+
+void
+on_prefwin_realize (GtkWidget *widget,
+ gpointer user_data)
+{
+ wingeom_restore (widget, "prefwin", -1, -1, -1, -1, 0);
+}
+
+void
+on_gui_plugin_changed (GtkComboBox *combobox,
+ gpointer user_data)
+{
+ gchar *txt = gtk_combo_box_get_active_text (combobox);
+ if (txt) {
+ deadbeef->conf_set_str ("gui_plugin", txt);
+ g_free (txt);
+ }
+}
+
+void
+on_gui_fps_value_changed (GtkRange *range,
+ gpointer user_data)
+{
+ int val = gtk_range_get_value (range);
+ deadbeef->conf_set_int ("gtkui.refresh_rate", val);
+ gtkui_setup_gui_refresh ();
+}
+
+void
+on_ignore_archives_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data)
+{
+
+ deadbeef->conf_set_int ("ignore_archives", gtk_toggle_button_get_active (togglebutton));
+}
+
diff --git a/plugins/gtkui/progress.c b/plugins/gtkui/progress.c
index d986a162..1941c40e 100644
--- a/plugins/gtkui/progress.c
+++ b/plugins/gtkui/progress.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -34,9 +34,36 @@ static GtkWidget *progressdlg;
static GtkWidget *progressitem;
static int progress_aborted;
+static void
+on_progress_abort (GtkButton *button,
+ gpointer user_data)
+{
+ progress_aborted = 1;
+}
+
+static gboolean
+on_addprogress_delete_event (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ progress_aborted = 1;
+ return gtk_widget_hide_on_delete (widget);
+}
void
progress_init (void) {
- progressdlg = create_addprogress ();
+ progressdlg = create_progressdlg ();
+
+ gtk_window_set_title (GTK_WINDOW (progressdlg), _("Adding files..."));
+
+ g_signal_connect ((gpointer) progressdlg, "delete_event",
+ G_CALLBACK (on_addprogress_delete_event),
+ NULL);
+
+ GtkWidget *cancelbtn = lookup_widget (progressdlg, "cancelbtn");
+ g_signal_connect ((gpointer) cancelbtn, "clicked",
+ G_CALLBACK (on_progress_abort),
+ NULL);
+
gtk_window_set_transient_for (GTK_WINDOW (progressdlg), GTK_WINDOW (mainwin));
progressitem = lookup_widget (progressdlg, "progresstitle");
}
@@ -81,24 +108,9 @@ progress_abort (void) {
progress_aborted = 1;
}
-void
-on_progress_abort (GtkButton *button,
- gpointer user_data)
-{
- progress_aborted = 1;
-}
-
int
progress_is_aborted (void) {
return progress_aborted;
}
-gboolean
-on_addprogress_delete_event (GtkWidget *widget,
- GdkEvent *event,
- gpointer user_data)
-{
- progress_aborted = 1;
- return gtk_widget_hide_on_delete (widget);
-}
diff --git a/plugins/gtkui/progress.h b/plugins/gtkui/progress.h
index 49b20248..86558106 100644
--- a/plugins/gtkui/progress.h
+++ b/plugins/gtkui/progress.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
diff --git a/plugins/gtkui/search.c b/plugins/gtkui/search.c
index ee096930..4509d3d5 100644
--- a/plugins/gtkui/search.c
+++ b/plugins/gtkui/search.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -38,6 +38,8 @@
#include "gtkui.h"
+#include "wingeom.h"
+
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
@@ -49,27 +51,8 @@ extern GtkWidget *searchwin;
extern GtkWidget *mainwin;
void
-search_restore_attrs (void) {
- int x = deadbeef->conf_get_int ("searchwin.geometry.x", -1);
- int y = deadbeef->conf_get_int ("searchwin.geometry.y", -1);
- int w = deadbeef->conf_get_int ("searchwin.geometry.w", 450);
- int h = deadbeef->conf_get_int ("searchwin.geometry.h", 150);
- gtk_widget_show (searchwin);
- if (x != -1 && y != -1) {
- gtk_window_move (GTK_WINDOW (searchwin), x, y);
- gtk_window_resize (GTK_WINDOW (searchwin), w, h);
- if (deadbeef->conf_get_int ("searchwin.geometry.maximized", 0)) {
- gtk_window_maximize (GTK_WINDOW (searchwin));
- }
- gtk_window_present (GTK_WINDOW (searchwin));
- }
- else {
- gtk_window_resize (GTK_WINDOW (searchwin), w, h);
- }
-}
-
-void
search_start (void) {
+ wingeom_restore (searchwin, "searchwin", -1, -1, 450, 150, 0);
gtk_entry_set_text (GTK_ENTRY (lookup_widget (searchwin, "searchentry")), "");
gtk_widget_show (searchwin);
gtk_window_present (GTK_WINDOW (searchwin));
@@ -98,14 +81,14 @@ on_searchentry_changed (GtkEditable *editable,
search_refresh ();
// redraw main playlist to be in sync selection-wise
- ddb_listview_refresh (DDB_LISTVIEW (lookup_widget (mainwin, "playlist")), DDB_REFRESH_LIST | DDB_EXPOSE_LIST);
+ ddb_listview_refresh (DDB_LISTVIEW (lookup_widget (mainwin, "playlist")), DDB_REFRESH_LIST);
}
void
search_refresh (void) {
if (searchwin && gtk_widget_get_visible (searchwin)) {
GtkWidget *pl = lookup_widget (searchwin, "searchlist");
- ddb_listview_refresh (DDB_LISTVIEW (pl), DDB_REFRESH_VSCROLL | DDB_REFRESH_LIST | DDB_EXPOSE_LIST);
+ ddb_listview_refresh (DDB_LISTVIEW (pl), DDB_REFRESH_VSCROLL | DDB_REFRESH_LIST);
}
}
@@ -176,7 +159,7 @@ on_searchwin_key_press_event (GtkWidget *widget,
int row = deadbeef->pl_get_cursor (PL_SEARCH);
DB_playItem_t *it = deadbeef->pl_get_for_idx_and_iter (max (row, 0), PL_SEARCH);
if (it) {
- deadbeef->sendmessage (M_PLAYSONGNUM, 0, deadbeef->pl_get_idx_of (it), 0);
+ deadbeef->sendmessage (M_PLAY_NUM, 0, deadbeef->pl_get_idx_of (it), 0);
deadbeef->pl_item_unref (it);
}
}
@@ -198,21 +181,7 @@ on_searchwin_configure_event (GtkWidget *widget,
GdkEventConfigure *event,
gpointer user_data)
{
-#if GTK_CHECK_VERSION(2,2,0)
- GdkWindowState window_state = gdk_window_get_state (GDK_WINDOW (widget->window));
-#else
- GdkWindowState window_state = gdk_window_get_state (G_OBJECT (widget));
-#endif
- if (!(window_state & GDK_WINDOW_STATE_MAXIMIZED) && gtk_widget_get_visible (widget)) {
- int x, y;
- int w, h;
- gtk_window_get_position (GTK_WINDOW (widget), &x, &y);
- gtk_window_get_size (GTK_WINDOW (widget), &w, &h);
- deadbeef->conf_set_int ("searchwin.geometry.x", x);
- deadbeef->conf_set_int ("searchwin.geometry.y", y);
- deadbeef->conf_set_int ("searchwin.geometry.w", w);
- deadbeef->conf_set_int ("searchwin.geometry.h", h);
- }
+ wingeom_save (widget, "searchwin");
return FALSE;
}
@@ -221,30 +190,7 @@ on_searchwin_window_state_event (GtkWidget *widget,
GdkEventWindowState *event,
gpointer user_data)
{
- if (!gtk_widget_get_visible (widget)) {
- return FALSE;
- }
- // based on pidgin maximization handler
-#if GTK_CHECK_VERSION(2,2,0)
- if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) {
- if (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
- deadbeef->conf_set_int ("searchwin.geometry.maximized", 1);
- }
- else {
- deadbeef->conf_set_int ("searchwin.geometry.maximized", 0);
- }
- }
-#else
- GdkWindowState new_window_state = gdk_window_get_state(G_OBJECT(widget));
-
- if ()
- if (new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
- deadbeef->conf_set_int ("searchwin.geometry.maximized", 1);
- }
- else {
- deadbeef->conf_set_int ("searchwin.geometry.maximized", 0);
- }
-#endif
+ wingeom_save_max (event, widget, "searchwin");
return FALSE;
}
@@ -364,13 +310,13 @@ void search_col_free_user_data (void *data) {
}
void search_handle_doubleclick (DdbListview *listview, DdbListviewIter iter, int idx) {
- deadbeef->sendmessage (M_PLAYSONGNUM, 0, deadbeef->pl_get_idx_of ((DB_playItem_t *)iter), 0);
+ deadbeef->sendmessage (M_PLAY_NUM, 0, deadbeef->pl_get_idx_of ((DB_playItem_t *)iter), 0);
}
void search_selection_changed (DdbListviewIter it, int idx) {
DdbListview *main = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
if (idx == -1) {
- ddb_listview_refresh (main, DDB_REFRESH_LIST | DDB_EXPOSE_LIST);
+ ddb_listview_refresh (main, DDB_REFRESH_LIST);
}
else {
ddb_listview_draw_row (main, main_get_idx ((DB_playItem_t *)it), it);
@@ -438,7 +384,7 @@ search_playlist_init (GtkWidget *widget) {
if (!col) {
add_column_helper (listview, _("Artist / Album"), 150, -1, "%a - %b", 0);
add_column_helper (listview, _("Track No"), 50, -1, "%n", 1);
- add_column_helper (listview, _("Title / Track Artist"), 150, -1, "%t", 0);
+ add_column_helper (listview, _("Title"), 150, -1, "%t", 0);
add_column_helper (listview, _("Duration"), 50, -1, "%l", 0);
}
else {
diff --git a/plugins/gtkui/search.h b/plugins/gtkui/search.h
index 7e34d4db..98216d5c 100644
--- a/plugins/gtkui/search.h
+++ b/plugins/gtkui/search.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -30,9 +30,6 @@ search_start (void);
void
search_refresh (void);
-void
-search_restore_attrs (void);
-
int
search_get_idx (DdbListviewIter it);
diff --git a/plugins/gtkui/support.h b/plugins/gtkui/support.h
index a32649e5..b4b0ace3 100644
--- a/plugins/gtkui/support.h
+++ b/plugins/gtkui/support.h
@@ -27,7 +27,9 @@
# define dgettext(Domain,Message) (Message)
# define dcgettext(Domain,Message,Type) (Message)
# define bindtextdomain(Domain,Directory) (Domain)
+#ifndef _
# define _(String) (String)
+#endif
# define Q_(String) g_strip_context ((String), (String))
# define N_(String) (String)
#endif
diff --git a/plugins/gtkui/tagwritersettings.c b/plugins/gtkui/tagwritersettings.c
new file mode 100644
index 00000000..ede3d447
--- /dev/null
+++ b/plugins/gtkui/tagwritersettings.c
@@ -0,0 +1,204 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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 HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <gtk/gtk.h>
+#include "../../gettext.h"
+#include "interface.h"
+#include "support.h"
+#include "../../deadbeef.h"
+#include "gtkui.h"
+
+void
+run_tagwriter_settings (GtkWidget *parentwindow) {
+ GtkWidget *dlg = create_tagwritersettings ();
+ gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (parentwindow));
+
+ // tag writer
+ int strip_id3v2 = deadbeef->conf_get_int ("mp3.strip_id3v2", 0);
+ int strip_id3v1 = deadbeef->conf_get_int ("mp3.strip_id3v1", 0);
+ int strip_apev2 = deadbeef->conf_get_int ("mp3.strip_apev2", 0);
+ int write_id3v2 = deadbeef->conf_get_int ("mp3.write_id3v2", 1);
+ int write_id3v1 = deadbeef->conf_get_int ("mp3.write_id3v1", 1);
+ int write_apev2 = deadbeef->conf_get_int ("mp3.write_apev2", 0);
+ int id3v2_version = deadbeef->conf_get_int ("mp3.id3v2_version", 3);
+ char id3v1_encoding[50];
+ deadbeef->conf_get_str ("mp3.id3v1_encoding", "iso8859-1", id3v1_encoding, sizeof (id3v1_encoding));
+ int ape_strip_id3v2 = deadbeef->conf_get_int ("ape.strip_id3v2", 0);
+ int ape_strip_apev2 = deadbeef->conf_get_int ("ape.strip_apev2", 0);
+ int ape_write_id3v2 = deadbeef->conf_get_int ("ape.write_id3v2", 0);
+ int ape_write_apev2 = deadbeef->conf_get_int ("ape.write_apev2", 1);
+ int wv_strip_apev2 = deadbeef->conf_get_int ("wv.strip_apev2", 0);
+ int wv_strip_id3v1 = deadbeef->conf_get_int ("wv.strip_id3v1", 0);
+ int wv_write_apev2 = deadbeef->conf_get_int ("wv.write_apev2", 1);
+ int wv_write_id3v1 = deadbeef->conf_get_int ("wv.write_id3v1", 0);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "strip_id3v2")), strip_id3v2);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "strip_id3v1")), strip_id3v1);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "strip_apev2")), strip_apev2);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "write_id3v2")), write_id3v2);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "write_id3v1")), write_id3v1);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "write_apev2")), write_apev2);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (lookup_widget (dlg, "id3v2_version")), id3v2_version != 4 ? 0 : 1);
+ gtk_entry_set_text (GTK_ENTRY (lookup_widget (dlg, "id3v1_encoding")), id3v1_encoding);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "ape_strip_id3v2")), ape_strip_id3v2);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "ape_strip_apev2")), ape_strip_apev2);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "ape_write_apev2")), ape_write_apev2);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "ape_write_id3v2")), ape_write_id3v2);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "wv_strip_id3v1")), wv_strip_id3v1);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "wv_strip_apev2")), wv_strip_apev2);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "wv_write_apev2")), wv_write_apev2);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (dlg, "wv_write_id3v1")), wv_write_id3v1);
+
+
+ int response = gtk_dialog_run (GTK_DIALOG (dlg));
+ gtk_widget_destroy (dlg);
+}
+
+void
+on_write_id3v2_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data)
+{
+ deadbeef->conf_set_int ("mp3.write_id3v2", gtk_toggle_button_get_active (togglebutton));
+}
+
+
+void
+on_write_id3v1_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data)
+{
+ deadbeef->conf_set_int ("mp3.write_id3v1", gtk_toggle_button_get_active (togglebutton));
+}
+
+
+void
+on_write_apev2_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data)
+{
+ deadbeef->conf_set_int ("mp3.write_apev2", gtk_toggle_button_get_active (togglebutton));
+}
+
+
+void
+on_strip_id3v2_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data)
+{
+ deadbeef->conf_set_int ("mp3.strip_id3v2", gtk_toggle_button_get_active (togglebutton));
+}
+
+
+void
+on_strip_id3v1_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data)
+{
+ deadbeef->conf_set_int ("mp3.strip_id3v1", gtk_toggle_button_get_active (togglebutton));
+}
+
+
+void
+on_strip_apev2_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data)
+{
+ deadbeef->conf_set_int ("mp3.strip_apev2", gtk_toggle_button_get_active (togglebutton));
+}
+
+
+void
+on_id3v2_version_changed (GtkComboBox *combobox,
+ gpointer user_data)
+{
+ int version = 3;
+ int active = gtk_combo_box_get_active (combobox);
+ if (active == 1) {
+ version = 4;
+ }
+ deadbeef->conf_set_int ("mp3.id3v2_version", version);
+}
+
+
+void
+on_id3v1_encoding_changed (GtkEditable *editable,
+ gpointer user_data)
+{
+ deadbeef->conf_set_str ("mp3.id3v1_encoding", gtk_entry_get_text (GTK_ENTRY (editable)));
+}
+
+
+void
+on_ape_write_id3v2_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data)
+{
+ deadbeef->conf_set_int ("ape.write_id3v2", gtk_toggle_button_get_active (togglebutton));
+}
+
+
+void
+on_ape_write_apev2_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data)
+{
+ deadbeef->conf_set_int ("ape.write_apev2", gtk_toggle_button_get_active (togglebutton));
+}
+
+
+void
+on_ape_strip_id3v2_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data)
+{
+ deadbeef->conf_set_int ("ape.strip_id3v2", gtk_toggle_button_get_active (togglebutton));
+}
+
+
+void
+on_ape_strip_apev2_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data)
+{
+ deadbeef->conf_set_int ("ape.strip_apev2", gtk_toggle_button_get_active (togglebutton));
+}
+
+
+void
+on_wv_write_apev2_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data)
+{
+ deadbeef->conf_set_int ("wv.write_apev2", gtk_toggle_button_get_active (togglebutton));
+}
+
+
+void
+on_wv_write_id3v1_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data)
+{
+ deadbeef->conf_set_int ("wv.write_id3v1", gtk_toggle_button_get_active (togglebutton));
+}
+
+void
+on_wv_strip_apev2_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data)
+{
+ deadbeef->conf_set_int ("wv.strip_apev2", gtk_toggle_button_get_active (togglebutton));
+}
+
+
+void
+on_wv_strip_id3v1_toggled (GtkToggleButton *togglebutton,
+ gpointer user_data)
+{
+ deadbeef->conf_set_int ("wv.strip_id3v1", gtk_toggle_button_get_active (togglebutton));
+}
diff --git a/plugins/gtkui/tagwritersettings.h b/plugins/gtkui/tagwritersettings.h
new file mode 100644
index 00000000..a48aaacb
--- /dev/null
+++ b/plugins/gtkui/tagwritersettings.h
@@ -0,0 +1,25 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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.
+*/
+#ifndef __TAGWRITERSETTINGS_H
+#define __TAGWRITERSETTINGS_H
+
+void
+run_tagwriter_settings (GtkWidget *parentwindow);
+
+#endif
diff --git a/plugins/gtkui/timeline.c b/plugins/gtkui/timeline.c
index 4543f6c6..83fc7f0f 100644
--- a/plugins/gtkui/timeline.c
+++ b/plugins/gtkui/timeline.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
diff --git a/plugins/gtkui/timeline.h b/plugins/gtkui/timeline.h
index 5325288e..4223a84b 100644
--- a/plugins/gtkui/timeline.h
+++ b/plugins/gtkui/timeline.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
diff --git a/plugins/gtkui/trkproperties.c b/plugins/gtkui/trkproperties.c
index f60a7b0b..cc419d59 100644
--- a/plugins/gtkui/trkproperties.c
+++ b/plugins/gtkui/trkproperties.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -23,6 +23,7 @@
#include <gdk/gdkkeysyms.h>
#include <string.h>
#include <math.h>
+#include <assert.h>
#include "../../gettext.h"
#include "ddblistview.h"
#include "trkproperties.h"
@@ -33,16 +34,121 @@
#include "mainplaylist.h"
#include "search.h"
#include "ddbcellrenderertextmultiline.h"
+#include "tagwritersettings.h"
+#include "wingeom.h"
//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
#define trace(fmt,...)
+#define min(x,y) ((x)<(y)?(x):(y))
+
static GtkWidget *trackproperties;
-static DB_playItem_t *track;
static GtkCellRenderer *rend_text2;
static GtkListStore *store;
static GtkListStore *propstore;
static int trkproperties_modified;
+static DB_playItem_t **tracks;
+static int numtracks;
+static GtkWidget *progressdlg;
+static int progress_aborted;
+
+static int
+build_key_list (const char ***pkeys, int props) {
+ int sz = 20;
+ const char **keys = malloc (sizeof (const char *) * sz);
+ if (!keys) {
+ fprintf (stderr, "fatal: out of memory allocating key list\n");
+ assert (0);
+ return 0;
+ }
+
+ int n = 0;
+
+ for (int i = 0; i < numtracks; i++) {
+ DB_metaInfo_t *meta = deadbeef->pl_get_metadata_head (tracks[i]);
+ while (meta) {
+ if ((props && meta->key[0] == ':') || (!props && meta->key[0] != ':')) {
+ int k = 0;
+ for (; k < n; k++) {
+ if (meta->key == keys[k]) {
+ break;
+ }
+ }
+ if (k == n) {
+ if (n >= sz) {
+ sz *= 2;
+ keys = realloc (keys, sizeof (const char *) * sz);
+ if (!keys) {
+ fprintf (stderr, "fatal: out of memory reallocating key list (%d keys)\n", sz);
+ assert (0);
+ }
+ }
+ keys[n++] = meta->key;
+ }
+ }
+ meta = meta->next;
+ }
+ }
+
+ *pkeys = keys;
+ return n;
+}
+
+static int
+equals_ptr (const char *a, const char *b) {
+ return a == b;
+}
+
+static int
+get_field_value (char *out, int size, const char *key, const char *(*getter)(DB_playItem_t *it, const char *key), int (*equals)(const char *a, const char *b)) {
+ int multiple = 0;
+ *out = 0;
+ if (numtracks == 0) {
+ return 0;
+ }
+ char *p = out;
+ const char **prev = malloc (sizeof (const char *) * numtracks);
+ memset (prev, 0, sizeof (const char *) * numtracks);
+ for (int i = 0; i < numtracks; i++) {
+ const char *val = getter (tracks[i], key);
+ if (val && val[0] == 0) {
+ val = NULL;
+ }
+ if (i > 0) {
+ int n = 0;
+ for (; n < i; n++) {
+ if (equals (prev[n], val)) {
+ break;
+ }
+ }
+ if (n == i) {
+ multiple = 1;
+ if (val) {
+ size_t l = snprintf (out, size, out == p ? "%s" : "; %s", val ? val : "");
+ l = min (l, size);
+ out += l;
+ size -= l;
+ }
+ }
+ }
+ else if (val) {
+ size_t l = snprintf (out, size, "%s", val ? val : "");
+ l = min (l, size);
+ out += l;
+ size -= l;
+ }
+ prev[i] = val;
+ if (size <= 1) {
+ break;
+ }
+ }
+ if (size <= 1) {
+ gchar *prev = g_utf8_prev_char (out-4);
+ strcpy (prev, "...");
+ }
+ free (prev);
+ return multiple;
+}
gboolean
on_trackproperties_delete_event (GtkWidget *widget,
@@ -50,7 +156,7 @@ on_trackproperties_delete_event (GtkWidget *widget,
gpointer user_data)
{
if (trkproperties_modified) {
- GtkWidget *dlg = gtk_message_dialog_new (GTK_WINDOW (mainwin), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("You've modified data for this track."));
+ GtkWidget *dlg = gtk_message_dialog_new (GTK_WINDOW (trackproperties), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("You've modified data for this track."));
gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (trackproperties));
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg), _("Really close the window?"));
gtk_window_set_title (GTK_WINDOW (dlg), _("Warning"));
@@ -64,9 +170,13 @@ on_trackproperties_delete_event (GtkWidget *widget,
gtk_widget_destroy (widget);
rend_text2 = NULL;
trackproperties = NULL;
- if (track) {
- deadbeef->pl_item_unref (track);
- track = NULL;
+ if (tracks) {
+ for (int i = 0; i < numtracks; i++) {
+ deadbeef->pl_item_unref (tracks[i]);
+ }
+ free (tracks);
+ tracks = NULL;
+ numtracks = 0;
}
return TRUE;
}
@@ -108,7 +218,7 @@ on_metadata_edited (GtkCellRendererText *renderer, gchar *path, gchar *new_text,
gtk_tree_model_get_value (GTK_TREE_MODEL (store), &iter, 1, &value);
const char *svalue = g_value_get_string (&value);
if (strcmp (svalue, new_text)) {
- gtk_list_store_set (store, &iter, 1, new_text, -1);
+ gtk_list_store_set (store, &iter, 1, new_text, 3, 0, -1);
trkproperties_modified = 1;
}
}
@@ -117,8 +227,6 @@ on_metadata_edited (GtkCellRendererText *renderer, gchar *path, gchar *new_text,
static const char *types[] = {
"artist", "Artist",
"title", "Track Title",
- "performer", "Performer",
- "band", "Band / Album Artist",
"album", "Album",
"year", "Date",
"track", "Track Number",
@@ -127,17 +235,36 @@ static const char *types[] = {
"composer", "Composer",
"disc", "Disc Number",
"comment", "Comment",
- "vendor", "Encoder / Vendor",
- "copyright", "Copyright",
- // nonstandard frames, let's hide them for now
-// "<performer>", "<PERFORMER>",
-// "<albumartist>", "<ALBUM ARTIST>",
NULL
};
-static inline float
-amp_to_db (float amp) {
- return 20*log10 (amp);
+static const char *hc_props[] = {
+ ":URI", "Location",
+ ":TRACKNUM", "Subtrack Index",
+ ":DURATION", "Duration",
+ ":TAGS", "Tag Type(s)",
+ ":HAS_EMBEDDED_CUESHEET", "Embedded Cuesheet",
+ ":DECODER", "Codec",
+ NULL
+};
+
+void
+add_field (GtkListStore *store, const char *key, const char *title, int is_prop) {
+ // get value to edit
+ const char *mult = is_prop ? "" : _("[Multiple values] ");
+ char val[1000];
+ size_t ml = strlen (mult);
+ memcpy (val, mult, ml+1);
+ int n = get_field_value (val + ml, sizeof (val) - ml, key, deadbeef->pl_find_meta, equals_ptr);
+
+ GtkTreeIter iter;
+ gtk_list_store_append (store, &iter);
+ if (!is_prop) {
+ gtk_list_store_set (store, &iter, 0, title, 1, n ? val : val + ml, 2, key, 3, n ? 1 : 0, -1);
+ }
+ else {
+ gtk_list_store_set (store, &iter, 0, title, 1, n ? val : val + ml, -1);
+ }
}
void
@@ -148,105 +275,126 @@ trkproperties_fill_metadata (void) {
trkproperties_modified = 0;
gtk_list_store_clear (store);
deadbeef->pl_lock ();
- int i = 0;
- while (types[i]) {
- GtkTreeIter iter;
- gtk_list_store_append (store, &iter);
- const char *value = deadbeef->pl_find_meta (track, types[i]);
- if (!value) {
- value = "";
+
+ const char **keys = NULL;
+ int nkeys = build_key_list (&keys, 0);
+
+ int k;
+
+ // add "standard" fields
+ for (int i = 0; types[i]; i += 2) {
+ add_field (store, types[i], _(types[i+1]), 0);
+ }
+
+ // add all other fields
+ for (int k = 0; k < nkeys; k++) {
+ int i;
+ for (i = 0; types[i]; i += 2) {
+ if (!strcasecmp (keys[k], types[i])) {
+ break;
+ }
}
- gtk_list_store_set (store, &iter, 0, _(types[i+1]), 1, value, 2, types[i], -1);
- i += 2;
+ if (types[i]) {
+ continue;
+ }
+
+ char title[1000];
+ if (!types[i]) {
+ snprintf (title, sizeof (title), "<%s>", keys[k]);
+ }
+ add_field (store, keys[k], title, 0);
+ }
+ if (keys) {
+ free (keys);
}
- deadbeef->pl_unlock ();
+ // hardcoded properties
+ for (int i = 0; hc_props[i]; i += 2) {
+ add_field (propstore, hc_props[i], _(hc_props[i+1]), 1);
+ }
// properties
- char temp[200];
- GtkTreeIter iter;
- gtk_list_store_clear (propstore);
- gtk_list_store_append (propstore, &iter);
- gtk_list_store_set (propstore, &iter, 0, _("Location"), 1, track->fname, -1);
- gtk_list_store_append (propstore, &iter);
- snprintf (temp, sizeof (temp), "%d", track->tracknum);
- gtk_list_store_set (propstore, &iter, 0, _("Subtrack Index"), 1, temp, -1);
- gtk_list_store_append (propstore, &iter);
- deadbeef->pl_format_time (deadbeef->pl_get_item_duration (track), temp, sizeof (temp));
- gtk_list_store_set (propstore, &iter, 0, _("Duration"), 1, temp, -1);
- gtk_list_store_append (propstore, &iter);
- deadbeef->pl_format_title (track, -1, temp, sizeof (temp), -1, "%T");
- gtk_list_store_set (propstore, &iter, 0, _("Tag Type(s)"), 1, temp, -1);
- gtk_list_store_append (propstore, &iter);
- gtk_list_store_set (propstore, &iter, 0, _("Embedded Cuesheet"), 1, (deadbeef->pl_get_item_flags (track) & DDB_HAS_EMBEDDED_CUESHEET) ? _("Yes") : _("No"), -1);
- gtk_list_store_append (propstore, &iter);
- gtk_list_store_set (propstore, &iter, 0, _("Codec"), 1, track->decoder_id, -1);
-
- gtk_list_store_append (propstore, &iter);
- snprintf (temp, sizeof (temp), "%0.2f dB", track->replaygain_album_gain);
- gtk_list_store_set (propstore, &iter, 0, "REPLAYGAIN_ALBUM_GAIN", 1, temp, -1);
- gtk_list_store_append (propstore, &iter);
- snprintf (temp, sizeof (temp), "%0.6f", track->replaygain_album_peak);
- gtk_list_store_set (propstore, &iter, 0, "REPLAYGAIN_ALBUM_PEAK", 1, temp, -1);
-
- gtk_list_store_append (propstore, &iter);
- snprintf (temp, sizeof (temp), "%0.2f dB", track->replaygain_track_gain);
- gtk_list_store_set (propstore, &iter, 0, "REPLAYGAIN_TRACK_GAIN", 1, temp, -1);
- gtk_list_store_append (propstore, &iter);
- snprintf (temp, sizeof (temp), "%0.6f", track->replaygain_track_peak);
- gtk_list_store_set (propstore, &iter, 0, "REPLAYGAIN_TRACK_PEAK", 1, temp, -1);
-}
-
-void
-show_track_properties_dlg (DB_playItem_t *it) {
- if (track) {
- deadbeef->pl_item_unref (track);
- track = NULL;
+ keys = NULL;
+ nkeys = build_key_list (&keys, 1);
+ for (int k = 0; k < nkeys; k++) {
+ int i;
+ for (i = 0; hc_props[i]; i += 2) {
+ if (!strcasecmp (keys[k], hc_props[i])) {
+ break;
+ }
+ }
+ if (hc_props[i]) {
+ continue;
+ }
+ char title[1000];
+ snprintf (title, sizeof (title), "<%s>", keys[k]+1);
+ add_field (propstore, keys[k], title, 1);
}
- if (it) {
- deadbeef->pl_item_ref (it);
+ if (keys) {
+ free (keys);
}
- track = it;
+ deadbeef->pl_unlock ();
+}
- int allow_editing = 0;
+void
+show_track_properties_dlg (void) {
- int is_subtrack = deadbeef->pl_get_item_flags (it) & DDB_IS_SUBTRACK;
+ deadbeef->plt_lock ();
+ deadbeef->pl_lock ();
- if (!is_subtrack && deadbeef->is_local_file (it->fname)) {
- // get decoder plugin by id
- DB_decoder_t *dec = NULL;
- if (it->decoder_id) {
- DB_decoder_t **decoders = deadbeef->plug_get_decoder_list ();
- for (int i = 0; decoders[i]; i++) {
- if (!strcmp (decoders[i]->plugin.id, it->decoder_id)) {
- dec = decoders[i];
- break;
+ if (tracks) {
+ for (int i = 0; i < numtracks; i++) {
+ deadbeef->pl_item_unref (tracks[i]);
+ }
+ free (tracks);
+ tracks = NULL;
+ numtracks = 0;
+ }
+
+ int nsel = deadbeef->pl_getselcount ();
+ if (0 < nsel) {
+ tracks = malloc (sizeof (DB_playItem_t *) * nsel);
+ if (tracks) {
+ int n = 0;
+ DB_playItem_t *it = deadbeef->pl_get_first (PL_MAIN);
+ while (it) {
+ if (deadbeef->pl_is_selected (it)) {
+ assert (n < nsel);
+ deadbeef->pl_item_ref (it);
+ tracks[n++] = it;
}
+ DB_playItem_t *next = deadbeef->pl_get_next (it, PL_MAIN);
+ deadbeef->pl_item_unref (it);
+ it = next;
}
+ numtracks = nsel;
}
-
- if (dec && dec->write_metadata) {
- allow_editing = 1;
+ else {
+ deadbeef->pl_unlock ();
+ deadbeef->plt_unlock ();
+ return;
}
}
+ deadbeef->pl_unlock ();
+ deadbeef->plt_unlock ();
+
GtkTreeView *tree;
GtkTreeView *proptree;
if (!trackproperties) {
trackproperties = create_trackproperties ();
gtk_window_set_transient_for (GTK_WINDOW (trackproperties), GTK_WINDOW (mainwin));
+ wingeom_restore (trackproperties, "trkproperties", -1, -1, 300, 400, 0);
// metadata tree
tree = GTK_TREE_VIEW (lookup_widget (trackproperties, "metalist"));
- store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+ store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
gtk_tree_view_set_model (tree, GTK_TREE_MODEL (store));
GtkCellRenderer *rend_text = gtk_cell_renderer_text_new ();
- rend_text2 = GTK_CELL_RENDERER (ddb_cell_renderer_text_multiline_new ());//gtk_cell_renderer_text_new ();
- if (allow_editing) {
- g_signal_connect ((gpointer)rend_text2, "edited",
- G_CALLBACK (on_metadata_edited),
- store);
- }
+ rend_text2 = GTK_CELL_RENDERER (ddb_cell_renderer_text_multiline_new ());
+ g_signal_connect ((gpointer)rend_text2, "edited",
+ G_CALLBACK (on_metadata_edited),
+ store);
GtkTreeViewColumn *col1 = gtk_tree_view_column_new_with_attributes (_("Key"), rend_text, "text", 0, NULL);
GtkTreeViewColumn *col2 = gtk_tree_view_column_new_with_attributes (_("Value"), rend_text2, "text", 1, NULL);
gtk_tree_view_append_column (tree, col1);
@@ -273,12 +421,7 @@ show_track_properties_dlg (DB_playItem_t *it) {
gtk_list_store_clear (propstore);
}
-// if (allow_editing) {
- g_object_set (G_OBJECT (rend_text2), "editable", TRUE, NULL);
-// }
-// else {
-// g_object_set (G_OBJECT (rend_text2), "editable", FALSE, NULL);
-// }
+ g_object_set (G_OBJECT (rend_text2), "editable", TRUE, NULL);
GtkWidget *widget = trackproperties;
GtkWidget *w;
@@ -286,12 +429,7 @@ show_track_properties_dlg (DB_playItem_t *it) {
trkproperties_fill_metadata ();
- if (allow_editing) {
- gtk_widget_set_sensitive (lookup_widget (widget, "write_tags"), TRUE);
- }
- else {
- gtk_widget_set_sensitive (lookup_widget (widget, "write_tags"), FALSE);
- }
+ gtk_widget_set_sensitive (lookup_widget (widget, "write_tags"), TRUE);
gtk_widget_show (widget);
gtk_window_present (GTK_WINDOW (widget));
@@ -299,46 +437,322 @@ show_track_properties_dlg (DB_playItem_t *it) {
static gboolean
set_metadata_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) {
- GValue key = {0,}, value = {0,};
- gtk_tree_model_get_value (model, iter, 2, &key);
- gtk_tree_model_get_value (model, iter, 1, &value);
- const char *skey = g_value_get_string (&key);
- const char *svalue = g_value_get_string (&value);
+ GValue mult = {0,};
+ gtk_tree_model_get_value (model, iter, 3, &mult);
+ int smult = g_value_get_int (&mult);
+ if (!smult) {
+ GValue key = {0,}, value = {0,};
+ gtk_tree_model_get_value (model, iter, 2, &key);
+ gtk_tree_model_get_value (model, iter, 1, &value);
+ const char *skey = g_value_get_string (&key);
+ const char *svalue = g_value_get_string (&value);
+ if (*svalue) {
+ for (int i = 0; i < numtracks; i++) {
+ deadbeef->pl_replace_meta (tracks[i], skey, svalue);
+ }
+ }
+ else {
+ for (int i = 0; i < numtracks; i++) {
+ deadbeef->pl_delete_meta (tracks[i], skey);
+ }
+ }
+ }
+ return FALSE;
+}
- for (int i = 0; types[i]; i += 2) {
- if (!strcmp (skey, types[i])) {
- deadbeef->pl_replace_meta (DB_PLAYITEM (data), types[i], svalue);
+static gboolean
+write_finished_cb (void *ctx) {
+ gtk_widget_destroy (progressdlg);
+ progressdlg = NULL;
+ main_refresh ();
+ search_refresh ();
+ trkproperties_modified = 0;
+ return FALSE;
+}
+
+static gboolean
+set_progress_cb (void *ctx) {
+ DB_playItem_t *track = ctx;
+ GtkWidget *progressitem = lookup_widget (progressdlg, "progresstitle");
+ const char *fname = deadbeef->pl_find_meta (track, ":URI");
+ gtk_entry_set_text (GTK_ENTRY (progressitem), fname);
+ deadbeef->pl_item_unref (track);
+}
+
+static void
+write_meta_worker (void *ctx) {
+ for (int t = 0; t < numtracks; t++) {
+ if (progress_aborted) {
+ break;
+ }
+ DB_playItem_t *track = tracks[t];
+ const char *decoder_id = deadbeef->pl_find_meta (track, ":DECODER");
+ if (track && decoder_id) {
+ int is_subtrack = deadbeef->pl_get_item_flags (track) & DDB_IS_SUBTRACK;
+ if (is_subtrack) {
+ continue;
+ }
+ deadbeef->pl_item_ref (track);
+ g_idle_add (set_progress_cb, track);
+ // find decoder
+ DB_decoder_t *dec = NULL;
+ DB_decoder_t **decoders = deadbeef->plug_get_decoder_list ();
+ for (int i = 0; decoders[i]; i++) {
+ if (!strcmp (decoders[i]->plugin.id, decoder_id)) {
+ dec = decoders[i];
+ if (dec->write_metadata) {
+ dec->write_metadata (track);
+ }
+ break;
+ }
+ }
}
}
+ g_idle_add (write_finished_cb, ctx);
+}
- return FALSE;
+static gboolean
+on_progress_delete_event (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ progress_aborted = 1;
+ return gtk_widget_hide_on_delete (widget);
+}
+
+static void
+on_progress_abort (GtkButton *button,
+ gpointer user_data)
+{
+ progress_aborted = 1;
}
void
on_write_tags_clicked (GtkButton *button,
gpointer user_data)
{
- if (!track || !track->decoder_id) {
- return;
+ deadbeef->pl_lock ();
+ GtkTreeView *tree = GTK_TREE_VIEW (lookup_widget (trackproperties, "metalist"));
+ GtkTreeModel *model = GTK_TREE_MODEL (gtk_tree_view_get_model (tree));
+
+ // delete all metadata properties that are not in the listview
+ for (int i = 0; i < numtracks; i++) {
+ DB_metaInfo_t *meta = deadbeef->pl_get_metadata_head (tracks[i]);
+ while (meta) {
+ DB_metaInfo_t *next = meta->next;
+ if (meta->key[0] != ':') {
+ GtkTreeIter iter;
+ gboolean res = gtk_tree_model_get_iter_first (model, &iter);
+ int mult = 0;
+ while (res) {
+ GValue key = {0,};
+ gtk_tree_model_get_value (model, &iter, 2, &key);
+ const char *skey = g_value_get_string (&key);
+
+ if (!strcasecmp (skey, meta->key)) {
+ // field found, don't delete
+ break;
+ }
+ res = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
+ }
+ if (!res) {
+ // field not found, delete
+ deadbeef->pl_delete_metadata (tracks[i], meta);
+ }
+ }
+ meta = next;
+ }
}
- // find decoder
- DB_decoder_t *dec = NULL;
- DB_decoder_t **decoders = deadbeef->plug_get_decoder_list ();
- for (int i = 0; decoders[i]; i++) {
- if (!strcmp (decoders[i]->plugin.id, track->decoder_id)) {
- dec = decoders[i];
- if (dec->write_metadata) {
- // put all metainfo into track
- GtkTreeView *tree = GTK_TREE_VIEW (lookup_widget (trackproperties, "metalist"));
- GtkTreeModel *model = GTK_TREE_MODEL (gtk_tree_view_get_model (tree));
- gtk_tree_model_foreach (model, set_metadata_cb, track);
- dec->write_metadata (track);
- main_refresh ();
- search_refresh ();
+ // put all metainfo into track
+ gtk_tree_model_foreach (model, set_metadata_cb, NULL);
+ deadbeef->pl_unlock ();
+
+ progress_aborted = 0;
+ progressdlg = create_progressdlg ();
+ gtk_window_set_title (GTK_WINDOW (progressdlg), _("Writing tags..."));
+
+ g_signal_connect ((gpointer) progressdlg, "delete_event",
+ G_CALLBACK (on_progress_delete_event),
+ NULL);
+ GtkWidget *cancelbtn = lookup_widget (progressdlg, "cancelbtn");
+ g_signal_connect ((gpointer) cancelbtn, "clicked",
+ G_CALLBACK (on_progress_abort),
+ NULL);
+
+ gtk_widget_show_all (progressdlg);
+ gtk_window_present (GTK_WINDOW (progressdlg));
+ gtk_window_set_transient_for (GTK_WINDOW (progressdlg), GTK_WINDOW (trackproperties));
+
+ // start new thread for writing metadata
+ intptr_t tid = deadbeef->thread_start (write_meta_worker, NULL);
+ deadbeef->thread_detach (tid);
+}
+
+void
+on_add_field_activate (GtkMenuItem *menuitem,
+ gpointer user_data) {
+ GtkWidget *dlg = create_entrydialog ();
+ gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK);
+ gtk_window_set_title (GTK_WINDOW (dlg), _("Edit playlist"));
+ GtkWidget *e;
+ e = lookup_widget (dlg, "title_label");
+ gtk_label_set_text (GTK_LABEL(e), _("Name:"));
+ for (;;) {
+ int res = gtk_dialog_run (GTK_DIALOG (dlg));
+ if (res == GTK_RESPONSE_OK) {
+ e = lookup_widget (dlg, "title");
+
+ const char *text = gtk_entry_get_text (GTK_ENTRY(e));
+
+ GtkTreeIter iter;
+
+ // check for _ and :
+ if (text[0] == '_' || text[0] == ':') {
+ GtkWidget *d = gtk_message_dialog_new (GTK_WINDOW (dlg), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Field names must not start with : or _"));
+ gtk_window_set_title (GTK_WINDOW (d), _("Cannot add field"));
+
+ gtk_dialog_run (GTK_DIALOG (d));
+ gtk_widget_destroy (d);
+ continue;
}
+
+ // check if a field with the same name already exists
+ int dup = 0;
+ gboolean res = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
+ while (res) {
+ GValue value = {0,};
+ gtk_tree_model_get_value (GTK_TREE_MODEL (store), &iter, 2, &value);
+ const char *svalue = g_value_get_string (&value);
+ if (!strcasecmp (svalue, text)) {
+ dup = 1;
+ break;
+ }
+ res = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
+ }
+
+ if (!dup) {
+ int l = strlen (text);
+ char title[l+3];
+ snprintf (title, sizeof (title), "<%s>", text);
+ const char *value = "";
+ const char *key = text;
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, title, 1, value, 2, key, -1);
+ trkproperties_modified = 1;
+ }
+ else {
+ GtkWidget *d = gtk_message_dialog_new (GTK_WINDOW (dlg), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Field with such name already exists, please try different name."));
+ gtk_window_set_title (GTK_WINDOW (d), _("Cannot add field"));
+
+ gtk_dialog_run (GTK_DIALOG (d));
+ gtk_widget_destroy (d);
+ continue;
+ }
+ }
+ break;
+ }
+ gtk_widget_destroy (dlg);
+}
+
+void
+on_remove_field_activate (GtkMenuItem *menuitem,
+ gpointer user_data) {
+
+ GtkTreePath *path;
+ GtkTreeViewColumn *col;
+ GtkTreeView *treeview = GTK_TREE_VIEW (lookup_widget (trackproperties, "metalist"));
+ gtk_tree_view_get_cursor (treeview, &path, &col);
+ if (!path || !col) {
+ return;
+ }
+
+ GtkWidget *dlg = gtk_message_dialog_new (GTK_WINDOW (trackproperties), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("Really remove selected field?"));
+ gtk_window_set_title (GTK_WINDOW (dlg), _("Warning"));
+
+ int response = gtk_dialog_run (GTK_DIALOG (dlg));
+ gtk_widget_destroy (dlg);
+ if (response != GTK_RESPONSE_YES) {
+ return;
+ }
+
+ GtkTreeIter iter;
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
+ GValue value = {0,};
+ gtk_tree_model_get_value (GTK_TREE_MODEL (store), &iter, 2, &value);
+ const char *svalue = g_value_get_string (&value);
+
+ // delete unknown fields completely; otherwise just clear
+ int i = 0;
+ for (; types[i]; i += 2) {
+ if (!strcasecmp (svalue, types[i])) {
break;
}
}
- trkproperties_modified = 0;
+ if (types[i]) { // known val, clear
+ gtk_list_store_set (store, &iter, 1, "", 3, 0, -1);
+ }
+ else {
+ gtk_list_store_remove (store, &iter);
+ }
+ gtk_tree_path_free (path);
+ trkproperties_modified = 1;
+}
+
+gboolean
+on_metalist_button_press_event (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ if (event->button == 3) {
+ GtkWidget *menu;
+ GtkWidget *add;
+ GtkWidget *remove;
+ menu = gtk_menu_new ();
+ add = gtk_menu_item_new_with_mnemonic (_("Add field"));
+ gtk_widget_show (add);
+ gtk_container_add (GTK_CONTAINER (menu), add);
+ remove = gtk_menu_item_new_with_mnemonic (_("Remove field"));
+ gtk_widget_show (remove);
+ gtk_container_add (GTK_CONTAINER (menu), remove);
+
+ g_signal_connect ((gpointer) add, "activate",
+ G_CALLBACK (on_add_field_activate),
+ NULL);
+
+ g_signal_connect ((gpointer) remove, "activate",
+ G_CALLBACK (on_remove_field_activate),
+ NULL);
+
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, widget, event->button, gtk_get_current_event_time());
+ }
+ return FALSE;
+}
+
+void
+on_tagwriter_settings_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ run_tagwriter_settings (trackproperties);
+}
+
+gboolean
+on_trackproperties_configure_event (GtkWidget *widget,
+ GdkEventConfigure *event,
+ gpointer user_data)
+{
+ wingeom_save (widget, "trkproperties");
+ return FALSE;
}
+
+
+gboolean
+on_trackproperties_window_state_event (GtkWidget *widget,
+ GdkEventWindowState *event,
+ gpointer user_data)
+{
+ wingeom_save_max (event, widget, "trkproperties");
+ return FALSE;
+}
+
diff --git a/plugins/gtkui/trkproperties.h b/plugins/gtkui/trkproperties.h
index 8bd1a903..ccdaa69f 100644
--- a/plugins/gtkui/trkproperties.h
+++ b/plugins/gtkui/trkproperties.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -22,7 +22,7 @@
struct DB_playItem_s;
void
-show_track_properties_dlg (struct DB_playItem_s *it);
+show_track_properties_dlg (void);
void
trkproperties_destroy (void);
diff --git a/plugins/gtkui/wingeom.c b/plugins/gtkui/wingeom.c
new file mode 100644
index 00000000..8591a5c6
--- /dev/null
+++ b/plugins/gtkui/wingeom.c
@@ -0,0 +1,101 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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 HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <gtk/gtk.h>
+#include "wingeom.h"
+#include "../../deadbeef.h"
+#include "gtkui.h"
+
+void
+wingeom_save (GtkWidget *widget, const char *name) {
+#if GTK_CHECK_VERSION(2,2,0)
+ GdkWindowState window_state = gdk_window_get_state (GDK_WINDOW (widget->window));
+#else
+ GdkWindowState window_state = gdk_window_get_state (G_OBJECT (widget));
+#endif
+ if (!(window_state & GDK_WINDOW_STATE_MAXIMIZED) && gtk_widget_get_visible (widget)) {
+ int x, y;
+ int w, h;
+ char key[100];
+ gtk_window_get_position (GTK_WINDOW (widget), &x, &y);
+ gtk_window_get_size (GTK_WINDOW (widget), &w, &h);
+ snprintf (key, sizeof (key), "%s.geometry.x", name);
+ deadbeef->conf_set_int (key, x);
+ snprintf (key, sizeof (key), "%s.geometry.y", name);
+ deadbeef->conf_set_int (key, y);
+ snprintf (key, sizeof (key), "%s.geometry.w", name);
+ deadbeef->conf_set_int (key, w);
+ snprintf (key, sizeof (key), "%s.geometry.h", name);
+ deadbeef->conf_set_int (key, h);
+ }
+}
+
+void
+wingeom_save_max (GdkEventWindowState *event, GtkWidget *widget, const char *name) {
+ if (!gtk_widget_get_visible (widget)) {
+ return;
+ }
+ char key[100];
+ snprintf (key, sizeof (key), "%s.geometry.maximized", name);
+ // based on pidgin maximization handler
+#if GTK_CHECK_VERSION(2,2,0)
+ if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) {
+ if (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
+ deadbeef->conf_set_int (key, 1);
+ }
+ else {
+ deadbeef->conf_set_int (key, 0);
+ }
+ }
+#else
+ GdkWindowState new_window_state = gdk_window_get_state(G_OBJECT(widget));
+
+ if (new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
+ deadbeef->conf_set_int (key, 1);
+ }
+ else {
+ deadbeef->conf_set_int (key, 0);
+ }
+#endif
+}
+
+void
+wingeom_restore (GtkWidget *win, const char *name, int dx, int dy, int dw, int dh, int dmax) {
+ char key[100];
+ snprintf (key, sizeof (key), "%s.geometry.x", name);
+ int x = deadbeef->conf_get_int (key, dx);
+ snprintf (key, sizeof (key), "%s.geometry.y", name);
+ int y = deadbeef->conf_get_int (key, dy);
+ snprintf (key, sizeof (key), "%s.geometry.w", name);
+ int w = deadbeef->conf_get_int (key, dw);
+ snprintf (key, sizeof (key), "%s.geometry.h", name);
+ int h = deadbeef->conf_get_int (key, dh);
+ if (x != -1 && y != -1) {
+ gtk_window_move (GTK_WINDOW (win), x, y);
+ }
+ if (w != -1 && h != -1) {
+ gtk_window_resize (GTK_WINDOW (win), w, h);
+ }
+ snprintf (key, sizeof (key), "%s.geometry.maximized", name);
+ if (deadbeef->conf_get_int (key, dmax)) {
+ gtk_window_maximize (GTK_WINDOW (win));
+ }
+}
diff --git a/plugins/gtkui/wingeom.h b/plugins/gtkui/wingeom.h
new file mode 100644
index 00000000..9b468846
--- /dev/null
+++ b/plugins/gtkui/wingeom.h
@@ -0,0 +1,31 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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.
+*/
+#ifndef __WINGEOM_H
+#define __WINGEOM_H
+
+void
+wingeom_save (GtkWidget *widget, const char *name);
+
+void
+wingeom_save_max (GdkEventWindowState *event, GtkWidget *widget, const char *name);
+
+void
+wingeom_restore (GtkWidget *win, const char *name, int dx, int dy, int dw, int dh, int dmax);
+
+#endif
diff --git a/plugins/hotkeys/hotkeys.c b/plugins/hotkeys/hotkeys.c
index 2be24387..ec8f2e96 100644
--- a/plugins/hotkeys/hotkeys.c
+++ b/plugins/hotkeys/hotkeys.c
@@ -111,7 +111,7 @@ cmd_stop_after_current (void *unused) {
int var = deadbeef->conf_get_int ("playlist.stop_after_current", 0);
var = 1 - var;
deadbeef->conf_set_int ("playlist.stop_after_current", var);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
}
/*
@@ -461,7 +461,7 @@ hotkeys_event_loop (void *unused) {
}
static int
-hotkeys_start (void) {
+hotkeys_connect (void) {
finished = 0;
loop_tid = 0;
disp = XOpenDisplay (NULL);
@@ -475,12 +475,11 @@ hotkeys_start (void) {
read_config (disp);
XSync (disp, 0);
loop_tid = deadbeef->thread_start (hotkeys_event_loop, 0);
-
return 0;
}
static int
-hotkeys_stop (void) {
+hotkeys_disconnect (void) {
if (loop_tid) {
finished = 1;
deadbeef->thread_join (loop_tid);
@@ -508,31 +507,31 @@ hotkeys_reset (void) {
int
action_play_cb (struct DB_plugin_action_s *action, DB_playItem_t *it) {
- deadbeef->playback_play ();
+ deadbeef->sendmessage (M_PLAY_CURRENT, 0, 0, 0);
return 0;
}
int
action_prev_cb (struct DB_plugin_action_s *action, DB_playItem_t *it) {
- deadbeef->playback_prev ();
+ deadbeef->sendmessage (M_PREV, 0, 0, 0);
return 0;
}
int
action_next_cb (struct DB_plugin_action_s *action, DB_playItem_t *it) {
- deadbeef->playback_next ();
+ deadbeef->sendmessage (M_NEXT, 0, 0, 0);
return 0;
}
int
action_stop_cb (struct DB_plugin_action_s *action, DB_playItem_t *it) {
- deadbeef->playback_stop ();
+ deadbeef->sendmessage (M_STOP, 0, 0, 0);
return 0;
}
int
action_toggle_pause_cb (struct DB_plugin_action_s *action, DB_playItem_t *it) {
- deadbeef->playback_pause ();
+ deadbeef->sendmessage (M_TOGGLE_PAUSE, 0, 0, 0);
return 0;
}
@@ -540,17 +539,17 @@ int
action_play_pause_cb (struct DB_plugin_action_s *action, DB_playItem_t *it) {
int state = deadbeef->get_output ()->state ();
if (state == OUTPUT_STATE_PLAYING) {
- deadbeef->playback_pause ();
+ deadbeef->sendmessage (M_PAUSE, 0, 0, 0);
}
else {
- deadbeef->playback_play ();
+ deadbeef->sendmessage (M_PLAY_CURRENT, 0, 0, 0);
}
return 0;
}
int
action_play_random_cb (struct DB_plugin_action_s *action, DB_playItem_t *it) {
- deadbeef->playback_random ();
+ deadbeef->sendmessage (M_PLAY_RANDOM, 0, 0, 0);
return 0;
}
@@ -583,7 +582,7 @@ action_toggle_stop_after_current_cb (struct DB_plugin_action_s *action, DB_playI
int var = deadbeef->conf_get_int ("playlist.stop_after_current", 0);
var = 1 - var;
deadbeef->conf_set_int ("playlist.stop_after_current", var);
- deadbeef->sendmessage (M_CONFIGCHANGED, 0, 0, 0);
+ deadbeef->sendmessage (M_CONFIG_CHANGED, 0, 0, 0);
return 0;
}
@@ -693,16 +692,34 @@ hotkeys_get_actions (DB_playItem_t *it)
static DB_hotkeys_plugin_t plugin = {
.misc.plugin.api_vmajor = DB_API_VERSION_MAJOR,
.misc.plugin.api_vminor = DB_API_VERSION_MINOR,
+ .misc.plugin.version_major = 1,
+ .misc.plugin.version_minor = 0,
.misc.plugin.type = DB_PLUGIN_MISC,
.misc.plugin.id = "hotkeys",
.misc.plugin.name = "Global hotkeys support",
.misc.plugin.descr = "Allows to control player with global hotkeys",
- .misc.plugin.author = "Viktor Semykin",
- .misc.plugin.email = "thesame.ml@gmail.com",
+ .misc.plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "Copyright (C) 2009-2011 Viktor Semykin <thesame.ml@gmail.com>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.misc.plugin.website = "http://deadbeef.sf.net",
- .misc.plugin.start = hotkeys_start,
- .misc.plugin.stop = hotkeys_stop,
.misc.plugin.get_actions = hotkeys_get_actions,
+ .misc.plugin.connect = hotkeys_connect,
+ .misc.plugin.disconnect = hotkeys_disconnect,
.get_name_for_keycode = hotkeys_get_name_for_keycode,
.reset = hotkeys_reset,
};
diff --git a/plugins/hotkeys/hotkeys.h b/plugins/hotkeys/hotkeys.h
index f520aa41..010f0919 100644
--- a/plugins/hotkeys/hotkeys.h
+++ b/plugins/hotkeys/hotkeys.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
diff --git a/plugins/lastfm/lastfm.c b/plugins/lastfm/lastfm.c
index 4a234e8f..b29355b1 100644
--- a/plugins/lastfm/lastfm.c
+++ b/plugins/lastfm/lastfm.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -67,13 +67,15 @@ static DB_playItem_t *lfm_subm_queue[LFM_SUBMISSION_QUEUE_SIZE];
static void
lfm_update_auth (void) {
- const char *user = deadbeef->conf_get_str ("lastfm.login", "");
- const char *pass = deadbeef->conf_get_str ("lastfm.password", "");
+ deadbeef->conf_lock ();
+ const char *user = deadbeef->conf_get_str_fast ("lastfm.login", "");
+ const char *pass = deadbeef->conf_get_str_fast ("lastfm.password", "");
if (strcmp (user, lfm_user) || strcmp (pass, lfm_pass)) {
strcpy (lfm_user, user);
strcpy (lfm_pass, pass);
lfm_sess[0] = 0;
}
+ deadbeef->conf_unlock ();
}
static size_t
@@ -128,9 +130,10 @@ curl_req_send (const char *req, const char *post) {
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(post));
}
if (deadbeef->conf_get_int ("network.proxy", 0)) {
- curl_easy_setopt (curl, CURLOPT_PROXY, deadbeef->conf_get_str ("network.proxy.address", ""));
+ deadbeef->conf_lock ();
+ curl_easy_setopt (curl, CURLOPT_PROXY, deadbeef->conf_get_str_fast ("network.proxy.address", ""));
curl_easy_setopt (curl, CURLOPT_PROXYPORT, deadbeef->conf_get_int ("network.proxy.port", 8080));
- const char *type = deadbeef->conf_get_str ("network.proxy.type", "HTTP");
+ const char *type = deadbeef->conf_get_str_fast ("network.proxy.type", "HTTP");
int curlproxytype = CURLPROXY_HTTP;
if (!strcasecmp (type, "HTTP")) {
curlproxytype = CURLPROXY_HTTP;
@@ -158,8 +161,8 @@ curl_req_send (const char *req, const char *post) {
#endif
curl_easy_setopt (curl, CURLOPT_PROXYTYPE, curlproxytype);
- const char *proxyuser = deadbeef->conf_get_str ("network.proxy.username", "");
- const char *proxypass = deadbeef->conf_get_str ("network.proxy.password", "");
+ const char *proxyuser = deadbeef->conf_get_str_fast ("network.proxy.username", "");
+ const char *proxypass = deadbeef->conf_get_str_fast ("network.proxy.password", "");
if (*proxyuser || *proxypass) {
#if LIBCURL_VERSION_MINOR >= 19 && LIBCURL_VERSION_PATCH >= 1
curl_easy_setopt (curl, CURLOPT_PROXYUSERNAME, proxyuser);
@@ -170,6 +173,7 @@ curl_req_send (const char *req, const char *post) {
curl_easy_setopt (curl, CURLOPT_PROXYUSERPWD, pwd);
#endif
}
+ deadbeef->conf_unlock ();
}
int status = curl_easy_perform(curl);
curl_easy_cleanup (curl);
@@ -207,12 +211,14 @@ auth (void) {
deadbeef->md5 (sig, token, strlen (token));
deadbeef->md5_to_str (token, sig);
- const char *scrobbler_url = deadbeef->conf_get_str ("lastfm.scrobbler_url", SCROBBLER_URL_LFM);
+ deadbeef->conf_lock ();
+ const char *scrobbler_url = deadbeef->conf_get_str_fast ("lastfm.scrobbler_url", SCROBBLER_URL_LFM);
#if LFM_TESTMODE
snprintf (req, sizeof (req), "%s/?hs=true&p=1.2.1&c=tst&v=1.0&u=%s&t=%d&a=%s", scrobbler_url, lfm_user, (int)timestamp, token);
#else
snprintf (req, sizeof (req), "%s/?hs=true&p=1.2.1&c=%s&v=%d.%d&u=%s&t=%d&a=%s", scrobbler_url, LFM_CLIENTID, plugin.plugin.version_major, plugin.plugin.version_minor, lfm_user, (int)timestamp, token);
#endif
+ deadbeef->conf_unlock ();
// handshake
int status = curl_req_send (req, NULL);
if (!status) {
@@ -846,7 +852,6 @@ lfm_action_lookup (DB_plugin_action_t *action, DB_playItem_t *it)
char *command = NULL;
if (-1 == asprintf (&command, "xdg-open 'http://www.last.fm/music/%s/_/%s' &", eartist, etitle))
return 0;
- printf ("executing %s\n", command);
system (command);
free (command);
}
@@ -902,13 +907,28 @@ static const char settings_dlg[] =
// define plugin interface
static DB_misc_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_MISC,
.plugin.name = "last.fm scrobbler",
- .plugin.descr = "sends played songs information to your last.fm account",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.descr = "Sends played songs information to your last.fm account, or other service that use AudioScrobbler protocol",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = lastfm_start,
.plugin.stop = lastfm_stop,
diff --git a/plugins/m3u/Makefile.am b/plugins/m3u/Makefile.am
new file mode 100644
index 00000000..e77663c6
--- /dev/null
+++ b/plugins/m3u/Makefile.am
@@ -0,0 +1,11 @@
+if HAVE_M3U
+pkglib_LTLIBRARIES = m3u.la
+
+m3u_la_SOURCES = m3u.c
+
+m3u_la_LDFLAGS = -module
+
+m3u_la_LIBADD = $(LIBADD)
+
+m3u_la_CFLAGS = $(CFLAGS) -std=c99
+endif
diff --git a/plugins/m3u/m3u.c b/plugins/m3u/m3u.c
new file mode 100644
index 00000000..4e5afe83
--- /dev/null
+++ b/plugins/m3u/m3u.c
@@ -0,0 +1,469 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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 <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include "../../deadbeef.h"
+
+//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+#define trace(fmt,...)
+
+#define min(x,y) ((x)<(y)?(x):(y))
+#define max(x,y) ((x)>(y)?(x):(y))
+
+static DB_functions_t *deadbeef;
+
+static const uint8_t *
+skipspaces (const uint8_t *p, const uint8_t *end) {
+ while (p < end && *p <= ' ') {
+ p++;
+ }
+ return p;
+}
+
+static DB_playItem_t *
+load_m3u (DB_playItem_t *after, const char *fname, int *pabort, int (*cb)(DB_playItem_t *it, void *data), void *user_data) {
+ const char *slash = strrchr (fname, '/');
+ trace ("enter pl_insert_m3u\n");
+ // skip all empty lines and comments
+ DB_FILE *fp = deadbeef->fopen (fname);
+ if (!fp) {
+ trace ("failed to open file %s\n", fname);
+ return NULL;
+ }
+ int sz = deadbeef->fgetlength (fp);
+ trace ("loading m3u...\n");
+ uint8_t *buffer = malloc (sz);
+ if (!buffer) {
+ deadbeef->fclose (fp);
+ trace ("failed to allocate %d bytes to read the file %s\n", sz, fname);
+ return NULL;
+ }
+ deadbeef->fread (buffer, 1, sz, fp);
+ deadbeef->fclose (fp);
+ const uint8_t *p = buffer;
+ const uint8_t *end = buffer+sz;
+ deadbeef->pl_lock ();
+ while (p < end) {
+ p = skipspaces (p, end);
+ if (p >= end) {
+ break;
+ }
+ if (*p == '#') {
+ while (p < end && *p >= 0x20) {
+ p++;
+ }
+ if (p >= end) {
+ break;
+ }
+ continue;
+ }
+ const uint8_t *e = p;
+ while (e < end && *e >= 0x20) {
+ e++;
+ }
+ int n = e-p;
+ uint8_t nm[n+1];
+ memcpy (nm, p, n);
+ nm[n] = 0;
+
+ DB_playItem_t *it = NULL;
+ if (strrchr (nm, '/')) {
+ trace ("pl_insert_m3u: adding file %s\n", nm);
+ it = deadbeef->pl_insert_file (after, nm, pabort, cb, user_data);
+ }
+ else {
+ int l = strlen (nm);
+ char fullpath[slash - fname + l + 2];
+ memcpy (fullpath, fname, slash - fname + 1);
+ strcpy (fullpath + (slash - fname + 1), nm);
+ trace ("pl_insert_m3u: adding file %s\n", fullpath);
+ it = deadbeef->pl_insert_file (after, fullpath, pabort, cb, user_data);
+ }
+ if (it) {
+ after = it;
+ }
+ if (pabort && *pabort) {
+ deadbeef->pl_unlock ();
+ free (buffer);
+ return after;
+ }
+ p = e;
+ if (p >= end) {
+ break;
+ }
+ }
+ deadbeef->pl_unlock ();
+ trace ("leave pl_insert_m3u\n");
+ free (buffer);
+ return after;
+}
+
+static DB_playItem_t *
+pls_insert_file (DB_playItem_t *after, const char *fname, const char *uri, int *pabort, int (*cb)(DB_playItem_t *it, void *data), void *user_data, const char *title, const char *length) {
+ trace ("pls_insert_file uri: %s\n", uri);
+ DB_playItem_t *it = NULL;
+ const char *slash = NULL;
+
+ if (strrchr (uri, '/')) {
+ it = deadbeef->pl_insert_file (after, uri, pabort, cb, user_data);
+ }
+ else if (slash = strrchr (fname, '/')) {
+ int l = strlen (uri);
+ char fullpath[slash - fname + l + 2];
+ memcpy (fullpath, fname, slash - fname + 1);
+ strcpy (fullpath + (slash - fname + 1), uri);
+ trace ("pls_insert_file: adding file %s\n", fullpath);
+ it = deadbeef->pl_insert_file (after, fullpath, pabort, cb, user_data);
+ }
+ if (length[0]) {
+ deadbeef->pl_set_item_duration (it, atoi (length));
+ }
+ if (title[0]) {
+ deadbeef->pl_replace_meta (it, "title", title);
+ }
+ return it;
+}
+
+static DB_playItem_t *
+load_pls (DB_playItem_t *after, const char *fname, int *pabort, int (*cb)(DB_playItem_t *it, void *data), void *user_data) {
+ const char *slash = strrchr (fname, '/');
+ DB_FILE *fp = deadbeef->fopen (fname);
+ if (!fp) {
+ trace ("failed to open file %s\n", fname);
+ return NULL;
+ }
+ int sz = deadbeef->fgetlength (fp);
+ deadbeef->rewind (fp);
+ uint8_t *buffer = malloc (sz);
+ if (!buffer) {
+ deadbeef->fclose (fp);
+ trace ("failed to allocate %d bytes to read the file %s\n", sz, fname);
+ return NULL;
+ }
+ deadbeef->fread (buffer, 1, sz, fp);
+ deadbeef->fclose (fp);
+ // 1st line must be "[playlist]"
+ const uint8_t *p = buffer;
+ const uint8_t *end = buffer+sz;
+ if (strncasecmp (p, "[playlist]", 10)) {
+ trace ("file %s doesn't begin with [playlist]\n", fname);
+ free (buffer);
+ return NULL;
+ }
+ p += 10;
+ p = skipspaces (p, end);
+ if (p >= end) {
+ trace ("file %s finished before numberofentries had been read\n", fname);
+ free (buffer);
+ return NULL;
+ }
+ // fetch all tracks
+ char uri[1024] = "";
+ char title[1024] = "";
+ char length[20] = "";
+ int lastidx = -1;
+ deadbeef->pl_lock ();
+ while (p < end) {
+ p = skipspaces (p, end);
+ if (p >= end) {
+ break;
+ }
+ if (end-p < 6) {
+ break;
+ }
+ const uint8_t *e;
+ int n;
+ if (!strncasecmp (p, "numberofentries=", 16) || !strncasecmp (p, "version=", 8)) {
+ while (p < end && *p >= 0x20) {
+ p++;
+ }
+ continue;
+ }
+ else if (!strncasecmp (p, "file", 4)) {
+ int idx = atoi (p + 4);
+ if (uri[0] && idx != lastidx && lastidx != -1) {
+ trace ("uri%d\n", idx);
+ DB_playItem_t *it = pls_insert_file (after, fname, uri, pabort, cb, user_data, title, length);
+ if (it) {
+ after = it;
+ }
+ if (pabort && *pabort) {
+ deadbeef->pl_unlock ();
+ free (buffer);
+ return after;
+ }
+ uri[0] = 0;
+ title[0] = 0;
+ length[0] = 0;
+ }
+ lastidx = idx;
+ p += 4;
+ while (p < end && *p != '=') {
+ p++;
+ }
+ p++;
+ if (p >= end) {
+ break;
+ }
+ e = p;
+ while (e < end && *e >= 0x20) {
+ e++;
+ }
+ n = e-p;
+ n = min (n, sizeof (uri)-1);
+ memcpy (uri, p, n);
+ uri[n] = 0;
+ trace ("uri: %s\n", uri);
+ trace ("uri%d=%s\n", idx, uri);
+ p = ++e;
+ }
+ else if (!strncasecmp (p, "title", 5)) {
+ int idx = atoi (p + 5);
+ if (uri[0] && idx != lastidx && lastidx != -1) {
+ trace ("title%d\n", idx);
+ DB_playItem_t *it = pls_insert_file (after, fname, uri, pabort, cb, user_data, title, length);
+ if (it) {
+ after = it;
+ }
+ if (pabort && *pabort) {
+ deadbeef->pl_unlock ();
+ free (buffer);
+ return after;
+ }
+ uri[0] = 0;
+ title[0] = 0;
+ length[0] = 0;
+ }
+ lastidx = idx;
+ p += 5;
+ while (p < end && *p != '=') {
+ p++;
+ }
+ p++;
+ if (p >= end) {
+ break;
+ }
+ e = p;
+ while (e < end && *e >= 0x20) {
+ e++;
+ }
+ n = e-p;
+ n = min (n, sizeof (title)-1);
+ memcpy (title, p, n);
+ title[n] = 0;
+ trace ("title%d=%s\n", idx, title);
+ p = ++e;
+ }
+ else if (!strncasecmp (p, "length", 6)) {
+ int idx = atoi (p + 6);
+ if (uri[0] && idx != lastidx && lastidx != -1) {
+ trace ("length%d\n", idx);
+ DB_playItem_t *it = pls_insert_file (after, fname, uri, pabort, cb, user_data, title, length);
+ if (it) {
+ after = it;
+ }
+ if (pabort && *pabort) {
+ deadbeef->pl_unlock ();
+ free (buffer);
+ return after;
+ }
+ uri[0] = 0;
+ title[0] = 0;
+ length[0] = 0;
+ }
+ lastidx = idx;
+ p += 6;
+ // skip =
+ while (p < end && *p != '=') {
+ p++;
+ }
+ p++;
+ if (p >= end) {
+ break;
+ }
+ e = p;
+ while (e < end && *e >= 0x20) {
+ e++;
+ }
+ n = e-p;
+ n = min (n, sizeof (length)-1);
+ memcpy (length, p, n);
+ trace ("length%d=%s\n", idx, length);
+ }
+ else {
+ trace ("invalid entry in pls file: %s\n", p);
+ break;
+ }
+ while (e < end && *e < 0x20) {
+ e++;
+ }
+ p = e;
+ }
+ if (uri[0]) {
+ DB_playItem_t *it = pls_insert_file (after, fname, uri, pabort, cb, user_data, title, length);
+ if (it) {
+ after = it;
+ }
+ }
+ deadbeef->pl_unlock ();
+ free (buffer);
+ return after;
+}
+
+static DB_playItem_t *
+m3uplug_load (DB_playItem_t *after, const char *fname, int *pabort, int (*cb)(DB_playItem_t *it, void *data), void *user_data) {
+ const char *ext = strrchr (fname, '.');
+ if (!ext) {
+ return NULL;
+ }
+ ext++;
+
+ if (!strcasecmp (ext, "m3u") || !strcasecmp (ext, "m3u8")) {
+ return load_m3u (after, fname, pabort, cb, user_data);
+ }
+ else if (!strcasecmp (ext, "pls")) {
+ return load_pls (after, fname, pabort, cb, user_data);
+ }
+
+ return NULL;
+}
+
+int
+m3uplug_save_m3u (const char *fname, DB_playItem_t *first, DB_playItem_t *last) {
+ FILE *fp = fopen (fname, "w+t");
+ if (!fp) {
+ return -1;
+ }
+ DB_playItem_t *it = first;
+ deadbeef->pl_item_ref (it);
+ while (it) {
+ int dur = (int)ceil(deadbeef->pl_get_item_duration (it));
+ char s[1000];
+ deadbeef->pl_format_title (it, -1, s, sizeof (s), -1, "%a - %t");
+ const char *fname = deadbeef->pl_find_meta (it, ":URI");
+ fprintf (fp, "#EXTINF:%d,%s\n", dur, s);
+ fprintf (fp, "%s\n", fname);
+
+ if (it == last) {
+ break;
+ }
+ DB_playItem_t *next = deadbeef->pl_get_next (it, PL_MAIN);
+ deadbeef->pl_item_unref (it);
+ it = next;
+ }
+ fclose (fp);
+ return 0;
+}
+
+int
+m3uplug_save_pls (const char *fname, DB_playItem_t *first, DB_playItem_t *last) {
+ FILE *fp = fopen (fname, "w+t");
+ if (!fp) {
+ return -1;
+ }
+
+ int n = 0;
+ DB_playItem_t *it = first;
+ deadbeef->pl_item_ref (it);
+ while (it) {
+ n++;
+ if (it == last) {
+ break;
+ }
+ DB_playItem_t *next = deadbeef->pl_get_next (it, PL_MAIN);
+ deadbeef->pl_item_unref (it);
+ it = next;
+ }
+
+ fprintf (fp, "[playlist]\n");
+ fprintf (fp, "NumberOfEntries=%d\n", n);
+
+ it = first;
+ deadbeef->pl_item_ref (it);
+ int i = 1;
+ while (it) {
+ const char *fname = deadbeef->pl_find_meta (it, ":URI");
+ fprintf (fp, "File%d=%s\n", i, fname);
+
+ if (it == last) {
+ break;
+ }
+ DB_playItem_t *next = deadbeef->pl_get_next (it, PL_MAIN);
+ deadbeef->pl_item_unref (it);
+ it = next;
+ i++;
+ }
+ fclose (fp);
+ return 0;
+}
+
+int
+m3uplug_save (const char *fname, DB_playItem_t *first, DB_playItem_t *last) {
+ const char *e = strrchr (fname, '.');
+ if (!e) {
+ return -1;
+ }
+ if (!strcasecmp (e, ".m3u") || !strcasecmp (e, ".m3u8")) {
+ return m3uplug_save_m3u (fname, first, last);
+ }
+ else if (!strcasecmp (e, ".pls")) {
+ return m3uplug_save_pls (fname, first, last);
+ }
+ return -1;
+}
+
+static const char * exts[] = { "m3u", "m3u8", "pls", NULL };
+DB_playlist_t plugin = {
+ DB_PLUGIN_SET_API_VERSION
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
+ .plugin.type = DB_PLUGIN_PLAYLIST,
+ .plugin.id = "m3u",
+ .plugin.name = "M3U and PLS support",
+ .plugin.descr = "Importing and exporting M3U and PLS formats\nRecognizes .pls, .m3u and .m3u8 file types\n\nNOTE: only utf8 file names are currently supported",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
+ .plugin.website = "http://deadbeef.sf.net",
+ .load = m3uplug_load,
+ .save = m3uplug_save,
+ .extensions = exts,
+};
+
+DB_plugin_t *
+m3u_load (DB_functions_t *api) {
+ deadbeef = api;
+ return &plugin.plugin;
+}
diff --git a/plugins/mms/mmsplug.c b/plugins/mms/mmsplug.c
index 4ad57832..787af70d 100644
--- a/plugins/mms/mmsplug.c
+++ b/plugins/mms/mmsplug.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -108,15 +108,42 @@ mms_get_content_type (DB_FILE *stream) {
static const char *scheme_names[] = { "mms://", "mmsh://", NULL };
+const char **
+mms_get_schemes (void) {
+ return scheme_names;
+}
+
+int
+mms_is_streaming (void) {
+ return 1;
+}
+
static DB_vfs_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_VFS,
.plugin.name = "mms vfs",
.plugin.descr = "MMS streaming plugin based on libmms",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "Uses modified libmms-0.6.0, http://sourceforge.net/projects/libmms/\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.open = mms_open,
.close = mms_close,
@@ -126,8 +153,8 @@ static DB_vfs_t plugin = {
.rewind = mms_rewind,
.getlength = mms_getlength,
.get_content_type = mms_get_content_type,
- .scheme_names = scheme_names,
- .streaming = 1
+ .get_schemes = mms_get_schemes,
+ .is_streaming = mms_is_streaming,
};
DB_plugin_t *
diff --git a/plugins/mpgmad/mpgmad.c b/plugins/mpgmad/mpgmad.c
index 13544238..3f8c4260 100644
--- a/plugins/mpgmad/mpgmad.c
+++ b/plugins/mpgmad/mpgmad.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
+#include <sys/time.h>
#include "../../deadbeef.h"
//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
@@ -45,13 +46,15 @@ static DB_functions_t *deadbeef;
#define READBUFFER 0x2800 // 10k is enough for single frame
// vbrmethod constants
-#define LAME_CBR 1
-#define LAME_CBR2 8
-#define LAME_ABR 2
-#define LAME_VBR1 3
-#define LAME_VBR2 4
-#define LAME_VBR3 5
-#define LAME_VBR4 6
+#define XING_CBR 1
+#define XING_ABR 2
+#define XING_VBR1 3
+#define XING_VBR2 4
+#define XING_VBR3 5
+#define XING_VBR4 6
+#define XING_CBR2 8
+#define XING_ABR2 9
+#define DETECTED_VBR 100
// xing header flags
#define FRAMES_FLAG 0x0001
@@ -78,24 +81,34 @@ typedef struct {
int bitrate;
int samplerate;
int packetlength;
- float frameduration;
int bitspersample;
int channels;
float duration;
+
+ // currentsample and totalsamples are in the entire file scope (delay/padding inclusive)
int currentsample;
int totalsamples;
+
int skipsamples;
- int startoffset;
- int endoffset;
+
+ int startoffset; // in bytes (id3v2, xing/lame)
+ int endoffset; // in bytes (apev2, id3v1)
+
+ // startsample and endsample exclude delay/padding
int startsample;
int endsample;
- int startdelay;
- int enddelay;
- int avg_packetlength;
+
+ // number of samples to skip at the start/end of file
+ int delay;
+ int padding;
+
+ float avg_packetlength;
int avg_samplerate;
int avg_samples_per_frame;
int nframes;
int last_comment_update;
+ int vbr;
+ int have_xing_header;
} buffer_t;
typedef struct {
@@ -175,25 +188,29 @@ extract_f32 (unsigned char *buf) {
static int
cmp3_scan_stream (buffer_t *buffer, int sample) {
trace ("cmp3_scan_stream %d\n", sample);
+
int initpos = deadbeef->ftell (buffer->file);
trace ("initpos: %d\n", initpos);
-// if (sample == 0) {
-// sample = -1;
-// }
int packetlength = 0;
int nframe = 0;
- int got_xing_header = 0;
- buffer->duration = 0;
int scansamples = 0;
buffer->currentsample = 0;
buffer->skipsamples = 0;
- int fsize = 0;
- int avg_bitrate = 0;
+// int avg_bitrate = 0;
int valid_frames = 0;
+ int prev_bitrate = -1;
+ buffer->samplerate = 0;
+ int64_t fsize = deadbeef->fgetlength (buffer->file);
if (sample <= 0) {
buffer->totalsamples = 0;
- fsize = deadbeef->fgetlength (buffer->file) - initpos;
+ if (fsize > 0) {
+ fsize -= initpos;
+ if (fsize < 0) {
+ trace ("cmp3_scan_stream: invalid file: bad header\n");
+ return -1;
+ }
+ }
}
if (sample <= 0 && buffer->avg_packetlength == 0) {
buffer->avg_packetlength = 0;
@@ -204,37 +221,40 @@ cmp3_scan_stream (buffer_t *buffer, int sample) {
buffer->startoffset = initpos;
}
+ int lastframe_valid = 0;
+ int64_t offs = -1;
+
for (;;) {
- uint32_t hdr;
- uint8_t sync;
- //size_t pos = deadbeef->ftell (buffer->file);
- if (deadbeef->fread (&sync, 1, 1, buffer->file) != 1) {
+ if (!lastframe_valid && offs >= 0) {
+ deadbeef->fseek (buffer->file, offs+1, SEEK_SET);
+ }
+ offs = deadbeef->ftell (buffer->file);
+ uint8_t fb[4];
+ if (deadbeef->fread (fb, 1, 4, buffer->file) != 4) {
break; // eof
}
+
+ uint32_t hdr;
+ uint8_t sync = fb[0];
if (sync != 0xff) {
// trace ("[1]frame %d didn't seek to frame end\n", nframe);
+ lastframe_valid = 0;
continue; // not an mpeg frame
}
else {
// 2nd sync byte
- if (deadbeef->fread (&sync, 1, 1, buffer->file) != 1) {
- break; // eof
- }
+ sync = fb[1];
if ((sync >> 5) != 7) {
// trace ("[2]frame %d didn't seek to frame end\n", nframe);
+ lastframe_valid = 0;
continue;
}
}
// found frame
hdr = (0xff<<24) | (sync << 16);
- // read 2 bytes more
- if (deadbeef->fread (&sync, 1, 1, buffer->file) != 1) {
- break; // eof
- }
+ sync = fb[2];
hdr |= sync << 8;
- if (deadbeef->fread (&sync, 1, 1, buffer->file) != 1) {
- break; // eof
- }
+ sync = fb[3];
hdr |= sync;
// parse header
@@ -246,20 +266,22 @@ cmp3_scan_stream (buffer_t *buffer, int sample) {
}
// mpeg version
- static int vertbl[] = {3, -1, 2, 1}; // 3 is 2.5
+ static const int vertbl[] = {3, -1, 2, 1}; // 3 is 2.5
int ver = (hdr & (3<<19)) >> 19;
ver = vertbl[ver];
if (ver < 0) {
trace ("frame %d bad mpeg version %d\n", nframe, (hdr & (3<<19)) >> 19);
+ lastframe_valid = 0;
continue; // invalid frame
}
// layer info
- static int ltbl[] = { -1, 3, 2, 1 };
+ static const int ltbl[] = { -1, 3, 2, 1 };
int layer = (hdr & (3<<17)) >> 17;
layer = ltbl[layer];
if (layer < 0) {
trace ("frame %d bad layer %d\n", nframe, (hdr & (3<<17)) >> 17);
+ lastframe_valid = 0;
continue; // invalid frame
}
@@ -282,6 +304,7 @@ cmp3_scan_stream (buffer_t *buffer, int sample) {
bitrate = brtable[idx][bitrate];
if (bitrate <= 0) {
trace ("frame %d bad bitrate %d\n", nframe, (hdr & (0x0f<<12)) >> 12);
+ lastframe_valid = 0;
continue; // invalid frame
}
@@ -295,13 +318,14 @@ cmp3_scan_stream (buffer_t *buffer, int sample) {
samplerate = srtable[ver-1][samplerate];
if (samplerate < 0) {
trace ("frame %d bad samplerate %d\n", nframe, (hdr & (0x03<<10))>>10);
+ lastframe_valid = 0;
continue; // invalid frame
}
// padding
int padding = (hdr & (0x1 << 9)) >> 9;
- static int chantbl[4] = { 2, 2, 2, 1 };
+ static const int chantbl[4] = { 2, 2, 2, 1 };
int nchannels = (hdr & (0x3 << 6)) >> 6;
nchannels = chantbl[nchannels];
@@ -309,10 +333,12 @@ cmp3_scan_stream (buffer_t *buffer, int sample) {
if (layer == 2) {
if ((bitrate <= 56 || bitrate == 80) && nchannels != 1) {
trace ("mpgmad: bad frame %d: layer %d, channels %d, bitrate %d\n", nframe, layer, nchannels, bitrate);
+ lastframe_valid = 0;
continue; // bad frame
}
if (bitrate >= 224 && nchannels == 1) {
trace ("mpgmad: bad frame %d: layer %d, channels %d, bitrate %d\n", nframe, layer, nchannels, bitrate);
+ lastframe_valid = 0;
continue; // bad frame
}
}
@@ -320,34 +346,35 @@ cmp3_scan_stream (buffer_t *buffer, int sample) {
// packetlength
packetlength = 0;
bitrate *= 1000;
- float dur = 0;
int samples_per_frame = 0;
if (samplerate > 0 && bitrate > 0) {
if (layer == 1) {
samples_per_frame = 384;
- dur = (float)384 / samplerate;
}
else if (layer == 2) {
samples_per_frame = 1152;
- dur = (float)1152 / samplerate;
}
else if (layer == 3) {
if (ver == 1) {
samples_per_frame = 1152;
- dur = (float)1152 / samplerate;
}
else {
samples_per_frame = 576;
- dur = (float)576 / samplerate;
}
}
packetlength = samples_per_frame / 8 * bitrate / samplerate + padding;
}
else {
trace ("frame %d samplerate or bitrate is invalid\n", nframe);
+ lastframe_valid = 0;
continue;
}
+ if (!buffer->have_xing_header && prev_bitrate != -1 && prev_bitrate != bitrate) {
+ buffer->vbr = DETECTED_VBR;
+ }
+ prev_bitrate = bitrate;
+
valid_frames++;
#if 0
if (nframe < 1000) {
@@ -356,23 +383,26 @@ cmp3_scan_stream (buffer_t *buffer, int sample) {
#endif
if (sample != 0 || nframe == 0)
{
+ if (sample == 0 && lastframe_valid) {
+ return 0;
+ }
buffer->version = ver;
buffer->layer = layer;
buffer->bitrate = bitrate;
buffer->samplerate = samplerate;
buffer->packetlength = packetlength;
- buffer->frameduration = dur;
if (nchannels > buffer->channels) {
buffer->channels = nchannels;
}
buffer->bitspersample = 16;
- //trace ("frame %d mpeg v%d layer %d bitrate %d samplerate %d packetlength %d framedur %f channels %d\n", nframe, ver, layer, bitrate, samplerate, packetlength, dur, nchannels);
+ trace ("frame %d mpeg v%d layer %d bitrate %d samplerate %d packetlength %d channels %d\n", nframe, ver, layer, bitrate, samplerate, packetlength, nchannels);
}
+ lastframe_valid = 1;
// try to read xing/info tag (only on initial scans)
- if (sample <= 0 && !got_xing_header)
+ if (sample <= 0 && !buffer->have_xing_header)
{
size_t framepos = deadbeef->ftell (buffer->file);
- if (!buffer->file->vfs->streaming) {
+ if (!buffer->file->vfs->is_streaming ()) {
// trace ("trying to read xing header at pos %d\n", framepos);
if (ver == 1) {
deadbeef->fseek (buffer->file, 32, SEEK_CUR);
@@ -408,7 +438,9 @@ cmp3_scan_stream (buffer_t *buffer, int sample) {
return -1; // EOF
}
uint32_t nframes = extract_i32 (buf);
- buffer->duration = (float)nframes * (float)samples_per_frame / (float)samplerate;
+ if (sample == 0) {
+ buffer->duration = (((uint64_t)nframes * (uint64_t)samples_per_frame) - buffer->delay - buffer->padding)/ (uint64_t)samplerate;
+ }
trace ("xing totalsamples: %d, nframes: %d, samples_per_frame: %d\n", nframes*samples_per_frame, nframes, samples_per_frame);
if (nframes <= 0 || samples_per_frame <= 0) {
trace ("bad xing header\n");
@@ -432,9 +464,23 @@ cmp3_scan_stream (buffer_t *buffer, int sample) {
return -1; // EOF
}
// trace ("tell=%x, %c%c%c%c\n", deadbeef->ftell(buffer->file), buf[0], buf[1], buf[2], buf[3]);
+
+ deadbeef->fseek (buffer->file, 5, SEEK_CUR);
+ uint8_t rev = 0;
+ if (deadbeef->fread (&rev, 1, 1, buffer->file) != 1) {
+ trace ("cmp3_scan_stream: EOF while reading info tag revision / vbr method\n");
+ }
+ switch (rev & 0x0f) {
+ case XING_ABR ... XING_VBR4:
+ case XING_ABR2:
+ buffer->vbr = rev & 0x0f;
+ break;
+ default:
+ buffer->vbr = DETECTED_VBR;
+ break;
+ }
if (!memcmp (buf, "LAME", 4)) {
trace ("lame header found\n");
- deadbeef->fseek (buffer->file, 6, SEEK_CUR);
// FIXME: that can be optimized by single read
uint8_t lpf;
@@ -451,8 +497,8 @@ cmp3_scan_stream (buffer_t *buffer, int sample) {
// skip
deadbeef->fseek (buffer->file, 2, SEEK_CUR);
deadbeef->fread (buf, 1, 3, buffer->file);
- uint32_t startdelay = (((uint32_t)buf[0]) << 4) | ((((uint32_t)buf[1]) & 0xf0)>>4);
- uint32_t enddelay = ((((uint32_t)buf[1])&0x0f)<<8) | ((uint32_t)buf[2]);
+// buffer->delay = (((uint32_t)buf[0]) << 4) | ((((uint32_t)buf[1]) & 0xf0)>>4);
+// buffer->padding = ((((uint32_t)buf[1])&0x0f)<<8) | ((uint32_t)buf[2]);
// skip
deadbeef->fseek (buffer->file, 1, SEEK_CUR);
// mp3gain
@@ -464,43 +510,54 @@ cmp3_scan_stream (buffer_t *buffer, int sample) {
deadbeef->fread (buf, 1, 4, buffer->file);
// uint32_t musiclen = extract_i32 (buf);
- //trace ("lpf: %d, peaksignalamp: %f, radiogain: %d, audiophile: %d, startdelay: %d, enddelay: %d, mp3gain: %d, musiclen: %d\n", lpf, rg_peaksignalamp, rg_radio, rg_audiophile, startdelay, enddelay, mp3gain, musiclen);
+ //trace ("lpf: %d, peaksignalamp: %f, radiogain: %d, audiophile: %d, delay: %d, padding: %d, mp3gain: %d, musiclen: %d\n", lpf, rg_peaksignalamp, rg_radio, rg_audiophile, delay, padding, mp3gain, musiclen);
// skip crc
//deadbeef->fseek (buffer->file, 4, SEEK_CUR);
- buffer->startdelay = startdelay;
- buffer->enddelay = enddelay;
trace ("lame totalsamples: %d\n", buffer->totalsamples);
}
if (sample <= 0 && (flags&FRAMES_FLAG)) {
- buffer->totalsamples -= buffer->enddelay;
+ buffer->have_xing_header = 1;
deadbeef->fseek (buffer->file, framepos+packetlength-4, SEEK_SET);
- return 0;
+ if (fsize >= 0) {
+ buffer->bitrate = (fsize - deadbeef->ftell (buffer->file))/ buffer->samplerate * 1000;
+ }
+ buffer->startoffset = deadbeef->ftell (buffer->file);
}
}
}
if (sample == 0) {
- // xing header failed, calculate based on file size
-// trace ("xing header failed\n");
+ trace ("cmp3_scan_stream: trying to figure out duration from file size\n");
buffer->samplerate = samplerate;
- if (buffer->file->vfs->streaming) {
+ if (buffer->file->vfs->is_streaming ()) {
// only suitable for cbr files, used if streaming
- int sz = deadbeef->fgetlength (buffer->file) - buffer->startoffset - buffer->endoffset;
+ int sz = deadbeef->fgetlength (buffer->file);
+ if (sz > 0) {
+ sz -= buffer->startoffset + buffer->endoffset;
+ if (sz < 0) {
+ trace ("cmp3_scan_stream: bad file headers\n");
+ return -1;
+ }
+ }
if (sz < 0) {
// unable to determine duration
buffer->duration = -1;
buffer->totalsamples = -1;
if (sample == 0) {
- deadbeef->fseek (buffer->file, framepos/*+packetlength-4*/, SEEK_SET);
+ trace ("check validity of the next frame...\n");
+ deadbeef->fseek (buffer->file, framepos+packetlength-4, SEEK_SET);
+ continue;
}
+ trace ("cmp3_scan_stream: unable to determine duration");
return 0;
}
buffer->nframes = sz / packetlength;
buffer->avg_packetlength = packetlength;
buffer->avg_samplerate = samplerate;
buffer->avg_samples_per_frame = samples_per_frame;
- buffer->duration = buffer->nframes * samples_per_frame / samplerate;
+ buffer->duration = (buffer->nframes * samples_per_frame - buffer->delay - buffer->padding) / samplerate;
buffer->totalsamples = buffer->nframes * samples_per_frame;
-// trace ("bitrate=%d, layer=%d, packetlength=%d, fsize=%d, nframes=%d, samples_per_frame=%d, samplerate=%d, duration=%f, totalsamples=%d\n", bitrate, layer, packetlength, sz, nframes, samples_per_frame, samplerate, buffer->duration, buffer->totalsamples);
+ trace ("totalsamples: %d, samplesperframe: %d, fsize=%lld\n", buffer->totalsamples, samples_per_frame, fsize);
+// trace ("bitrate=%d, layer=%d, packetlength=%d, fsize=%d, nframes=%d, samples_per_frame=%d, samplerate=%d, duration=%f, totalsamples=%d\n", bitrate, layer, packetlength, sz, nframe, samples_per_frame, samplerate, buffer->duration, buffer->totalsamples);
if (sample == 0) {
deadbeef->fseek (buffer->file, framepos/*+packetlength-4*/, SEEK_SET);
@@ -513,7 +570,7 @@ cmp3_scan_stream (buffer_t *buffer, int sample) {
}
else {
deadbeef->fseek (buffer->file, framepos+packetlength-4, SEEK_SET);
- got_xing_header = 1;
+ buffer->have_xing_header = 1;
}
}
@@ -526,18 +583,9 @@ cmp3_scan_stream (buffer_t *buffer, int sample) {
buffer->avg_packetlength += packetlength;
buffer->avg_samplerate += samplerate;
buffer->avg_samples_per_frame += samples_per_frame;
- avg_bitrate += bitrate;
+ //avg_bitrate += bitrate;
if (nframe >= 100) {
- buffer->avg_packetlength /= valid_frames;
- buffer->avg_samplerate /= valid_frames;
- buffer->avg_samples_per_frame /= valid_frames;
- avg_bitrate /= valid_frames;
- trace ("valid_frames=%d, avg_bitrate=%d, avg_packetlength=%d, avg_samplerate=%d, avg_samples_per_frame=%d\n", valid_frames, avg_bitrate, buffer->avg_packetlength, buffer->avg_samplerate, buffer->avg_samples_per_frame);
-
- buffer->nframes = fsize / buffer->avg_packetlength;
- buffer->duration = buffer->nframes * buffer->avg_samples_per_frame / buffer->avg_samplerate;
- buffer->totalsamples = buffer->nframes * buffer->avg_samples_per_frame;
- return 0;
+ goto end_scan;
}
}
else {
@@ -549,37 +597,133 @@ cmp3_scan_stream (buffer_t *buffer, int sample) {
}
}
scansamples += samples_per_frame;
- buffer->duration += dur;
nframe++;
if (packetlength > 0) {
deadbeef->fseek (buffer->file, packetlength-4, SEEK_CUR);
}
}
+end_scan:
if (nframe == 0) {
trace ("cmp3_scan_stream: couldn't find mpeg frames in file\n");
return -1;
}
+ if (sample == 0) {
+ buffer->avg_packetlength /= (float)valid_frames;
+ buffer->avg_samplerate /= valid_frames;
+ buffer->avg_samples_per_frame /= valid_frames;
+// avg_bitrate /= valid_frames;
+ //trace ("valid_frames=%d, avg_bitrate=%d, avg_packetlength=%f, avg_samplerate=%d, avg_samples_per_frame=%d\n", valid_frames, avg_bitrate, buffer->avg_packetlength, buffer->avg_samplerate, buffer->avg_samples_per_frame);
+ trace ("startoffs: %d, endoffs: %d\n", buffer->startoffset, buffer->endoffset);
+
+ buffer->nframes = (fsize - buffer->startoffset - buffer->endoffset) / buffer->avg_packetlength;
+ if (!buffer->have_xing_header) {
+ buffer->totalsamples = buffer->nframes * buffer->avg_samples_per_frame;
+ buffer->duration = (buffer->totalsamples - buffer->delay - buffer->padding) / buffer->avg_samplerate;
+ }
+ buffer->bitrate = (fsize-buffer->startoffset-buffer->endoffset) / buffer->duration * 8;
+ trace ("nframes: %d, fsize: %lld, spf: %d, smp: %d, totalsamples: %d\n", buffer->nframes, fsize, buffer->avg_samples_per_frame, buffer->avg_samplerate, buffer->totalsamples);
+ return 0;
+ }
+
buffer->totalsamples = scansamples;
-// buffer->duration = buffer->totalsamples / buffer->samplerate;
+ buffer->duration = (buffer->totalsamples - buffer->delay - buffer->padding) / buffer->samplerate;
trace ("nframes=%d, totalsamples=%d, samplerate=%d, dur=%f\n", nframe, scansamples, buffer->samplerate, buffer->duration);
return 0;
}
+int
+cmp3_seek_stream (DB_fileinfo_t *_info, int sample) {
+ mpgmad_info_t *info = (mpgmad_info_t *)_info;
+ sample += info->buffer.delay;
+ if (sample == 0) {
+ _info->readpos = 0;
+ info->buffer.currentsample = 0;
+ return 0;
+
+ }
+ return cmp3_scan_stream (&info->buffer, sample);
+}
+
static DB_fileinfo_t *
-cmp3_open (void) {
+cmp3_open (uint32_t hints) {
DB_fileinfo_t *_info = malloc (sizeof (mpgmad_info_t));
mpgmad_info_t *info = (mpgmad_info_t *)_info;
memset (info, 0, sizeof (mpgmad_info_t));
return _info;
}
+void
+cmp3_set_extra_properties (buffer_t *buffer) {
+ char s[100];
+ int64_t size = deadbeef->fgetlength (buffer->file);
+ if (size >= 0) {
+ snprintf (s, sizeof (s), "%lld", size);
+ deadbeef->pl_replace_meta (buffer->it, ":FILE_SIZE", s);
+ }
+ else {
+ deadbeef->pl_replace_meta (buffer->it, ":FILE_SIZE", "∞");
+ }
+ if (buffer->bitrate > 0) {
+ snprintf (s, sizeof (s), "%d", buffer->bitrate/1000);
+ deadbeef->pl_replace_meta (buffer->it, ":BITRATE", s);
+ }
+ deadbeef->pl_replace_meta (buffer->it, ":BPS", "16");
+ snprintf (s, sizeof (s), "%d", buffer->channels);
+ deadbeef->pl_replace_meta (buffer->it, ":CHANNELS", s);
+ snprintf (s, sizeof (s), "%d", buffer->samplerate);
+ deadbeef->pl_replace_meta (buffer->it, ":SAMPLERATE", s);
+
+ // set codec profile (cbr or vbr) and mp3 vbr method (guessed, or from Xing/Info header)
+
+ switch (buffer->vbr) {
+ case XING_ABR:
+ deadbeef->pl_replace_meta (buffer->it, ":CODEC_PROFILE", "VBR");
+ deadbeef->pl_replace_meta (buffer->it, ":MP3_VBR_METHOD", "ABR");
+ break;
+ case XING_VBR1:
+ deadbeef->pl_replace_meta (buffer->it, ":CODEC_PROFILE", "VBR");
+ deadbeef->pl_replace_meta (buffer->it, ":MP3_VBR_METHOD", "full VBR method 1");
+ break;
+ case XING_VBR2:
+ deadbeef->pl_replace_meta (buffer->it, ":CODEC_PROFILE", "VBR");
+ deadbeef->pl_replace_meta (buffer->it, ":MP3_VBR_METHOD", "full VBR method 2");
+ break;
+ case XING_VBR3:
+ deadbeef->pl_replace_meta (buffer->it, ":CODEC_PROFILE", "VBR");
+ deadbeef->pl_replace_meta (buffer->it, ":MP3_VBR_METHOD", "full VBR method 3");
+ break;
+ case XING_VBR4:
+ deadbeef->pl_replace_meta (buffer->it, ":CODEC_PROFILE", "VBR");
+ deadbeef->pl_replace_meta (buffer->it, ":MP3_VBR_METHOD", "full VBR method 4");
+ break;
+ case XING_CBR2:
+ deadbeef->pl_replace_meta (buffer->it, ":CODEC_PROFILE", "CBR");
+ break;
+ case XING_ABR2:
+ deadbeef->pl_replace_meta (buffer->it, ":CODEC_PROFILE", "VBR");
+ deadbeef->pl_replace_meta (buffer->it, ":MP3_VBR_METHOD", "ABR 2 pass");
+ break;
+ case DETECTED_VBR:
+ deadbeef->pl_replace_meta (buffer->it, ":CODEC_PROFILE", "VBR");
+ deadbeef->pl_replace_meta (buffer->it, ":MP3_VBR_METHOD", "unspecified");
+ break;
+ default:
+ deadbeef->pl_replace_meta (buffer->it, ":CODEC_PROFILE", "CBR");
+ break;
+ }
+ const char *versions[] = {"1", "2", "2.5"};
+ snprintf (s, sizeof (s), "MPEG%s layer%d", versions[buffer->version-1], buffer->layer);
+ deadbeef->pl_replace_meta (buffer->it, ":MPEG_VERSION", s);
+ deadbeef->pl_replace_meta (buffer->it, ":XING_HEADER", buffer->have_xing_header ? "Yes" : "No");
+}
+
static int
cmp3_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
mpgmad_info_t *info = (mpgmad_info_t *)_info;
_info->plugin = &plugin;
memset (&info->buffer, 0, sizeof (info->buffer));
- info->buffer.file = deadbeef->fopen (it->fname);
+ info->buffer.file = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!info->buffer.file) {
return -1;
}
@@ -587,33 +731,35 @@ cmp3_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
deadbeef->pl_item_ref (it);
info->buffer.it = it;
info->info.readpos = 0;
- if (!info->buffer.file->vfs->streaming) {
+ if (!info->buffer.file->vfs->is_streaming ()) {
int skip = deadbeef->junk_get_leading_size (info->buffer.file);
if (skip > 0) {
trace ("mpgmad: skipping %d(%xH) bytes of junk\n", skip, skip);
deadbeef->fseek (info->buffer.file, skip, SEEK_SET);
}
- cmp3_scan_stream (&info->buffer, -1); // scan entire stream, calc duration
+ int res = cmp3_scan_stream (&info->buffer, -1);
+ if (res < 0) {
+ trace ("mpgmad: cmp3_init: initial cmp3_scan_stream failed\n");
+ return -1;
+ }
if (it->endsample > 0) {
info->buffer.startsample = it->startsample;
info->buffer.endsample = it->endsample;
// that comes from cue, don't calc duration, just seek and play
- plugin.seek_sample (_info, 0);
}
else {
deadbeef->pl_set_item_duration (it, info->buffer.duration);
info->buffer.startsample = 0;
- info->buffer.endsample = info->buffer.totalsamples-1;
- info->buffer.skipsamples = info->buffer.startdelay;
- info->buffer.currentsample = info->buffer.startdelay;
+ info->buffer.endsample = info->buffer.totalsamples-info->buffer.delay-info->buffer.padding;
trace ("mpgmad: seeking to %d(%xH) start offset\n", info->buffer.startoffset, info->buffer.startoffset);
deadbeef->fseek (info->buffer.file, info->buffer.startoffset, SEEK_SET);
}
+ plugin.seek_sample (_info, 0);
}
else {
deadbeef->fset_track (info->buffer.file, it);
- info->buffer.it->filetype = NULL;
- int len = deadbeef->fgetlength (info->buffer.file);
+ deadbeef->pl_delete_meta (info->buffer.it, ":FILETYPE");
+ int64_t len = deadbeef->fgetlength (info->buffer.file);
if (len > 0) {
deadbeef->pl_delete_all_meta (it);
int v2err = deadbeef->junk_id3v2_read (it, info->buffer.file);
@@ -627,6 +773,10 @@ cmp3_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
trace ("mpgmad: cmp3_init: initial cmp3_scan_stream failed\n");
return -1;
}
+ deadbeef->fseek (info->buffer.file, 0, SEEK_SET);
+
+ cmp3_set_extra_properties (&info->buffer);
+
deadbeef->pl_set_item_duration (it, info->buffer.duration);
if (info->buffer.duration >= 0) {
info->buffer.endsample = info->buffer.totalsamples - 1;
@@ -648,12 +798,14 @@ cmp3_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
trace ("duration=%f, endsample=%d, totalsamples=%d\n", info->buffer.duration, info->buffer.endsample, info->buffer.totalsamples);
}
if (info->buffer.samplerate == 0) {
- trace ("bad mpeg file: %f\n", it->fname);
+ trace ("bad mpeg file: %f\n", deadbeef->pl_find_meta (it, ":URI"));
return -1;
}
- _info->bps = info->buffer.bitspersample;
- _info->samplerate = info->buffer.samplerate;
- _info->channels = info->buffer.channels;
+ _info->fmt.bps = info->buffer.bitspersample;
+ _info->fmt.samplerate = info->buffer.samplerate;
+ _info->fmt.channels = info->buffer.channels;
+ _info->fmt.channelmask = _info->fmt.channels == 1 ? DDB_SPEAKER_FRONT_LEFT : (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT);
+ trace ("mp3 format: bps:%d sr:%d channels:%d\n", _info->fmt.bps, _info->fmt.samplerate, _info->fmt.channels);
mad_stream_init(&info->stream);
mad_stream_options (&info->stream, MAD_OPTION_IGNORECRC);
@@ -716,14 +868,6 @@ cmp3_decode_cut (mpgmad_info_t *info, int framesize) {
trace ("mpgmad: got frame with invalid number of channels (%d)\n", info->buffer.channels);
return 1;
}
- if (info->buffer.currentsample + info->buffer.readsize / (framesize * info->buffer.channels) > info->buffer.endsample) {
- int sz = (info->buffer.endsample - info->buffer.currentsample + 1) * framesize * info->buffer.channels;
- trace ("size truncated to %d bytes, cursample=%d, endsample=%d, totalsamples=%d\n", info->buffer.readsize, info->buffer.currentsample, info->buffer.endsample, info->buffer.totalsamples);
- if (sz <= 0) {
- return 1;
- }
- info->buffer.readsize = sz;
- }
}
return 0;
}
@@ -732,6 +876,7 @@ static inline void
cmp3_skip (mpgmad_info_t *info) {
if (info->buffer.skipsamples > 0) {
int skip = min (info->buffer.skipsamples, info->buffer.decode_remaining);
+// printf ("skip %d / %d\n", skip, info->buffer.skipsamples);
info->buffer.skipsamples -= skip;
info->buffer.decode_remaining -= skip;
}
@@ -743,23 +888,43 @@ cmp3_decode_requested_int16 (mpgmad_info_t *info) {
cmp3_skip (info);
// copy synthesized samples into readbuffer
int idx = info->synth.pcm.length-info->buffer.decode_remaining;
- while (info->buffer.decode_remaining > 0 && info->buffer.readsize > 0) {
- int16_t sample = MadFixedToSshort (info->synth.pcm.samples[0][idx]);
- *((int16_t*)info->buffer.out) = sample;
- info->buffer.readsize -= 2;
- info->buffer.out += 2;
- if (MAD_NCHANNELS(&info->frame.header) == 2 && info->info.channels == 2) {
+
+ // stereo
+ if (MAD_NCHANNELS(&info->frame.header) == 2 && info->info.fmt.channels == 2) {
+ while (info->buffer.decode_remaining > 0 && info->buffer.readsize > 0) {
+ *((int16_t*)info->buffer.out) = MadFixedToSshort (info->synth.pcm.samples[0][idx]);
+ info->buffer.readsize -= 2;
+ info->buffer.out += 2;
*((int16_t*)info->buffer.out) = MadFixedToSshort (info->synth.pcm.samples[1][idx]);
info->buffer.readsize -= 2;
info->buffer.out += 2;
+ info->buffer.decode_remaining--;
+ idx++;
}
- else if (MAD_NCHANNELS(&info->frame.header) == 1 && info->info.channels == 2) {
+ }
+ // mono
+ else if (MAD_NCHANNELS(&info->frame.header) == 1 && info->info.fmt.channels == 1){
+ while (info->buffer.decode_remaining > 0 && info->buffer.readsize > 0) {
+ *((int16_t*)info->buffer.out) = MadFixedToSshort (info->synth.pcm.samples[0][idx]);
+ info->buffer.readsize -= 2;
+ info->buffer.out += 2;
+ info->buffer.decode_remaining--;
+ idx++;
+ }
+ }
+ // workaround for bad mp3s that have both mono and stereo frames
+ else if (MAD_NCHANNELS(&info->frame.header) == 1 && info->info.fmt.channels == 2) {
+ while (info->buffer.decode_remaining > 0 && info->buffer.readsize > 0) {
+ int16_t sample = MadFixedToSshort (info->synth.pcm.samples[0][idx]);
*((int16_t*)info->buffer.out) = sample;
info->buffer.readsize -= 2;
info->buffer.out += 2;
+ *((int16_t*)info->buffer.out) = sample;
+ info->buffer.readsize -= 2;
+ info->buffer.out += 2;
+ info->buffer.decode_remaining--;
+ idx++;
}
- info->buffer.decode_remaining--;
- idx++;
}
assert (info->buffer.readsize >= 0);
}
@@ -775,12 +940,12 @@ cmp3_decode_requested_float32 (mpgmad_info_t *info) {
*((float*)info->buffer.out) = sample;
info->buffer.readsize -= 4;
info->buffer.out += 4;
- if (MAD_NCHANNELS(&info->frame.header) == 2 && info->info.channels == 2) {
+ if (MAD_NCHANNELS(&info->frame.header) == 2 && info->info.fmt.channels == 2) {
*((float*)info->buffer.out) = MadFixedToFloat (info->synth.pcm.samples[1][idx]);
info->buffer.readsize -= 4;
info->buffer.out += 4;
}
- else if (MAD_NCHANNELS(&info->frame.header) == 1 && info->info.channels == 2) {
+ else if (MAD_NCHANNELS(&info->frame.header) == 1 && info->info.fmt.channels == 2) {
*((float*)info->buffer.out) = sample;
info->buffer.readsize -= 4;
info->buffer.out += 4;
@@ -834,41 +999,43 @@ cmp3_stream_frame (mpgmad_info_t *info) {
}
}
info->stream.error=0;
+
// decode next frame
if(mad_frame_decode(&info->frame,&info->stream))
{
if(MAD_RECOVERABLE(info->stream.error))
{
if(info->stream.error!=MAD_ERROR_LOSTSYNC) {
- trace ("mpgmad: recoverable frame level error (%s)\n", MadErrorString(&info->stream));
+ //trace ("mpgmad: recoverable frame level error (%s)\n", MadErrorString(&info->stream));
}
continue;
}
else {
if(info->stream.error==MAD_ERROR_BUFLEN) {
- trace ("mpgmad: recoverable frame level error (%s)\n", MadErrorString(&info->stream));
+ //trace ("mpgmad: recoverable frame level error (%s)\n", MadErrorString(&info->stream));
continue;
}
else
{
- trace ("mpgmad: unrecoverable frame level error (%s).\n", MadErrorString(&info->stream));
+ //trace ("mpgmad: unrecoverable frame level error (%s).\n", MadErrorString(&info->stream));
return -1; // fatal error
}
}
}
- if (!info->buffer.it->filetype) {
- int layer = info->frame.header.layer;
- if (layer >= 1 && layer <= 3) {
- info->buffer.it->filetype = plugin.filetypes[layer-1];
- }
- }
+// const char *filetype = deadbeef->pl_find_meta (info->buffer.it, ":FILETYPE");
+// if (!filetype) {
+// int layer = info->frame.header.layer;
+// if (layer >= 1 && layer <= 3) {
+// deadbeef->pl_replace_meta (info->buffer.it, ":FILETYPE", plugin.filetypes[layer-1]);
+// }
+// }
- info->info.samplerate = info->frame.header.samplerate;
+ info->info.fmt.samplerate = info->frame.header.samplerate;
#if 0
// don't switch number of channels on the fly
- if (info->info.channels == 0) {
- info->info.channels = MAD_NCHANNELS(&info->frame.header);
+ if (info->info.fmt.channels == 0) {
+ info->info.fmt.channels = MAD_NCHANNELS(&info->frame.header);
}
#endif
@@ -937,36 +1104,36 @@ cmp3_free (DB_fileinfo_t *_info) {
}
static int
-cmp3_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
+cmp3_read (DB_fileinfo_t *_info, char *bytes, int size) {
#if WRITE_DUMP
if (!out) {
out = fopen ("out.raw", "w+b");
}
#endif
mpgmad_info_t *info = (mpgmad_info_t *)_info;
+ if (info->buffer.duration >= 0) {
+ int samplesize = _info->fmt.channels * _info->fmt.bps / 8;
+ int curr = info->buffer.currentsample - info->buffer.delay;
+ if (size / samplesize + curr > info->buffer.endsample) {
+ size = (info->buffer.endsample - curr + 1) * samplesize;
+ trace ("mp3: size truncated to %d bytes (%d samples), cursample=%d, endsample=%d\n", size, info->buffer.endsample - curr + 1, curr, info->buffer.endsample);
+ if (size <= 0) {
+ return 0;
+ }
+ }
+ }
+ int initsize = size;
info->buffer.readsize = size;
info->buffer.out = bytes;
cmp3_decode_int16 (info);
info->buffer.currentsample += (size - info->buffer.readsize) / 4;
- _info->readpos = (float)(info->buffer.currentsample - info->buffer.startsample) / info->buffer.samplerate;
+ _info->readpos = (float)(info->buffer.currentsample - info->buffer.delay - info->buffer.startsample) / info->buffer.samplerate;
#if WRITE_DUMP
if (size - info->buffer.readsize > 0) {
fwrite (bytes, 1, size - info->buffer.readsize, out);
}
#endif
- return size - info->buffer.readsize;
-}
-
-static int
-cmp3_read_float32 (DB_fileinfo_t *_info, char *bytes, int size) {
- mpgmad_info_t *info = (mpgmad_info_t *)_info;
-// trace ("cmp3_read_float32 readsize=%d, nchannels=%d\n", size, _info->channels);
- info->buffer.readsize = size;
- info->buffer.out = bytes;
- cmp3_decode_float32 (info);
- info->buffer.currentsample += (size - info->buffer.readsize) / 8;
- _info->readpos = (float)(info->buffer.currentsample - info->buffer.startsample) / info->buffer.samplerate;
- return size - info->buffer.readsize;
+ return initsize - info->buffer.readsize;
}
static int
@@ -976,23 +1143,22 @@ cmp3_seek_sample (DB_fileinfo_t *_info, int sample) {
return -1;
}
- if (info->buffer.file->vfs->streaming) {
- if (info->buffer.totalsamples > 0 && info->buffer.avg_samples_per_frame && info->buffer.avg_packetlength) { // that means seekable remote stream, like podcast
+ if (info->buffer.file->vfs->is_streaming ()) {
+ if (info->buffer.totalsamples > 0 && info->buffer.avg_samples_per_frame > 0 && info->buffer.avg_packetlength > 0) { // that means seekable remote stream, like podcast
trace ("seeking is possible!\n");
// get length excluding id3v2
- int64_t l = deadbeef->fgetlength (info->buffer.file) - info->buffer.startoffset;
+ int64_t l = deadbeef->fgetlength (info->buffer.file) - info->buffer.startoffset - info->buffer.endoffset;
int r;
// seek to beginning of the frame
- int frm = sample / info->buffer.avg_samples_per_frame;
- r = deadbeef->fseek (info->buffer.file, frm * info->buffer.avg_packetlength, SEEK_SET);
+ int64_t frm = sample / info->buffer.avg_samples_per_frame;
+ r = deadbeef->fseek (info->buffer.file, frm * info->buffer.avg_packetlength + info->buffer.startoffset, SEEK_SET);
// l = l * sample / buffer.totalsamples;
// r = deadbeef->fseek (buffer.file, l, SEEK_SET);
if (!r) {
- trace ("seek successful!\n");
info->buffer.skipsamples = sample - frm * info->buffer.avg_samples_per_frame;
info->buffer.currentsample = sample;
@@ -1018,17 +1184,14 @@ cmp3_seek_sample (DB_fileinfo_t *_info, int sample) {
return 0;
}
- sample += info->buffer.startsample + info->buffer.startdelay;
+ sample += info->buffer.startsample;
+// sample += info->buffer.delay;
if (sample > info->buffer.endsample) {
trace ("seek sample %d is beyond end of track (%d)\n", sample, info->buffer.endsample);
return -1; // eof
}
// restart file, and load until we hit required pos
- deadbeef->fseek (info->buffer.file, 0, SEEK_SET);
- int skip = deadbeef->junk_get_leading_size (info->buffer.file);
- if (skip > 0) {
- deadbeef->fseek (info->buffer.file, skip, SEEK_SET);
- }
+ deadbeef->fseek (info->buffer.file, info->buffer.startoffset, SEEK_SET);
mad_synth_finish (&info->synth);
mad_frame_finish (&info->frame);
mad_stream_finish (&info->stream);
@@ -1036,23 +1199,23 @@ cmp3_seek_sample (DB_fileinfo_t *_info, int sample) {
info->buffer.readsize = 0;
info->buffer.decode_remaining = 0;
- if (sample == 0) {
- _info->readpos = 0;
- info->buffer.currentsample = 0;
- info->buffer.skipsamples = info->buffer.startdelay;
- return 0;
- }
-
- if (cmp3_scan_stream (&info->buffer, sample) == -1) {
+// struct timeval tm1;
+// gettimeofday (&tm1, NULL);
+ if (cmp3_seek_stream (_info, sample) == -1) {
trace ("failed to seek to sample %d\n", sample);
_info->readpos = 0;
return -1;
}
+// struct timeval tm2;
+// gettimeofday (&tm2, NULL);
+// int ms = (tm2.tv_sec*1000+tm2.tv_usec/1000) - (tm1.tv_sec*1000+tm1.tv_usec/1000);
+// printf ("cmp3_scan_stream took %d ms\n", ms);
mad_stream_init(&info->stream);
mad_stream_options (&info->stream, MAD_OPTION_IGNORECRC);
mad_frame_init(&info->frame);
mad_synth_init(&info->synth);
- _info->readpos = (float)(info->buffer.currentsample - info->buffer.startsample) / info->buffer.samplerate;
+ trace ("seeked to %d\n", info->buffer.currentsample-info->buffer.delay);
+ _info->readpos = (float)(info->buffer.currentsample - info->buffer.delay - info->buffer.startsample) / info->buffer.samplerate;
return 0;
}
@@ -1075,14 +1238,11 @@ cmp3_insert (DB_playItem_t *after, const char *fname) {
trace ("failed to open file %s\n", fname);
return NULL;
}
- if (fp->vfs->streaming) {
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (fname);
+ if (fp->vfs->is_streaming ()) {
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
deadbeef->fclose (fp);
deadbeef->pl_add_meta (it, "title", NULL);
deadbeef->pl_set_item_duration (it, -1);
- it->filetype = NULL;//filetypes[0];
after = deadbeef->pl_insert_item (after, it);
deadbeef->pl_item_unref (it);
return after;
@@ -1143,9 +1303,7 @@ cmp3_insert (DB_playItem_t *after, const char *fname) {
break;
}
}
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (fname);
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
deadbeef->rewind (fp);
// reset tags
@@ -1155,13 +1313,18 @@ cmp3_insert (DB_playItem_t *after, const char *fname) {
/*int apeerr = */deadbeef->junk_apev2_read (it, fp);
/*int v2err = */deadbeef->junk_id3v2_read (it, fp);
/*int v1err = */deadbeef->junk_id3v1_read (it, fp);
- deadbeef->pl_add_meta (it, "title", NULL);
+ deadbeef->pl_set_meta_int (it, ":MP3_DELAY", buffer.delay);
+ deadbeef->pl_set_meta_int (it, ":MP3_PADDING", buffer.padding);
+
+ buffer.it = it;
+ cmp3_set_extra_properties (&buffer);
+
deadbeef->pl_set_item_duration (it, buffer.duration);
- it->filetype = ftype;
+ deadbeef->pl_replace_meta (it, ":FILETYPE", ftype);
deadbeef->fclose (fp);
// FIXME! bad numsamples passed to cue
- DB_playItem_t *cue_after = deadbeef->pl_insert_cue (after, it, buffer.duration*buffer.samplerate, buffer.samplerate);
+ DB_playItem_t *cue_after = deadbeef->pl_insert_cue (after, it, buffer.totalsamples-buffer.delay-buffer.padding, buffer.samplerate);
if (cue_after) {
deadbeef->pl_item_unref (it);
deadbeef->pl_item_unref (cue_after);
@@ -1175,7 +1338,7 @@ cmp3_insert (DB_playItem_t *after, const char *fname) {
int
cmp3_read_metadata (DB_playItem_t *it) {
- DB_FILE *fp = deadbeef->fopen (it->fname);
+ DB_FILE *fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!fp) {
return -1;
}
@@ -1223,7 +1386,8 @@ cmp3_write_metadata (DB_playItem_t *it) {
if (id3v2_version != 3 && id3v2_version != 4) {
id3v2_version = 3;
}
- const char *id3v1_encoding = deadbeef->conf_get_str ("mp3.id3v1_encoding", "iso8859-1");
+ char id3v1_encoding[50];
+ deadbeef->conf_get_str ("mp3.id3v1_encoding", "iso8859-1", id3v1_encoding, sizeof (id3v1_encoding));
return deadbeef->junk_rewrite_tags (it, junk_flags, id3v2_version, id3v1_encoding);
}
@@ -1234,20 +1398,34 @@ static const char *exts[] = {
// define plugin interface
static DB_decoder_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.id = "stdmpg",
.plugin.name = "MPEG decoder",
.plugin.descr = "MPEG v1/2 layer1/2/3 decoder based on libmad",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.open = cmp3_open,
.init = cmp3_init,
.free = cmp3_free,
- .read_int16 = cmp3_read_int16,
- .read_float32 = cmp3_read_float32,
+ .read = cmp3_read,
.seek = cmp3_seek,
.seek_sample = cmp3_seek_sample,
.insert = cmp3_insert,
diff --git a/plugins/musepack/Makefile.am b/plugins/musepack/Makefile.am
index 213fee32..c82490aa 100644
--- a/plugins/musepack/Makefile.am
+++ b/plugins/musepack/Makefile.am
@@ -27,6 +27,6 @@ mpc/minimax.h
musepack_la_LDFLAGS = -module
musepack_la_LIBADD = $(LDADD) -lm
-AM_CFLAGS = $(CFLAGS) -fPIC
+AM_CFLAGS = $(CFLAGS) -fPIC -std=c99
endif
diff --git a/plugins/musepack/mpc_decoder.c b/plugins/musepack/mpc_decoder.c
index a7732bf2..952789fd 100644
--- a/plugins/musepack/mpc_decoder.c
+++ b/plugins/musepack/mpc_decoder.c
@@ -650,11 +650,11 @@ void mpc_decoder_read_bitstream_sv8(mpc_decoder * d, mpc_bits_reader * r, mpc_bo
for ( ; k < 36; k += 2 ) {
union {
mpc_int8_t sym;
- struct { mpc_int8_t s1:4, s2:4; };
+ struct { mpc_int8_t s1:4, s2:4; } symf;
} tmp;
tmp.sym = mpc_bits_can_dec(r, Table);
- q[k] = tmp.s1;
- q[k + 1] = tmp.s2;
+ q[k] = tmp.symf.s1;
+ q[k + 1] = tmp.symf.s2;
}
} else if (Res <= 8) {
Tables[0] = & mpc_can_Q [Res - 3][0];
diff --git a/plugins/musepack/musepack.c b/plugins/musepack/musepack.c
index 69d18027..7f34c624 100644
--- a/plugins/musepack/musepack.c
+++ b/plugins/musepack/musepack.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -80,7 +80,7 @@ mpc_bool_t musepack_vfs_canseek (mpc_reader *r) {
}
static DB_fileinfo_t *
-musepack_open (void) {
+musepack_open (uint32_t hints) {
DB_fileinfo_t *_info = malloc (sizeof (musepack_info_t));
musepack_info_t *info = (musepack_info_t *)_info;
memset (info, 0, sizeof (musepack_info_t));
@@ -97,7 +97,7 @@ musepack_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
info->reader.get_size = musepack_vfs_get_size;
info->reader.canseek = musepack_vfs_canseek;
- DB_FILE *fp = deadbeef->fopen (it->fname);
+ DB_FILE *fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!fp) {
return -1;
}
@@ -112,19 +112,17 @@ musepack_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
}
mpc_demux_get_info (info->demux, &info->si);
-// info->mpcdec = mpc_decoder_init (&info->si);
-// if (!info->mpcdec) {
-// deadbeef->fclose ((DB_FILE *)info->reader.data);
-// info->reader.data = NULL;
-// return -1;
-// }
info->vbr_update_acc = 0;
info->vbr_update_bits = 0;
info->remaining = 0;
- _info->bps = 16;
- _info->channels = info->si.channels;
- _info->samplerate = info->si.sample_freq;
+ _info->fmt.is_float = 1;
+ _info->fmt.bps = 32;
+ _info->fmt.channels = info->si.channels;
+ _info->fmt.samplerate = info->si.sample_freq;
+ for (int i = 0; i < _info->fmt.channels; i++) {
+ _info->fmt.channelmask |= 1 << i;
+ }
_info->readpos = 0;
_info->plugin = &plugin;
@@ -145,10 +143,6 @@ static void
musepack_free (DB_fileinfo_t *_info) {
musepack_info_t *info = (musepack_info_t *)_info;
if (info) {
-// if (info->mpcdec) {
-// mpc_decoder_exit (info->mpcdec);
-// info->decoder = NULL;
-// }
if (info->demux) {
mpc_demux_exit (info->demux);
info->demux = NULL;
@@ -161,27 +155,24 @@ musepack_free (DB_fileinfo_t *_info) {
}
}
+#if 0
static int
-musepack_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
+musepack_read (DB_fileinfo_t *_info, char *bytes, int size) {
musepack_info_t *info = (musepack_info_t *)_info;
- if (info->currentsample + size / (2 * _info->channels) > info->endsample) {
- size = (info->endsample - info->currentsample + 1) * 2 * _info->channels;
+ int samplesize = _info->fmt.bps / 8 * _info->fmt.channels;
+ if (info->currentsample + size / samplesize > info->endsample) {
+ size = (info->endsample - info->currentsample + 1) * samplesize;
if (size <= 0) {
return 0;
}
}
int initsize = size;
- int out_channels = _info->channels;
- if (out_channels > 2) {
- out_channels = 2;
- }
- int sample_size = ((_info->bps >> 3) * out_channels);
while (size > 0) {
if (info->remaining > 0) {
- int n = size / sample_size;
+ int n = size / samplesize;
n = min (n, info->remaining);
int nn = n;
float *p = info->buffer;
@@ -195,7 +186,7 @@ musepack_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
}
*((int16_t *)bytes) = (int16_t)sample;
bytes += 2;
- if (_info->channels == 2) {
+ if (_info->fmt.channels == 2) {
sample = (int)(*(p+1) * 32767.0f);
if (sample > 32767) {
sample = 32767;
@@ -207,11 +198,11 @@ musepack_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
bytes += 2;
}
n--;
- size -= sample_size;
+ size -= samplesize;
p += info->si.channels;
}
if (info->remaining > nn) {
- memmove (info->buffer, p, (info->remaining - nn) * sizeof (float) * _info->channels);
+ memmove (info->buffer, p, (info->remaining - nn) * sizeof (float) * _info->fmt.channels);
}
info->remaining -= nn;
}
@@ -227,48 +218,39 @@ musepack_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
info->remaining = frame.samples;
}
}
- info->currentsample += (initsize-size) / sample_size;
+ info->currentsample += (initsize-size) / samplesize;
return initsize-size;
}
+#endif
static int
-musepack_read_float32 (DB_fileinfo_t *_info, char *bytes, int size) {
+musepack_read (DB_fileinfo_t *_info, char *bytes, int size) {
musepack_info_t *info = (musepack_info_t *)_info;
+ int samplesize = _info->fmt.bps / 8 * _info->fmt.channels;
- if (info->currentsample + size / (4 * _info->channels) > info->endsample) {
- size = (info->endsample - info->currentsample + 1) * 4 * _info->channels;
+ if (info->currentsample + size / samplesize > info->endsample) {
+ size = (info->endsample - info->currentsample + 1) * samplesize;
if (size <= 0) {
return 0;
}
}
int initsize = size;
- int out_channels = _info->channels;
- if (out_channels > 2) {
- out_channels = 2;
- }
while (size > 0) {
if (info->remaining > 0) {
- int n = size / (out_channels * 4);
+ int n = size / samplesize;
n = min (n, info->remaining);
- int nn = n;
- float *p = info->buffer;
- while (n > 0) {
- *((float *)bytes) = *p;
- bytes += 4;
- if (out_channels == 2) {
- *((float *)bytes) = *(p+1);
- bytes += 4;
- }
- n--;
- size -= out_channels * 4;
- p += info->si.channels;
- }
- if (info->remaining > nn) {
- memmove (info->buffer, p, (info->remaining - nn) * 4 * _info->channels);
+
+ memcpy (bytes, info->buffer, n * samplesize);
+
+ size -= n * samplesize;
+ bytes += n * samplesize;
+
+ if (info->remaining > n) {
+ memmove (info->buffer, ((char *)info->buffer) + n * samplesize, (info->remaining - n) * samplesize);
}
- info->remaining -= nn;
+ info->remaining -= n;
}
if (size > 0 && !info->remaining) {
@@ -282,9 +264,10 @@ musepack_read_float32 (DB_fileinfo_t *_info, char *bytes, int size) {
info->remaining = frame.samples;
}
}
- info->currentsample += (initsize-size) / (4 * _info->channels);
+ info->currentsample += (initsize-size) / samplesize;
return initsize-size;
}
+
static int
musepack_seek_sample (DB_fileinfo_t *_info, int sample) {
musepack_info_t *info = (musepack_info_t *)_info;
@@ -294,7 +277,7 @@ musepack_seek_sample (DB_fileinfo_t *_info, int sample) {
return -1;
}
info->currentsample = sample + info->startsample;
- _info->readpos = (float)sample / _info->samplerate;
+ _info->readpos = (float)sample / _info->fmt.samplerate;
info->remaining = 0;
return 0;
}
@@ -302,7 +285,37 @@ musepack_seek_sample (DB_fileinfo_t *_info, int sample) {
static int
musepack_seek (DB_fileinfo_t *_info, float time) {
musepack_info_t *info = (musepack_info_t *)_info;
- return musepack_seek_sample (_info, time * _info->samplerate);
+ return musepack_seek_sample (_info, time * _info->fmt.samplerate);
+}
+
+void
+mpc_set_trk_properties (DB_playItem_t *it, mpc_streaminfo *si, int64_t fsize) {
+ char s[100];
+ snprintf (s, sizeof (s), "%lld", fsize);
+ deadbeef->pl_add_meta (it, ":FILE_SIZE", s);
+ deadbeef->pl_add_meta (it, ":BPS", "32");
+ snprintf (s, sizeof (s), "%d", si->channels);
+ deadbeef->pl_add_meta (it, ":CHANNELS", s);
+ snprintf (s, sizeof (s), "%d", si->sample_freq);
+ deadbeef->pl_add_meta (it, ":SAMPLERATE", s);
+ snprintf (s, sizeof (s), "%d", (int)(si->average_bitrate/1000));
+ deadbeef->pl_add_meta (it, ":BITRATE", s);
+ snprintf (s, sizeof (s), "%f", si->profile);
+ deadbeef->pl_add_meta (it, ":MPC_QUALITY_PROFILE", s);
+ deadbeef->pl_add_meta (it, ":MPC_PROFILE_NAME", si->profile_name);
+ deadbeef->pl_add_meta (it, ":MPC_ENCODER", si->encoder);
+ snprintf (s, sizeof (s), "%d.%d", (si->encoder_version&0xff000000)>>24, (si->encoder_version&0x00ff0000)>>16);
+ deadbeef->pl_add_meta (it, ":MPC_ENCODER_VERSION", s);
+ deadbeef->pl_add_meta (it, ":MPC_PNS_USED", si->pns ? "1" : "0");
+ deadbeef->pl_add_meta (it, ":MPC_TRUE_GAPLESS", si->is_true_gapless ? "1" : "0");
+ snprintf (s, sizeof (s), "%d", si->beg_silence);
+ deadbeef->pl_add_meta (it, ":MPC_BEG_SILENCE", s);
+ snprintf (s, sizeof (s), "%d", si->stream_version);
+ deadbeef->pl_add_meta (it, ":MPC_STREAM_VERSION", s);
+ snprintf (s, sizeof (s), "%d", si->max_band);
+ deadbeef->pl_add_meta (it, ":MPC_MAX_BAND", s);
+ deadbeef->pl_add_meta (it, ":MPC_MS", si->ms ? "1" : "0");
+ deadbeef->pl_add_meta (it, ":MPC_FAST_SEEK", si->fast_seek ? "1" : "0");
}
static DB_playItem_t *
@@ -321,6 +334,7 @@ musepack_insert (DB_playItem_t *after, const char *fname) {
trace ("mpc: insert failed to open %s\n", fname);
return NULL;
}
+ int64_t fsize = deadbeef->fgetlength (fp);
reader.data = fp;
mpc_demux *demux = mpc_demux_init (&reader);
@@ -363,11 +377,9 @@ musepack_insert (DB_playItem_t *after, const char *fname) {
int i;
for (i = 0; i < nchapters; i++) {
const mpc_chap_info *ch = mpc_demux_chap (demux, i);
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (fname);
- it->filetype = "MusePack";
- it->tracknum = i;
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
+ deadbeef->pl_add_meta (it, ":FILETYPE", "MusePack");
+ deadbeef->pl_set_meta_int (it, ":TRACKNUM", i);
it->startsample = ch->sample;
it->endsample = totalsamples-1;
float gain = gain_title, peak = peak_title;
@@ -377,10 +389,10 @@ musepack_insert (DB_playItem_t *after, const char *fname) {
if (ch->peak != 0) {
peak = pow (10, ch->peak / (20.0 * 256.0)) / (1<<15);
}
- it->replaygain_album_gain = gain_album;
- it->replaygain_album_peak = peak_album;
- it->replaygain_track_gain = gain_title;
- it->replaygain_track_peak = peak_title;
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMGAIN, gain_album);
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMPEAK, peak_album);
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKGAIN, gain_title);
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKPEAK, peak_title);
deadbeef->pl_set_item_flags (it, DDB_IS_SUBTRACK);
if (!prev) {
meta = deadbeef->pl_item_alloc ();
@@ -402,6 +414,9 @@ musepack_insert (DB_playItem_t *after, const char *fname) {
deadbeef->pl_items_copy_junk (meta, it, it);
}
}
+
+ mpc_set_trk_properties (it, &si, fsize);
+
after = deadbeef->pl_insert_item (after, it);
prev = it;
deadbeef->pl_item_unref (it);
@@ -415,17 +430,15 @@ musepack_insert (DB_playItem_t *after, const char *fname) {
return after;
}
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (fname);
- it->filetype = "MusePack";
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
+ deadbeef->pl_add_meta (it, ":FILETYPE", "MusePack");
deadbeef->pl_set_item_duration (it, dur);
/*int apeerr = */deadbeef->junk_apev2_read (it, fp);
- it->replaygain_album_gain = gain_album;
- it->replaygain_album_peak = peak_album;
- it->replaygain_track_gain = gain_title;
- it->replaygain_track_peak = peak_title;
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMGAIN, gain_album);
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMPEAK, peak_album);
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKGAIN, gain_title);
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKPEAK, peak_title);
deadbeef->fclose (fp);
@@ -447,6 +460,7 @@ musepack_insert (DB_playItem_t *after, const char *fname) {
}
deadbeef->pl_unlock ();
+ mpc_set_trk_properties (it, &si, fsize);
cue = deadbeef->pl_insert_cue (after, it, totalsamples, si.sample_freq);
if (cue) {
deadbeef->pl_item_unref (it);
@@ -468,7 +482,7 @@ musepack_insert (DB_playItem_t *after, const char *fname) {
}
static int musepack_read_metadata (DB_playItem_t *it) {
- DB_FILE *fp = deadbeef->fopen (it->fname);
+ DB_FILE *fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!fp) {
return -1;
}
@@ -512,22 +526,38 @@ static const char *filetypes[] = { "MusePack", NULL };
// define plugin interface
static DB_decoder_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.id = "musepack",
.plugin.name = "MusePack decoder",
.plugin.descr = "Musepack decoder using libmppdec",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "Uses Musepack SV8 libs (r435), (C) 2005-2009, The Musepack Development Team\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = musepack_start,
.plugin.stop = musepack_stop,
.open = musepack_open,
.init = musepack_init,
.free = musepack_free,
- .read_int16 = musepack_read_int16,
- .read_float32 = musepack_read_float32,
+ .read = musepack_read,
.seek = musepack_seek,
.seek_sample = musepack_seek_sample,
.insert = musepack_insert,
diff --git a/plugins/notify/notify.c b/plugins/notify/notify.c
index ba7daa92..c572b131 100644
--- a/plugins/notify/notify.c
+++ b/plugins/notify/notify.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include "../../gettext.h"
+#include "../artwork/artwork.h"
#define E_NOTIFICATION_BUS_NAME "org.freedesktop.Notifications"
#define E_NOTIFICATION_INTERFACE "org.freedesktop.Notifications"
@@ -29,8 +30,62 @@
DB_functions_t *deadbeef;
DB_misc_t plugin;
+DB_artwork_plugin_t *artwork_plugin;
-#define NOTIFY_DEFAULT_FORMAT "%a - %t"
+static dbus_uint32_t replaces_id = 0;
+
+#define NOTIFY_DEFAULT_TITLE "%t"
+#define NOTIFY_DEFAULT_CONTENT "%a - %b"
+
+static void
+notify_thread (void *ctx) {
+
+ DBusMessage *msg = (DBusMessage*) ctx;
+ DBusMessage *reply = NULL;
+
+ DBusError error;
+ dbus_error_init (&error);
+ DBusConnection *conn = dbus_bus_get (DBUS_BUS_SESSION, &error);
+ if(dbus_error_is_set (&error)) {
+ fprintf(stderr, "connection failed: %s",error.message);
+ dbus_error_free(&error);
+ dbus_message_unref (msg);
+ deadbeef->thread_exit(NULL);
+ }
+
+ reply = dbus_connection_send_with_reply_and_block (conn, msg, -1, &error);
+ if (dbus_error_is_set (&error)) {
+ fprintf(stderr, "send_with_reply_and_block error: (%s)\n", error.message);
+ dbus_error_free(&error);
+ dbus_message_unref (msg);
+ deadbeef->thread_exit(NULL);
+ }
+
+ if (reply != NULL) {
+ // Process the reply message
+ DBusMessageIter args;
+
+ dbus_uint32_t id = 0;
+ if (dbus_message_iter_init(reply, &args)) {
+ if (DBUS_TYPE_UINT32 == dbus_message_iter_get_arg_type(&args)) {
+ dbus_message_iter_get_basic(&args, &id);
+ if (id != replaces_id) {
+ replaces_id = id;
+ }
+ dbus_message_unref (reply);
+ } else {
+ fprintf(stderr, "Argument is not uint32\n");
+ }
+ } else {
+ fprintf(stderr, "Reply has no arguments\n");
+ }
+ }
+
+ dbus_message_unref (msg);
+ dbus_connection_unref (conn);
+ deadbeef->thread_exit(NULL);
+
+}
#if 0
static void
@@ -62,107 +117,137 @@ notify_marshal_dict_string(DBusMessageIter *iter, const char *key, const char *v
}
#endif
+static void
+esc_xml (const char *cmd, char *esc, int size) {
+ const char *src = cmd;
+ char *dst = esc;
+ char *end = dst + size - 1;
+ while (*src && dst < end) {
+ if (*src == '&') {
+ if (end - dst < 5) {
+ break;
+ }
+ strcpy (dst, "&amp;");
+ dst += 5;
+ src++;
+ }
+ else if (*src == '<') {
+ if (end - dst < 4) {
+ break;
+ }
+ strcpy (dst, "&lt;");
+ dst += 4;
+ src++;
+ }
+ else if (*src == '>') {
+ if (end - dst < 4) {
+ break;
+ }
+ strcpy (dst, "&gt;");
+ dst += 4;
+ src++;
+ }
+ else if (*src == '\'') {
+ if (end - dst < 6) {
+ break;
+ }
+ strcpy (dst, "&apos;");
+ dst += 6;
+ src++;
+ }
+ else if (*src == '"') {
+ if (end - dst < 6) {
+ break;
+ }
+ strcpy (dst, "&quot;");
+ dst += 6;
+ src++;
+ }
+ else if (*src == '\\' && *(src+1) == 'n') {
+ strcpy (dst, "\n");
+ dst++;
+ src+=2;
+ }
+ else {
+ *dst++ = *src++;
+ }
+ }
+ *dst = 0;
+}
+
+
+static void
+cover_avail_callback (const char *fname, const char *artist, const char *album, void *user_data) {
+// show_notification (track);
+}
+
+static void show_notification (DB_playItem_t *track) {
+ char title[1024];
+ char content[1024];
+ deadbeef->conf_lock ();
+ deadbeef->pl_format_title (track, -1, title, sizeof (title), -1, deadbeef->conf_get_str_fast ("notify.format", NOTIFY_DEFAULT_TITLE));
+ deadbeef->pl_format_title (track, -1, content, sizeof (content), -1, deadbeef->conf_get_str_fast ("notify.format_content", NOTIFY_DEFAULT_CONTENT));
+ deadbeef->conf_unlock ();
+
+ // escape &
+// char esc_title[1024];
+ char esc_content[1024];
+// esc_xml (title, esc_title, sizeof (esc_title));
+ esc_xml (content, esc_content, sizeof (esc_content));
+ DBusMessage *msg = dbus_message_new_method_call (E_NOTIFICATION_BUS_NAME, E_NOTIFICATION_PATH, E_NOTIFICATION_INTERFACE, "Notify");
+
+ const char *v_appname = "DeaDBeeF";
+ dbus_uint32_t v_id = 0;
+ char *v_iconname = NULL;
+ if (deadbeef->conf_get_int("notify.albumart", 0) && artwork_plugin) {
+ const char *album = deadbeef->pl_find_meta (track, "album");
+ const char *artist = deadbeef->pl_find_meta (track, "artist");
+ v_iconname = artwork_plugin->get_album_art (deadbeef->pl_find_meta (track, ":URI"), artist, album, deadbeef->conf_get_int ("notify.albumart_size", 64), cover_avail_callback, NULL);
+ }
+ if (!v_iconname) {
+ v_iconname = strdup ("deadbeef");
+ }
+ const char *v_summary = title;
+ const char *v_body = esc_content;
+ dbus_int32_t v_timeout = -1;
+
+ dbus_message_append_args (msg
+ , DBUS_TYPE_STRING, &v_appname
+ , DBUS_TYPE_UINT32, &replaces_id
+ , DBUS_TYPE_STRING, &v_iconname
+ , DBUS_TYPE_STRING, &v_summary
+ , DBUS_TYPE_STRING, &v_body
+ , DBUS_TYPE_INVALID
+ );
+
+ DBusMessageIter iter, sub;
+ // actions
+ dbus_message_iter_init_append(msg, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub);
+ dbus_message_iter_close_container(&iter, &sub);
+ // hints
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub);
+ dbus_message_iter_close_container(&iter, &sub);
+
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &v_timeout);
+
+ intptr_t tid = 0;
+ if ((tid=deadbeef->thread_start(notify_thread, msg)) != 0) {
+ dbus_message_ref (msg);
+ deadbeef->thread_detach (tid);
+ }
+ dbus_message_unref (msg);
+ if (v_iconname) {
+ free (v_iconname);
+ }
+}
+
static int
on_songchanged (DB_event_trackchange_t *ev, uintptr_t data) {
if (ev->to && deadbeef->conf_get_int ("notify.enable", 0)) {
DB_playItem_t *track = ev->to;
if (track) {
- char cmd[1024];
- deadbeef->pl_format_title (track, -1, cmd, sizeof (cmd), -1, deadbeef->conf_get_str ("notify.format", NOTIFY_DEFAULT_FORMAT));
-
- // escape &
- char esc[1024];
-
- char *src = cmd;
- char *dst = esc;
- char *end = dst + sizeof (esc) - 1;
- while (*src && dst < end) {
- if (*src == '&') {
- if (end - dst < 5) {
- break;
- }
- strcpy (dst, "&amp;");
- dst += 5;
- src++;
- }
- else if (*src == '<') {
- if (end - dst < 4) {
- break;
- }
- strcpy (dst, "&lt;");
- dst += 4;
- src++;
- }
- else if (*src == '>') {
- if (end - dst < 4) {
- break;
- }
- strcpy (dst, "&gt;");
- dst += 4;
- src++;
- }
- else if (*src == '\'') {
- if (end - dst < 6) {
- break;
- }
- strcpy (dst, "&apos;");
- dst += 6;
- src++;
- }
- else if (*src == '"') {
- if (end - dst < 6) {
- break;
- }
- strcpy (dst, "&quot;");
- dst += 6;
- src++;
- }
- else {
- *dst++ = *src++;
- }
- }
- *dst = 0;
-
- DBusError error;
- dbus_error_init (&error);
- DBusConnection *conn = dbus_bus_get (DBUS_BUS_SESSION, &error);
- if(conn == NULL) {
- printf("connection failed: %s",error.message);
- exit(1);
- }
- DBusMessage *msg = dbus_message_new_method_call (E_NOTIFICATION_BUS_NAME, E_NOTIFICATION_PATH, E_NOTIFICATION_INTERFACE, "Notify");
-
- const char *v_appname = "DeaDBeeF";
- dbus_uint32_t v_id = 0;
- const char *v_iconname = "deadbeef";
- const char *v_summary = _("DeaDBeeF now playing");
- const char *v_body = esc;
- dbus_int32_t v_timeout = -1;
-
- dbus_message_append_args (msg
- , DBUS_TYPE_STRING, &v_appname
- , DBUS_TYPE_UINT32, &v_id
- , DBUS_TYPE_STRING, &v_iconname
- , DBUS_TYPE_STRING, &v_summary
- , DBUS_TYPE_STRING, &v_body
- , DBUS_TYPE_INVALID
- );
-
- DBusMessageIter iter, sub;
- // actions
- dbus_message_iter_init_append(msg, &iter);
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub);
- dbus_message_iter_close_container(&iter, &sub);
- // hints
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub);
- dbus_message_iter_close_container(&iter, &sub);
-
- dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &v_timeout);
-
- int serial;
- dbus_bool_t retval = dbus_connection_send(conn,msg,&serial);
- dbus_connection_flush (conn);
- dbus_message_unref (msg);
+ show_notification (track);
}
}
return 0;
@@ -180,9 +265,24 @@ notify_stop (void) {
return 0;
}
+static int
+notify_connect (void) {
+ artwork_plugin = (DB_artwork_plugin_t *)deadbeef->plug_get_for_id ("artwork");
+ return 0;
+}
+
+static int
+notify_disconnect (void) {
+ artwork_plugin = NULL;
+ return 0;
+}
+
static const char settings_dlg[] =
"property \"Enable\" checkbox notify.enable 0;\n"
- "property \"Notification format\" entry notify.format \"" NOTIFY_DEFAULT_FORMAT "\";\n"
+ "property \"Notification title format\" entry notify.format \"" NOTIFY_DEFAULT_TITLE "\";\n"
+ "property \"Notification content format\" entry notify.format_content \"" NOTIFY_DEFAULT_CONTENT "\";\n"
+ "property \"Show album art\" checkbox notify.albumart 1;\n"
+ "property \"Album art size (px)\" entry notify.albumart_size 64;\n"
;
DB_misc_t plugin = {
@@ -192,12 +292,29 @@ DB_misc_t plugin = {
.plugin.version_minor = 0,
.plugin.id = "notify",
.plugin.name = "OSD Notify",
- .plugin.descr = "notification daemon OSD",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.descr = "Displays notifications when new track starts.\nRequires dbus and notification daemon to be running.\nNotification daemon should be provided by your desktop environment.\n",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sourceforge.net",
.plugin.start = notify_start,
.plugin.stop = notify_stop,
+ .plugin.connect = notify_connect,
+ .plugin.disconnect = notify_disconnect,
.plugin.configdialog = settings_dlg,
};
diff --git a/plugins/nullout/nullout.c b/plugins/nullout/nullout.c
index 8720de6d..c568f5d2 100644
--- a/plugins/nullout/nullout.c
+++ b/plugins/nullout/nullout.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -32,7 +32,6 @@ DB_functions_t *deadbeef;
static intptr_t null_tid;
static int null_terminate;
-static int null_rate;
static int state;
static void
@@ -47,8 +46,8 @@ pnull_init (void);
static int
pnull_free (void);
-static int
-pnull_change_rate (int rate);
+int
+pnull_setformat (ddb_waveformat_t *fmt);
static int
pnull_play (void);
@@ -62,32 +61,19 @@ pnull_pause (void);
static int
pnull_unpause (void);
-static int
-pnull_get_rate (void);
-
-static int
-pnull_get_bps (void);
-
-static int
-pnull_get_channels (void);
-
-static int
-pnull_get_endianness (void);
-
int
pnull_init (void) {
trace ("pnull_init\n");
state = OUTPUT_STATE_STOPPED;
- null_rate = 44100;
null_terminate = 0;
null_tid = deadbeef->thread_start (pnull_thread, NULL);
return 0;
}
int
-pnull_change_rate (int rate) {
- null_rate = rate;
- return null_rate;
+pnull_setformat (ddb_waveformat_t *fmt) {
+ memcpy (&plugin.fmt, fmt, sizeof (ddb_waveformat_t));
+ return 0;
}
int
@@ -140,21 +126,6 @@ pnull_unpause (void) {
return 0;
}
-int
-pnull_get_rate (void) {
- return null_rate;
-}
-
-int
-pnull_get_bps (void) {
- return 16;
-}
-
-int
-pnull_get_channels (void) {
- return 2;
-}
-
static int
pnull_get_endianness (void) {
#if WORDS_BIGENDIAN
@@ -220,27 +191,39 @@ nullout_load (DB_functions_t *api) {
// define plugin interface
static DB_output_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
- .plugin.nostop = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_OUTPUT,
+ .plugin.id = "nullout",
.plugin.name = "null output plugin",
.plugin.descr = "doesn't play anything",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = null_start,
.plugin.stop = null_stop,
.init = pnull_init,
.free = pnull_free,
- .change_rate = pnull_change_rate,
+ .setformat = pnull_setformat,
.play = pnull_play,
.stop = pnull_stop,
.pause = pnull_pause,
.unpause = pnull_unpause,
.state = pnull_get_state,
- .samplerate = pnull_get_rate,
- .bitspersample = pnull_get_bps,
- .channels = pnull_get_channels,
- .endianness = pnull_get_endianness,
+ .fmt = {.samplerate = 44100, .channels = 2, .bps = 16, .channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT}
};
diff --git a/plugins/oss/oss.c b/plugins/oss/oss.c
index 52c417fa..953398af 100644
--- a/plugins/oss/oss.c
+++ b/plugins/oss/oss.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -48,6 +48,8 @@ static int state;
static int fd;
static uintptr_t mutex;
+static char oss_device[100];
+
#define BLOCKSIZE 8192
static void
@@ -56,70 +58,90 @@ oss_thread (void *context);
static int
oss_callback (char *stream, int len);
-static int
-oss_init (void) {
- trace ("oss_init\n");
- state = OUTPUT_STATE_STOPPED;
- oss_terminate = 0;
- mutex = 0;
-
- // prepare oss for playback
- const char *name = deadbeef->conf_get_str ("oss.device", "/dev/dsp");
- fd = open (name, O_WRONLY);
- if (fd == -1) {
- fprintf (stderr, "oss: failed to open file %s\n", name);
- perror (name);
- plugin.free ();
- return -1;
+int
+oss_set_hwparams (ddb_waveformat_t *fmt) {
+ int samplefmt;
+ switch (fmt->bps) {
+ case 8:
+ samplefmt = AFMT_S8;
+ break;
+ case 16:
+ samplefmt = AFMT_S16_NE;
+ break;
+ default:
+ samplefmt = AFMT_S16_NE;
+ break;
}
-
-#if OSS_VERSION>=0x040000
-/*
- int cooked = 1;
- ioctl (fd, SNDCTL_DSP_COOKEDMODE, &cooked);
- trace ("oss: cooked_mode=%d\n", cooked);
-
- int policy = 3;
- ioctl (fd, SNDCTL_DSP_POLICY, &policy);
- trace ("oss: policy=%d\n", policy);
-*/
-#endif
-
- int fmt = AFMT_S16_NE;
- if (ioctl (fd, SNDCTL_DSP_SETFMT, &fmt) == -1) {
+ if (ioctl (fd, SNDCTL_DSP_SETFMT, &samplefmt) == -1) {
fprintf (stderr, "oss: failed to set format\n");
perror ("SNDCTL_DSP_SETFMT");
- plugin.free ();
- return -1;
- }
-
- if (fmt != AFMT_S16_NE) {
- fprintf (stderr, "oss: device doesn't support 16 bit sample format\n");
- plugin.free ();
return -1;
}
- int channels = 2;
+ int channels = fmt->channels;
if (ioctl (fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
- fprintf (stderr, "oss: failed to set channels\n");
+ if (channels != 2) {
+ fprintf (stderr, "oss: failed to set %d channels, trying fallback to stereo\n", fmt->channels);
+ channels = 2;
+ if (ioctl (fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
+ fprintf (stderr, "oss: stereo fallback failed\n");
+ perror ("SNDCTL_DSP_CHANNELS");
+ return -1;
+ }
+ }
+ else {
+ fprintf (stderr, "oss: failed to set %d channels\n", fmt->channels);
+ perror ("SNDCTL_DSP_CHANNELS");
+ return -1;
+ }
+ }
+ int rate = fmt->samplerate;
+ if (ioctl (fd, SNDCTL_DSP_SPEED, &rate) == -1) {
+ fprintf (stderr, "oss: can't switch to %d samplerate\n", rate);
perror ("SNDCTL_DSP_CHANNELS");
- plugin.free ();
return -1;
}
- if (channels != 2) {
- fprintf (stderr, "oss: device doesn't support stereo output\n");
- plugin.free ();
+
+ plugin.fmt.samplerate = rate;
+ plugin.fmt.channels = channels;
+ switch (samplefmt) {
+ case AFMT_S8:
+ plugin.fmt.bps = 8;
+ break;
+ case AFMT_S16_LE:
+ case AFMT_S16_BE:
+ plugin.fmt.bps = 16;
+ break;
+ default:
+ fprintf (stderr, "oss: unsupported output format: 0x%X\n", samplefmt);
return -1;
}
+ plugin.fmt.channelmask = 0;
+ for (int i = 0; i < plugin.fmt.channels; i++) {
+ plugin.fmt.channelmask |= 1 << i;
+ }
- if (ioctl (fd, SNDCTL_DSP_SPEED, &oss_rate) == -1) {
- fprintf (stderr, "oss: failed to set samplerate\n");
- perror ("SNDCTL_DSP_CHANNELS");
+ return 0;
+}
+
+static int
+oss_init (void) {
+ trace ("oss_init\n");
+ state = OUTPUT_STATE_STOPPED;
+ oss_terminate = 0;
+ mutex = 0;
+
+ // prepare oss for playback
+ const char *name = oss_device;
+ fd = open (name, O_WRONLY);
+ if (fd == -1) {
+ fprintf (stderr, "oss: failed to open file %s\n", name);
+ perror (name);
plugin.free ();
return -1;
}
- trace ("oss: samplerate: %d\n", oss_rate);
+ oss_set_hwparams (&plugin.fmt);
mutex = deadbeef->mutex_create ();
@@ -128,28 +150,6 @@ oss_init (void) {
}
static int
-oss_change_rate (int rate) {
- if (!fd) {
- oss_rate = rate;
- return oss_rate;
- }
- if (rate == oss_rate) {
- trace ("oss_change_rate %d: ignored\n", rate);
- return rate;
- }
- deadbeef->mutex_lock (mutex);
- if (ioctl (fd, SNDCTL_DSP_SPEED, &rate) == -1) {
- fprintf (stderr, "oss: can't switch to %d samplerate\n", rate);
- perror ("SNDCTL_DSP_CHANNELS");
- plugin.free ();
- return -1;
- }
- oss_rate = rate;
- deadbeef->mutex_unlock (mutex);
- return oss_rate;
-}
-
-static int
oss_free (void) {
trace ("oss_free\n");
if (!oss_terminate) {
@@ -201,6 +201,41 @@ oss_pause (void) {
return 0;
}
+
+static int
+oss_setformat (ddb_waveformat_t *fmt) {
+ trace ("oss_setformat\n");
+ if (!fd) {
+ memcpy (&plugin.fmt, fmt, sizeof (ddb_waveformat_t));
+ }
+ if (!memcmp (fmt, &plugin.fmt, sizeof (ddb_waveformat_t))) {
+ return 0;
+ }
+ deadbeef->mutex_lock (mutex);
+
+ if (0 != oss_set_hwparams (fmt)) {
+ return -1;
+ }
+
+ deadbeef->mutex_unlock (mutex);
+
+ switch (state) {
+ case OUTPUT_STATE_STOPPED:
+ return oss_stop ();
+ case OUTPUT_STATE_PLAYING:
+ return oss_play ();
+ case OUTPUT_STATE_PAUSED:
+ if (0 != oss_play ()) {
+ return -1;
+ }
+ if (0 != oss_pause ()) {
+ return -1;
+ }
+ break;
+ }
+ return 0;
+}
+
static int
oss_unpause (void) {
oss_play ();
@@ -247,7 +282,14 @@ oss_thread (void *context) {
int res = 0;
- char buf[BLOCKSIZE];
+ int sample_size = plugin.fmt.channels * (plugin.fmt.bps / 8);
+ int bs = BLOCKSIZE;
+ int mod = bs % sample_size;
+ if (mod > 0) {
+ bs -= mod;
+ }
+ char buf[bs];
+
int write_size = oss_callback (buf, sizeof (buf));
deadbeef->mutex_lock (mutex);
if ( write_size > 0 )
@@ -264,13 +306,7 @@ oss_thread (void *context) {
static int
oss_callback (char *stream, int len) {
- int bytesread = deadbeef->streamer_read (stream, len);
- int16_t ivolume = deadbeef->volume_get_amp () * 1000;
- for (int i = 0; i < bytesread/2; i++) {
- ((int16_t*)stream)[i] = (int16_t)(((int32_t)(((int16_t*)stream)[i])) * ivolume / 1000);
- }
-
- return bytesread;
+ return deadbeef->streamer_read (stream, len);
}
static int
@@ -279,12 +315,28 @@ oss_get_state (void) {
}
static int
+oss_configchanged (DB_event_t *ev, uintptr_t data) {
+ deadbeef->conf_lock ();
+ const char *dev = deadbeef->conf_get_str_fast ("oss.device", "/dev/dsp");
+ if (strcmp (dev, oss_device)) {
+ strncpy (oss_device, dev, sizeof (oss_device)-1);
+ trace ("oss: config option changed, restarting\n");
+ deadbeef->sendmessage (M_REINIT_SOUND, 0, 0, 0);
+ }
+ deadbeef->conf_unlock ();
+ return 0;
+}
+
+static int
oss_plugin_start (void) {
+ deadbeef->conf_get_str ("oss.device", "/dev/dsp", oss_device, sizeof (oss_device));
+ deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_CONFIGCHANGED, DB_CALLBACK (oss_configchanged), 0);
return 0;
}
static int
oss_plugin_stop (void) {
+ deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_CONFIGCHANGED, DB_CALLBACK (oss_configchanged), 0);
return 0;
}
@@ -294,31 +346,46 @@ oss_load (DB_functions_t *api) {
return DB_PLUGIN (&plugin);
}
+static const char settings_dlg[] =
+ "property \"Device file\" entry oss.device /dev/dsp;\n";
+
// define plugin interface
static DB_output_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
- .plugin.nostop = 0,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_OUTPUT,
.plugin.id = "oss",
.plugin.name = "OSS output plugin",
.plugin.descr = "plays sound via OSS API",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = oss_plugin_start,
.plugin.stop = oss_plugin_stop,
+ .plugin.configdialog = settings_dlg,
.init = oss_init,
.free = oss_free,
- .change_rate = oss_change_rate,
+ .setformat = oss_setformat,
.play = oss_play,
.stop = oss_stop,
.pause = oss_pause,
.unpause = oss_unpause,
.state = oss_get_state,
- .samplerate = oss_get_rate,
- .bitspersample = oss_get_bps,
- .channels = oss_get_channels,
- .endianness = oss_get_endianness,
+ .fmt = {-1},
};
diff --git a/plugins/pulse/pulse.c b/plugins/pulse/pulse.c
index 266ea107..9a08ff08 100644
--- a/plugins/pulse/pulse.c
+++ b/plugins/pulse/pulse.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -42,7 +42,6 @@
static DB_output_t plugin;
DB_functions_t * deadbeef;
-#define CONFSTR_PULSE_SAMPLERATE "pulse.samplerate"
#define CONFSTR_PULSE_SERVERADDR "pulse.serveraddr"
#define CONFSTR_PULSE_BUFFERSIZE "pulse.buffersize"
@@ -51,6 +50,8 @@ static int pulse_terminate;
static pa_simple *s;
static pa_sample_spec ss;
+static pa_channel_map channel_map;
+static ddb_waveformat_t requested_fmt;
static int state;
static uintptr_t mutex;
@@ -60,29 +61,70 @@ static void pulse_thread(void *context);
static void pulse_callback(char *stream, int len);
-static int pulse_init(void)
+static int pulse_init();
+
+static int pulse_free();
+
+static int pulse_setformat(ddb_waveformat_t *fmt);
+
+static int pulse_play();
+
+static int pulse_stop();
+
+static int pulse_pause();
+
+static int pulse_unpause();
+
+static int pulse_set_spec(ddb_waveformat_t *fmt)
{
- trace ("pulse_init\n");
- state = OUTPUT_STATE_STOPPED;
- pulse_terminate = 0;
+ memcpy (&plugin.fmt, fmt, sizeof (ddb_waveformat_t));
+ if (!plugin.fmt.channels) {
+ // generic format
+ plugin.fmt.bps = 16;
+ plugin.fmt.is_float = 0;
+ plugin.fmt.channels = 2;
+ plugin.fmt.samplerate = 44100;
+ plugin.fmt.channelmask = 3;
+ }
- // Read serveraddr from config
- const char * server = deadbeef->conf_get_str(CONFSTR_PULSE_SERVERADDR, NULL);
+ trace ("format %dbit %s %dch %dHz channelmask=%X\n", plugin.fmt.bps, plugin.fmt.is_float ? "float" : "int", plugin.fmt.channels, plugin.fmt.samplerate, plugin.fmt.channelmask);
- if (server)
- server = strcmp(server, "default") ? server : NULL;
+ ss.channels = plugin.fmt.channels;
+ // Try to auto-configure the channel map, see <pulse/channelmap.h> for details
+ pa_channel_map_init_extend(&channel_map, ss.channels, PA_CHANNEL_MAP_DEFAULT);
+ //pa_channel_map_init(&channel_map);
+ trace ("pulse: channels: %d\n", ss.channels);
// Read samplerate from config
- ss.rate = deadbeef->conf_get_int(CONFSTR_PULSE_SAMPLERATE, 44100);
+ //ss.rate = deadbeef->conf_get_int(CONFSTR_PULSE_SAMPLERATE, 44100);
+ ss.rate = plugin.fmt.samplerate;
trace ("pulse: samplerate: %d\n", ss.rate);
- // TODO: add config for this
- pa_channel_map * map = NULL;//pa_channel_map_init_stereo(NULL);
- ss.channels = 2;
- ss.format = PA_SAMPLE_S16NE;
+ switch (plugin.fmt.bps) {
+ case 8:
+ ss.format = PA_SAMPLE_U8;
+ break;
+ case 16:
+ ss.format = PA_SAMPLE_S16LE;
+ break;
+ case 24:
+ ss.format = PA_SAMPLE_S24LE;
+ break;
+ case 32:
+ if (plugin.fmt.is_float) {
+ ss.format = PA_SAMPLE_FLOAT32LE;
+ }
+ else {
+ ss.format = PA_SAMPLE_S32LE;
+ }
+ break;
+ default:
+ return -1;
+ };
- // TODO: where list of all available devices? add this option to config too..
- char * dev = NULL;
+ if (s) {
+ pa_simple_free(s);
+ }
pa_buffer_attr * attr = NULL;
//attr->maxlength = Maximum length of the buffer.
@@ -93,11 +135,42 @@ static int pulse_init(void)
buffer_size = deadbeef->conf_get_int(CONFSTR_PULSE_BUFFERSIZE, 4096);
+ // TODO: where list of all available devices? add this option to config too..
+ char * dev = NULL;
+
int error;
- s = pa_simple_new(server, "Deadbeef", PA_STREAM_PLAYBACK, dev, "Music", &ss, map, attr, &error);
+
+ // Read serveraddr from config
+ deadbeef->conf_lock ();
+ const char * server = deadbeef->conf_get_str_fast (CONFSTR_PULSE_SERVERADDR, NULL);
+
+ if (server) {
+ server = strcmp(server, "default") ? server : NULL;
+ }
+
+ s = pa_simple_new(server, "Deadbeef", PA_STREAM_PLAYBACK, dev, "Music", &ss, &channel_map, attr, &error);
+ deadbeef->conf_unlock ();
if (!s)
{
+ trace ("pulse_init failed (%d)\n", error);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int pulse_init(void)
+{
+ trace ("pulse_init\n");
+ state = OUTPUT_STATE_STOPPED;
+ pulse_terminate = 0;
+
+ if (requested_fmt.samplerate != 0) {
+ memcpy (&plugin.fmt, &requested_fmt, sizeof (ddb_waveformat_t));
+ }
+
+ if (0 != pulse_set_spec(&plugin.fmt)) {
return -1;
}
@@ -106,6 +179,42 @@ static int pulse_init(void)
return 0;
}
+static int pulse_setformat (ddb_waveformat_t *fmt)
+{
+ memcpy (&requested_fmt, fmt, sizeof (ddb_waveformat_t));
+ if (!s) {
+ return -1;
+ }
+ if (!memcmp (fmt, &plugin.fmt, sizeof (ddb_waveformat_t))) {
+ trace ("pulse_setformat ignored\n");
+ return 0;
+ }
+ trace ("pulse_setformat %dbit %s %dch %dHz channelmask=%X\n", fmt->bps, fmt->is_float ? "float" : "int", fmt->channels, fmt->samplerate, fmt->channelmask);
+
+ int prev_state = state;
+ pulse_stop ();
+ deadbeef->mutex_lock(mutex);
+ pulse_set_spec(fmt);
+ deadbeef->mutex_unlock(mutex);
+ trace ("new format %dbit %s %dch %dHz channelmask=%X\n", plugin.fmt.bps, plugin.fmt.is_float ? "float" : "int", plugin.fmt.channels, plugin.fmt.samplerate, plugin.fmt.channelmask);
+
+ switch (prev_state) {
+ case OUTPUT_STATE_STOPPED:
+ return pulse_stop ();
+ case OUTPUT_STATE_PLAYING:
+ return pulse_play ();
+ case OUTPUT_STATE_PAUSED:
+ if (0 != pulse_play ()) {
+ return -1;
+ }
+ if (0 != pulse_pause ()) {
+ return -1;
+ }
+ break;
+ }
+ return 0;
+}
+
static int pulse_free(void)
{
trace("pulse_free\n");
@@ -118,7 +227,7 @@ static int pulse_free(void)
pulse_tid = 0;
state = OUTPUT_STATE_STOPPED;
- if (s != NULL)
+ if (s)
{
pa_simple_free(s);
s = NULL;
@@ -170,41 +279,6 @@ static int pulse_unpause(void)
return 0;
}
-static int pulse_change_rate(int rate)
-{
- pulse_free();
- ss.rate = rate;
-
- if (!pulse_init())
- return -1;
-
- return ss.rate;
-}
-
-static int pulse_get_rate(void)
-{
- return ss.rate;
-}
-
-static int pulse_get_bps(void)
-{
- return 16;
-}
-
-static int pulse_get_channels(void)
-{
- return ss.channels;
-}
-
-static int pulse_get_endianness(void)
-{
-#if WORDS_BIGENDIAN
- return 1;
-#else
- return 0;
-#endif
-}
-
static void pulse_thread(void *context)
{
#ifdef __linux__
@@ -219,7 +293,14 @@ static void pulse_thread(void *context)
continue;
}
- char buf[buffer_size];
+ int sample_size = plugin.fmt.channels * (plugin.fmt.bps / 8);
+ int bs = buffer_size;
+ int mod = bs % sample_size;
+ if (mod > 0) {
+ bs -= mod;
+ }
+
+ char buf[bs];
pulse_callback (buf, sizeof (buf));
int error;
@@ -240,13 +321,6 @@ static void pulse_thread(void *context)
static void pulse_callback(char *stream, int len)
{
int bytesread = deadbeef->streamer_read(stream, len);
- int16_t ivolume = deadbeef->volume_get_amp() * 1000;
-
- for (int i = 0; i < bytesread/2; i++)
- {
- ((int16_t*)stream)[i] = (int16_t)(((int32_t)(((int16_t*)stream)[i])) * ivolume / 1000);
- }
-
if (bytesread < len)
{
memset (stream + bytesread, 0, len-bytesread);
@@ -280,34 +354,45 @@ DB_plugin_t * pulse_load(DB_functions_t *api)
static const char settings_dlg[] =
"property \"PulseAudio server\" entry " CONFSTR_PULSE_SERVERADDR " default;\n"
- "property \"Preferred buffer size\" entry " CONFSTR_PULSE_BUFFERSIZE " 4096;\n"
- "property \"Samplerate\" entry " CONFSTR_PULSE_SAMPLERATE " 44100;\n";
+ "property \"Preferred buffer size\" entry " CONFSTR_PULSE_BUFFERSIZE " 4096;\n";
static DB_output_t plugin =
{
DB_PLUGIN_SET_API_VERSION
.plugin.version_major = 0,
.plugin.version_minor = 1,
- .plugin.nostop = 0,
.plugin.type = DB_PLUGIN_OUTPUT,
+ .plugin.id = "pulseaudio",
.plugin.name = "PulseAudio output plugin",
- .plugin.descr = "plays sound via pulse API",
- .plugin.author = "Anton Novikov",
- .plugin.email = "tonn.post@gmail.com",
+ .plugin.descr = "At the moment of this writing, PulseAudio seems to be very unstable in many (or most) GNU/Linux distributions.\nIf you experience problems - please try switching to ALSA or OSS output.\nIf that doesn't help - please uninstall PulseAudio from your system, and try ALSA or OSS again.\nThanks for understanding",
+ .plugin.copyright =
+ "Copyright (C) 2011 Jan D. Behrens <zykure@web.de>\n"
+ "Copyright (C) 2010-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "Copyright (C) 2010 Anton Novikov <tonn.post@gmail.com>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n",
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = pulse_plugin_start,
.plugin.stop = pulse_plugin_stop,
.plugin.configdialog = settings_dlg,
.init = pulse_init,
.free = pulse_free,
- .change_rate = pulse_change_rate,
+ .setformat = pulse_setformat,
.play = pulse_play,
.stop = pulse_stop,
.pause = pulse_pause,
.unpause = pulse_unpause,
.state = pulse_get_state,
- .samplerate = pulse_get_rate,
- .bitspersample = pulse_get_bps,
- .channels = pulse_get_channels,
- .endianness = pulse_get_endianness,
};
diff --git a/plugins/shellexec/Makefile.am b/plugins/shellexec/Makefile.am
index 65d6a5b8..212f6a0b 100644
--- a/plugins/shellexec/Makefile.am
+++ b/plugins/shellexec/Makefile.am
@@ -4,6 +4,6 @@ pkglib_LTLIBRARIES = shellexec.la
shellexec_la_SOURCES = shellexec.c
shellexec_la_LDFLAGS = -module
-shellexec_la_LIBADD = $(LDADD) $(HOTKEYS_LIBS)
+shellexec_la_LIBADD = $(LDADD)
AM_CFLAGS = $(CFLAGS) -std=c99
endif
diff --git a/plugins/shellexec/shellexec.c b/plugins/shellexec/shellexec.c
index e8298cab..a2c60af4 100644
--- a/plugins/shellexec/shellexec.c
+++ b/plugins/shellexec/shellexec.c
@@ -1,5 +1,6 @@
/*
Shellexec plugin for DeaDBeeF
+ Copyright (C) 2010-2011 Alexey Yakovenko <waker@users.sf.net>
Copyright (C) 2010 Viktor Semykin <thesame.ml@gmail.com>
This program is free software: you can redistribute it and/or modify
@@ -101,7 +102,7 @@ shx_callback (Shx_action_t *action, DB_playItem_t *it)
static DB_plugin_action_t *
shx_get_actions (DB_playItem_t *it)
{
- int is_local = it ? deadbeef->is_local_file (it->fname) : 1;
+ int is_local = it ? deadbeef->is_local_file (deadbeef->pl_find_meta (it, ":URI")) : 1;
Shx_action_t *action;
for (action = actions; action; action = (Shx_action_t *)action->parent.next)
@@ -200,12 +201,30 @@ shx_start ()
static DB_misc_t plugin = {
.plugin.api_vmajor = DB_API_VERSION_MAJOR,
.plugin.api_vminor = DB_API_VERSION_MINOR,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_MISC,
.plugin.id = "shellexec",
.plugin.name = "Shell commands",
.plugin.descr = "Executes configurable shell commands for tracks",
- .plugin.author = "Viktor Semykin",
- .plugin.email = "thesame.ml@gmail.com",
+ .plugin.copyright =
+ "Copyright (C) 2010-2011 Alexey Yakovenko <waker@users.sf.net>\n"
+ "Copyright (C) 2010 Viktor Semykin <thesame.ml@gmail.com>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = shx_start,
.plugin.get_actions = shx_get_actions
diff --git a/plugins/shn/Makefile b/plugins/shn/Makefile
new file mode 100644
index 00000000..7ce0e430
--- /dev/null
+++ b/plugins/shn/Makefile
@@ -0,0 +1,22 @@
+OUT=shn.so
+
+CC=gcc
+
+CFLAGS+=-Wall -fPIC -std=c99 -D_GNU_SOURCE -DHAVE_CONFIG_H -I. -I../..
+
+LDFLAGS+=-module -shared -lm
+
+SOURCES=array.c convert.c misc.c output.c seek.c shn.c shorten.c sulawalaw.c vario.c wave.c
+
+OBJECTS=$(SOURCES:.c=.o)
+
+all: $(SOURCES) $(OUT)
+
+$(OUT): $(OBJECTS)
+ $(CC) $(LDFLAGS) $(OBJECTS) -o $@
+
+.c.o:
+ $(CC) $(CFLAGS) $< -c -o $@
+
+clean:
+ rm $(OBJECTS) $(OUT)
diff --git a/plugins/shn/Makefile.am b/plugins/shn/Makefile.am
deleted file mode 100644
index 335dacff..00000000
--- a/plugins/shn/Makefile.am
+++ /dev/null
@@ -1,10 +0,0 @@
-if HAVE_SHN
-shndir = $(libdir)/$(PACKAGE)
-pkglib_LTLIBRARIES = shn.la
-shn_la_SOURCES = array.c convert.c misc.c output.c seek.c shn.c shn.h shorten.c shorten.h sulawalaw.c vario.c wave.c bitshift.h
-
-shn_la_LDFLAGS = -module
-
-shn_la_LIBADD = $(LDADD) -lm
-AM_CFLAGS = $(CFLAGS) -std=c99
-endif
diff --git a/plugins/shn/shn.c b/plugins/shn/shn.c
index 1d44f6e8..4a90583c 100644
--- a/plugins/shn/shn.c
+++ b/plugins/shn/shn.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -33,11 +33,6 @@ static DB_decoder_t plugin;
DB_functions_t *deadbeef;
shn_file *load_shn(const char *filename);
-static void shn_play(char *);
-static void shn_stop(void);
-static int shn_get_time(void);
-static void shn_get_file_info(char *,char **,int *);
-static void shn_display_file_info(char *);
typedef struct {
DB_fileinfo_t info;
@@ -67,7 +62,7 @@ typedef struct {
shn_config shn_cfg;
DB_fileinfo_t *
-shn_open (void) {
+shn_open (uint32_t hints) {
DB_fileinfo_t *_info = malloc (sizeof (shn_fileinfo_t));
shn_fileinfo_t *info = (shn_fileinfo_t *)_info;
memset (info, 0, sizeof (shn_fileinfo_t));
@@ -311,8 +306,9 @@ shn_init_decoder (shn_fileinfo_t *info) {
static void
shn_init_config (void) {
shn_cfg.error_output_method = ERROR_OUTPUT_DEVNULL;
- strncpy (shn_cfg.seek_tables_path, deadbeef->conf_get_str ("shn.seektable_path", ""), sizeof (shn_cfg.seek_tables_path));
- strncpy (shn_cfg.relative_seek_tables_path, deadbeef->conf_get_str ("shn.relative_seektable_path", "seektables"), sizeof (shn_cfg.relative_seek_tables_path));
+
+ deadbeef->conf_get_str ("shn.seektable_path", "", shn_cfg.seek_tables_path, sizeof (shn_cfg.seek_tables_path));
+ deadbeef->conf_get_str ("shn.relative_seektable_path", "seektables", shn_cfg.relative_seek_tables_path, sizeof (shn_cfg.relative_seek_tables_path));
shn_cfg.verbose = 0;
shn_cfg.swap_bytes = deadbeef->conf_get_int ("shn.swap_bytes", 0);
}
@@ -326,9 +322,9 @@ shn_init(DB_fileinfo_t *_info, DB_playItem_t *it) {
char data[4];
DB_FILE *f;
- f = deadbeef->fopen (it->fname);
+ f = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!f) {
- trace ("shn: failed to open %s\n", it->fname);
+ trace ("shn: failed to open %s\n", deadbeef->pl_find_meta (it, ":URI"));
return -1;
}
@@ -340,7 +336,7 @@ shn_init(DB_fileinfo_t *_info, DB_playItem_t *it) {
if (deadbeef->fread((void *)data,1,4,f) != 4)
{
deadbeef->fclose(f);
- trace ("shn: failed to read magic from %s\n", it->fname);
+ trace ("shn: failed to read magic from %s\n", deadbeef->pl_find_meta (it, ":URI"));
return -1;
}
deadbeef->fclose(f);
@@ -350,14 +346,17 @@ shn_init(DB_fileinfo_t *_info, DB_playItem_t *it) {
return -1;
}
- if (!(info->shnfile = load_shn(it->fname))) {
+ if (!(info->shnfile = load_shn(deadbeef->pl_find_meta (it, ":URI")))) {
trace ("shn: load_shn failed\n");
return -1;
}
- _info->bps = info->shnfile->wave_header.bits_per_sample;
- _info->channels = info->shnfile->wave_header.channels;
- _info->samplerate = info->shnfile->wave_header.samples_per_sec;
+ _info->fmt.bps = info->shnfile->wave_header.bits_per_sample;
+ _info->fmt.channels = info->shnfile->wave_header.channels;
+ _info->fmt.samplerate = info->shnfile->wave_header.samples_per_sec;
+ for (int i = 0; i < _info->fmt.channels; i++) {
+ _info->fmt.channelmask |= 1 << i;
+ }
_info->plugin = &plugin;
int totalsamples = info->shnfile->wave_header.length * info->shnfile->wave_header.samples_per_sec;
@@ -732,22 +731,21 @@ shn_decode (shn_fileinfo_t *info) {
}
int
-shn_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
+shn_read (DB_fileinfo_t *_info, char *bytes, int size) {
shn_fileinfo_t *info = (shn_fileinfo_t *)_info;
- if (info->currentsample + size / (2 * _info->channels) > info->endsample) {
- size = (info->endsample - info->currentsample + 1) * 2 * _info->channels;
+ int samplesize = _info->fmt.channels * _info->fmt.bps / 8;
+ if (info->currentsample + size / samplesize > info->endsample) {
+ size = (info->endsample - info->currentsample + 1) * samplesize;
if (size <= 0) {
return 0;
}
}
int initsize = size;
- int ch = min (_info->channels, 2);
- int sample_size = ch * (_info->bps >> 3);
while (size > 0) {
if (info->shnfile->vars.bytes_in_buf > 0) {
- int n = size / sample_size;
- int nsamples = info->shnfile->vars.bytes_in_buf / (_info->channels * 2);
+ int n = size / samplesize;
+ int nsamples = info->shnfile->vars.bytes_in_buf / samplesize;
if (info->skipsamples > 0) {
int nskip = min(nsamples, info->skipsamples);
info->skipsamples -= nskip;
@@ -756,26 +754,23 @@ shn_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
continue;
}
else {
- memmove (info->shnfile->vars.buffer, info->shnfile->vars.buffer + nskip * (_info->channels * 2), info->shnfile->vars.bytes_in_buf - nskip * (_info->channels * 2));
+ memmove (info->shnfile->vars.buffer, info->shnfile->vars.buffer + nskip * samplesize, info->shnfile->vars.bytes_in_buf - nskip * samplesize);
nsamples -= nskip;
continue;
}
}
n = min (nsamples, n);
- char *src = info->shnfile->vars.buffer;
- for (int i = 0; i < n; i++) {
- memcpy (bytes, src, sample_size);
- bytes += sample_size;
- src += _info->channels * 2;
- }
-
- size -= n * sample_size;
- if (n == info->shnfile->vars.bytes_in_buf / (_info->channels * 2)) {
+ char *src = (char *)info->shnfile->vars.buffer;
+ memcpy (bytes, src, samplesize * n);
+ src += samplesize * n;
+ bytes += samplesize * n;
+ size -= n * samplesize;
+ if (n == info->shnfile->vars.bytes_in_buf / samplesize) {
info->shnfile->vars.bytes_in_buf = 0;
}
else {
- memmove (info->shnfile->vars.buffer, src, info->shnfile->vars.bytes_in_buf - n * (_info->channels * 2));
- info->shnfile->vars.bytes_in_buf -= n * (_info->channels * 2);
+ memmove (info->shnfile->vars.buffer, src, info->shnfile->vars.bytes_in_buf - n * samplesize);
+ info->shnfile->vars.bytes_in_buf -= n * samplesize;
}
continue;
}
@@ -785,7 +780,7 @@ shn_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
}
}
- info->currentsample += (initsize-size) / sample_size;
+ info->currentsample += (initsize-size) / samplesize;
if (size != 0) {
trace ("shn_read_int16 eof\n");
}
@@ -798,7 +793,7 @@ shn_seek_sample (DB_fileinfo_t *_info, int sample) {
sample += info->startsample;
- info->shnfile->vars.seek_to = sample / _info->samplerate;
+ info->shnfile->vars.seek_to = sample / _info->fmt.samplerate;
if (info->shnfile->vars.seek_table_entries == NO_SEEK_TABLE) {
// seek by skipping samples from the start
@@ -814,7 +809,7 @@ shn_seek_sample (DB_fileinfo_t *_info, int sample) {
}
info->skipsamples = sample;
}
- info->currentsample = info->shnfile->vars.seek_to * _info->samplerate;
+ info->currentsample = info->shnfile->vars.seek_to * _info->fmt.samplerate;
_info->readpos = info->shnfile->vars.seek_to;
return 0;
}
@@ -853,14 +848,14 @@ shn_seek_sample (DB_fileinfo_t *_info, int sample) {
info->shnfile->vars.bytes_in_buf = 0;
- info->currentsample = info->shnfile->vars.seek_to * _info->samplerate;
+ info->currentsample = info->shnfile->vars.seek_to * _info->fmt.samplerate;
_info->readpos = info->shnfile->vars.seek_to;
return 0;
}
int
shn_seek (DB_fileinfo_t *_info, float time) {
- return shn_seek_sample (_info, time * _info->samplerate);
+ return shn_seek_sample (_info, time * _info->fmt.samplerate);
return 0;
}
@@ -874,6 +869,7 @@ shn_insert (DB_playItem_t *after, const char *fname) {
if (!f) {
return NULL;
}
+ int64_t fsize = deadbeef->fgetlength (f);
int id3v2_tag_size = deadbeef->junk_get_leading_size (f);
if (id3v2_tag_size > 0) {
@@ -898,10 +894,8 @@ shn_insert (DB_playItem_t *after, const char *fname) {
return NULL;
}
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (fname);
- it->filetype = "Shorten";
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
+ deadbeef->pl_add_meta (it, ":FILETYPE", "Shorten");
deadbeef->pl_set_item_duration (it, tmp_file->wave_header.length);
int apeerr = deadbeef->junk_apev2_read (it, tmp_file->vars.fd);
@@ -910,6 +904,18 @@ shn_insert (DB_playItem_t *after, const char *fname) {
shn_unload(tmp_file);
+ char s[100];
+ snprintf (s, sizeof (s), "%lld", fsize);
+ deadbeef->pl_add_meta (it, ":FILE_SIZE", s);
+ snprintf (s, sizeof (s), "%d", tmp_file->wave_header.bits_per_sample);
+ deadbeef->pl_add_meta (it, ":BPS", s);
+ snprintf (s, sizeof (s), "%d", tmp_file->wave_header.channels);
+ deadbeef->pl_add_meta (it, ":CHANNELS", s);
+ snprintf (s, sizeof (s), "%d", tmp_file->wave_header.samples_per_sec);
+ deadbeef->pl_add_meta (it, ":SAMPLERATE", s);
+ int br = (int)roundf(fsize / (float)tmp_file->wave_header.length * 8 / 1000);
+ snprintf (s, sizeof (s), "%d", br);
+ deadbeef->pl_add_meta (it, ":BITRATE", s);
deadbeef->pl_add_meta (it, "title", NULL);
after = deadbeef->pl_insert_item (after, it);
@@ -1792,20 +1798,38 @@ static const char settings_dlg[] =
// define plugin interface
static DB_decoder_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.id = "shn",
- .plugin.name = "SHN player",
- .plugin.descr = "SHN player based on xmms-shn",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.name = "Shorten player",
+ .plugin.descr = "decodes shn files",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "Based on xmms-shn, http://www.etree.org/shnutils/xmms-shn/\n"
+ "Copyright (C) 2000-2007 Jason Jordan <shnutils@freeshell.org>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.configdialog = settings_dlg,
.open = shn_open,
.init = shn_init,
.free = shn_free,
- .read_int16 = shn_read_int16,
+ .read = shn_read,
.seek = shn_seek,
.seek_sample = shn_seek_sample,
.insert = shn_insert,
diff --git a/plugins/sid/Makefile.am b/plugins/sid/Makefile.am
index 38caa014..f5408088 100644
--- a/plugins/sid/Makefile.am
+++ b/plugins/sid/Makefile.am
@@ -103,9 +103,9 @@ sidplay-libs/libsidplay/src/kernal.bin\
sidplay-libs/libsidplay/src/psiddrv.bin\
sidplay-libs/libsidplay/src/poweron.bin
-sid_la_LIBADD = -lstdc++
-sid_la_LDFLAGS = -module
+sid_la_LDFLAGS = -module -nostdlib -lsupc++
AM_CFLAGS = $(CFLAGS) -std=c99 -I$(sidpath)/libsidplay/include -I$(sidpath)/builders/resid-builder/include -fPIC
-AM_CPPFLAGS = $(CXXFLAGS) -DHAVE_UNIX -I$(sidpath) -I$(sidpath)/unix -I$(sidpath)/libsidplay -I$(sidpath)/libsidplay/include -I$(sidpath)/libsidplay/include/sidplay -I$(sidpath)/libsidutils/include/sidplay/utils -I$(sidpath)/builders/resid-builder/include/sidplay/builders -I$(sidpath)/builders/resid-builder/include -DHAVE_STRCASECMP -DHAVE_STRNCASECMP
+AM_CPPFLAGS = $(CXXFLAGS) -DHAVE_UNIX -I$(sidpath) -I$(sidpath)/unix -I$(sidpath)/libsidplay -I$(sidpath)/libsidplay/include -I$(sidpath)/libsidplay/include/sidplay -I$(sidpath)/libsidutils/include/sidplay/utils -I$(sidpath)/builders/resid-builder/include/sidplay/builders -I$(sidpath)/builders/resid-builder/include -DHAVE_STRCASECMP -DHAVE_STRNCASECMP -fno-exceptions -fno-rtti -fno-unwind-tables
+
endif
diff --git a/plugins/sid/csid.cpp b/plugins/sid/csid.cpp
index ccb2ecb3..ffdd4548 100644
--- a/plugins/sid/csid.cpp
+++ b/plugins/sid/csid.cpp
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -34,12 +34,26 @@
#include "../../deadbeef.h"
#include "csid.h"
+#ifndef ANDROID
+int _Unwind_Resume_or_Rethrow;
+int _Unwind_RaiseException;
+int _Unwind_GetLanguageSpecificData;
+int _Unwind_Resume;
+int _Unwind_DeleteException;
+int _Unwind_GetTextRelBase;
+int _Unwind_SetIP;
+int _Unwind_GetDataRelBase;
+int _Unwind_GetRegionStart;
+int _Unwind_SetGR;
+int _Unwind_GetIPInfo;
+#endif
+
extern DB_decoder_t sid_plugin;
//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
#define trace(fmt,...)
-static DB_functions_t *deadbeef;
+DB_functions_t *deadbeef;
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
@@ -94,8 +108,9 @@ sldb_load()
sldb_disable = 1;
return;
}
- const char *conf_hvsc_path = deadbeef->conf_get_str ("hvsc_path", NULL);
- if (!conf_hvsc_path) {
+ char conf_hvsc_path[1000];
+ deadbeef->conf_get_str ("hvsc_path", "", conf_hvsc_path, sizeof (conf_hvsc_path));
+ if (!conf_hvsc_path[0]) {
sldb_disable = 1;
return;
}
@@ -276,7 +291,7 @@ sldb_find (const uint8_t *digest) {
}
DB_fileinfo_t *
-csid_open (void) {
+csid_open (uint32_t hints) {
DB_fileinfo_t *_info = (DB_fileinfo_t *)malloc (sizeof (sid_info_t));
memset (_info, 0, sizeof (sid_info_t));
return _info;
@@ -288,26 +303,28 @@ csid_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
// libsidplay crashes if file doesn't exist
// so i have to check it here
- FILE *fp = fopen (it->fname, "rb");
+ DB_FILE *fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!fp ){
return -1;
}
- fclose (fp);
+ deadbeef->fclose (fp);
info->sidplay = new sidplay2;
info->resid = new ReSIDBuilder ("wtf");
info->resid->create (info->sidplay->info ().maxsids);
-// resid->create (1);
info->resid->filter (true);
int samplerate = deadbeef->conf_get_int ("sid.samplerate", 44100);
- int bps = deadbeef->get_output ()->bitspersample ();
+ int bps = deadbeef->conf_get_int ("sid.bps", 16);
+ if (bps != 16 && bps != 8) {
+ bps = 16;
+ }
info->resid->sampling (samplerate);
info->duration = deadbeef->pl_get_item_duration (it);
- info->tune = new SidTune (it->fname);
+ info->tune = new SidTune (deadbeef->pl_find_meta (it, ":URI"));
- info->tune->selectSong (it->tracknum+1);
+ info->tune->selectSong (deadbeef->pl_find_meta_int (it, ":TRACKNUM", 0)+1);
sid2_config_t conf;
conf = info->sidplay->config ();
conf.frequency = samplerate;
@@ -319,9 +336,10 @@ csid_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
info->sidplay->load (info->tune);
_info->plugin = &sid_plugin;
- _info->channels = info->tune->isStereo () ? 2 : 1;
- _info->bps = bps;
- _info->samplerate = conf.frequency;
+ _info->fmt.channels = conf.playback == sid2_stereo ? 2 : 1;
+ _info->fmt.bps = bps;
+ _info->fmt.samplerate = conf.frequency;
+ _info->fmt.channelmask = _info->fmt.channels == 1 ? DDB_SPEAKER_FRONT_LEFT : (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT);
_info->readpos = 0;
int maxsids = info->sidplay->info ().maxsids;
@@ -354,24 +372,15 @@ csid_read (DB_fileinfo_t *_info, char *bytes, int size) {
if (_info->readpos > info->duration) {
return 0;
}
- int rd = info->sidplay->play (bytes, size/_info->channels);
- _info->readpos += size/_info->channels/2 / (float)_info->samplerate;
-#if 0
-#if WORDS_BIGENDIAN
- // convert samples from le to be
- int n = rd * _info->channels/2;
- int16_t *ptr = (int16_t *)bytes;
- while (n > 0) {
- int16_t out;
- le_int16 (*ptr, (unsigned char *)&out);
- *ptr = out;
- ptr++;
- n--;
- }
-#endif
-#endif
- return rd * _info->channels;
+ int rd = info->sidplay->play (bytes, size);
+
+ int samplesize = (_info->fmt.bps>>3) * _info->fmt.channels;
+
+ _info->readpos += rd / samplesize / (float)_info->fmt.samplerate;
+
+ return size;
+
}
int
@@ -386,11 +395,11 @@ csid_seek (DB_fileinfo_t *_info, float time) {
t -= _info->readpos;
}
info->resid->filter (false);
- int samples = t * _info->samplerate;
- samples *= 2 * _info->channels;
- uint16_t buffer[2048 * _info->channels];
+ int samples = t * _info->fmt.samplerate;
+ samples *= (_info->fmt.bps>>3) * _info->fmt.channels;
+ uint16_t buffer[2048 * _info->fmt.channels];
while (samples > 0) {
- int n = min (samples, 2048) * _info->channels;
+ int n = min (samples, 2048) * _info->fmt.channels;
int done = info->sidplay->play (buffer, n);
if (done < n) {
trace ("sid seek failure\n");
@@ -478,15 +487,13 @@ csid_insert (DB_playItem_t *after, const char *fname) {
// Include number of songs.
endian_little16 (tmp,tune->getInfo ().songs);
myMD5.append (tmp,sizeof(tmp));
- { // Include song speed for each song.
- //uint_least16_t currentSong = tune->getInfo ().currentSong;
+ {
+ // Include song speed for each song.
for (uint_least16_t s = 1; s <= tune->getInfo ().songs; s++)
{
tune->selectSong (s);
myMD5.append (&tune->getInfo ().songSpeed,1);
}
- // Restore old song
- //tune->selectSong (currentSong);
}
// Deal with PSID v2NG clock speed flags: Let only NTSC
// clock speed change the MD5 fingerprint. That way the
@@ -499,7 +506,6 @@ csid_insert (DB_playItem_t *after, const char *fname) {
memcpy (sig, myMD5.getDigest (), 16);
#endif
-// sldb_load ();
int song = -1;
if (sldb_loaded) {
song = sldb_find (sig);
@@ -509,10 +515,8 @@ csid_insert (DB_playItem_t *after, const char *fname) {
for (int s = 0; s < tunes; s++) {
trace ("select %d...\n", s);
if (tune->selectSong (s+1)) {
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (sid_plugin.plugin.id);
- it->fname = strdup (fname);
- it->tracknum = s;
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, sid_plugin.plugin.id);
+ deadbeef->pl_set_meta_int (it, ":TRACKNUM", s);
SidTuneInfo sidinfo;
tune->getInfo (sidinfo);
int i = sidinfo.numberOfInfoStrings;
@@ -549,7 +553,7 @@ csid_insert (DB_playItem_t *after, const char *fname) {
deadbeef->pl_add_meta (it, "title", NULL);
}
- float length = 120;
+ float length = deadbeef->conf_get_float ("sid.defaultlength", 180);
if (sldb_loaded) {
if (song >= 0 && sldb->sldb_lengths[song][s] >= 0) {
length = sldb->sldb_lengths[song][s];
@@ -563,7 +567,7 @@ csid_insert (DB_playItem_t *after, const char *fname) {
// }
}
deadbeef->pl_set_item_duration (it, length);
- it->filetype = "SID";
+ deadbeef->pl_add_meta (it, ":FILETYPE", "SID");
after = deadbeef->pl_insert_item (after, it);
deadbeef->pl_item_unref (it);
diff --git a/plugins/sid/csid.h b/plugins/sid/csid.h
index 273daa2c..c35be3d7 100644
--- a/plugins/sid/csid.h
+++ b/plugins/sid/csid.h
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -23,7 +23,7 @@
extern "C" {
#endif
-DB_fileinfo_t *csid_open (void);
+DB_fileinfo_t *csid_open (uint32_t hints);
int csid_init (DB_fileinfo_t *_info, DB_playItem_t *it);
void csid_free (DB_fileinfo_t *);
int csid_read (DB_fileinfo_t *, char *bytes, int size);
diff --git a/plugins/sid/plugin.c b/plugins/sid/plugin.c
index 9a2e9a27..c8f1f7b0 100644
--- a/plugins/sid/plugin.c
+++ b/plugins/sid/plugin.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -22,21 +22,42 @@ static const char *exts[] = { "sid",NULL };
const char *filetypes[] = { "SID", NULL };
static const char settings_dlg[] =
- "property \"Enable HVSC\" checkbox hvsc_enable 0;\n"
- "property \"HVSC path\" file hvsc_path \"\";\n"
- "property \"Samplerate\" entry sid.samplerate 48000;\n"
+ "property \"Enable HVSC Songlength DB\" checkbox hvsc_enable 0;\n"
+ "property \"Songlengths.txt (from HVSC)\" file hvsc_path \"\";\n"
+ "property \"Samplerate\" entry sid.samplerate 44100;\n"
+ "property \"Bits per sample (8 or 16)\" entry sid.bps 16;\n"
+ "property \"Default song length (sec)\" entry sid.defaultlength 180;\n"
;
// define plugin interface
DB_decoder_t sid_plugin = {
DB_PLUGIN_SET_API_VERSION
.plugin.type = DB_PLUGIN_DECODER,
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.name = "SID decoder",
.plugin.descr = "SID player based on libsidplay2",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "Uses modified libsidplay2-2.1.0\n"
+ "Commodore 64 SID emulation library\n"
+ "Copyright (C) Simon White and other authors\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = csid_start,
.plugin.stop = csid_stop,
@@ -45,7 +66,7 @@ DB_decoder_t sid_plugin = {
.open = csid_open,
.init = csid_init,
.free = csid_free,
- .read_int16 = csid_read,
+ .read = csid_read,
.seek = csid_seek,
.seek_sample = NULL,
.insert = csid_insert,
diff --git a/plugins/sid/sidplay-libs/libsidplay/src/sidtune/SidTune.cpp b/plugins/sid/sidplay-libs/libsidplay/src/sidtune/SidTune.cpp
index 4dfba1d7..fdbd64e1 100644
--- a/plugins/sid/sidplay-libs/libsidplay/src/sidtune/SidTune.cpp
+++ b/plugins/sid/sidplay-libs/libsidplay/src/sidtune/SidTune.cpp
@@ -25,6 +25,7 @@
#include "sidendian.h"
#include "PP20.h"
#include <stdio.h>
+#include "../../../../../../../deadbeef.h"
#ifdef HAVE_EXCEPTIONS
# include <new>
@@ -32,6 +33,8 @@
#include <string.h>
#include <limits.h>
+extern DB_functions_t *deadbeef;
+
#if defined(HAVE_IOS_OPENMODE)
typedef std::ios::openmode openmode;
#else
@@ -252,7 +255,7 @@ bool SidTune::loadFile(const char* fileName, Buffer_sidtt<const uint_least8_t>&
Buffer_sidtt<uint_least8_t> fileBuf;
uint_least32_t fileLen = 0;
- FILE *fp = fopen (fileName, "rb");
+ DB_FILE *fp = deadbeef->fopen (fileName);
if (!fp)
{
@@ -261,9 +264,7 @@ bool SidTune::loadFile(const char* fileName, Buffer_sidtt<const uint_least8_t>&
}
else
{
- fseek (fp, 0, SEEK_END);
- fileLen = ftell (fp);
- rewind (fp);
+ fileLen = deadbeef->fgetlength(fp);
#ifdef HAVE_EXCEPTIONS
if ( !fileBuf.assign(new(std::nothrow) uint_least8_t[fileLen],fileLen) )
#else
@@ -274,7 +275,7 @@ bool SidTune::loadFile(const char* fileName, Buffer_sidtt<const uint_least8_t>&
return false;
}
uint_least32_t restFileLen = fileLen;
- int res = fread((char*)fileBuf.get()+(fileLen-restFileLen),1,restFileLen,fp);
+ int res = deadbeef->fread((char*)fileBuf.get()+(fileLen-restFileLen),1,restFileLen,fp);
if ( res != restFileLen )
{
info.statusString = SidTune::txt_cantLoadFile;
@@ -285,7 +286,7 @@ bool SidTune::loadFile(const char* fileName, Buffer_sidtt<const uint_least8_t>&
info.statusString = SidTune::txt_noErrors;
}
}
- fclose(fp);
+ deadbeef->fclose(fp);
if ( fileLen==0 )
{
info.statusString = SidTune::txt_empty;
diff --git a/plugins/sndfile/sndfile.c b/plugins/sndfile/sndfile.c
index ab1d1ee9..3af4616f 100644
--- a/plugins/sndfile/sndfile.c
+++ b/plugins/sndfile/sndfile.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -21,6 +21,8 @@
#endif
#include <string.h>
#include <sndfile.h>
+#include <math.h>
+#include <stdlib.h>
#include "../../deadbeef.h"
#define min(x,y) ((x)<(y)?(x):(y))
@@ -85,20 +87,78 @@ static SF_VIRTUAL_IO vfs = {
};
static DB_fileinfo_t *
-sndfile_open (void) {
+sndfile_open (uint32_t hints) {
DB_fileinfo_t *_info = malloc (sizeof (sndfile_info_t));
memset (_info, 0, sizeof (sndfile_info_t));
return _info;
}
+
+// taken from libsndfile
+#define ARRAY_LEN(x) ((int) (sizeof (x) / sizeof ((x) [0])))
+/* This stores which bit in dwChannelMask maps to which channel */
+static const struct chanmap_s
+{ int id ;
+ const char * name ;
+} channel_mask_bits [] =
+{ /* WAVEFORMATEXTENSIBLE doesn't distuingish FRONT_LEFT from LEFT */
+ { SF_CHANNEL_MAP_LEFT, "L" },
+ { SF_CHANNEL_MAP_RIGHT, "R" },
+ { SF_CHANNEL_MAP_CENTER, "C" },
+ { SF_CHANNEL_MAP_LFE, "LFE" },
+ { SF_CHANNEL_MAP_REAR_LEFT, "Ls" },
+ { SF_CHANNEL_MAP_REAR_RIGHT, "Rs" },
+ { SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER, "Lc" },
+ { SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER, "Rc" },
+ { SF_CHANNEL_MAP_REAR_CENTER, "Cs" },
+ { SF_CHANNEL_MAP_SIDE_LEFT, "Sl" },
+ { SF_CHANNEL_MAP_SIDE_RIGHT, "Sr" },
+ { SF_CHANNEL_MAP_TOP_CENTER, "Tc" },
+ { SF_CHANNEL_MAP_TOP_FRONT_LEFT, "Tfl" },
+ { SF_CHANNEL_MAP_TOP_FRONT_CENTER, "Tfc" },
+ { SF_CHANNEL_MAP_TOP_FRONT_RIGHT, "Tfr" },
+ { SF_CHANNEL_MAP_TOP_REAR_LEFT, "Trl" },
+ { SF_CHANNEL_MAP_TOP_REAR_CENTER, "Trc" },
+ { SF_CHANNEL_MAP_TOP_REAR_RIGHT, "Trr" },
+} ;
+
+
+static int
+wavex_gen_channel_mask (const int *chan_map, int channels)
+{ int chan, mask = 0, bit = -1, last_bit = -1 ;
+
+ if (chan_map == NULL)
+ return 0 ;
+
+ for (chan = 0 ; chan < channels ; chan ++)
+ { int k ;
+
+ for (k = bit + 1 ; k < ARRAY_LEN (channel_mask_bits) ; k++)
+ if (chan_map [chan] == channel_mask_bits [k].id)
+ { bit = k ;
+ break ;
+ } ;
+
+ /* Check for bad sequence. */
+ if (bit <= last_bit)
+ return 0 ;
+
+ mask += 1 << bit ;
+ last_bit = bit ;
+ } ;
+
+ return mask ;
+} /* wavex_gen_channel_mask */
+
+
static int
sndfile_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
sndfile_info_t *info = (sndfile_info_t*)_info;
SF_INFO inf;
- DB_FILE *fp = deadbeef->fopen (it->fname);
+ DB_FILE *fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!fp) {
- trace ("sndfile: failed to open %s\n", it->fname);
+ trace ("sndfile: failed to open %s\n", deadbeef->pl_find_meta (it, ":URI"));
return -1;
}
int fsize = deadbeef->fgetlength (fp);
@@ -114,27 +174,45 @@ sndfile_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
switch (inf.format&0x000f) {
case SF_FORMAT_PCM_S8:
case SF_FORMAT_PCM_U8:
- _info->bps = 8;
+ _info->fmt.bps = 8;
break;
case SF_FORMAT_PCM_16:
- _info->bps = 16;
+ _info->fmt.bps = 16;
break;
case SF_FORMAT_PCM_24:
- _info->bps = 24;
+ _info->fmt.bps = 24;
break;
- case SF_FORMAT_PCM_32:
case SF_FORMAT_FLOAT:
- _info->bps = 24;
+ _info->fmt.is_float = 1;
+ case SF_FORMAT_PCM_32:
+ _info->fmt.bps = 32;
break;
case SF_FORMAT_DOUBLE:
- _info->bps = 64;
+ fprintf (stderr, "[sndfile] 64 bit float input format is not supported (yet)\n");
+ return -1;
+// _info->fmt.bps = 64;
break;
default:
- _info->bps = 16;
+ fprintf (stderr, "[sndfile] unidentified input format: 0x%X\n", inf.format&0x000f);
+ return -1;
+ }
+
+ _info->fmt.channels = inf.channels;
+ _info->fmt.samplerate = inf.samplerate;
+
+ int channel_map [inf.channels];
+ int cmdres = sf_command (info->ctx, SFC_GET_CHANNEL_MAP_INFO, channel_map, sizeof (channel_map)) ;
+ if (cmdres != SF_FALSE) {
+ // channel map found, convert to channel mask
+ _info->fmt.channelmask = wavex_gen_channel_mask (channel_map, inf.channels);
+ }
+ else {
+ // channel map not found, generate from channel number
+ for (int i = 0; i < inf.channels; i++) {
+ _info->fmt.channelmask |= 1 << i;
+ }
}
- _info->channels = inf.channels;
- _info->samplerate = inf.samplerate;
_info->readpos = 0;
if (it->endsample > 0) {
info->startsample = it->startsample;
@@ -148,7 +226,9 @@ sndfile_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
info->endsample = inf.frames-1;
}
// hack bitrate
- float sec = (float)(info->endsample-info->startsample) / inf.samplerate;
+
+ int totalsamples = inf.frames;
+ float sec = (float)totalsamples / inf.samplerate;
if (sec > 0) {
info->bitrate = fsize / sec * 8 / 1000;
}
@@ -172,11 +252,11 @@ sndfile_free (DB_fileinfo_t *_info) {
}
static int
-sndfile_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
+sndfile_read (DB_fileinfo_t *_info, char *bytes, int size) {
sndfile_info_t *info = (sndfile_info_t*)_info;
- int out_ch = min (_info->channels, 2);
- if (size / (2 * out_ch) + info->currentsample > info->endsample) {
- size = (info->endsample - info->currentsample + 1) * 2 * out_ch;
+ int samplesize = _info->fmt.channels * _info->fmt.bps / 8;
+ if (size / samplesize + info->currentsample > info->endsample) {
+ size = (info->endsample - info->currentsample + 1) * samplesize;
trace ("sndfile: size truncated to %d bytes, cursample=%d, endsample=%d\n", size, info->currentsample, info->endsample);
if (size <= 0) {
return 0;
@@ -184,61 +264,12 @@ sndfile_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
}
int n = 0;
- if (out_ch != _info->channels) {
- // read into temp buffer, and downmix
- int nframes = size / out_ch / 2;
- int16_t buf[nframes * _info->channels];
- n = sf_readf_short (info->ctx, buf, nframes);
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < out_ch; j++) {
- ((int16_t *)bytes)[i * out_ch + j] = buf[i * _info->channels + j];
- }
- }
- }
- else {
- n = sf_readf_short (info->ctx, (short *)bytes, size/(2*_info->channels));
- }
+ n = sf_read_raw (info->ctx, (short *)bytes, size);
+ n /= samplesize;
info->currentsample += n;
-
- size = n * 2 * out_ch;
- _info->readpos = (float)(info->currentsample-info->startsample)/_info->samplerate;
- if (info->bitrate > 0) {
- deadbeef->streamer_set_bitrate (info->bitrate);
- }
- return size;
-}
-
-static int
-sndfile_read_float32 (DB_fileinfo_t *_info, char *bytes, int size) {
- sndfile_info_t *info = (sndfile_info_t*)_info;
- int out_ch = min (_info->channels, 2);
- if (size / (4 * out_ch) + info->currentsample > info->endsample) {
- size = (info->endsample - info->currentsample + 1) * 4 * out_ch;
- trace ("sndfile: size truncated to %d bytes, cursample=%d, endsample=%d\n", size, info->currentsample, info->endsample);
- if (size <= 0) {
- return 0;
- }
- }
- int n = 0;
- if (out_ch != _info->channels) {
- // read into temp buffer, and downmix
- int nframes = size / out_ch / 4;
- float buf[nframes * _info->channels];
- n = sf_readf_float (info->ctx, buf, nframes);
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < out_ch; j++) {
- ((float *)bytes)[i * out_ch + j] = buf[i * _info->channels + j];
- }
- }
- }
- else {
- n = sf_readf_float (info->ctx, (float *)bytes, size/(4*_info->channels));
- }
-
- info->currentsample += n;
- size = n * 4 * out_ch;
- _info->readpos = (float)(info->currentsample-info->startsample)/_info->samplerate;
+ size = n * samplesize;
+ _info->readpos = (float)(info->currentsample-info->startsample)/_info->fmt.samplerate;
if (info->bitrate > 0) {
deadbeef->streamer_set_bitrate (info->bitrate);
}
@@ -253,13 +284,13 @@ sndfile_seek_sample (DB_fileinfo_t *_info, int sample) {
return -1;
}
info->currentsample = ret;
- _info->readpos = (float)(info->currentsample - info->startsample) / _info->samplerate;
+ _info->readpos = (float)(info->currentsample - info->startsample) / _info->fmt.samplerate;
return 0;
}
static int
sndfile_seek (DB_fileinfo_t *_info, float sec) {
- return sndfile_seek_sample (_info, sec * _info->samplerate);
+ return sndfile_seek_sample (_info, sec * _info->fmt.samplerate);
}
static DB_playItem_t *
@@ -272,6 +303,7 @@ sndfile_insert (DB_playItem_t *after, const char *fname) {
trace ("sndfile: failed to open %s\n", fname);
return NULL;
}
+ int64_t fsize = deadbeef->fgetlength (info.file);
info.ctx = sf_open_virtual (&vfs, SFM_READ, &inf, &info);
if (!info.ctx) {
trace ("sndfile: sf_open failed");
@@ -284,14 +316,45 @@ sndfile_insert (DB_playItem_t *after, const char *fname) {
deadbeef->fclose (info.file);
float duration = (float)totalsamples / samplerate;
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (fname);
- it->filetype = "wav";
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
+ deadbeef->pl_add_meta (it, ":FILETYPE", "wav");
deadbeef->pl_set_item_duration (it, duration);
trace ("sndfile: totalsamples=%d, samplerate=%d, duration=%f\n", totalsamples, samplerate, duration);
+ char s[100];
+ snprintf (s, sizeof (s), "%lld", fsize);
+ deadbeef->pl_add_meta (it, ":FILE_SIZE", s);
+
+ int bps = -1;
+ switch (inf.format&0x000f) {
+ case SF_FORMAT_PCM_S8:
+ case SF_FORMAT_PCM_U8:
+ bps = 8;
+ break;
+ case SF_FORMAT_PCM_16:
+ bps = 16;
+ break;
+ case SF_FORMAT_PCM_24:
+ bps = 24;
+ break;
+ case SF_FORMAT_FLOAT:
+ case SF_FORMAT_PCM_32:
+ bps = 32;
+ break;
+ }
+
+ snprintf (s, sizeof (s), "%d", bps);
+ deadbeef->pl_add_meta (it, ":BPS", s);
+ snprintf (s, sizeof (s), "%d", inf.channels);
+ deadbeef->pl_add_meta (it, ":CHANNELS", s);
+ snprintf (s, sizeof (s), "%d", samplerate);
+ deadbeef->pl_add_meta (it, ":SAMPLERATE", s);
+ int br = (int)roundf(fsize / duration * 8 / 1000);
+ snprintf (s, sizeof (s), "%d", br);
+ deadbeef->pl_add_meta (it, ":BITRATE", s);
+
+
DB_playItem_t *cue_after = deadbeef->pl_insert_cue (after, it, totalsamples, samplerate);
if (cue_after) {
deadbeef->pl_item_unref (it);
@@ -306,31 +369,116 @@ sndfile_insert (DB_playItem_t *after, const char *fname) {
return after;
}
-static const char * exts[] = { "wav", "aif", "aiff", "snd", "au", "paf", "svx", "nist", "voc", "ircam", "w64", "mat4", "mat5", "pvf", "xi", "htk", "sds", "avr", "wavex", "sd2", "caf", "wve", NULL };
+#define DEFAULT_EXTS "wav;aif;aiff;snd;au;paf;svx;nist;voc;ircam;w64;mat4;mat5;pvf;xi;htk;sds;avr;wavex;sd2;caf;wve"
+
+#define EXT_MAX 100
+
+static char *exts[EXT_MAX] = {NULL};
static const char *filetypes[] = { "WAV", NULL };
+
+static void
+sndfile_init_exts (void) {
+ for (int i = 0; exts[i]; i++) {
+ free (exts[i]);
+ }
+ exts[0] = NULL;
+
+ int n = 0;
+ deadbeef->conf_lock ();
+ const char *new_exts = deadbeef->conf_get_str_fast ("sndfile.extensions", DEFAULT_EXTS);
+ while (*new_exts) {
+ if (n >= EXT_MAX) {
+ fprintf (stderr, "sndfile: too many extensions, max is %d\n", EXT_MAX);
+ break;
+ }
+ const char *e = new_exts;
+ while (*e && *e != ';') {
+ e++;
+ }
+ if (e != new_exts) {
+ char *ext = malloc (e-new_exts+1);
+ memcpy (ext, new_exts, e-new_exts);
+ ext[e-new_exts] = 0;
+ exts[n++] = ext;
+ }
+ if (*e == 0) {
+ break;
+ }
+ new_exts = e+1;
+ }
+ deadbeef->conf_unlock ();
+ exts[n] = NULL;
+}
+
+
+static int
+sndfile_on_configchanged (DB_event_t *ev, uintptr_t data) {
+ sndfile_init_exts ();
+ return 0;
+}
+
+static int
+sndfile_start (void) {
+ sndfile_init_exts ();
+ deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_CONFIGCHANGED, DB_CALLBACK (sndfile_on_configchanged), 0);
+ return 0;
+}
+
+static int
+sndfile_stop (void) {
+ deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_CONFIGCHANGED, DB_CALLBACK (sndfile_on_configchanged), 0);
+ for (int i = 0; exts[i]; i++) {
+ free (exts[i]);
+ }
+ exts[0] = NULL;
+ return 0;
+}
+
+static const char settings_dlg[] =
+ "property \"File Extensions (separate with ';')\" entry sndfile.extensions \"" DEFAULT_EXTS "\";\n"
+;
+
+
// define plugin interface
static DB_decoder_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.id = "sndfile",
- .plugin.name = "pcm player",
+ .plugin.name = "WAV/PCM player",
.plugin.descr = "wav/aiff player using libsndfile",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.open = sndfile_open,
.init = sndfile_init,
.free = sndfile_free,
- .read_int16 = sndfile_read_int16,
- .read_float32 = sndfile_read_float32,
+ .read = sndfile_read,
.seek = sndfile_seek,
.seek_sample = sndfile_seek_sample,
.insert = sndfile_insert,
- .exts = exts,
- .filetypes = filetypes
+ .exts = (const char **)exts,
+ .filetypes = filetypes,
+ .plugin.start = sndfile_start,
+ .plugin.stop = sndfile_stop,
+ .plugin.configdialog = settings_dlg,
};
DB_plugin_t *
diff --git a/plugins/soundtouch/Makefile b/plugins/soundtouch/Makefile
new file mode 100644
index 00000000..ce4a0ad0
--- /dev/null
+++ b/plugins/soundtouch/Makefile
@@ -0,0 +1,52 @@
+CC=gcc
+CXX=g++
+
+OUT=ddb_soundtouch.so
+
+soundtouch_path=soundtouch
+
+CFLAGS+=-Wall -g -D_GNU_SOURCE -I$(soundtouch_path)/include -I../../include -std=c99 -fPIC -msse2
+CXXFLAGS+=-Wall -g -D_GNU_SOURCE -I$(soundtouch_path)/include -I../../include -fPIC -msse2
+
+LDFLAGS+=-shared -lm
+
+SOURCES=plugin.c
+
+CXX_SOURCES=st.cpp\
+$(soundtouch_path)/source/SoundTouch/AAFilter.cpp\
+$(soundtouch_path)/source/SoundTouch/BPMDetect.cpp\
+$(soundtouch_path)/source/SoundTouch/cpu_detect_x86_gcc.cpp\
+$(soundtouch_path)/source/SoundTouch/FIFOSampleBuffer.cpp\
+$(soundtouch_path)/source/SoundTouch/FIRFilter.cpp\
+$(soundtouch_path)/source/SoundTouch/mmx_optimized.cpp\
+$(soundtouch_path)/source/SoundTouch/PeakFinder.cpp\
+$(soundtouch_path)/source/SoundTouch/RateTransposer.cpp\
+$(soundtouch_path)/source/SoundTouch/SoundTouch.cpp\
+$(soundtouch_path)/source/SoundTouch/sse_optimized.cpp\
+$(soundtouch_path)/source/SoundTouch/TDStretch.cpp
+
+HEADERS=st.h\
+$(soundtouch_path)/include/BPMDetect.h\
+$(soundtouch_path)/include/FIFOSampleBuffer.h\
+$(soundtouch_path)/include/FIFOSamplePipe.h\
+$(soundtouch_path)/include/soundtouch_config.h\
+$(soundtouch_path)/include/SoundTouch.h\
+$(soundtouch_path)/include/STTypes.h
+
+CXX_OBJECTS=$(CXX_SOURCES:.cpp=.o)
+OBJECTS=$(SOURCES:.c=.o)
+
+all: $(SOURCES) $(OUT)
+
+$(OUT): $(OBJECTS) $(CXX_OBJECTS)
+ $(CXX) $(LDFLAGS) $(OBJECTS) $(CXX_OBJECTS) -o $@
+
+.c.o: $(HEADERS)
+ $(CC) $(CFLAGS) $< -c -o $@
+
+.cpp.o: $(HEADERS)
+ $(CXX) $(CXXFLAGS) $< -c -o $@
+
+clean:
+ rm $(OBJECTS) $(CXX_OBJECTS) $(OUT)
+
diff --git a/plugins/soundtouch/plugin.c b/plugins/soundtouch/plugin.c
new file mode 100644
index 00000000..42b633ac
--- /dev/null
+++ b/plugins/soundtouch/plugin.c
@@ -0,0 +1,308 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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 <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "../../deadbeef.h"
+#include "st.h"
+
+enum {
+ ST_PARAM_TEMPO,
+ ST_PARAM_PITCH,
+ ST_PARAM_RATE,
+ ST_PARAM_USE_AA_FILTER,
+ ST_PARAM_AA_FILTER_LENGTH,
+ ST_PARAM_USE_QUICKSEEK,
+ ST_PARAM_SEQUENCE_MS,
+ ST_PARAM_SEEKWINDOW_MS,
+ ST_PARAM_SET_OUTPUT_SAMPLERATE,
+ ST_PARAM_COUNT
+};
+
+static DB_functions_t *deadbeef;
+static DB_dsp_t plugin;
+
+typedef struct {
+ ddb_dsp_context_t ctx;
+ void *st;
+ float tempo;
+ float pitch;
+ float rate;
+ int use_aa_filter;
+ int aa_filter_length;
+ int use_quickseek;
+ int sequence_ms;
+ int seekwindow_ms;
+ int set_output_samplerate;
+ int changed;
+} ddb_soundtouch_t;
+
+ddb_dsp_context_t*
+st_open (void) {
+ ddb_soundtouch_t *st = malloc (sizeof (ddb_soundtouch_t));
+ DDB_INIT_DSP_CONTEXT (st,ddb_soundtouch_t,&plugin);
+ st->st = st_alloc ();
+ st->changed = 1;
+ st->tempo = 0;
+ st->rate = 0;
+ st->pitch = 0;
+ st->use_aa_filter = 0;
+ st->aa_filter_length = 32;
+ st->use_quickseek = 0;
+ st->sequence_ms = 82;
+ st->seekwindow_ms = 28;
+ return (ddb_dsp_context_t *)st;
+}
+
+void
+st_close (ddb_dsp_context_t *_src) {
+ ddb_soundtouch_t *st = (ddb_soundtouch_t *)_src;
+ if (st->st) {
+ st_free (st->st);
+ }
+ free (st);
+}
+
+void
+st_reset (ddb_dsp_context_t *_src) {
+ ddb_soundtouch_t *st = (ddb_soundtouch_t *)_src;
+ st_clear (st->st);
+}
+
+int
+st_process (ddb_dsp_context_t *_src, float *samples, int nframes, int maxframes, ddb_waveformat_t *fmt, float *ratio) {
+ ddb_soundtouch_t *st = (ddb_soundtouch_t *)_src;
+ if (st->changed) {
+ if (st->set_output_samplerate > 0) {
+ st_set_rate_change (st->st, 0);
+ st_set_rate (st->st, fmt->samplerate / (float)st->set_output_samplerate);
+ }
+ else {
+ st_set_rate (st->st, 1);
+ st_set_rate_change (st->st, st->rate);
+ }
+ st_set_pitch_semi_tones (st->st, st->pitch);
+ st_set_tempo_change (st->st, st->tempo);
+ st_set_setting (st->st, SETTING_USE_AA_FILTER, st->use_aa_filter);
+ st_set_setting (st->st, SETTING_AA_FILTER_LENGTH, st->aa_filter_length);
+ st_set_setting (st->st, SETTING_USE_QUICKSEEK, st->use_quickseek);
+ st_set_setting (st->st, SETTING_SEQUENCE_MS, st->sequence_ms);
+ st_set_setting (st->st, SETTING_SEEKWINDOW_MS, st->seekwindow_ms);
+ st->changed = 0;
+ }
+ *ratio = (1.f + 0.01f * st->tempo);
+
+ if (st->set_output_samplerate > 0) {
+ fmt->samplerate = st->set_output_samplerate;
+ }
+ else {
+ *ratio *= (1.f + 0.01f * st->rate);
+ }
+
+ st_set_sample_rate (st->st, fmt->samplerate);
+ st_set_channels (st->st, fmt->channels);
+
+ st_put_samples (st->st, samples, nframes);
+ int nout = 0;
+ int n = 0;
+ do {
+ n = st_receive_samples (st->st, samples, maxframes);
+ maxframes -= n;
+ samples += n * fmt->channels;
+ nout += n;
+ } while (n != 0);
+
+ return nout;
+}
+
+const char *
+st_get_param_name (int p) {
+ switch (p) {
+ case ST_PARAM_TEMPO:
+ return "Tempo";
+ case ST_PARAM_PITCH:
+ return "Pitch";
+ case ST_PARAM_RATE:
+ return "Playback Rate";
+ case ST_PARAM_USE_AA_FILTER:
+ return "Use AA Filter";
+ case ST_PARAM_AA_FILTER_LENGTH:
+ return "AA Filter Length";
+ case ST_PARAM_USE_QUICKSEEK:
+ return "Use Quickseek";
+ case ST_PARAM_SEQUENCE_MS:
+ return "Time Stretch Sequence Length (ms)";
+ case ST_PARAM_SEEKWINDOW_MS:
+ return "Time Stretch Seek Window Length (ms)";
+ case ST_PARAM_SET_OUTPUT_SAMPLERATE:
+ return "Set Output Samplerate";
+ default:
+ fprintf (stderr, "st_param_name: invalid param index (%d)\n", p);
+ }
+ return NULL;
+}
+
+int
+st_num_params (void) {
+ return ST_PARAM_COUNT;
+}
+
+void
+st_set_param (ddb_dsp_context_t *ctx, int p, const char *val) {
+ ddb_soundtouch_t *st = (ddb_soundtouch_t *)ctx;
+ switch (p) {
+ case ST_PARAM_TEMPO:
+ st->tempo = atof (val);
+ st->changed = 1;
+ break;
+ case ST_PARAM_PITCH:
+ st->pitch = atof (val);
+ st->changed = 1;
+ break;
+ case ST_PARAM_RATE:
+ st->rate = atof (val);
+ st->changed = 1;
+ break;
+ case ST_PARAM_USE_AA_FILTER:
+ st->use_aa_filter = atoi (val);
+ st->changed = 1;
+ break;
+ case ST_PARAM_AA_FILTER_LENGTH:
+ st->aa_filter_length = atoi (val);
+ st->changed = 1;
+ break;
+ case ST_PARAM_USE_QUICKSEEK:
+ st->use_quickseek = atoi (val);
+ st->changed = 1;
+ break;
+ case ST_PARAM_SEQUENCE_MS:
+ st->sequence_ms = atoi (val);
+ st->changed = 1;
+ break;
+ case ST_PARAM_SEEKWINDOW_MS:
+ st->seekwindow_ms = atoi (val);
+ st->changed = 1;
+ break;
+ case ST_PARAM_SET_OUTPUT_SAMPLERATE:
+ st->set_output_samplerate = atoi (val);
+ if (st->set_output_samplerate < 8000) {
+ st->set_output_samplerate = 0;
+ }
+ else if (st->set_output_samplerate > 192000) {
+ st->set_output_samplerate = 192000;
+ }
+ break;
+ default:
+ fprintf (stderr, "st_param: invalid param index (%d)\n", p);
+ }
+}
+
+void
+st_get_param (ddb_dsp_context_t *ctx, int p, char *val, int sz) {
+ ddb_soundtouch_t *st = (ddb_soundtouch_t *)ctx;
+ switch (p) {
+ case ST_PARAM_TEMPO:
+ snprintf (val, sz, "%f", st->tempo);
+ break;
+ case ST_PARAM_PITCH:
+ snprintf (val, sz, "%f", st->pitch);
+ break;
+ case ST_PARAM_RATE:
+ snprintf (val, sz, "%f", st->rate);
+ break;
+ case ST_PARAM_USE_AA_FILTER:
+ snprintf (val, sz, "%d", st->use_aa_filter);
+ break;
+ case ST_PARAM_AA_FILTER_LENGTH:
+ snprintf (val, sz, "%d", st->aa_filter_length);
+ break;
+ case ST_PARAM_USE_QUICKSEEK:
+ snprintf (val, sz, "%d", st->use_quickseek);
+ break;
+ case ST_PARAM_SEQUENCE_MS:
+ snprintf (val, sz, "%d", st->sequence_ms);
+ break;
+ case ST_PARAM_SEEKWINDOW_MS:
+ snprintf (val, sz, "%d", st->seekwindow_ms);
+ break;
+ case ST_PARAM_SET_OUTPUT_SAMPLERATE:
+ snprintf (val, sz, "%d", st->set_output_samplerate);
+ break;
+ default:
+ fprintf (stderr, "st_get_param: invalid param index (%d)\n", p);
+ }
+}
+
+static const char settings_dlg[] =
+ "property \"Tempo Change (%)\" spinbtn[-200,200,1] 0 0;\n"
+ "property \"Pitch Change (semi-tones)\" spinbtn[-24,24,1] 1 0;\n"
+ "property \"Playback Rate Change (%)\" spinbtn[-200,200,1] 2 0;\n"
+ "property \"Absolute Samplerate (overrides Rate Change if nonzero)\" spinbtn[0,192000,1] 8 0;\n"
+ "property \"Use AA Filter\" checkbox 3 0;\n"
+ "property \"AA Filter Length\" spinbtn[16,64,1] 4 32;\n"
+ "property \"Use Quickseek\" checkbox 5 0;\n"
+ "property \"Time Stretch Sequence Length (ms)\" spinbtn[10,500,1] 6 82;\n"
+ "property \"Time Stretch Seek Window Length (ms)\" spinbtn[10,500,1] 7 28;\n"
+;
+
+static DB_dsp_t plugin = {
+ .plugin.api_vmajor = DB_API_VERSION_MAJOR,
+ .plugin.api_vminor = DB_API_VERSION_MINOR,
+ .open = st_open,
+ .close = st_close,
+ .process = st_process,
+ .plugin.version_major = 0,
+ .plugin.version_minor = 1,
+ .plugin.type = DB_PLUGIN_DSP,
+ .plugin.id = "soundtouch",
+ .plugin.name = "Soundtouch",
+ .plugin.descr = "Tempo/Pitch/Rate changer using SoundTouch Library (http://www.surina.net/soundtouch)",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "uses SoundTouch Library, (C) Olli Parviainen"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
+ .plugin.website = "http://deadbeef.sf.net",
+ .num_params = st_num_params,
+ .get_param_name = st_get_param_name,
+ .set_param = st_set_param,
+ .get_param = st_get_param,
+ .reset = st_reset,
+ .configdialog = settings_dlg,
+};
+
+DB_plugin_t *
+ddb_soundtouch_load (DB_functions_t *f) {
+ deadbeef = f;
+ return &plugin.plugin;
+}
diff --git a/plugins/soundtouch/soundtouch/COPYING.TXT b/plugins/soundtouch/soundtouch/COPYING.TXT
new file mode 100644
index 00000000..5b2161be
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/COPYING.TXT
@@ -0,0 +1,458 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authoried party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
diff --git a/plugins/soundtouch/soundtouch/README.html b/plugins/soundtouch/soundtouch/README.html
new file mode 100644
index 00000000..15a34c86
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/README.html
@@ -0,0 +1,752 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=windows-1252">
+ <meta http-equiv="Content-Language" content="en-us">
+ <meta name="author" content="Olli Parviainen">
+ <meta name="description"
+ content="Readme file for SoundTouch audio processing library">
+ <meta name="GENERATOR" content="Microsoft FrontPage 4.0">
+ <meta name="ProgId" content="FrontPage.Editor.Document">
+ <title>SoundTouch library README</title>
+ <style>
+<!--
+.normal { font-family: Arial }
+-->
+ </style>
+</head>
+<body class="normal">
+<hr>
+<h1>SoundTouch audio processing library v1.5.0
+</h1>
+<p class="normal">SoundTouch library Copyright (c) Olli
+Parviainen 2002-2009 </p>
+<hr>
+<h2>1. Introduction </h2>
+<p>SoundTouch is an open-source audio
+processing library that allows changing the sound tempo, pitch
+and playback rate parameters independently from each other, i.e.:</p>
+<ul>
+ <li>Sound tempo can be increased or decreased while
+maintaining the original pitch</li>
+ <li>Sound pitch can be increased or decreased while
+maintaining the original tempo </li>
+ <li>Change playback rate that affects both tempo
+and pitch at the same time </li>
+ <li>Choose any combination of tempo/pitch/rate</li>
+</ul>
+<h3>1.1 Contact information </h3>
+<p>Author email: oparviai 'at' iki.fi </p>
+<p>SoundTouch WWW page: <a href="http://www.surina.net/soundtouch">http://www.surina.net/soundtouch</a></p>
+<hr>
+<h2>2. Compiling SoundTouch</h2>
+<p>Before compiling, notice that you can choose the sample data format
+if it's desirable to use floating point sample
+data instead of 16bit integers. See section "sample data format"
+for more information.</p>
+<h3>2.1. Building in Microsoft Windows</h3>
+<p>Project files for Microsoft Visual C++ 6.0 and Visual C++ .NET are
+supplied with the source code package.&nbsp;</p>
+<p> Please notice that SoundTouch
+library uses processor-specific optimizations for Pentium III and AMD
+processors. Visual Studio .NET and later versions supports the required
+instructions by default, but Visual Studio 6.0 requires a processor pack upgrade
+to be installed in order to support these optimizations. The processor pack upgrade can be downloaded from
+Microsoft site at this URL:</p>
+<p><a href="http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx">http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx</a></p>
+<p>If the above URL is unavailable or removed, go
+to <a href="http://msdn.microsoft.com/">http://msdn.microsoft.com</a>
+and perform a search with keywords &quot;processor pack&quot;. </p>
+<p>To build the binaries with Visual C++
+compiler, either run &quot;make-win.bat&quot; script, or open the
+appropriate project files in source code directories with Visual
+Studio. The final executable will appear under the &quot;SoundTouch\bin&quot;
+directory. If using the Visual Studio IDE instead of the make-win.bat script, directories bin and
+lib may need to be created manually to the SoundTouch
+package root for the final executables. The make-win.bat script
+creates these directories automatically.
+</p>
+<h3>2.2. Building in Gnu platforms</h3>
+<p>The SoundTouch library can be compiled in
+practically any platform supporting GNU compiler (GCC) tools.
+SoundTouch have been tested with gcc version 3.3.4., but it
+shouldn't be very specific about the gcc version. Assembler-level
+performance optimizations for GNU platform are currently available in
+x86 platforms only, they are automatically disabled and replaced with
+standard C routines in other processor platforms.</p>
+<p>To build and install the binaries, run the
+following commands in the SoundTouch/ directory:</p>
+<table border="0" cellpadding="0" cellspacing="4">
+ <tbody>
+ <tr valign="top">
+ <td>
+ <pre>./configure -</pre>
+ </td>
+ <td>
+ <p>Configures the SoundTouch package for the local
+environment.</p>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td>
+ <pre>make -</pre>
+ </td>
+ <td>
+ <p>Builds the SoundTouch library &amp;
+SoundStretch utility.</p>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td>
+ <pre>make install -</pre>
+ </td>
+ <td>
+ <p>Installs the SoundTouch &amp; BPM libraries
+to <b>/usr/local/lib</b> and SoundStretch utility to <b>/usr/local/bin</b>.
+Please notice that 'root' privileges may be required to install the
+binaries to the destination locations.</p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+<h4><b>2.2.1 Required GNU tools</b>&nbsp;</h4>
+<p> Bash shell, GNU C++ compiler, libtool, autoconf and automake tools are required
+for compiling
+the SoundTouch library. These are usually included with the GNU/Linux distribution, but if
+not, install these packages first. For example, in Ubuntu Linux these can be acquired and
+installed with the following command:</p>
+<pre><b>sudo apt-get install <font SIZE="2">automake autoconf libtool build-essential</font></b></pre>
+<h4><b>2.2.2 Problems with GCC compiler compatibility</b></h4>
+<p>At the release time the SoundTouch package has been tested to compile in
+GNU/Linux platform. However, in past it's happened that new gcc versions aren't
+necessarily compatible with the assembler settings used in the optimized
+routines. <b>If you have problems getting the
+SoundTouch library compiled, try the workaround of disabling the optimizations</b>
+by editing the file &quot;include/STTypes.h&quot; and removing the following
+definition there:</p>
+<blockquote>
+ <pre>#define ALLOW_OPTIMIZATIONS 1</pre>
+</blockquote>
+<h4><b>2.2.3 Problems with configure script or build process</b>&nbsp;</h4>
+<p>Incompatibilities between various GNU toolchain versions may cause errors when running the &quot;configure&quot; script or building the source
+codes, if your GNU tool versions are not compatible with the versions used for
+preparing the SoundTouch kit.&nbsp;</p>
+<p>To resolve the issue, regenerate the configure scripts with your local tool
+set by running
+the &quot;<b>./bootstrap</b>&quot; script included in the SoundTouch source code
+kit. After that, run the <b>configure</b> script and <b>make</b> as usually.</p>
+<h4><b>2.2.4 Compiler issues with non-x86 processors</b></h4>
+<p>SoundTouch library works also on non-x86 processors.</p>
+<p>However, in case that you get compiler errors when trying to compile for non-Intel processor, edit the file
+&quot;<b>source\SoundTouch\Makefile.am</b>&quot; and remove the &quot;<b>-msse2</b>&quot;
+flag on the <b>AM_CXXFLAGS </b>line:</p>
+<pre><b>AM_CXXFLAGS=-O3 -fcheck-new -I../../include&nbsp;&nbsp;&nbsp; # Note: -msse2 flag removed!</b></pre>
+<p>After that, run &quot;<b>./bootstrap</b>&quot; script, and then run <b>configure</b>
+and <b>make</b> again.</p>
+<hr>
+<h2>3. About implementation &amp; Usage tips</h2>
+<h3>3.1. Supported sample data formats</h3>
+<p>The sample data format can be chosen
+between 16bit signed integer and 32bit floating point values, the
+default is 32bit floating point. </p>
+
+<p>
+In Windows environment, the sample data format is chosen
+in file &quot;STTypes.h&quot; by choosing one of the following
+defines:</p>
+<ul>
+ <li><span style="font-weight: bold;">#define INTEGER_SAMPLES</span>
+for 16bit signed
+integer</li>
+ <li><span style="font-weight: bold;">#define FLOAT_SAMPLES</span> for
+32bit floating point</li>
+</ul>
+<p>
+In GNU environment, the floating sample format is used by default, but
+integer sample format can be chosen by giving the
+following switch to the configure script:
+<blockquote>
+<pre>./configure --enable-integer-samples</pre>
+</blockquote>
+
+<p>The sample data can have either single (mono)
+or double (stereo) audio channel. Stereo data is interleaved so
+that every other data value is for left channel and every second
+for right channel. Notice that while it'd be possible in theory
+to process stereo sound as two separate mono channels, this isn't
+recommended because processing the channels separately would
+result in losing the phase coherency between the channels, which
+consequently would ruin the stereo effect.</p>
+<p>Sample rates between 8000-48000H are
+supported.</p>
+<h3>3.2. Processing latency</h3>
+<p>The processing and latency constraints of
+the SoundTouch library are:</p>
+<ul>
+ <li>Input/output processing latency for the
+SoundTouch processor is around 100 ms. This is when time-stretching is
+used. If the rate transposing effect alone is used, the latency
+requirement
+is much shorter, see section 'About algorithms'.</li>
+ <li>Processing CD-quality sound (16bit stereo
+sound with 44100H sample rate) in real-time or faster is possible
+starting from processors equivalent to Intel Pentium 133Mh or better,
+if using the "quick" processing algorithm. If not using the "quick"
+mode or
+if floating point sample data are being used, several times more CPU
+power is typically required.</li>
+</ul>
+<h3>3.3. About algorithms</h3>
+<p>SoundTouch provides three seemingly
+independent effects: tempo, pitch and playback rate control.
+These three controls are implemented as combination of two primary
+effects, <em>sample rate transposing</em> and <em>time-stretching</em>.</p>
+<p><em>Sample rate transposing</em> affects
+both the audio stream duration and pitch. It's implemented simply
+by converting the original audio sample stream to the&nbsp; desired
+duration by interpolating from the original audio samples. In SoundTouch, linear interpolation with anti-alias filtering is
+used. Theoretically a higher-order interpolation provide better
+result than 1st order linear interpolation, but in audio
+application linear interpolation together with anti-alias
+filtering performs subjectively about as well as higher-order
+filtering would.</p>
+<p><em>Time-stretching </em>means changing
+the audio stream duration without affecting it's pitch. SoundTouch
+uses WSOLA-like time-stretching routines that operate in the time
+domain. Compared to sample rate transposing, time-stretching is a
+much heavier operation and also requires a longer processing
+"window" of sound samples used by the
+processing algorithm, thus increasing the algorithm input/output
+latency. Typical i/o latency for the SoundTouch
+time-stretch algorithm is around 100 ms.</p>
+<p>Sample rate transposing and time-stretching
+are then used together to produce the tempo, pitch and rate
+controls:</p>
+<ul>
+ <li><strong>'Tempo'</strong> control is
+implemented purely by time-stretching.</li>
+ <li><strong>'Rate</strong>' control is implemented
+purely by sample rate transposing.</li>
+ <li><strong>'Pitch</strong>' control is
+implemented as a combination of time-stretching and sample rate
+transposing. For example, to increase pitch the audio stream is first
+time-stretched to longer duration (without affecting pitch) and then
+transposed back to original duration by sample rate transposing, which
+simultaneously reduces duration and increases pitch. The result is
+original duration but increased pitch.</li>
+</ul>
+<h3>3.4 Tuning the algorithm parameters</h3>
+<p>The time-stretch algorithm has few
+parameters that can be tuned to optimize sound quality for
+certain application. The current default parameters have been
+chosen by iterative if-then analysis (read: "trial and error")
+to obtain best subjective sound quality in pop/rock music
+processing, but in applications processing different kind of
+sound the default parameter set may result into a sub-optimal
+result.</p>
+<p>The time-stretch algorithm default
+parameter values are set by the following #defines in file &quot;TDStretch.h&quot;:</p>
+<blockquote>
+ <pre>#define DEFAULT_SEQUENCE_MS AUTOMATIC
+#define DEFAULT_SEEKWINDOW_MS AUTOMATIC
+#define DEFAULT_OVERLAP_MS 8</pre>
+</blockquote>
+<p>These parameters affect to the time-stretch
+algorithm as follows:</p>
+<ul>
+ <li><strong>DEFAULT_SEQUENCE_MS</strong>: This is
+the default length of a single processing sequence in milliseconds
+which determines the how the original sound is chopped in
+the time-stretch algorithm. Larger values mean fewer sequences
+are used in processing. In principle a larger value sounds better when
+slowing down the tempo, but worse when increasing the tempo and vice
+versa.&nbsp;<br>
+ <br>
+ By default, this setting value is calculated automatically according to
+ tempo value.<br>
+ </li>
+ <li><strong>DEFAULT_SEEKWINDOW_MS</strong>: The seeking window
+default length in milliseconds is for the algorithm that seeks the best
+possible overlapping location. This determines from how
+wide a sample "window" the algorithm can use to find an optimal mixing
+location when the sound sequences are to be linked back together.&nbsp;<br>
+ <br>
+The bigger this window setting is, the higher the possibility to find a
+better mixing position becomes, but at the same time large values may
+cause a "drifting" sound artifact because neighboring sequences can be
+chosen at more uneven intervals. If there's a disturbing artifact that
+sounds as if a constant frequency was drifting around, try reducing
+this setting.<br>
+ <br>
+ By default, this setting value is calculated automatically according to
+ tempo value.<br>
+ </li>
+ <li><strong>DEFAULT_OVERLAP_MS</strong>: Overlap
+length in milliseconds. When the sound sequences are mixed back
+together to form again a continuous sound stream, this parameter
+defines how much the ends of the consecutive sequences will overlap with each other.<br>
+ <br>
+ This shouldn't be that critical parameter. If you reduce the
+DEFAULT_SEQUENCE_MS setting by a large amount, you might wish to try a
+smaller value on this.</li>
+</ul>
+<p>Notice that these parameters can also be
+set during execution time with functions "<strong>TDStretch::setParameters()</strong>"
+and "<strong>SoundTouch::setSetting()</strong>".</p>
+<p>The table below summaries how the
+parameters can be adjusted for different applications:</p>
+<table border="1">
+ <tbody>
+ <tr>
+ <td valign="top"><strong>Parameter name</strong></td>
+ <td valign="top"><strong>Default value
+magnitude</strong></td>
+ <td valign="top"><strong>Larger value
+affects...</strong></td>
+ <td valign="top"><strong>Smaller value
+affects...</strong></td>
+ <td valign="top"><strong>Effect to CPU burden</strong></td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <pre>SEQUENCE_MS</pre>
+ </td>
+ <td valign="top">Default value is relatively
+large, chosen for slowing down music tempo</td>
+ <td valign="top">Larger value is usually
+better for slowing down tempo. Growing the value decelerates the
+"echoing" artifact when slowing down the tempo.</td>
+ <td valign="top">Smaller value might be better
+for speeding up tempo. Reducing the value accelerates the "echoing"
+artifact when slowing down the tempo </td>
+ <td valign="top">Increasing the parameter
+value reduces computation burden</td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <pre>SEEKWINDOW_MS</pre>
+ </td>
+ <td valign="top">Default value is relatively
+large, chosen for slowing down music tempo</td>
+ <td valign="top">Larger value eases finding a
+good mixing position, but may cause a "drifting" artifact</td>
+ <td valign="top">Smaller reduce possibility to
+find a good mixing position, but reduce the "drifting" artifact.</td>
+ <td valign="top">Increasing the parameter
+value increases computation burden</td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <pre>OVERLAP_MS</pre>
+ </td>
+ <td valign="top">Default value is relatively
+large, chosen to suit with above parameters.</td>
+ <td valign="top">&nbsp;</td>
+ <td valign="top">If you reduce the "sequence
+ms" setting, you might wish to try a smaller value.</td>
+ <td valign="top">Increasing the parameter
+value increases computation burden</td>
+ </tr>
+ </tbody>
+</table>
+<h3>3.5 Performance Optimizations </h3>
+<p><strong>General optimizations:</strong></p>
+<p>The time-stretch routine has a 'quick' mode
+that substantially speeds up the algorithm but may degrade the
+sound quality by a small amount. This mode is activated by
+calling SoundTouch::setSetting() function with parameter&nbsp; id
+of SETTING_USE_QUICKSEEK and value "1", i.e. </p>
+<blockquote>
+ <p>setSetting(SETTING_USE_QUICKSEEK, 1);</p>
+</blockquote>
+<p><strong>CPU-specific optimizations:</strong></p>
+<ul>
+ <li>Intel MMX optimized routines are used with
+compatible CPUs when 16bit integer sample type is used. MMX optimizations are available both in Win32 and Gnu/x86 platforms.
+Compatible processors are Intel PentiumMMX and later; AMD K6-2, Athlon
+and later. </li>
+ <li>Intel SSE optimized routines are used with
+compatible CPUs when floating point sample type is used. SSE optimizations are currently implemented for Win32 platform only.
+Processors compatible with SSE extension are Intel processors starting
+from Pentium-III, and AMD processors starting from Athlon XP. </li>
+ <li>AMD 3DNow! optimized routines are used with
+compatible CPUs when floating point sample type is used, but SSE
+extension isn't supported . 3DNow! optimizations are currently
+implemented for Win32 platform only. These optimizations are used in
+AMD K6-2 and Athlon (classic) CPU's; better performing SSE routines are
+used with AMD processor starting from Athlon XP. </li>
+</ul>
+<hr>
+<h2><a name="SoundStretch"></a>4. SoundStretch audio processing utility
+</h2>
+<p>SoundStretch audio processing utility<br>
+Copyright (c) Olli Parviainen 2002-2009</p>
+<p>SoundStretch is a simple command-line
+application that can change tempo, pitch and playback rates of
+WAV sound files. This program is intended primarily to
+demonstrate how the &quot;SoundTouch&quot; library can be used to
+process sound in your own program, but it can as well be used for
+processing sound files.</p>
+<h3>4.1. SoundStretch Usage Instructions</h3>
+<p>SoundStretch Usage syntax:</p>
+<blockquote>
+ <pre>soundstretch infilename outfilename [switches]</pre>
+</blockquote>
+<p>Where: </p>
+<table border="0" cellpadding="2" width="100%">
+ <tbody>
+ <tr>
+ <td valign="top">
+ <pre>&quot;infilename&quot;</pre>
+ </td>
+ <td valign="top">Name of the input sound
+data file (in .WAV audio file format). Give &quot;stdin&quot; as filename to use
+ standard input pipe. </td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <pre>&quot;outfilename&quot;</pre>
+ </td>
+ <td valign="top">Name of the output sound
+file where the resulting sound is saved (in .WAV audio file format).
+This parameter may be omitted if you&nbsp; don't want to save the
+output
+(e.g. when only calculating BPM rate with '-bpm' switch). Give &quot;stdout&quot;
+ as filename to use standard output pipe.</td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <pre>&nbsp;[switches]</pre>
+ </td>
+ <td valign="top">Are one or more control
+switches.</td>
+ </tr>
+ </tbody>
+</table>
+<p>Available control switches are:</p>
+<table border="0" cellpadding="2" width="100%">
+ <tbody>
+ <tr>
+ <td valign="top">
+ <pre>-tempo=n </pre>
+ </td>
+ <td valign="top">Change the sound tempo by n
+percents (n = -95.0 .. +5000.0 %) </td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <pre>-pitch=n</pre>
+ </td>
+ <td valign="top">Change the sound pitch by n
+semitones (n = -60.0 .. + 60.0 semitones) </td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <pre>-rate=n</pre>
+ </td>
+ <td valign="top">Change the sound playback rate by
+n percents (n = -95.0 .. +5000.0 %) </td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <pre>-bpm=n</pre>
+ </td>
+ <td valign="top">Detect the Beats-Per-Minute (BPM) rate of the sound and adjust the tempo to meet 'n'
+ BPMs. When this switch is
+ applied, the &quot;-tempo&quot; switch is ignored. If "=n" is
+omitted, i.e. switch &quot;-bpm&quot; is used alone, then the BPM rate is
+ estimated and displayed, but tempo not adjusted according to the BPM
+value. </td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <pre>-quick</pre>
+ </td>
+ <td valign="top">Use quicker tempo change
+algorithm. Gains speed but loses sound quality. </td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <pre>-naa</pre>
+ </td>
+ <td valign="top">Don't use anti-alias
+filtering in sample rate transposing. Gains speed but loses sound
+quality. </td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <pre>-license</pre>
+ </td>
+ <td valign="top">Displays the program license
+text (LGPL)</td>
+ </tr>
+ </tbody>
+</table>
+<p>Notes:</p>
+<ul>
+ <li>To use standard input/output pipes for processing, give &quot;stdin&quot;
+ and &quot;stdout&quot; as input/output filenames correspondingly. The
+ standard input/output pipes will still carry the audio data in .wav audio
+ file format.</li>
+ <li>The numerical switches allow both integer (e.g. "-tempo=123") and decimal (e.g.
+"-tempo=123.45") numbers.</li>
+ <li>The &quot;-naa&quot; and/or "-quick" switches can be
+used to reduce CPU usage while compromising some sound quality </li>
+ <li>The BPM detection algorithm works by detecting
+repeating bass or drum patterns at low frequencies of &lt;250Hz. A
+ lower-than-expected BPM figure may be reported for music with uneven or
+ complex bass patterns. </li>
+</ul>
+<h3>4.2. SoundStretch usage examples </h3>
+<p><strong>Example 1</strong></p>
+<p>The following command increases tempo of
+the sound file &quot;originalfile.wav&quot; by 12.5% and stores result to file &quot;destinationfile.wav&quot;:</p>
+<blockquote>
+ <pre>soundstretch originalfile.wav destinationfile.wav -tempo=12.5</pre>
+</blockquote>
+<p><strong>Example 2</strong></p>
+<p>The following command decreases the sound
+pitch (key) of the sound file &quot;orig.wav&quot; by two
+semitones and stores the result to file &quot;dest.wav&quot;:</p>
+<blockquote>
+ <pre>soundstretch orig.wav dest.wav -pitch=-2</pre>
+</blockquote>
+<p><strong>Example 3</strong></p>
+<p>The following command processes the file &quot;orig.wav&quot; by decreasing the sound tempo by 25.3% and
+increasing the sound pitch (key) by 1.5 semitones. Resulting .wav audio data is
+directed to standard output pipe:</p>
+<blockquote>
+ <pre>soundstretch orig.wav stdout -tempo=-25.3 -pitch=1.5</pre>
+</blockquote>
+<p><strong>Example 4</strong></p>
+<p>The following command detects the BPM rate
+of the file &quot;orig.wav&quot; and adjusts the tempo to match
+100 beats per minute. Result is stored to file &quot;dest.wav&quot;:</p>
+<blockquote>
+ <pre>soundstretch orig.wav dest.wav -bpm=100</pre>
+</blockquote>
+<p><strong>Example 5</strong></p>
+<p>The following command reads .wav sound data from standard input pipe and
+estimates the BPM rate:</p>
+<blockquote>
+ <pre>soundstretch stdin -bpm</pre>
+</blockquote>
+<hr>
+<h2>5. Change History</h2>
+<h3>5.1. SoundTouch library Change History </h3>
+
+<p><strong>1.5.0:</strong></p>
+<ul>
+<li>Added normalization to correlation calculation and improvement automatic seek/sequence parameter calculation to improve sound quality</li>
+
+<li>Bugfixes:&nbsp;
+ <ul>
+ <li>Fixed negative array indexing in quick seek algorithm</li>
+ <li>FIR autoalias filter running too far in processing buffer</li>
+ <li>Check against zero sample count in rate transposing</li>
+ <li>Fix for x86-64 support: Removed pop/push instructions from the cpu detection algorithm.&nbsp;</li>
+ <li>Check against empty buffers in FIFOSampleBuffer</li>
+ <li>Other minor fixes &amp; code cleanup</li>
+ </ul>
+</li>
+
+<li>Fixes in compilation scripts for non-Intel platforms</li>
+<li>Added Dynamic-Link-Library (DLL) version of SoundTouch library build,
+ provided with Delphi/Pascal wrapper for calling the dll routines</li>
+<li>Added #define PREVENT_CLICK_AT_RATE_CROSSOVER that prevents a click artifact
+ when crossing the nominal pitch from either positive to negative side or vice
+ versa</li>
+
+</ul>
+
+<p><strong>1.4.1:</strong></p>
+<ul>
+<li>Fixed a buffer overflow bug in BPM detect algorithm routines if processing
+ more than 2048 samples at one call&nbsp;</li>
+
+</ul>
+
+<p><strong>1.4.0:</strong></p>
+<ul>
+<li>Improved sound quality by automatic calculation of time stretch algorithm
+ processing parameters according to tempo setting</li>
+<li>Moved BPM detection routines from SoundStretch application into SoundTouch
+ library</li>
+<li>Bugfixes: Usage of uninitialied variables, GNU build scripts, compiler errors
+ due to 'const' keyword mismatch.</li>
+<li>Source code cleanup</li>
+
+</ul>
+
+<p><strong>v1.3.1:
+</strong></p>
+<ul>
+<li>Changed static class declaration to GCC 4.x compiler compatible syntax.</li>
+<li>Enabled MMX/SSE-optimized routines also for GCC compilers. Earlier
+the MMX/SSE-optimized routines were written in compiler-specific inline
+assembler, now these routines are migrated to use compiler intrinsic
+syntax which allows compiling the same MMX/SSE-optimized source code with
+both Visual C++ and GCC compilers. </li>
+<li>Set floating point as the default sample format and added switch to
+the GNU configure script for selecting the other sample format.</li>
+
+</ul>
+
+<p><strong>v1.3.0:
+</strong></p>
+<ul>
+ <li>Fixed tempo routine output duration inaccuracy due to rounding
+error </li>
+ <li>Implemented separate processing routines for integer and
+floating arithmetic to allow improvements to floating point routines
+(earlier used algorithms mostly optimized for integer arithmetic also
+for floating point samples) </li>
+ <li>Fixed a bug that distorts sound if sample rate changes during the
+sound stream </li>
+ <li>Fixed a memory leak that appeared in MMX/SSE/3DNow! optimized
+routines </li>
+ <li>Reduced redundant code pieces in MMX/SSE/3DNow! optimized
+routines vs. the standard C routines.</li>
+ <li>MMX routine incompatibility with new gcc compiler versions </li>
+ <li>Other miscellaneous bug fixes </li>
+</ul>
+<p><strong>v1.2.1: </strong></p>
+<ul>
+ <li>Added automake/autoconf scripts for GNU
+platforms (in courtesy of David Durham)</li>
+ <li>Fixed SCALE overflow bug in rate transposer
+routine.</li>
+ <li>Fixed 64bit address space bugs.</li>
+ <li>Created a 'soundtouch' namespace for
+SAMPLETYPE definitions.</li>
+</ul>
+<p><strong>v1.2.0: </strong></p>
+<ul>
+ <li>Added support for 32bit floating point sample
+data type with SSE/3DNow! optimizations for Win32 platform (SSE/3DNow! optimizations currently not supported in GCC environment)</li>
+ <li>Replaced 'make-gcc' script for GNU environment
+by master Makefile</li>
+ <li>Added time-stretch routine configurability to
+SoundTouch main class</li>
+ <li>Bugfixes</li>
+</ul>
+<p><strong>v1.1.1: </strong></p>
+<ul>
+ <li>Moved SoundTouch under lesser GPL license (LGPL). This allows using SoundTouch library in programs that aren't
+released under GPL license. </li>
+ <li>Changed MMX routine organiation so that MMX optimized routines are now implemented in classes that are derived from
+the basic classes having the standard non-mmx routines. </li>
+ <li>MMX routines to support gcc version 3. </li>
+ <li>Replaced windows makefiles by script using the .dsw files </li>
+</ul>
+<p><strong>v1.01: </strong></p>
+<ul>
+ <li>&quot;mmx_gcc.cpp&quot;: Added "using namespace std" and
+removed "return 0" from a function with void return value to fix
+compiler errors when compiling the library in Solaris environment. </li>
+ <li>Moved file &quot;FIFOSampleBuffer.h&quot; to "include"
+directory to allow accessing the FIFOSampleBuffer class from external
+files. </li>
+</ul>
+<p><strong>v1.0: </strong></p>
+<ul>
+ <li>Initial release </li>
+</ul>
+<p>&nbsp;</p>
+<h3>5.2. SoundStretch application Change
+History </h3>
+
+<p><strong>1.4.0:</strong></p>
+<ul>
+<li>Moved BPM detection routines from SoundStretch application into SoundTouch
+ library</li>
+<li>Allow using standard input/output pipes as audio processing input/output
+ streams</li>
+
+</ul>
+
+<p><strong>v1.3.0:</strong></p>
+<ul>
+ <li>Simplified accessing WAV files with floating
+point sample format.
+ </li>
+</ul>
+<p><strong>v1.2.1: </strong></p>
+<ul>
+ <li>Fixed 64bit address space bugs.</li>
+</ul>
+<p><strong>v1.2.0: </strong></p>
+<ul>
+ <li>Added support for 32bit floating point sample
+data type</li>
+ <li>Restructured the BPM routines into separate
+library</li>
+ <li>Fixed big-endian conversion bugs in WAV file
+routines (hopefully :)</li>
+</ul>
+<p><strong>v1.1.1: </strong></p>
+<ul>
+ <li>Fixed bugs in WAV file reading &amp; added
+byte-order conversion for big-endian processors. </li>
+ <li>Moved SoundStretch source code under 'example'
+directory to highlight difference from SoundTouch stuff. </li>
+ <li>Replaced windows makefiles by script using the .dsw files </li>
+ <li>Output file name isn't required if output
+isn't desired (e.g. if using the switch '-bpm' in plain format only) </li>
+</ul>
+<p><strong>v1.1:</strong></p>
+<ul>
+ <li>Fixed "Release" settings in Microsoft Visual
+C++ project file (.dsp) </li>
+ <li>Added beats-per-minute (BPM) detection routine
+and command-line switch &quot;-bpm&quot; </li>
+</ul>
+<p><strong>v1.01: </strong></p>
+<ul>
+ <li>Initial release </li>
+</ul>
+<hr>
+<h2 >6. Acknowledgements </h2>
+<p >Kudos for these people who have contributed to development or submitted
+bugfixes since
+SoundTouch v1.3.1: </p>
+<ul>
+ <li>Arthur A</li>
+ <li>Richard Ash</li>
+ <li>Stanislav Brabec</li>
+ <li>Christian Budde</li>
+ <li>Brian Cameron</li>
+ <li>Jason Champion</li>
+ <li>Patrick Colis</li>
+ <li>Justin Frankel</li>
+ <li>Jason Garland</li>
+ <li>Takashi Iwai</li>
+ <li>Paulo Pizarro</li>
+ <li>RJ Ryan</li>
+ <li>John Sheehy</li>
+</ul>
+<p >Moral greetings to all other contributors and users also!</p>
+<hr>
+<h2 >7. LICENSE </h2>
+<p>SoundTouch audio processing library<br>
+Copyright (c) Olli Parviainen</p>
+<p>This library is free software; you can
+redistribute it and/or modify it under the terms of the GNU
+Lesser General Public License version 2.1 as published by the Free Software
+Foundation.</p>
+<p>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.</p>
+<p>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., 59 Temple Place,
+Suite 330, Boston, MA 02111-1307 USA</p>
+<hr>
+<!--
+$Id: README.html 81 2009-12-28 20:51:18Z oparviai $
+-->
+</body>
+</html>
diff --git a/plugins/soundtouch/soundtouch/include/BPMDetect.h b/plugins/soundtouch/soundtouch/include/BPMDetect.h
new file mode 100644
index 00000000..4def43f1
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/include/BPMDetect.h
@@ -0,0 +1,161 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Beats-per-minute (BPM) detection routine.
+///
+/// The beat detection algorithm works as follows:
+/// - Use function 'inputSamples' to input a chunks of samples to the class for
+/// analysis. It's a good idea to enter a large sound file or stream in smallish
+/// chunks of around few kilosamples in order not to extinguish too much RAM memory.
+/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden,
+/// which is basically ok as low (bass) frequencies mostly determine the beat rate.
+/// Simple averaging is used for anti-alias filtering because the resulting signal
+/// quality isn't of that high importance.
+/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by
+/// taking absolute value that's smoothed by sliding average. Signal levels that
+/// are below a couple of times the general RMS amplitude level are cut away to
+/// leave only notable peaks there.
+/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term
+/// autocorrelation function of the enveloped signal.
+/// - After whole sound data file has been analyzed as above, the bpm level is
+/// detected by function 'getBpm' that finds the highest peak of the autocorrelation
+/// function, calculates it's precise location and converts this reading to bpm's.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-02-21 18:00:14 +0200 (Sat, 21 Feb 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: BPMDetect.h 63 2009-02-21 16:00:14Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef _BPMDetect_H_
+#define _BPMDetect_H_
+
+#include "STTypes.h"
+#include "FIFOSampleBuffer.h"
+
+namespace soundtouch
+{
+
+/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit.
+#define MIN_BPM 29
+
+/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit.
+#define MAX_BPM 230
+
+
+/// Class for calculating BPM rate for audio data.
+class BPMDetect
+{
+protected:
+ /// Auto-correlation accumulator bins.
+ float *xcorr;
+
+ /// Amplitude envelope sliding average approximation level accumulator
+ float envelopeAccu;
+
+ /// RMS volume sliding average approximation level accumulator
+ float RMSVolumeAccu;
+
+ /// Sample average counter.
+ int decimateCount;
+
+ /// Sample average accumulator for FIFO-like decimation.
+ soundtouch::LONG_SAMPLETYPE decimateSum;
+
+ /// Decimate sound by this coefficient to reach approx. 500 Hz.
+ int decimateBy;
+
+ /// Auto-correlation window length
+ int windowLen;
+
+ /// Number of channels (1 = mono, 2 = stereo)
+ int channels;
+
+ /// sample rate
+ int sampleRate;
+
+ /// Beginning of auto-correlation window: Autocorrelation isn't being updated for
+ /// the first these many correlation bins.
+ int windowStart;
+
+ /// FIFO-buffer for decimated processing samples.
+ soundtouch::FIFOSampleBuffer *buffer;
+
+ /// Updates auto-correlation function for given number of decimated samples that
+ /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe
+ /// though).
+ void updateXCorr(int process_samples /// How many samples are processed.
+ );
+
+ /// Decimates samples to approx. 500 Hz.
+ ///
+ /// \return Number of output samples.
+ int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer
+ const soundtouch::SAMPLETYPE *src, ///< Source sample buffer
+ int numsamples ///< Number of source samples.
+ );
+
+ /// Calculates amplitude envelope for the buffer of samples.
+ /// Result is output to 'samples'.
+ void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer
+ int numsamples ///< Number of samples in buffer
+ );
+
+public:
+ /// Constructor.
+ BPMDetect(int numChannels, ///< Number of channels in sample data.
+ int sampleRate ///< Sample rate in Hz.
+ );
+
+ /// Destructor.
+ virtual ~BPMDetect();
+
+ /// Inputs a block of samples for analyzing: Envelopes the samples and then
+ /// updates the autocorrelation estimation. When whole song data has been input
+ /// in smaller blocks using this function, read the resulting bpm with 'getBpm'
+ /// function.
+ ///
+ /// Notice that data in 'samples' array can be disrupted in processing.
+ void inputSamples(const soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer
+ int numSamples ///< Number of samples in buffer
+ );
+
+
+ /// Analyzes the results and returns the BPM rate. Use this function to read result
+ /// after whole song data has been input to the class by consecutive calls of
+ /// 'inputSamples' function.
+ ///
+ /// \return Beats-per-minute rate, or zero if detection failed.
+ float getBpm();
+};
+
+}
+
+#endif // _BPMDetect_H_
diff --git a/plugins/soundtouch/soundtouch/include/FIFOSampleBuffer.h b/plugins/soundtouch/soundtouch/include/FIFOSampleBuffer.h
new file mode 100644
index 00000000..76cbf951
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/include/FIFOSampleBuffer.h
@@ -0,0 +1,174 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// A buffer class for temporarily storaging sound samples, operates as a
+/// first-in-first-out pipe.
+///
+/// Samples are added to the end of the sample buffer with the 'putSamples'
+/// function, and are received from the beginning of the buffer by calling
+/// the 'receiveSamples' function. The class automatically removes the
+/// output samples from the buffer as well as grows the storage size
+/// whenever necessary.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-02-21 18:00:14 +0200 (Sat, 21 Feb 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: FIFOSampleBuffer.h 63 2009-02-21 16:00:14Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef FIFOSampleBuffer_H
+#define FIFOSampleBuffer_H
+
+#include "FIFOSamplePipe.h"
+
+namespace soundtouch
+{
+
+/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes
+/// care of storage size adjustment and data moving during input/output operations.
+///
+/// Notice that in case of stereo audio, one sample is considered to consist of
+/// both channel data.
+class FIFOSampleBuffer : public FIFOSamplePipe
+{
+private:
+ /// Sample buffer.
+ SAMPLETYPE *buffer;
+
+ // Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first
+ // 16-byte aligned location of this buffer
+ SAMPLETYPE *bufferUnaligned;
+
+ /// Sample buffer size in bytes
+ uint sizeInBytes;
+
+ /// How many samples are currently in buffer.
+ uint samplesInBuffer;
+
+ /// Channels, 1=mono, 2=stereo.
+ uint channels;
+
+ /// Current position pointer to the buffer. This pointer is increased when samples are
+ /// removed from the pipe so that it's necessary to actually rewind buffer (move data)
+ /// only new data when is put to the pipe.
+ uint bufferPos;
+
+ /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real
+ /// beginning of the buffer.
+ void rewind();
+
+ /// Ensures that the buffer has capacity for at least this many samples.
+ void ensureCapacity(uint capacityRequirement);
+
+ /// Returns current capacity.
+ uint getCapacity() const;
+
+public:
+
+ /// Constructor
+ FIFOSampleBuffer(int numChannels = 2 ///< Number of channels, 1=mono, 2=stereo.
+ ///< Default is stereo.
+ );
+
+ /// destructor
+ ~FIFOSampleBuffer();
+
+ /// Returns a pointer to the beginning of the output samples.
+ /// This function is provided for accessing the output samples directly.
+ /// Please be careful for not to corrupt the book-keeping!
+ ///
+ /// When using this function to output samples, also remember to 'remove' the
+ /// output samples from the buffer by calling the
+ /// 'receiveSamples(numSamples)' function
+ virtual SAMPLETYPE *ptrBegin();
+
+ /// Returns a pointer to the end of the used part of the sample buffer (i.e.
+ /// where the new samples are to be inserted). This function may be used for
+ /// inserting new samples into the sample buffer directly. Please be careful
+ /// not corrupt the book-keeping!
+ ///
+ /// When using this function as means for inserting new samples, also remember
+ /// to increase the sample count afterwards, by calling the
+ /// 'putSamples(numSamples)' function.
+ SAMPLETYPE *ptrEnd(
+ uint slackCapacity ///< How much free capacity (in samples) there _at least_
+ ///< should be so that the caller can succesfully insert the
+ ///< desired samples to the buffer. If necessary, the function
+ ///< grows the buffer size to comply with this requirement.
+ );
+
+ /// Adds 'numSamples' pcs of samples from the 'samples' memory position to
+ /// the sample buffer.
+ virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
+ uint numSamples ///< Number of samples to insert.
+ );
+
+ /// Adjusts the book-keeping to increase number of samples in the buffer without
+ /// copying any actual samples.
+ ///
+ /// This function is used to update the number of samples in the sample buffer
+ /// when accessing the buffer directly with 'ptrEnd' function. Please be
+ /// careful though!
+ virtual void putSamples(uint numSamples ///< Number of samples been inserted.
+ );
+
+ /// Output samples from beginning of the sample buffer. Copies requested samples to
+ /// output buffer and removes them from the sample buffer. If there are less than
+ /// 'numsample' samples in the buffer, returns all that available.
+ ///
+ /// \return Number of samples returned.
+ virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
+ uint maxSamples ///< How many samples to receive at max.
+ );
+
+ /// Adjusts book-keeping so that given number of samples are removed from beginning of the
+ /// sample buffer without copying them anywhere.
+ ///
+ /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
+ /// with 'ptrBegin' function.
+ virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
+ );
+
+ /// Returns number of samples currently available.
+ virtual uint numSamples() const;
+
+ /// Sets number of channels, 1 = mono, 2 = stereo.
+ void setChannels(int numChannels);
+
+ /// Returns nonzero if there aren't any samples available for outputting.
+ virtual int isEmpty() const;
+
+ /// Clears all the samples.
+ virtual void clear();
+};
+
+}
+
+#endif
diff --git a/plugins/soundtouch/soundtouch/include/FIFOSamplePipe.h b/plugins/soundtouch/soundtouch/include/FIFOSamplePipe.h
new file mode 100644
index 00000000..b5fc3b77
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/include/FIFOSamplePipe.h
@@ -0,0 +1,221 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound
+/// samples by operating like a first-in-first-out pipe: New samples are fed
+/// into one end of the pipe with the 'putSamples' function, and the processed
+/// samples are received from the other end with the 'receiveSamples' function.
+///
+/// 'FIFOProcessor' : A base class for classes the do signal processing with
+/// the samples while operating like a first-in-first-out pipe. When samples
+/// are input with the 'putSamples' function, the class processes them
+/// and moves the processed samples to the given 'output' pipe object, which
+/// may be either another processing stage, or a fifo sample buffer object.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-04-13 16:18:48 +0300 (Mon, 13 Apr 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: FIFOSamplePipe.h 69 2009-04-13 13:18:48Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef FIFOSamplePipe_H
+#define FIFOSamplePipe_H
+
+#include <assert.h>
+#include <stdlib.h>
+#include "STTypes.h"
+
+namespace soundtouch
+{
+
+/// Abstract base class for FIFO (first-in-first-out) sample processing classes.
+class FIFOSamplePipe
+{
+public:
+ // virtual default destructor
+ virtual ~FIFOSamplePipe() {}
+
+
+ /// Returns a pointer to the beginning of the output samples.
+ /// This function is provided for accessing the output samples directly.
+ /// Please be careful for not to corrupt the book-keeping!
+ ///
+ /// When using this function to output samples, also remember to 'remove' the
+ /// output samples from the buffer by calling the
+ /// 'receiveSamples(numSamples)' function
+ virtual SAMPLETYPE *ptrBegin() = 0;
+
+ /// Adds 'numSamples' pcs of samples from the 'samples' memory position to
+ /// the sample buffer.
+ virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
+ uint numSamples ///< Number of samples to insert.
+ ) = 0;
+
+
+ // Moves samples from the 'other' pipe instance to this instance.
+ void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data.
+ )
+ {
+ int oNumSamples = other.numSamples();
+
+ putSamples(other.ptrBegin(), oNumSamples);
+ other.receiveSamples(oNumSamples);
+ };
+
+ /// Output samples from beginning of the sample buffer. Copies requested samples to
+ /// output buffer and removes them from the sample buffer. If there are less than
+ /// 'numsample' samples in the buffer, returns all that available.
+ ///
+ /// \return Number of samples returned.
+ virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
+ uint maxSamples ///< How many samples to receive at max.
+ ) = 0;
+
+ /// Adjusts book-keeping so that given number of samples are removed from beginning of the
+ /// sample buffer without copying them anywhere.
+ ///
+ /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
+ /// with 'ptrBegin' function.
+ virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
+ ) = 0;
+
+ /// Returns number of samples currently available.
+ virtual uint numSamples() const = 0;
+
+ // Returns nonzero if there aren't any samples available for outputting.
+ virtual int isEmpty() const = 0;
+
+ /// Clears all the samples.
+ virtual void clear() = 0;
+};
+
+
+
+/// Base-class for sound processing routines working in FIFO principle. With this base
+/// class it's easy to implement sound processing stages that can be chained together,
+/// so that samples that are fed into beginning of the pipe automatically go through
+/// all the processing stages.
+///
+/// When samples are input to this class, they're first processed and then put to
+/// the FIFO pipe that's defined as output of this class. This output pipe can be
+/// either other processing stage or a FIFO sample buffer.
+class FIFOProcessor :public FIFOSamplePipe
+{
+protected:
+ /// Internal pipe where processed samples are put.
+ FIFOSamplePipe *output;
+
+ /// Sets output pipe.
+ void setOutPipe(FIFOSamplePipe *pOutput)
+ {
+ assert(output == NULL);
+ assert(pOutput != NULL);
+ output = pOutput;
+ }
+
+
+ /// Constructor. Doesn't define output pipe; it has to be set be
+ /// 'setOutPipe' function.
+ FIFOProcessor()
+ {
+ output = NULL;
+ }
+
+
+ /// Constructor. Configures output pipe.
+ FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe.
+ )
+ {
+ output = pOutput;
+ }
+
+
+ /// Destructor.
+ virtual ~FIFOProcessor()
+ {
+ }
+
+
+ /// Returns a pointer to the beginning of the output samples.
+ /// This function is provided for accessing the output samples directly.
+ /// Please be careful for not to corrupt the book-keeping!
+ ///
+ /// When using this function to output samples, also remember to 'remove' the
+ /// output samples from the buffer by calling the
+ /// 'receiveSamples(numSamples)' function
+ virtual SAMPLETYPE *ptrBegin()
+ {
+ return output->ptrBegin();
+ }
+
+public:
+
+ /// Output samples from beginning of the sample buffer. Copies requested samples to
+ /// output buffer and removes them from the sample buffer. If there are less than
+ /// 'numsample' samples in the buffer, returns all that available.
+ ///
+ /// \return Number of samples returned.
+ virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples.
+ uint maxSamples ///< How many samples to receive at max.
+ )
+ {
+ return output->receiveSamples(outBuffer, maxSamples);
+ }
+
+
+ /// Adjusts book-keeping so that given number of samples are removed from beginning of the
+ /// sample buffer without copying them anywhere.
+ ///
+ /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
+ /// with 'ptrBegin' function.
+ virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
+ )
+ {
+ return output->receiveSamples(maxSamples);
+ }
+
+
+ /// Returns number of samples currently available.
+ virtual uint numSamples() const
+ {
+ return output->numSamples();
+ }
+
+
+ /// Returns nonzero if there aren't any samples available for outputting.
+ virtual int isEmpty() const
+ {
+ return output->isEmpty();
+ }
+};
+
+}
+
+#endif
diff --git a/plugins/soundtouch/soundtouch/include/STTypes.h b/plugins/soundtouch/soundtouch/include/STTypes.h
new file mode 100644
index 00000000..c09a45f9
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/include/STTypes.h
@@ -0,0 +1,149 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Common type definitions for SoundTouch audio processing library.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-05-17 14:30:57 +0300 (Sun, 17 May 2009) $
+// File revision : $Revision: 3 $
+//
+// $Id: STTypes.h 70 2009-05-17 11:30:57Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef STTypes_H
+#define STTypes_H
+
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+#ifdef __GNUC__
+ // In GCC, include soundtouch_config.h made by config scritps
+ #include "soundtouch_config.h"
+#endif
+
+#ifndef _WINDEF_
+ // if these aren't defined already by Windows headers, define now
+
+ typedef int BOOL;
+
+ #define FALSE 0
+ #define TRUE 1
+
+#endif // _WINDEF_
+
+
+namespace soundtouch
+{
+
+/// Activate these undef's to overrule the possible sampletype
+/// setting inherited from some other header file:
+//#undef INTEGER_SAMPLES
+//#undef FLOAT_SAMPLES
+
+#if !(INTEGER_SAMPLES || FLOAT_SAMPLES)
+
+ /// Choose either 32bit floating point or 16bit integer sampletype
+ /// by choosing one of the following defines, unless this selection
+ /// has already been done in some other file.
+ ////
+ /// Notes:
+ /// - In Windows environment, choose the sample format with the
+ /// following defines.
+ /// - In GNU environment, the floating point samples are used by
+ /// default, but integer samples can be chosen by giving the
+ /// following switch to the configure script:
+ /// ./configure --enable-integer-samples
+ /// However, if you still prefer to select the sample format here
+ /// also in GNU environment, then please #undef the INTEGER_SAMPLE
+ /// and FLOAT_SAMPLE defines first as in comments above.
+ //#define INTEGER_SAMPLES 1 //< 16bit integer samples
+ #define FLOAT_SAMPLES 1 //< 32bit float samples
+
+ #endif
+
+ #if (WIN32 || __i386__ || __x86_64__)
+ /// Define this to allow X86-specific assembler/intrinsic optimizations.
+ /// Notice that library contains also usual C++ versions of each of these
+ /// these routines, so if you're having difficulties getting the optimized
+ /// routines compiled for whatever reason, you may disable these optimizations
+ /// to make the library compile.
+
+ #define ALLOW_X86_OPTIMIZATIONS 0
+
+ #endif
+
+ // If defined, allows the SIMD-optimized routines to take minor shortcuts
+ // for improved performance. Undefine to require faithfully similar SIMD
+ // calculations as in normal C implementation.
+ #define ALLOW_NONEXACT_SIMD_OPTIMIZATION 1
+
+
+ #ifdef INTEGER_SAMPLES
+ // 16bit integer sample type
+ typedef short SAMPLETYPE;
+ // data type for sample accumulation: Use 32bit integer to prevent overflows
+ typedef long LONG_SAMPLETYPE;
+
+ #ifdef FLOAT_SAMPLES
+ // check that only one sample type is defined
+ #error "conflicting sample types defined"
+ #endif // FLOAT_SAMPLES
+
+ #ifdef ALLOW_X86_OPTIMIZATIONS
+ // Allow MMX optimizations
+ #define ALLOW_MMX 1
+ #endif
+
+ #else
+
+ // floating point samples
+ typedef float SAMPLETYPE;
+ // data type for sample accumulation: Use double to utilize full precision.
+ typedef double LONG_SAMPLETYPE;
+
+ #ifdef ALLOW_X86_OPTIMIZATIONS
+ // Allow 3DNow! and SSE optimizations
+ #if WIN32
+ #define ALLOW_3DNOW 1
+ #endif
+
+ #define ALLOW_SSE 1
+ #endif
+
+ #endif // INTEGER_SAMPLES
+};
+
+
+// When this #define is active, eliminates a clicking sound when the "rate" or "pitch"
+// parameter setting crosses from value <1 to >=1 or vice versa during processing.
+// Default is off as such crossover is untypical case and involves a slight sound
+// quality compromise.
+//#define PREVENT_CLICK_AT_RATE_CROSSOVER 1
+
+#endif
diff --git a/plugins/soundtouch/soundtouch/include/SoundTouch.h b/plugins/soundtouch/soundtouch/include/SoundTouch.h
new file mode 100644
index 00000000..0e042d3c
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/include/SoundTouch.h
@@ -0,0 +1,252 @@
+//////////////////////////////////////////////////////////////////////////////
+///
+/// SoundTouch - main class for tempo/pitch/rate adjusting routines.
+///
+/// Notes:
+/// - Initialize the SoundTouch object instance by setting up the sound stream
+/// parameters with functions 'setSampleRate' and 'setChannels', then set
+/// desired tempo/pitch/rate settings with the corresponding functions.
+///
+/// - The SoundTouch class behaves like a first-in-first-out pipeline: The
+/// samples that are to be processed are fed into one of the pipe by calling
+/// function 'putSamples', while the ready processed samples can be read
+/// from the other end of the pipeline with function 'receiveSamples'.
+///
+/// - The SoundTouch processing classes require certain sized 'batches' of
+/// samples in order to process the sound. For this reason the classes buffer
+/// incoming samples until there are enough of samples available for
+/// processing, then they carry out the processing step and consequently
+/// make the processed samples available for outputting.
+///
+/// - For the above reason, the processing routines introduce a certain
+/// 'latency' between the input and output, so that the samples input to
+/// SoundTouch may not be immediately available in the output, and neither
+/// the amount of outputtable samples may not immediately be in direct
+/// relationship with the amount of previously input samples.
+///
+/// - The tempo/pitch/rate control parameters can be altered during processing.
+/// Please notice though that they aren't currently protected by semaphores,
+/// so in multi-thread application external semaphore protection may be
+/// required.
+///
+/// - This class utilizes classes 'TDStretch' for tempo change (without modifying
+/// pitch) and 'RateTransposer' for changing the playback rate (that is, both
+/// tempo and pitch in the same ratio) of the sound. The third available control
+/// 'pitch' (change pitch but maintain tempo) is produced by a combination of
+/// combining the two other controls.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-12-28 22:10:14 +0200 (Mon, 28 Dec 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: SoundTouch.h 78 2009-12-28 20:10:14Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SoundTouch_H
+#define SoundTouch_H
+
+#include "FIFOSamplePipe.h"
+#include "STTypes.h"
+
+namespace soundtouch
+{
+
+/// Soundtouch library version string
+#define SOUNDTOUCH_VERSION "1.5.0"
+
+/// SoundTouch library version id
+#define SOUNDTOUCH_VERSION_ID (10500)
+
+//
+// Available setting IDs for the 'setSetting' & 'get_setting' functions:
+
+/// Enable/disable anti-alias filter in pitch transposer (0 = disable)
+#define SETTING_USE_AA_FILTER 0
+
+/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32)
+#define SETTING_AA_FILTER_LENGTH 1
+
+/// Enable/disable quick seeking algorithm in tempo changer routine
+/// (enabling quick seeking lowers CPU utilization but causes a minor sound
+/// quality compromising)
+#define SETTING_USE_QUICKSEEK 2
+
+/// Time-stretch algorithm single processing sequence length in milliseconds. This determines
+/// to how long sequences the original sound is chopped in the time-stretch algorithm.
+/// See "STTypes.h" or README for more information.
+#define SETTING_SEQUENCE_MS 3
+
+/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the
+/// best possible overlapping location. This determines from how wide window the algorithm
+/// may look for an optimal joining location when mixing the sound sequences back together.
+/// See "STTypes.h" or README for more information.
+#define SETTING_SEEKWINDOW_MS 4
+
+/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences
+/// are mixed back together, to form a continuous sound stream, this parameter defines over
+/// how long period the two consecutive sequences are let to overlap each other.
+/// See "STTypes.h" or README for more information.
+#define SETTING_OVERLAP_MS 5
+
+
+class SoundTouch : public FIFOProcessor
+{
+private:
+ /// Rate transposer class instance
+ class RateTransposer *pRateTransposer;
+
+ /// Time-stretch class instance
+ class TDStretch *pTDStretch;
+
+ /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
+ float virtualRate;
+
+ /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
+ float virtualTempo;
+
+ /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
+ float virtualPitch;
+
+ /// Flag: Has sample rate been set?
+ BOOL bSrateSet;
+
+ /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and
+ /// 'virtualPitch' parameters.
+ void calcEffectiveRateAndTempo();
+
+protected :
+ /// Number of channels
+ uint channels;
+
+ /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
+ float rate;
+
+ /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
+ float tempo;
+
+public:
+ SoundTouch();
+ virtual ~SoundTouch();
+
+ /// Get SoundTouch library version string
+ static const char *getVersionString();
+
+ /// Get SoundTouch library version Id
+ static uint getVersionId();
+
+ /// Sets new rate control value. Normal rate = 1.0, smaller values
+ /// represent slower rate, larger faster rates.
+ void setRate(float newRate);
+
+ /// Sets new tempo control value. Normal tempo = 1.0, smaller values
+ /// represent slower tempo, larger faster tempo.
+ void setTempo(float newTempo);
+
+ /// Sets new rate control value as a difference in percents compared
+ /// to the original rate (-50 .. +100 %)
+ void setRateChange(float newRate);
+
+ /// Sets new tempo control value as a difference in percents compared
+ /// to the original tempo (-50 .. +100 %)
+ void setTempoChange(float newTempo);
+
+ /// Sets new pitch control value. Original pitch = 1.0, smaller values
+ /// represent lower pitches, larger values higher pitch.
+ void setPitch(float newPitch);
+
+ /// Sets pitch change in octaves compared to the original pitch
+ /// (-1.00 .. +1.00)
+ void setPitchOctaves(float newPitch);
+
+ /// Sets pitch change in semi-tones compared to the original pitch
+ /// (-12 .. +12)
+ void setPitchSemiTones(int newPitch);
+ void setPitchSemiTones(float newPitch);
+
+ /// Sets the number of channels, 1 = mono, 2 = stereo
+ void setChannels(uint numChannels);
+
+ /// Sets sample rate.
+ void setSampleRate(uint srate);
+
+ /// Flushes the last samples from the processing pipeline to the output.
+ /// Clears also the internal processing buffers.
+ //
+ /// Note: This function is meant for extracting the last samples of a sound
+ /// stream. This function may introduce additional blank samples in the end
+ /// of the sound stream, and thus it's not recommended to call this function
+ /// in the middle of a sound stream.
+ void flush();
+
+ /// Adds 'numSamples' pcs of samples from the 'samples' memory position into
+ /// the input of the object. Notice that sample rate _has_to_ be set before
+ /// calling this function, otherwise throws a runtime_error exception.
+ virtual void putSamples(
+ const SAMPLETYPE *samples, ///< Pointer to sample buffer.
+ uint numSamples ///< Number of samples in buffer. Notice
+ ///< that in case of stereo-sound a single sample
+ ///< contains data for both channels.
+ );
+
+ /// Clears all the samples in the object's output and internal processing
+ /// buffers.
+ virtual void clear();
+
+ /// Changes a setting controlling the processing system behaviour. See the
+ /// 'SETTING_...' defines for available setting ID's.
+ ///
+ /// \return 'TRUE' if the setting was succesfully changed
+ BOOL setSetting(int settingId, ///< Setting ID number. see SETTING_... defines.
+ int value ///< New setting value.
+ );
+
+ /// Reads a setting controlling the processing system behaviour. See the
+ /// 'SETTING_...' defines for available setting ID's.
+ ///
+ /// \return the setting value.
+ int getSetting(int settingId ///< Setting ID number, see SETTING_... defines.
+ ) const;
+
+ /// Returns number of samples currently unprocessed.
+ virtual uint numUnprocessedSamples() const;
+
+
+ /// Other handy functions that are implemented in the ancestor classes (see
+ /// classes 'FIFOProcessor' and 'FIFOSamplePipe')
+ ///
+ /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch.
+ /// - numSamples() : Get number of 'ready' samples that can be received with
+ /// function 'receiveSamples()'
+ /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples.
+ /// - clear() : Clears all samples from ready/processing buffers.
+};
+
+}
+#endif
diff --git a/plugins/soundtouch/soundtouch/include/soundtouch_config.h b/plugins/soundtouch/soundtouch/include/soundtouch_config.h
new file mode 100644
index 00000000..4097691b
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/include/soundtouch_config.h
@@ -0,0 +1,88 @@
+/* include/soundtouch_config.h. Generated from soundtouch_config.h.in by configure. */
+/* include/soundtouch_config.h.in. Generated from configure.ac by autoheader. */
+
+/* Use Float as Sample type */
+#define FLOAT_SAMPLES 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `m' library (-lm). */
+#define HAVE_LIBM 1
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+ to 0 otherwise. */
+#define HAVE_MALLOC 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Use Integer as Sample type */
+/* #undef INTEGER_SAMPLES */
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Name of package */
+#define PACKAGE "soundtouch"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "http://www.surina.net/soundtouch"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "SoundTouch"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "SoundTouch 1.4.0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "soundtouch"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.4.0"
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "1.4.0"
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to rpl_malloc if the replacement function should be used. */
+/* #undef malloc */
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/3dnow_win.cpp b/plugins/soundtouch/soundtouch/source/SoundTouch/3dnow_win.cpp
new file mode 100644
index 00000000..f0a9d7ec
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/3dnow_win.cpp
@@ -0,0 +1,349 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Win32 version of the AMD 3DNow! optimized routines for AMD K6-2/Athlon
+/// processors. All 3DNow! optimized functions have been gathered into this
+/// single source code file, regardless to their class or original source code
+/// file, in order to ease porting the library to other compiler and processor
+/// platforms.
+///
+/// By the way; the performance gain depends heavily on the CPU generation: On
+/// K6-2 these routines provided speed-up of even 2.4 times, while on Athlon the
+/// difference to the original routines stayed at unremarkable 8%! Such a small
+/// improvement on Athlon is due to 3DNow can perform only two operations in
+/// parallel, and obviously also the Athlon FPU is doing a very good job with
+/// the standard C floating point routines! Here these routines are anyway,
+/// although it might not be worth the effort to convert these to GCC platform,
+/// for Athlon CPU at least. The situation is different regarding the SSE
+/// optimizations though, thanks to the four parallel operations of SSE that
+/// already make a difference.
+///
+/// This file is to be compiled in Windows platform with Microsoft Visual C++
+/// Compiler. Please see '3dnow_gcc.cpp' for the gcc compiler version for all
+/// GNU platforms (if file supplied).
+///
+/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++
+/// 6.0 processor pack" update to support 3DNow! instruction set. The update is
+/// available for download at Microsoft Developers Network, see here:
+/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx
+///
+/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and
+/// perform a search with keywords "processor pack".
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-02-21 18:00:14 +0200 (Sat, 21 Feb 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: 3dnow_win.cpp 63 2009-02-21 16:00:14Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include "cpu_detect.h"
+#include "STTypes.h"
+
+#ifndef WIN32
+#error "wrong platform - this source code file is exclusively for Win32 platform"
+#endif
+
+using namespace soundtouch;
+
+#ifdef ALLOW_3DNOW
+// 3DNow! routines available only with float sample type
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// implementation of 3DNow! optimized functions of class 'TDStretch3DNow'
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include "TDStretch.h"
+
+
+// Calculates cross correlation of two buffers
+double TDStretch3DNow::calcCrossCorrStereo(const float *pV1, const float *pV2) const
+{
+ int overlapLengthLocal = overlapLength;
+ float corr = 0;
+
+ // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
+ /*
+ c-pseudocode:
+
+ corr = 0;
+ for (i = 0; i < overlapLength / 4; i ++)
+ {
+ corr += pV1[0] * pV2[0];
+ pV1[1] * pV2[1];
+ pV1[2] * pV2[2];
+ pV1[3] * pV2[3];
+ pV1[4] * pV2[4];
+ pV1[5] * pV2[5];
+ pV1[6] * pV2[6];
+ pV1[7] * pV2[7];
+
+ pV1 += 8;
+ pV2 += 8;
+ }
+ */
+
+ _asm
+ {
+ // give prefetch hints to CPU of what data are to be needed soonish.
+ // give more aggressive hints on pV1 as that changes more between different calls
+ // while pV2 stays the same.
+ prefetch [pV1]
+ prefetch [pV2]
+ prefetch [pV1 + 32]
+
+ mov eax, dword ptr pV2
+ mov ebx, dword ptr pV1
+
+ pxor mm0, mm0
+
+ mov ecx, overlapLengthLocal
+ shr ecx, 2 // div by four
+
+ loop1:
+ movq mm1, [eax]
+ prefetch [eax + 32] // give a prefetch hint to CPU what data are to be needed soonish
+ pfmul mm1, [ebx]
+ prefetch [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish
+
+ movq mm2, [eax + 8]
+ pfadd mm0, mm1
+ pfmul mm2, [ebx + 8]
+
+ movq mm3, [eax + 16]
+ pfadd mm0, mm2
+ pfmul mm3, [ebx + 16]
+
+ movq mm4, [eax + 24]
+ pfadd mm0, mm3
+ pfmul mm4, [ebx + 24]
+
+ add eax, 32
+ pfadd mm0, mm4
+ add ebx, 32
+
+ dec ecx
+ jnz loop1
+
+ // add halfs of mm0 together and return the result.
+ // note: mm1 is used as a dummy parameter only, we actually don't care about it's value
+ pfacc mm0, mm1
+ movd corr, mm0
+ femms
+ }
+
+ return corr;
+}
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// implementation of 3DNow! optimized functions of class 'FIRFilter'
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include "FIRFilter.h"
+
+FIRFilter3DNow::FIRFilter3DNow() : FIRFilter()
+{
+ filterCoeffsUnalign = NULL;
+ filterCoeffsAlign = NULL;
+}
+
+
+FIRFilter3DNow::~FIRFilter3DNow()
+{
+ delete[] filterCoeffsUnalign;
+ filterCoeffsUnalign = NULL;
+ filterCoeffsAlign = NULL;
+}
+
+
+// (overloaded) Calculates filter coefficients for 3DNow! routine
+void FIRFilter3DNow::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor)
+{
+ uint i;
+ float fDivider;
+
+ FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor);
+
+ // Scale the filter coefficients so that it won't be necessary to scale the filtering result
+ // also rearrange coefficients suitably for 3DNow!
+ // Ensure that filter coeffs array is aligned to 16-byte boundary
+ delete[] filterCoeffsUnalign;
+ filterCoeffsUnalign = new float[2 * newLength + 4];
+ filterCoeffsAlign = (float *)(((uint)filterCoeffsUnalign + 15) & (uint)-16);
+
+ fDivider = (float)resultDivider;
+
+ // rearrange the filter coefficients for mmx routines
+ for (i = 0; i < newLength; i ++)
+ {
+ filterCoeffsAlign[2 * i + 0] =
+ filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider;
+ }
+}
+
+
+// 3DNow!-optimized version of the filter routine for stereo sound
+uint FIRFilter3DNow::evaluateFilterStereo(float *dest, const float *src, uint numSamples) const
+{
+ float *filterCoeffsLocal = filterCoeffsAlign;
+ uint count = (numSamples - length) & (uint)-2;
+ uint lengthLocal = length / 4;
+
+ assert(length != 0);
+ assert(count % 2 == 0);
+
+ /* original code:
+
+ double suml1, suml2;
+ double sumr1, sumr2;
+ uint i, j;
+
+ for (j = 0; j < count; j += 2)
+ {
+ const float *ptr;
+
+ suml1 = sumr1 = 0.0;
+ suml2 = sumr2 = 0.0;
+ ptr = src;
+ filterCoeffsLocal = filterCoeffs;
+ for (i = 0; i < lengthLocal; i ++)
+ {
+ // unroll loop for efficiency.
+
+ suml1 += ptr[0] * filterCoeffsLocal[0] +
+ ptr[2] * filterCoeffsLocal[2] +
+ ptr[4] * filterCoeffsLocal[4] +
+ ptr[6] * filterCoeffsLocal[6];
+
+ sumr1 += ptr[1] * filterCoeffsLocal[1] +
+ ptr[3] * filterCoeffsLocal[3] +
+ ptr[5] * filterCoeffsLocal[5] +
+ ptr[7] * filterCoeffsLocal[7];
+
+ suml2 += ptr[8] * filterCoeffsLocal[0] +
+ ptr[10] * filterCoeffsLocal[2] +
+ ptr[12] * filterCoeffsLocal[4] +
+ ptr[14] * filterCoeffsLocal[6];
+
+ sumr2 += ptr[9] * filterCoeffsLocal[1] +
+ ptr[11] * filterCoeffsLocal[3] +
+ ptr[13] * filterCoeffsLocal[5] +
+ ptr[15] * filterCoeffsLocal[7];
+
+ ptr += 16;
+ filterCoeffsLocal += 8;
+ }
+ dest[0] = (float)suml1;
+ dest[1] = (float)sumr1;
+ dest[2] = (float)suml2;
+ dest[3] = (float)sumr2;
+
+ src += 4;
+ dest += 4;
+ }
+
+ */
+ _asm
+ {
+ mov eax, dword ptr dest
+ mov ebx, dword ptr src
+ mov edx, count
+ shr edx, 1
+
+ loop1:
+ // "outer loop" : during each round 2*2 output samples are calculated
+ prefetch [ebx] // give a prefetch hint to CPU what data are to be needed soonish
+ prefetch [filterCoeffsLocal] // give a prefetch hint to CPU what data are to be needed soonish
+
+ mov esi, ebx
+ mov edi, filterCoeffsLocal
+ pxor mm0, mm0
+ pxor mm1, mm1
+ mov ecx, lengthLocal
+
+ loop2:
+ // "inner loop" : during each round four FIR filter taps are evaluated for 2*2 output samples
+ movq mm2, [edi]
+ movq mm3, mm2
+ prefetch [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish
+ pfmul mm2, [esi]
+ prefetch [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish
+ pfmul mm3, [esi + 8]
+
+ movq mm4, [edi + 8]
+ movq mm5, mm4
+ pfadd mm0, mm2
+ pfmul mm4, [esi + 8]
+ pfadd mm1, mm3
+ pfmul mm5, [esi + 16]
+
+ movq mm2, [edi + 16]
+ movq mm6, mm2
+ pfadd mm0, mm4
+ pfmul mm2, [esi + 16]
+ pfadd mm1, mm5
+ pfmul mm6, [esi + 24]
+
+ movq mm3, [edi + 24]
+ movq mm7, mm3
+ pfadd mm0, mm2
+ pfmul mm3, [esi + 24]
+ pfadd mm1, mm6
+ pfmul mm7, [esi + 32]
+ add esi, 32
+ pfadd mm0, mm3
+ add edi, 32
+ pfadd mm1, mm7
+
+ dec ecx
+ jnz loop2
+
+ movq [eax], mm0
+ add ebx, 16
+ movq [eax + 8], mm1
+ add eax, 16
+
+ dec edx
+ jnz loop1
+
+ femms
+ }
+
+ return count;
+}
+
+
+#endif // ALLOW_3DNOW
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/AAFilter.cpp b/plugins/soundtouch/soundtouch/source/SoundTouch/AAFilter.cpp
new file mode 100644
index 00000000..96abda49
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/AAFilter.cpp
@@ -0,0 +1,184 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// FIR low-pass (anti-alias) filter with filter coefficient design routine and
+/// MMX optimization.
+///
+/// Anti-alias filter is used to prevent folding of high frequencies when
+/// transposing the sample rate with interpolation.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-01-11 13:34:24 +0200 (Sun, 11 Jan 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: AAFilter.cpp 45 2009-01-11 11:34:24Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <memory.h>
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include "AAFilter.h"
+#include "FIRFilter.h"
+
+using namespace soundtouch;
+
+#define PI 3.141592655357989
+#define TWOPI (2 * PI)
+
+/*****************************************************************************
+ *
+ * Implementation of the class 'AAFilter'
+ *
+ *****************************************************************************/
+
+AAFilter::AAFilter(uint len)
+{
+ pFIR = FIRFilter::newInstance();
+ cutoffFreq = 0.5;
+ setLength(len);
+}
+
+
+
+AAFilter::~AAFilter()
+{
+ delete pFIR;
+}
+
+
+
+// Sets new anti-alias filter cut-off edge frequency, scaled to
+// sampling frequency (nyquist frequency = 0.5).
+// The filter will cut frequencies higher than the given frequency.
+void AAFilter::setCutoffFreq(double newCutoffFreq)
+{
+ cutoffFreq = newCutoffFreq;
+ calculateCoeffs();
+}
+
+
+
+// Sets number of FIR filter taps
+void AAFilter::setLength(uint newLength)
+{
+ length = newLength;
+ calculateCoeffs();
+}
+
+
+
+// Calculates coefficients for a low-pass FIR filter using Hamming window
+void AAFilter::calculateCoeffs()
+{
+ uint i;
+ double cntTemp, temp, tempCoeff,h, w;
+ double fc2, wc;
+ double scaleCoeff, sum;
+ double *work;
+ SAMPLETYPE *coeffs;
+
+ assert(length >= 2);
+ assert(length % 4 == 0);
+ assert(cutoffFreq >= 0);
+ assert(cutoffFreq <= 0.5);
+
+ work = new double[length];
+ coeffs = new SAMPLETYPE[length];
+
+ fc2 = 2.0 * cutoffFreq;
+ wc = PI * fc2;
+ tempCoeff = TWOPI / (double)length;
+
+ sum = 0;
+ for (i = 0; i < length; i ++)
+ {
+ cntTemp = (double)i - (double)(length / 2);
+
+ temp = cntTemp * wc;
+ if (temp != 0)
+ {
+ h = fc2 * sin(temp) / temp; // sinc function
+ }
+ else
+ {
+ h = 1.0;
+ }
+ w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window
+
+ temp = w * h;
+ work[i] = temp;
+
+ // calc net sum of coefficients
+ sum += temp;
+ }
+
+ // ensure the sum of coefficients is larger than zero
+ assert(sum > 0);
+
+ // ensure we've really designed a lowpass filter...
+ assert(work[length/2] > 0);
+ assert(work[length/2 + 1] > -1e-6);
+ assert(work[length/2 - 1] > -1e-6);
+
+ // Calculate a scaling coefficient in such a way that the result can be
+ // divided by 16384
+ scaleCoeff = 16384.0f / sum;
+
+ for (i = 0; i < length; i ++)
+ {
+ // scale & round to nearest integer
+ temp = work[i] * scaleCoeff;
+ temp += (temp >= 0) ? 0.5 : -0.5;
+ // ensure no overfloods
+ assert(temp >= -32768 && temp <= 32767);
+ coeffs[i] = (SAMPLETYPE)temp;
+ }
+
+ // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384
+ pFIR->setCoefficients(coeffs, length, 14);
+
+ delete[] work;
+ delete[] coeffs;
+}
+
+
+// Applies the filter to the given sequence of samples.
+// Note : The amount of outputted samples is by value of 'filter length'
+// smaller than the amount of input samples.
+uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const
+{
+ return pFIR->evaluate(dest, src, numSamples, numChannels);
+}
+
+
+uint AAFilter::getLength() const
+{
+ return pFIR->getLength();
+}
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/AAFilter.h b/plugins/soundtouch/soundtouch/source/SoundTouch/AAFilter.h
new file mode 100644
index 00000000..d5c8ce4c
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/AAFilter.h
@@ -0,0 +1,91 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
+/// while maintaining the original pitch by using a time domain WSOLA-like method
+/// with several performance-increasing tweaks.
+///
+/// Anti-alias filter is used to prevent folding of high frequencies when
+/// transposing the sample rate with interpolation.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2008-02-10 18:26:55 +0200 (Sun, 10 Feb 2008) $
+// File revision : $Revision: 4 $
+//
+// $Id: AAFilter.h 11 2008-02-10 16:26:55Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef AAFilter_H
+#define AAFilter_H
+
+#include "STTypes.h"
+
+namespace soundtouch
+{
+
+class AAFilter
+{
+protected:
+ class FIRFilter *pFIR;
+
+ /// Low-pass filter cut-off frequency, negative = invalid
+ double cutoffFreq;
+
+ /// num of filter taps
+ uint length;
+
+ /// Calculate the FIR coefficients realizing the given cutoff-frequency
+ void calculateCoeffs();
+public:
+ AAFilter(uint length);
+
+ ~AAFilter();
+
+ /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling
+ /// frequency (nyquist frequency = 0.5). The filter will cut off the
+ /// frequencies than that.
+ void setCutoffFreq(double newCutoffFreq);
+
+ /// Sets number of FIR filter taps, i.e. ~filter complexity
+ void setLength(uint newLength);
+
+ uint getLength() const;
+
+ /// Applies the filter to the given sequence of samples.
+ /// Note : The amount of outputted samples is by value of 'filter length'
+ /// smaller than the amount of input samples.
+ uint evaluate(SAMPLETYPE *dest,
+ const SAMPLETYPE *src,
+ uint numSamples,
+ uint numChannels) const;
+};
+
+}
+
+#endif
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/BPMDetect.cpp b/plugins/soundtouch/soundtouch/source/SoundTouch/BPMDetect.cpp
new file mode 100644
index 00000000..405f514b
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/BPMDetect.cpp
@@ -0,0 +1,308 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Beats-per-minute (BPM) detection routine.
+///
+/// The beat detection algorithm works as follows:
+/// - Use function 'inputSamples' to input a chunks of samples to the class for
+/// analysis. It's a good idea to enter a large sound file or stream in smallish
+/// chunks of around few kilosamples in order not to extinguish too much RAM memory.
+/// - Inputted sound data is decimated to approx 500 Hz to reduce calculation burden,
+/// which is basically ok as low (bass) frequencies mostly determine the beat rate.
+/// Simple averaging is used for anti-alias filtering because the resulting signal
+/// quality isn't of that high importance.
+/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by
+/// taking absolute value that's smoothed by sliding average. Signal levels that
+/// are below a couple of times the general RMS amplitude level are cut away to
+/// leave only notable peaks there.
+/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term
+/// autocorrelation function of the enveloped signal.
+/// - After whole sound data file has been analyzed as above, the bpm level is
+/// detected by function 'getBpm' that finds the highest peak of the autocorrelation
+/// function, calculates it's precise location and converts this reading to bpm's.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-02-21 18:00:14 +0200 (Sat, 21 Feb 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: BPMDetect.cpp 63 2009-02-21 16:00:14Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <math.h>
+#include <assert.h>
+#include <string.h>
+#include "FIFOSampleBuffer.h"
+#include "PeakFinder.h"
+#include "BPMDetect.h"
+
+using namespace soundtouch;
+
+#define INPUT_BLOCK_SAMPLES 2048
+#define DECIMATED_BLOCK_SAMPLES 256
+
+/// decay constant for calculating RMS volume sliding average approximation
+/// (time constant is about 10 sec)
+const float avgdecay = 0.99986f;
+
+/// Normalization coefficient for calculating RMS sliding average approximation.
+const float avgnorm = (1 - avgdecay);
+
+
+
+BPMDetect::BPMDetect(int numChannels, int aSampleRate)
+{
+ this->sampleRate = aSampleRate;
+ this->channels = numChannels;
+
+ decimateSum = 0;
+ decimateCount = 0;
+
+ envelopeAccu = 0;
+
+ // Initialize RMS volume accumulator to RMS level of 3000 (out of 32768) that's
+ // a typical RMS signal level value for song data. This value is then adapted
+ // to the actual level during processing.
+#ifdef INTEGER_SAMPLES
+ // integer samples
+ RMSVolumeAccu = (3000 * 3000) / avgnorm;
+#else
+ // float samples, scaled to range [-1..+1[
+ RMSVolumeAccu = (0.092f * 0.092f) / avgnorm;
+#endif
+
+ // choose decimation factor so that result is approx. 500 Hz
+ decimateBy = sampleRate / 500;
+ assert(decimateBy > 0);
+ assert(INPUT_BLOCK_SAMPLES < decimateBy * DECIMATED_BLOCK_SAMPLES);
+
+ // Calculate window length & starting item according to desired min & max bpms
+ windowLen = (60 * sampleRate) / (decimateBy * MIN_BPM);
+ windowStart = (60 * sampleRate) / (decimateBy * MAX_BPM);
+
+ assert(windowLen > windowStart);
+
+ // allocate new working objects
+ xcorr = new float[windowLen];
+ memset(xcorr, 0, windowLen * sizeof(float));
+
+ // allocate processing buffer
+ buffer = new FIFOSampleBuffer();
+ // we do processing in mono mode
+ buffer->setChannels(1);
+ buffer->clear();
+}
+
+
+
+BPMDetect::~BPMDetect()
+{
+ delete[] xcorr;
+ delete buffer;
+}
+
+
+
+/// convert to mono, low-pass filter & decimate to about 500 Hz.
+/// return number of outputted samples.
+///
+/// Decimation is used to remove the unnecessary frequencies and thus to reduce
+/// the amount of data needed to be processed as calculating autocorrelation
+/// function is a very-very heavy operation.
+///
+/// Anti-alias filtering is done simply by averaging the samples. This is really a
+/// poor-man's anti-alias filtering, but it's not so critical in this kind of application
+/// (it'd also be difficult to design a high-quality filter with steep cut-off at very
+/// narrow band)
+int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples)
+{
+ int count, outcount;
+ LONG_SAMPLETYPE out;
+
+ assert(channels > 0);
+ assert(decimateBy > 0);
+ outcount = 0;
+ for (count = 0; count < numsamples; count ++)
+ {
+ int j;
+
+ // convert to mono and accumulate
+ for (j = 0; j < channels; j ++)
+ {
+ decimateSum += src[j];
+ }
+ src += j;
+
+ decimateCount ++;
+ if (decimateCount >= decimateBy)
+ {
+ // Store every Nth sample only
+ out = (LONG_SAMPLETYPE)(decimateSum / (decimateBy * channels));
+ decimateSum = 0;
+ decimateCount = 0;
+#ifdef INTEGER_SAMPLES
+ // check ranges for sure (shouldn't actually be necessary)
+ if (out > 32767)
+ {
+ out = 32767;
+ }
+ else if (out < -32768)
+ {
+ out = -32768;
+ }
+#endif // INTEGER_SAMPLES
+ dest[outcount] = (SAMPLETYPE)out;
+ outcount ++;
+ }
+ }
+ return outcount;
+}
+
+
+
+// Calculates autocorrelation function of the sample history buffer
+void BPMDetect::updateXCorr(int process_samples)
+{
+ int offs;
+ SAMPLETYPE *pBuffer;
+
+ assert(buffer->numSamples() >= (uint)(process_samples + windowLen));
+
+ pBuffer = buffer->ptrBegin();
+ for (offs = windowStart; offs < windowLen; offs ++)
+ {
+ LONG_SAMPLETYPE sum;
+ int i;
+
+ sum = 0;
+ for (i = 0; i < process_samples; i ++)
+ {
+ sum += pBuffer[i] * pBuffer[i + offs]; // scaling the sub-result shouldn't be necessary
+ }
+// xcorr[offs] *= xcorr_decay; // decay 'xcorr' here with suitable coefficients
+ // if it's desired that the system adapts automatically to
+ // various bpms, e.g. in processing continouos music stream.
+ // The 'xcorr_decay' should be a value that's smaller than but
+ // close to one, and should also depend on 'process_samples' value.
+
+ xcorr[offs] += (float)sum;
+ }
+}
+
+
+
+// Calculates envelope of the sample data
+void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples)
+{
+ const float decay = 0.7f; // decay constant for smoothing the envelope
+ const float norm = (1 - decay);
+
+ int i;
+ LONG_SAMPLETYPE out;
+ float val;
+
+ for (i = 0; i < numsamples; i ++)
+ {
+ // calc average RMS volume
+ RMSVolumeAccu *= avgdecay;
+ val = (float)fabs((float)samples[i]);
+ RMSVolumeAccu += val * val;
+
+ // cut amplitudes that are below 2 times average RMS volume
+ // (we're interested in peak values, not the silent moments)
+ val -= 2 * (float)sqrt(RMSVolumeAccu * avgnorm);
+ val = (val > 0) ? val : 0;
+
+ // smooth amplitude envelope
+ envelopeAccu *= decay;
+ envelopeAccu += val;
+ out = (LONG_SAMPLETYPE)(envelopeAccu * norm);
+
+#ifdef INTEGER_SAMPLES
+ // cut peaks (shouldn't be necessary though)
+ if (out > 32767) out = 32767;
+#endif // INTEGER_SAMPLES
+ samples[i] = (SAMPLETYPE)out;
+ }
+}
+
+
+
+void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples)
+{
+ SAMPLETYPE decimated[DECIMATED_BLOCK_SAMPLES];
+
+ // iterate so that max INPUT_BLOCK_SAMPLES processed per iteration
+ while (numSamples > 0)
+ {
+ int block;
+ int decSamples;
+
+ block = (numSamples > INPUT_BLOCK_SAMPLES) ? INPUT_BLOCK_SAMPLES : numSamples;
+
+ // decimate. note that converts to mono at the same time
+ decSamples = decimate(decimated, samples, block);
+ samples += block * channels;
+ numSamples -= block;
+
+ // envelope new samples and add them to buffer
+ calcEnvelope(decimated, decSamples);
+ buffer->putSamples(decimated, decSamples);
+ }
+
+ // when the buffer has enought samples for processing...
+ if ((int)buffer->numSamples() > windowLen)
+ {
+ int processLength;
+
+ // how many samples are processed
+ processLength = (int)buffer->numSamples() - windowLen;
+
+ // ... calculate autocorrelations for oldest samples...
+ updateXCorr(processLength);
+ // ... and remove them from the buffer
+ buffer->receiveSamples(processLength);
+ }
+}
+
+
+
+float BPMDetect::getBpm()
+{
+ double peakPos;
+ PeakFinder peakFinder;
+
+ // find peak position
+ peakPos = peakFinder.detectPeak(xcorr, windowStart, windowLen);
+
+ assert(decimateBy != 0);
+ if (peakPos < 1e-6) return 0.0; // detection failed.
+
+ // calculate BPM
+ return (float)(60.0 * (((double)sampleRate / (double)decimateBy) / peakPos));
+}
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/FIFOSampleBuffer.cpp b/plugins/soundtouch/soundtouch/source/SoundTouch/FIFOSampleBuffer.cpp
new file mode 100644
index 00000000..01f64b08
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/FIFOSampleBuffer.cpp
@@ -0,0 +1,262 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// A buffer class for temporarily storaging sound samples, operates as a
+/// first-in-first-out pipe.
+///
+/// Samples are added to the end of the sample buffer with the 'putSamples'
+/// function, and are received from the beginning of the buffer by calling
+/// the 'receiveSamples' function. The class automatically removes the
+/// outputted samples from the buffer, as well as grows the buffer size
+/// whenever necessary.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-02-27 19:24:42 +0200 (Fri, 27 Feb 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: FIFOSampleBuffer.cpp 68 2009-02-27 17:24:42Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <stdlib.h>
+#include <memory.h>
+#include <string.h>
+#include <assert.h>
+#include <stdexcept>
+
+#include "FIFOSampleBuffer.h"
+
+using namespace soundtouch;
+
+// Constructor
+FIFOSampleBuffer::FIFOSampleBuffer(int numChannels)
+{
+ assert(numChannels > 0);
+ sizeInBytes = 0; // reasonable initial value
+ buffer = NULL;
+ bufferUnaligned = NULL;
+ samplesInBuffer = 0;
+ bufferPos = 0;
+ channels = (uint)numChannels;
+ ensureCapacity(32); // allocate initial capacity
+}
+
+
+// destructor
+FIFOSampleBuffer::~FIFOSampleBuffer()
+{
+ delete[] bufferUnaligned;
+ bufferUnaligned = NULL;
+ buffer = NULL;
+}
+
+
+// Sets number of channels, 1 = mono, 2 = stereo
+void FIFOSampleBuffer::setChannels(int numChannels)
+{
+ uint usedBytes;
+
+ assert(numChannels > 0);
+ usedBytes = channels * samplesInBuffer;
+ channels = (uint)numChannels;
+ samplesInBuffer = usedBytes / channels;
+}
+
+
+// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and
+// zeroes this pointer by copying samples from the 'bufferPos' pointer
+// location on to the beginning of the buffer.
+void FIFOSampleBuffer::rewind()
+{
+ if (buffer && bufferPos)
+ {
+ memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer);
+ bufferPos = 0;
+ }
+}
+
+
+// Adds 'numSamples' pcs of samples from the 'samples' memory position to
+// the sample buffer.
+void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples)
+{
+ memcpy(ptrEnd(nSamples), samples, sizeof(SAMPLETYPE) * nSamples * channels);
+ samplesInBuffer += nSamples;
+}
+
+
+// Increases the number of samples in the buffer without copying any actual
+// samples.
+//
+// This function is used to update the number of samples in the sample buffer
+// when accessing the buffer directly with 'ptrEnd' function. Please be
+// careful though!
+void FIFOSampleBuffer::putSamples(uint nSamples)
+{
+ uint req;
+
+ req = samplesInBuffer + nSamples;
+ ensureCapacity(req);
+ samplesInBuffer += nSamples;
+}
+
+
+// Returns a pointer to the end of the used part of the sample buffer (i.e.
+// where the new samples are to be inserted). This function may be used for
+// inserting new samples into the sample buffer directly. Please be careful!
+//
+// Parameter 'slackCapacity' tells the function how much free capacity (in
+// terms of samples) there _at least_ should be, in order to the caller to
+// succesfully insert all the required samples to the buffer. When necessary,
+// the function grows the buffer size to comply with this requirement.
+//
+// When using this function as means for inserting new samples, also remember
+// to increase the sample count afterwards, by calling the
+// 'putSamples(numSamples)' function.
+SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity)
+{
+ ensureCapacity(samplesInBuffer + slackCapacity);
+ return buffer + samplesInBuffer * channels;
+}
+
+
+// Returns a pointer to the beginning of the currently non-outputted samples.
+// This function is provided for accessing the output samples directly.
+// Please be careful!
+//
+// When using this function to output samples, also remember to 'remove' the
+// outputted samples from the buffer by calling the
+// 'receiveSamples(numSamples)' function
+SAMPLETYPE *FIFOSampleBuffer::ptrBegin()
+{
+ assert(buffer);
+ return buffer + bufferPos * channels;
+}
+
+
+// Ensures that the buffer has enought capacity, i.e. space for _at least_
+// 'capacityRequirement' number of samples. The buffer is grown in steps of
+// 4 kilobytes to eliminate the need for frequently growing up the buffer,
+// as well as to round the buffer size up to the virtual memory page size.
+void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement)
+{
+ SAMPLETYPE *tempUnaligned, *temp;
+
+ if (capacityRequirement > getCapacity())
+ {
+ // enlarge the buffer in 4kbyte steps (round up to next 4k boundary)
+ sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096;
+ assert(sizeInBytes % 2 == 0);
+ tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)];
+ if (tempUnaligned == NULL)
+ {
+ throw std::runtime_error("Couldn't allocate memory!\n");
+ }
+ // Align the buffer to begin at 16byte cache line boundary for optimal performance
+ temp = (SAMPLETYPE *)(((ulong)tempUnaligned + 15) & (ulong)-16);
+ if (samplesInBuffer)
+ {
+ memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE));
+ }
+ delete[] bufferUnaligned;
+ buffer = temp;
+ bufferUnaligned = tempUnaligned;
+ bufferPos = 0;
+ }
+ else
+ {
+ // simply rewind the buffer (if necessary)
+ rewind();
+ }
+}
+
+
+// Returns the current buffer capacity in terms of samples
+uint FIFOSampleBuffer::getCapacity() const
+{
+ return sizeInBytes / (channels * sizeof(SAMPLETYPE));
+}
+
+
+// Returns the number of samples currently in the buffer
+uint FIFOSampleBuffer::numSamples() const
+{
+ return samplesInBuffer;
+}
+
+
+// Output samples from beginning of the sample buffer. Copies demanded number
+// of samples to output and removes them from the sample buffer. If there
+// are less than 'numsample' samples in the buffer, returns all available.
+//
+// Returns number of samples copied.
+uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples)
+{
+ uint num;
+
+ num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples;
+
+ memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num);
+ return receiveSamples(num);
+}
+
+
+// Removes samples from the beginning of the sample buffer without copying them
+// anywhere. Used to reduce the number of samples in the buffer, when accessing
+// the sample buffer with the 'ptrBegin' function.
+uint FIFOSampleBuffer::receiveSamples(uint maxSamples)
+{
+ if (maxSamples >= samplesInBuffer)
+ {
+ uint temp;
+
+ temp = samplesInBuffer;
+ samplesInBuffer = 0;
+ return temp;
+ }
+
+ samplesInBuffer -= maxSamples;
+ bufferPos += maxSamples;
+
+ return maxSamples;
+}
+
+
+// Returns nonzero if the sample buffer is empty
+int FIFOSampleBuffer::isEmpty() const
+{
+ return (samplesInBuffer == 0) ? 1 : 0;
+}
+
+
+// Clears the sample buffer
+void FIFOSampleBuffer::clear()
+{
+ samplesInBuffer = 0;
+ bufferPos = 0;
+}
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/FIRFilter.cpp b/plugins/soundtouch/soundtouch/source/SoundTouch/FIRFilter.cpp
new file mode 100644
index 00000000..231263ad
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/FIRFilter.cpp
@@ -0,0 +1,269 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// General FIR digital filter routines with MMX optimization.
+///
+/// Note : MMX optimized functions reside in a separate, platform-specific file,
+/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-02-25 19:13:51 +0200 (Wed, 25 Feb 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: FIRFilter.cpp 67 2009-02-25 17:13:51Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <memory.h>
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdexcept>
+#include "FIRFilter.h"
+#include "cpu_detect.h"
+
+using namespace soundtouch;
+
+/*****************************************************************************
+ *
+ * Implementation of the class 'FIRFilter'
+ *
+ *****************************************************************************/
+
+FIRFilter::FIRFilter()
+{
+ resultDivFactor = 0;
+ resultDivider = 0;
+ length = 0;
+ lengthDiv8 = 0;
+ filterCoeffs = NULL;
+}
+
+
+FIRFilter::~FIRFilter()
+{
+ delete[] filterCoeffs;
+}
+
+// Usual C-version of the filter routine for stereo sound
+uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
+{
+ uint i, j, end;
+ LONG_SAMPLETYPE suml, sumr;
+#ifdef FLOAT_SAMPLES
+ // when using floating point samples, use a scaler instead of a divider
+ // because division is much slower operation than multiplying.
+ double dScaler = 1.0 / (double)resultDivider;
+#endif
+
+ assert(length != 0);
+ assert(src != NULL);
+ assert(dest != NULL);
+ assert(filterCoeffs != NULL);
+
+ end = 2 * (numSamples - length);
+
+ for (j = 0; j < end; j += 2)
+ {
+ const SAMPLETYPE *ptr;
+
+ suml = sumr = 0;
+ ptr = src + j;
+
+ for (i = 0; i < length; i += 4)
+ {
+ // loop is unrolled by factor of 4 here for efficiency
+ suml += ptr[2 * i + 0] * filterCoeffs[i + 0] +
+ ptr[2 * i + 2] * filterCoeffs[i + 1] +
+ ptr[2 * i + 4] * filterCoeffs[i + 2] +
+ ptr[2 * i + 6] * filterCoeffs[i + 3];
+ sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] +
+ ptr[2 * i + 3] * filterCoeffs[i + 1] +
+ ptr[2 * i + 5] * filterCoeffs[i + 2] +
+ ptr[2 * i + 7] * filterCoeffs[i + 3];
+ }
+
+#ifdef INTEGER_SAMPLES
+ suml >>= resultDivFactor;
+ sumr >>= resultDivFactor;
+ // saturate to 16 bit integer limits
+ suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml;
+ // saturate to 16 bit integer limits
+ sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr;
+#else
+ suml *= dScaler;
+ sumr *= dScaler;
+#endif // INTEGER_SAMPLES
+ dest[j] = (SAMPLETYPE)suml;
+ dest[j + 1] = (SAMPLETYPE)sumr;
+ }
+ return numSamples - length;
+}
+
+
+
+
+// Usual C-version of the filter routine for mono sound
+uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
+{
+ uint i, j, end;
+ LONG_SAMPLETYPE sum;
+#ifdef FLOAT_SAMPLES
+ // when using floating point samples, use a scaler instead of a divider
+ // because division is much slower operation than multiplying.
+ double dScaler = 1.0 / (double)resultDivider;
+#endif
+
+
+ assert(length != 0);
+
+ end = numSamples - length;
+ for (j = 0; j < end; j ++)
+ {
+ sum = 0;
+ for (i = 0; i < length; i += 4)
+ {
+ // loop is unrolled by factor of 4 here for efficiency
+ sum += src[i + 0] * filterCoeffs[i + 0] +
+ src[i + 1] * filterCoeffs[i + 1] +
+ src[i + 2] * filterCoeffs[i + 2] +
+ src[i + 3] * filterCoeffs[i + 3];
+ }
+#ifdef INTEGER_SAMPLES
+ sum >>= resultDivFactor;
+ // saturate to 16 bit integer limits
+ sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum;
+#else
+ sum *= dScaler;
+#endif // INTEGER_SAMPLES
+ dest[j] = (SAMPLETYPE)sum;
+ src ++;
+ }
+ return end;
+}
+
+
+// Set filter coeffiecients and length.
+//
+// Throws an exception if filter length isn't divisible by 8
+void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor)
+{
+ assert(newLength > 0);
+ if (newLength % 8) throw std::runtime_error("FIR filter length not divisible by 8");
+
+ lengthDiv8 = newLength / 8;
+ length = lengthDiv8 * 8;
+ assert(length == newLength);
+
+ resultDivFactor = uResultDivFactor;
+ resultDivider = (SAMPLETYPE)::pow(2.0, (int)resultDivFactor);
+
+ delete[] filterCoeffs;
+ filterCoeffs = new SAMPLETYPE[length];
+ memcpy(filterCoeffs, coeffs, length * sizeof(SAMPLETYPE));
+}
+
+
+uint FIRFilter::getLength() const
+{
+ return length;
+}
+
+
+
+// Applies the filter to the given sequence of samples.
+//
+// Note : The amount of outputted samples is by value of 'filter_length'
+// smaller than the amount of input samples.
+uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const
+{
+ assert(numChannels == 1 || numChannels == 2);
+
+ assert(length > 0);
+ assert(lengthDiv8 * 8 == length);
+ if (numSamples < length) return 0;
+ if (numChannels == 2)
+ {
+ return evaluateFilterStereo(dest, src, numSamples);
+ } else {
+ return evaluateFilterMono(dest, src, numSamples);
+ }
+}
+
+
+
+// Operator 'new' is overloaded so that it automatically creates a suitable instance
+// depending on if we've a MMX-capable CPU available or not.
+void * FIRFilter::operator new(size_t s)
+{
+ // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead!
+ throw std::runtime_error("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!");
+ return NULL;
+}
+
+
+FIRFilter * FIRFilter::newInstance()
+{
+ uint uExtensions;
+
+ uExtensions = detectCPUextensions();
+
+ // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU
+
+#ifdef ALLOW_MMX
+ // MMX routines available only with integer sample types
+ if (uExtensions & SUPPORT_MMX)
+ {
+ return ::new FIRFilterMMX;
+ }
+ else
+#endif // ALLOW_MMX
+
+#ifdef ALLOW_SSE
+ if (uExtensions & SUPPORT_SSE)
+ {
+ // SSE support
+ return ::new FIRFilterSSE;
+ }
+ else
+#endif // ALLOW_SSE
+
+#ifdef ALLOW_3DNOW
+ if (uExtensions & SUPPORT_3DNOW)
+ {
+ // 3DNow! support
+ return ::new FIRFilter3DNow;
+ }
+ else
+#endif // ALLOW_3DNOW
+
+ {
+ // ISA optimizations not supported, use plain C version
+ return ::new FIRFilter;
+ }
+}
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/FIRFilter.h b/plugins/soundtouch/soundtouch/source/SoundTouch/FIRFilter.h
new file mode 100644
index 00000000..5713f7bb
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/FIRFilter.h
@@ -0,0 +1,164 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// General FIR digital filter routines with MMX optimization.
+///
+/// Note : MMX optimized functions reside in a separate, platform-specific file,
+/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-02-21 18:00:14 +0200 (Sat, 21 Feb 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: FIRFilter.h 63 2009-02-21 16:00:14Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef FIRFilter_H
+#define FIRFilter_H
+
+#include <stddef.h>
+#include "STTypes.h"
+
+namespace soundtouch
+{
+
+class FIRFilter
+{
+protected:
+ // Number of FIR filter taps
+ uint length;
+ // Number of FIR filter taps divided by 8
+ uint lengthDiv8;
+
+ // Result divider factor in 2^k format
+ uint resultDivFactor;
+
+ // Result divider value.
+ SAMPLETYPE resultDivider;
+
+ // Memory for filter coefficients
+ SAMPLETYPE *filterCoeffs;
+
+ virtual uint evaluateFilterStereo(SAMPLETYPE *dest,
+ const SAMPLETYPE *src,
+ uint numSamples) const;
+ virtual uint evaluateFilterMono(SAMPLETYPE *dest,
+ const SAMPLETYPE *src,
+ uint numSamples) const;
+
+public:
+ FIRFilter();
+ virtual ~FIRFilter();
+
+ /// Operator 'new' is overloaded so that it automatically creates a suitable instance
+ /// depending on if we've a MMX-capable CPU available or not.
+ static void * operator new(size_t s);
+
+ static FIRFilter *newInstance();
+
+ /// Applies the filter to the given sequence of samples.
+ /// Note : The amount of outputted samples is by value of 'filter_length'
+ /// smaller than the amount of input samples.
+ ///
+ /// \return Number of samples copied to 'dest'.
+ uint evaluate(SAMPLETYPE *dest,
+ const SAMPLETYPE *src,
+ uint numSamples,
+ uint numChannels) const;
+
+ uint getLength() const;
+
+ virtual void setCoefficients(const SAMPLETYPE *coeffs,
+ uint newLength,
+ uint uResultDivFactor);
+};
+
+
+// Optional subclasses that implement CPU-specific optimizations:
+
+#ifdef ALLOW_MMX
+
+/// Class that implements MMX optimized functions exclusive for 16bit integer samples type.
+ class FIRFilterMMX : public FIRFilter
+ {
+ protected:
+ short *filterCoeffsUnalign;
+ short *filterCoeffsAlign;
+
+ virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const;
+ public:
+ FIRFilterMMX();
+ ~FIRFilterMMX();
+
+ virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor);
+ };
+
+#endif // ALLOW_MMX
+
+
+#ifdef ALLOW_3DNOW
+
+ /// Class that implements 3DNow! optimized functions exclusive for floating point samples type.
+ class FIRFilter3DNow : public FIRFilter
+ {
+ protected:
+ float *filterCoeffsUnalign;
+ float *filterCoeffsAlign;
+
+ virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const;
+ public:
+ FIRFilter3DNow();
+ ~FIRFilter3DNow();
+ virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor);
+ };
+
+#endif // ALLOW_3DNOW
+
+
+#ifdef ALLOW_SSE
+ /// Class that implements SSE optimized functions exclusive for floating point samples type.
+ class FIRFilterSSE : public FIRFilter
+ {
+ protected:
+ float *filterCoeffsUnalign;
+ float *filterCoeffsAlign;
+
+ virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const;
+ public:
+ FIRFilterSSE();
+ ~FIRFilterSSE();
+
+ virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor);
+ };
+
+#endif // ALLOW_SSE
+
+}
+
+#endif // FIRFilter_H
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/PeakFinder.cpp b/plugins/soundtouch/soundtouch/source/SoundTouch/PeakFinder.cpp
new file mode 100644
index 00000000..03f60bfa
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/PeakFinder.cpp
@@ -0,0 +1,239 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Peak detection routine.
+///
+/// The routine detects highest value on an array of values and calculates the
+/// precise peak location as a mass-center of the 'hump' around the peak value.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-02-21 18:00:14 +0200 (Sat, 21 Feb 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: PeakFinder.cpp 63 2009-02-21 16:00:14Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <math.h>
+#include <assert.h>
+
+#include "PeakFinder.h"
+
+using namespace soundtouch;
+
+#define max(x, y) (((x) > (y)) ? (x) : (y))
+
+
+PeakFinder::PeakFinder()
+{
+ minPos = maxPos = 0;
+}
+
+
+// Finds 'ground level' of a peak hump by starting from 'peakpos' and proceeding
+// to direction defined by 'direction' until next 'hump' after minimum value will
+// begin
+int PeakFinder::findGround(const float *data, int peakpos, int direction) const
+{
+ float refvalue;
+ int lowpos;
+ int pos;
+ int climb_count;
+ float delta;
+
+ climb_count = 0;
+ refvalue = data[peakpos];
+ lowpos = peakpos;
+
+ pos = peakpos;
+
+ while ((pos > minPos) && (pos < maxPos))
+ {
+ int prevpos;
+
+ prevpos = pos;
+ pos += direction;
+
+ // calculate derivate
+ delta = data[pos] - data[prevpos];
+ if (delta <= 0)
+ {
+ // going downhill, ok
+ if (climb_count)
+ {
+ climb_count --; // decrease climb count
+ }
+
+ // check if new minimum found
+ if (data[pos] < refvalue)
+ {
+ // new minimum found
+ lowpos = pos;
+ refvalue = data[pos];
+ }
+ }
+ else
+ {
+ // going uphill, increase climbing counter
+ climb_count ++;
+ if (climb_count > 5) break; // we've been climbing too long => it's next uphill => quit
+ }
+ }
+ return lowpos;
+}
+
+
+// Find offset where the value crosses the given level, when starting from 'peakpos' and
+// proceeds to direction defined in 'direction'
+int PeakFinder::findCrossingLevel(const float *data, float level, int peakpos, int direction) const
+{
+ float peaklevel;
+ int pos;
+
+ peaklevel = data[peakpos];
+ assert(peaklevel >= level);
+ pos = peakpos;
+ while ((pos >= minPos) && (pos < maxPos))
+ {
+ if (data[pos + direction] < level) return pos; // crossing found
+ pos += direction;
+ }
+ return -1; // not found
+}
+
+
+// Calculates the center of mass location of 'data' array items between 'firstPos' and 'lastPos'
+double PeakFinder::calcMassCenter(const float *data, int firstPos, int lastPos) const
+{
+ int i;
+ float sum;
+ float wsum;
+
+ sum = 0;
+ wsum = 0;
+ for (i = firstPos; i <= lastPos; i ++)
+ {
+ sum += (float)i * data[i];
+ wsum += data[i];
+ }
+
+ if (wsum < 1e-6) return 0;
+ return sum / wsum;
+}
+
+
+
+/// get exact center of peak near given position by calculating local mass of center
+double PeakFinder::getPeakCenter(const float *data, int peakpos) const
+{
+ float peakLevel; // peak level
+ int crosspos1, crosspos2; // position where the peak 'hump' crosses cutting level
+ float cutLevel; // cutting value
+ float groundLevel; // ground level of the peak
+ int gp1, gp2; // bottom positions of the peak 'hump'
+
+ // find ground positions.
+ gp1 = findGround(data, peakpos, -1);
+ gp2 = findGround(data, peakpos, 1);
+
+ groundLevel = max(data[gp1], data[gp2]);
+ peakLevel = data[peakpos];
+
+ if (groundLevel < 1e-6) return 0; // ground level too small => detection failed
+ if ((peakLevel / groundLevel) < 1.3) return 0; // peak less than 30% of the ground level => no good peak detected
+
+ // calculate 70%-level of the peak
+ cutLevel = 0.70f * peakLevel + 0.30f * groundLevel;
+ // find mid-level crossings
+ crosspos1 = findCrossingLevel(data, cutLevel, peakpos, -1);
+ crosspos2 = findCrossingLevel(data, cutLevel, peakpos, 1);
+
+ if ((crosspos1 < 0) || (crosspos2 < 0)) return 0; // no crossing, no peak..
+
+ // calculate mass center of the peak surroundings
+ return calcMassCenter(data, crosspos1, crosspos2);
+}
+
+
+
+double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos)
+{
+
+ int i;
+ int peakpos; // position of peak level
+ double highPeak, peak;
+
+ this->minPos = aminPos;
+ this->maxPos = amaxPos;
+
+ // find absolute peak
+ peakpos = minPos;
+ peak = data[minPos];
+ for (i = minPos + 1; i < maxPos; i ++)
+ {
+ if (data[i] > peak)
+ {
+ peak = data[i];
+ peakpos = i;
+ }
+ }
+
+ // Calculate exact location of the highest peak mass center
+ highPeak = getPeakCenter(data, peakpos);
+ peak = highPeak;
+
+ // Now check if the highest peak were in fact harmonic of the true base beat peak
+ // - sometimes the highest peak can be Nth harmonic of the true base peak yet
+ // just a slightly higher than the true base
+ for (i = 2; i < 10; i ++)
+ {
+ double peaktmp, tmp;
+ int i1,i2;
+
+ peakpos = (int)(highPeak / (double)i + 0.5f);
+ if (peakpos < minPos) break;
+
+ // calculate mass-center of possible base peak
+ peaktmp = getPeakCenter(data, peakpos);
+
+ // now compare to highest detected peak
+ i1 = (int)(highPeak + 0.5);
+ i2 = (int)(peaktmp + 0.5);
+ tmp = 2 * (data[i2] - data[i1]) / (data[i2] + data[i1]);
+ if (fabs(tmp) < 0.1)
+ {
+ // The highest peak is harmonic of almost as high base peak,
+ // thus use the base peak instead
+ peak = peaktmp;
+ }
+ }
+
+ return peak;
+}
+
+
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/PeakFinder.h b/plugins/soundtouch/soundtouch/source/SoundTouch/PeakFinder.h
new file mode 100644
index 00000000..e3640cc6
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/PeakFinder.h
@@ -0,0 +1,93 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// The routine detects highest value on an array of values and calculates the
+/// precise peak location as a mass-center of the 'hump' around the peak value.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-02-21 18:00:14 +0200 (Sat, 21 Feb 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: PeakFinder.h 63 2009-02-21 16:00:14Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef _PeakFinder_H_
+#define _PeakFinder_H_
+
+namespace soundtouch
+{
+
+class PeakFinder
+{
+protected:
+ /// Min, max allowed peak positions within the data vector
+ int minPos, maxPos;
+
+ /// Calculates the mass center between given vector items.
+ double calcMassCenter(const float *data, ///< Data vector.
+ int firstPos, ///< Index of first vector item beloging to the peak.
+ int lastPos ///< Index of last vector item beloging to the peak.
+ ) const;
+
+ /// Finds the data vector index where the monotoniously decreasing signal crosses the
+ /// given level.
+ int findCrossingLevel(const float *data, ///< Data vector.
+ float level, ///< Goal crossing level.
+ int peakpos, ///< Peak position index within the data vector.
+ int direction /// Direction where to proceed from the peak: 1 = right, -1 = left.
+ ) const;
+
+ /// Finds the 'ground' level, i.e. smallest level between two neighbouring peaks, to right-
+ /// or left-hand side of the given peak position.
+ int findGround(const float *data, /// Data vector.
+ int peakpos, /// Peak position index within the data vector.
+ int direction /// Direction where to proceed from the peak: 1 = right, -1 = left.
+ ) const;
+
+ /// get exact center of peak near given position by calculating local mass of center
+ double getPeakCenter(const float *data, int peakpos) const;
+
+public:
+ /// Constructor.
+ PeakFinder();
+
+ /// Detect exact peak position of the data vector by finding the largest peak 'hump'
+ /// and calculating the mass-center location of the peak hump.
+ ///
+ /// \return The location of the largest base harmonic peak hump.
+ double detectPeak(const float *data, /// Data vector to be analyzed. The data vector has
+ /// to be at least 'maxPos' items long.
+ int minPos, ///< Min allowed peak location within the vector data.
+ int maxPos ///< Max allowed peak location within the vector data.
+ );
+};
+
+}
+
+#endif // _PeakFinder_H_
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/RateTransposer.cpp b/plugins/soundtouch/soundtouch/source/SoundTouch/RateTransposer.cpp
new file mode 100644
index 00000000..7e0b277d
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/RateTransposer.cpp
@@ -0,0 +1,628 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Sample rate transposer. Changes sample rate by using linear interpolation
+/// together with anti-alias filtering (first order interpolation with anti-
+/// alias filtering should be quite adequate for this application)
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-10-31 16:37:24 +0200 (Sat, 31 Oct 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: RateTransposer.cpp 74 2009-10-31 14:37:24Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <memory.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdexcept>
+#include "RateTransposer.h"
+#include "AAFilter.h"
+
+using namespace std;
+using namespace soundtouch;
+
+
+/// A linear samplerate transposer class that uses integer arithmetics.
+/// for the transposing.
+class RateTransposerInteger : public RateTransposer
+{
+protected:
+ int iSlopeCount;
+ int iRate;
+ SAMPLETYPE sPrevSampleL, sPrevSampleR;
+
+ virtual void resetRegisters();
+
+ virtual uint transposeStereo(SAMPLETYPE *dest,
+ const SAMPLETYPE *src,
+ uint numSamples);
+ virtual uint transposeMono(SAMPLETYPE *dest,
+ const SAMPLETYPE *src,
+ uint numSamples);
+
+public:
+ RateTransposerInteger();
+ virtual ~RateTransposerInteger();
+
+ /// Sets new target rate. Normal rate = 1.0, smaller values represent slower
+ /// rate, larger faster rates.
+ virtual void setRate(float newRate);
+
+};
+
+
+/// A linear samplerate transposer class that uses floating point arithmetics
+/// for the transposing.
+class RateTransposerFloat : public RateTransposer
+{
+protected:
+ float fSlopeCount;
+ SAMPLETYPE sPrevSampleL, sPrevSampleR;
+
+ virtual void resetRegisters();
+
+ virtual uint transposeStereo(SAMPLETYPE *dest,
+ const SAMPLETYPE *src,
+ uint numSamples);
+ virtual uint transposeMono(SAMPLETYPE *dest,
+ const SAMPLETYPE *src,
+ uint numSamples);
+
+public:
+ RateTransposerFloat();
+ virtual ~RateTransposerFloat();
+};
+
+
+
+
+// Operator 'new' is overloaded so that it automatically creates a suitable instance
+// depending on if we've a MMX/SSE/etc-capable CPU available or not.
+void * RateTransposer::operator new(size_t s)
+{
+ throw runtime_error("Error in RateTransoser::new: don't use \"new TDStretch\" directly, use \"newInstance\" to create a new instance instead!");
+ return NULL;
+}
+
+
+RateTransposer *RateTransposer::newInstance()
+{
+#ifdef INTEGER_SAMPLES
+ return ::new RateTransposerInteger;
+#else
+ return ::new RateTransposerFloat;
+#endif
+}
+
+
+// Constructor
+RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
+{
+ numChannels = 2;
+ bUseAAFilter = TRUE;
+ fRate = 0;
+
+ // Instantiates the anti-alias filter with default tap length
+ // of 32
+ pAAFilter = new AAFilter(32);
+}
+
+
+
+RateTransposer::~RateTransposer()
+{
+ delete pAAFilter;
+}
+
+
+
+/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
+void RateTransposer::enableAAFilter(BOOL newMode)
+{
+ bUseAAFilter = newMode;
+}
+
+
+/// Returns nonzero if anti-alias filter is enabled.
+BOOL RateTransposer::isAAFilterEnabled() const
+{
+ return bUseAAFilter;
+}
+
+
+AAFilter *RateTransposer::getAAFilter()
+{
+ return pAAFilter;
+}
+
+
+
+// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
+// iRate, larger faster iRates.
+void RateTransposer::setRate(float newRate)
+{
+ double fCutoff;
+
+ fRate = newRate;
+
+ // design a new anti-alias filter
+ if (newRate > 1.0f)
+ {
+ fCutoff = 0.5f / newRate;
+ }
+ else
+ {
+ fCutoff = 0.5f * newRate;
+ }
+ pAAFilter->setCutoffFreq(fCutoff);
+}
+
+
+// Outputs as many samples of the 'outputBuffer' as possible, and if there's
+// any room left, outputs also as many of the incoming samples as possible.
+// The goal is to drive the outputBuffer empty.
+//
+// It's allowed for 'output' and 'input' parameters to point to the same
+// memory position.
+/*
+void RateTransposer::flushStoreBuffer()
+{
+ if (storeBuffer.isEmpty()) return;
+
+ outputBuffer.moveSamples(storeBuffer);
+}
+*/
+
+
+// Adds 'nSamples' pcs of samples from the 'samples' memory position into
+// the input of the object.
+void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples)
+{
+ processSamples(samples, nSamples);
+}
+
+
+
+// Transposes up the sample rate, causing the observed playback 'rate' of the
+// sound to decrease
+void RateTransposer::upsample(const SAMPLETYPE *src, uint nSamples)
+{
+ uint count, sizeTemp, num;
+
+ // If the parameter 'uRate' value is smaller than 'SCALE', first transpose
+ // the samples and then apply the anti-alias filter to remove aliasing.
+
+ // First check that there's enough room in 'storeBuffer'
+ // (+16 is to reserve some slack in the destination buffer)
+ sizeTemp = (uint)((float)nSamples / fRate + 16.0f);
+
+ // Transpose the samples, store the result into the end of "storeBuffer"
+ count = transpose(storeBuffer.ptrEnd(sizeTemp), src, nSamples);
+ storeBuffer.putSamples(count);
+
+ // Apply the anti-alias filter to samples in "store output", output the
+ // result to "dest"
+ num = storeBuffer.numSamples();
+ count = pAAFilter->evaluate(outputBuffer.ptrEnd(num),
+ storeBuffer.ptrBegin(), num, (uint)numChannels);
+ outputBuffer.putSamples(count);
+
+ // Remove the processed samples from "storeBuffer"
+ storeBuffer.receiveSamples(count);
+}
+
+
+// Transposes down the sample rate, causing the observed playback 'rate' of the
+// sound to increase
+void RateTransposer::downsample(const SAMPLETYPE *src, uint nSamples)
+{
+ uint count, sizeTemp;
+
+ // If the parameter 'uRate' value is larger than 'SCALE', first apply the
+ // anti-alias filter to remove high frequencies (prevent them from folding
+ // over the lover frequencies), then transpose.
+
+ // Add the new samples to the end of the storeBuffer
+ storeBuffer.putSamples(src, nSamples);
+
+ // Anti-alias filter the samples to prevent folding and output the filtered
+ // data to tempBuffer. Note : because of the FIR filter length, the
+ // filtering routine takes in 'filter_length' more samples than it outputs.
+ assert(tempBuffer.isEmpty());
+ sizeTemp = storeBuffer.numSamples();
+
+ count = pAAFilter->evaluate(tempBuffer.ptrEnd(sizeTemp),
+ storeBuffer.ptrBegin(), sizeTemp, (uint)numChannels);
+
+ if (count == 0) return;
+
+ // Remove the filtered samples from 'storeBuffer'
+ storeBuffer.receiveSamples(count);
+
+ // Transpose the samples (+16 is to reserve some slack in the destination buffer)
+ sizeTemp = (uint)((float)nSamples / fRate + 16.0f);
+ count = transpose(outputBuffer.ptrEnd(sizeTemp), tempBuffer.ptrBegin(), count);
+ outputBuffer.putSamples(count);
+}
+
+
+// Transposes sample rate by applying anti-alias filter to prevent folding.
+// Returns amount of samples returned in the "dest" buffer.
+// The maximum amount of samples that can be returned at a time is set by
+// the 'set_returnBuffer_size' function.
+void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
+{
+ uint count;
+ uint sizeReq;
+
+ if (nSamples == 0) return;
+ assert(pAAFilter);
+
+ // If anti-alias filter is turned off, simply transpose without applying
+ // the filter
+ if (bUseAAFilter == FALSE)
+ {
+ sizeReq = (uint)((float)nSamples / fRate + 1.0f);
+ count = transpose(outputBuffer.ptrEnd(sizeReq), src, nSamples);
+ outputBuffer.putSamples(count);
+ return;
+ }
+
+ // Transpose with anti-alias filter
+ if (fRate < 1.0f)
+ {
+ upsample(src, nSamples);
+ }
+ else
+ {
+ downsample(src, nSamples);
+ }
+}
+
+
+// Transposes the sample rate of the given samples using linear interpolation.
+// Returns the number of samples returned in the "dest" buffer
+inline uint RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
+{
+ if (numChannels == 2)
+ {
+ return transposeStereo(dest, src, nSamples);
+ }
+ else
+ {
+ return transposeMono(dest, src, nSamples);
+ }
+}
+
+
+// Sets the number of channels, 1 = mono, 2 = stereo
+void RateTransposer::setChannels(int nChannels)
+{
+ assert(nChannels > 0);
+ if (numChannels == nChannels) return;
+
+ assert(nChannels == 1 || nChannels == 2);
+ numChannels = nChannels;
+
+ storeBuffer.setChannels(numChannels);
+ tempBuffer.setChannels(numChannels);
+ outputBuffer.setChannels(numChannels);
+
+ // Inits the linear interpolation registers
+ resetRegisters();
+}
+
+
+// Clears all the samples in the object
+void RateTransposer::clear()
+{
+ outputBuffer.clear();
+ storeBuffer.clear();
+}
+
+
+// Returns nonzero if there aren't any samples available for outputting.
+int RateTransposer::isEmpty() const
+{
+ int res;
+
+ res = FIFOProcessor::isEmpty();
+ if (res == 0) return 0;
+ return storeBuffer.isEmpty();
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// RateTransposerInteger - integer arithmetic implementation
+//
+
+/// fixed-point interpolation routine precision
+#define SCALE 65536
+
+// Constructor
+RateTransposerInteger::RateTransposerInteger() : RateTransposer()
+{
+ // Notice: use local function calling syntax for sake of clarity,
+ // to indicate the fact that C++ constructor can't call virtual functions.
+ RateTransposerInteger::resetRegisters();
+ RateTransposerInteger::setRate(1.0f);
+}
+
+
+RateTransposerInteger::~RateTransposerInteger()
+{
+}
+
+
+void RateTransposerInteger::resetRegisters()
+{
+ iSlopeCount = 0;
+ sPrevSampleL =
+ sPrevSampleR = 0;
+}
+
+
+
+// Transposes the sample rate of the given samples using linear interpolation.
+// 'Mono' version of the routine. Returns the number of samples returned in
+// the "dest" buffer
+uint RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
+{
+ unsigned int i, used;
+ LONG_SAMPLETYPE temp, vol1;
+
+ if (nSamples == 0) return 0; // no samples, no work
+
+ used = 0;
+ i = 0;
+
+ // Process the last sample saved from the previous call first...
+ while (iSlopeCount <= SCALE)
+ {
+ vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
+ temp = vol1 * sPrevSampleL + iSlopeCount * src[0];
+ dest[i] = (SAMPLETYPE)(temp / SCALE);
+ i++;
+ iSlopeCount += iRate;
+ }
+ // now always (iSlopeCount > SCALE)
+ iSlopeCount -= SCALE;
+
+ while (1)
+ {
+ while (iSlopeCount > SCALE)
+ {
+ iSlopeCount -= SCALE;
+ used ++;
+ if (used >= nSamples - 1) goto end;
+ }
+ vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
+ temp = src[used] * vol1 + iSlopeCount * src[used + 1];
+ dest[i] = (SAMPLETYPE)(temp / SCALE);
+
+ i++;
+ iSlopeCount += iRate;
+ }
+end:
+ // Store the last sample for the next round
+ sPrevSampleL = src[nSamples - 1];
+
+ return i;
+}
+
+
+// Transposes the sample rate of the given samples using linear interpolation.
+// 'Stereo' version of the routine. Returns the number of samples returned in
+// the "dest" buffer
+uint RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
+{
+ unsigned int srcPos, i, used;
+ LONG_SAMPLETYPE temp, vol1;
+
+ if (nSamples == 0) return 0; // no samples, no work
+
+ used = 0;
+ i = 0;
+
+ // Process the last sample saved from the sPrevSampleLious call first...
+ while (iSlopeCount <= SCALE)
+ {
+ vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
+ temp = vol1 * sPrevSampleL + iSlopeCount * src[0];
+ dest[2 * i] = (SAMPLETYPE)(temp / SCALE);
+ temp = vol1 * sPrevSampleR + iSlopeCount * src[1];
+ dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE);
+ i++;
+ iSlopeCount += iRate;
+ }
+ // now always (iSlopeCount > SCALE)
+ iSlopeCount -= SCALE;
+
+ while (1)
+ {
+ while (iSlopeCount > SCALE)
+ {
+ iSlopeCount -= SCALE;
+ used ++;
+ if (used >= nSamples - 1) goto end;
+ }
+ srcPos = 2 * used;
+ vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
+ temp = src[srcPos] * vol1 + iSlopeCount * src[srcPos + 2];
+ dest[2 * i] = (SAMPLETYPE)(temp / SCALE);
+ temp = src[srcPos + 1] * vol1 + iSlopeCount * src[srcPos + 3];
+ dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE);
+
+ i++;
+ iSlopeCount += iRate;
+ }
+end:
+ // Store the last sample for the next round
+ sPrevSampleL = src[2 * nSamples - 2];
+ sPrevSampleR = src[2 * nSamples - 1];
+
+ return i;
+}
+
+
+// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
+// iRate, larger faster iRates.
+void RateTransposerInteger::setRate(float newRate)
+{
+ iRate = (int)(newRate * SCALE + 0.5f);
+ RateTransposer::setRate(newRate);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// RateTransposerFloat - floating point arithmetic implementation
+//
+//////////////////////////////////////////////////////////////////////////////
+
+// Constructor
+RateTransposerFloat::RateTransposerFloat() : RateTransposer()
+{
+ // Notice: use local function calling syntax for sake of clarity,
+ // to indicate the fact that C++ constructor can't call virtual functions.
+ RateTransposerFloat::resetRegisters();
+ RateTransposerFloat::setRate(1.0f);
+}
+
+
+RateTransposerFloat::~RateTransposerFloat()
+{
+}
+
+
+void RateTransposerFloat::resetRegisters()
+{
+ fSlopeCount = 0;
+ sPrevSampleL =
+ sPrevSampleR = 0;
+}
+
+
+
+// Transposes the sample rate of the given samples using linear interpolation.
+// 'Mono' version of the routine. Returns the number of samples returned in
+// the "dest" buffer
+uint RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
+{
+ unsigned int i, used;
+
+ used = 0;
+ i = 0;
+
+ // Process the last sample saved from the previous call first...
+ while (fSlopeCount <= 1.0f)
+ {
+ dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]);
+ i++;
+ fSlopeCount += fRate;
+ }
+ fSlopeCount -= 1.0f;
+
+ if (nSamples > 1)
+ {
+ while (1)
+ {
+ while (fSlopeCount > 1.0f)
+ {
+ fSlopeCount -= 1.0f;
+ used ++;
+ if (used >= nSamples - 1) goto end;
+ }
+ dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[used] + fSlopeCount * src[used + 1]);
+ i++;
+ fSlopeCount += fRate;
+ }
+ }
+end:
+ // Store the last sample for the next round
+ sPrevSampleL = src[nSamples - 1];
+
+ return i;
+}
+
+
+// Transposes the sample rate of the given samples using linear interpolation.
+// 'Mono' version of the routine. Returns the number of samples returned in
+// the "dest" buffer
+uint RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
+{
+ unsigned int srcPos, i, used;
+
+ if (nSamples == 0) return 0; // no samples, no work
+
+ used = 0;
+ i = 0;
+
+ // Process the last sample saved from the sPrevSampleLious call first...
+ while (fSlopeCount <= 1.0f)
+ {
+ dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]);
+ dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleR + fSlopeCount * src[1]);
+ i++;
+ fSlopeCount += fRate;
+ }
+ // now always (iSlopeCount > 1.0f)
+ fSlopeCount -= 1.0f;
+
+ if (nSamples > 1)
+ {
+ while (1)
+ {
+ while (fSlopeCount > 1.0f)
+ {
+ fSlopeCount -= 1.0f;
+ used ++;
+ if (used >= nSamples - 1) goto end;
+ }
+ srcPos = 2 * used;
+
+ dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos]
+ + fSlopeCount * src[srcPos + 2]);
+ dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos + 1]
+ + fSlopeCount * src[srcPos + 3]);
+
+ i++;
+ fSlopeCount += fRate;
+ }
+ }
+end:
+ // Store the last sample for the next round
+ sPrevSampleL = src[2 * nSamples - 2];
+ sPrevSampleR = src[2 * nSamples - 1];
+
+ return i;
+}
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/RateTransposer.h b/plugins/soundtouch/soundtouch/source/SoundTouch/RateTransposer.h
new file mode 100644
index 00000000..f035af2c
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/RateTransposer.h
@@ -0,0 +1,159 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Sample rate transposer. Changes sample rate by using linear interpolation
+/// together with anti-alias filtering (first order interpolation with anti-
+/// alias filtering should be quite adequate for this application).
+///
+/// Use either of the derived classes of 'RateTransposerInteger' or
+/// 'RateTransposerFloat' for corresponding integer/floating point tranposing
+/// algorithm implementation.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-02-21 18:00:14 +0200 (Sat, 21 Feb 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: RateTransposer.h 63 2009-02-21 16:00:14Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef RateTransposer_H
+#define RateTransposer_H
+
+#include <stddef.h>
+#include "AAFilter.h"
+#include "FIFOSamplePipe.h"
+#include "FIFOSampleBuffer.h"
+
+#include "STTypes.h"
+
+namespace soundtouch
+{
+
+/// A common linear samplerate transposer class.
+///
+/// Note: Use function "RateTransposer::newInstance()" to create a new class
+/// instance instead of the "new" operator; that function automatically
+/// chooses a correct implementation depending on if integer or floating
+/// arithmetics are to be used.
+class RateTransposer : public FIFOProcessor
+{
+protected:
+ /// Anti-alias filter object
+ AAFilter *pAAFilter;
+
+ float fRate;
+
+ int numChannels;
+
+ /// Buffer for collecting samples to feed the anti-alias filter between
+ /// two batches
+ FIFOSampleBuffer storeBuffer;
+
+ /// Buffer for keeping samples between transposing & anti-alias filter
+ FIFOSampleBuffer tempBuffer;
+
+ /// Output sample buffer
+ FIFOSampleBuffer outputBuffer;
+
+ BOOL bUseAAFilter;
+
+ virtual void resetRegisters() = 0;
+
+ virtual uint transposeStereo(SAMPLETYPE *dest,
+ const SAMPLETYPE *src,
+ uint numSamples) = 0;
+ virtual uint transposeMono(SAMPLETYPE *dest,
+ const SAMPLETYPE *src,
+ uint numSamples) = 0;
+ inline uint transpose(SAMPLETYPE *dest,
+ const SAMPLETYPE *src,
+ uint numSamples);
+
+ void downsample(const SAMPLETYPE *src,
+ uint numSamples);
+ void upsample(const SAMPLETYPE *src,
+ uint numSamples);
+
+ /// Transposes sample rate by applying anti-alias filter to prevent folding.
+ /// Returns amount of samples returned in the "dest" buffer.
+ /// The maximum amount of samples that can be returned at a time is set by
+ /// the 'set_returnBuffer_size' function.
+ void processSamples(const SAMPLETYPE *src,
+ uint numSamples);
+
+
+public:
+ RateTransposer();
+ virtual ~RateTransposer();
+
+ /// Operator 'new' is overloaded so that it automatically creates a suitable instance
+ /// depending on if we're to use integer or floating point arithmetics.
+ static void *operator new(size_t s);
+
+ /// Use this function instead of "new" operator to create a new instance of this class.
+ /// This function automatically chooses a correct implementation, depending on if
+ /// integer ot floating point arithmetics are to be used.
+ static RateTransposer *newInstance();
+
+ /// Returns the output buffer object
+ FIFOSamplePipe *getOutput() { return &outputBuffer; };
+
+ /// Returns the store buffer object
+ FIFOSamplePipe *getStore() { return &storeBuffer; };
+
+ /// Return anti-alias filter object
+ AAFilter *getAAFilter();
+
+ /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
+ void enableAAFilter(BOOL newMode);
+
+ /// Returns nonzero if anti-alias filter is enabled.
+ BOOL isAAFilterEnabled() const;
+
+ /// Sets new target rate. Normal rate = 1.0, smaller values represent slower
+ /// rate, larger faster rates.
+ virtual void setRate(float newRate);
+
+ /// Sets the number of channels, 1 = mono, 2 = stereo
+ void setChannels(int channels);
+
+ /// Adds 'numSamples' pcs of samples from the 'samples' memory position into
+ /// the input of the object.
+ void putSamples(const SAMPLETYPE *samples, uint numSamples);
+
+ /// Clears all the samples in the object
+ void clear();
+
+ /// Returns nonzero if there aren't any samples available for outputting.
+ int isEmpty() const;
+};
+
+}
+
+#endif
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/SoundTouch.cpp b/plugins/soundtouch/soundtouch/source/SoundTouch/SoundTouch.cpp
new file mode 100644
index 00000000..aa7ac028
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/SoundTouch.cpp
@@ -0,0 +1,480 @@
+//////////////////////////////////////////////////////////////////////////////
+///
+/// SoundTouch - main class for tempo/pitch/rate adjusting routines.
+///
+/// Notes:
+/// - Initialize the SoundTouch object instance by setting up the sound stream
+/// parameters with functions 'setSampleRate' and 'setChannels', then set
+/// desired tempo/pitch/rate settings with the corresponding functions.
+///
+/// - The SoundTouch class behaves like a first-in-first-out pipeline: The
+/// samples that are to be processed are fed into one of the pipe by calling
+/// function 'putSamples', while the ready processed samples can be read
+/// from the other end of the pipeline with function 'receiveSamples'.
+///
+/// - The SoundTouch processing classes require certain sized 'batches' of
+/// samples in order to process the sound. For this reason the classes buffer
+/// incoming samples until there are enough of samples available for
+/// processing, then they carry out the processing step and consequently
+/// make the processed samples available for outputting.
+///
+/// - For the above reason, the processing routines introduce a certain
+/// 'latency' between the input and output, so that the samples input to
+/// SoundTouch may not be immediately available in the output, and neither
+/// the amount of outputtable samples may not immediately be in direct
+/// relationship with the amount of previously input samples.
+///
+/// - The tempo/pitch/rate control parameters can be altered during processing.
+/// Please notice though that they aren't currently protected by semaphores,
+/// so in multi-thread application external semaphore protection may be
+/// required.
+///
+/// - This class utilizes classes 'TDStretch' for tempo change (without modifying
+/// pitch) and 'RateTransposer' for changing the playback rate (that is, both
+/// tempo and pitch in the same ratio) of the sound. The third available control
+/// 'pitch' (change pitch but maintain tempo) is produced by a combination of
+/// combining the two other controls.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-05-19 07:57:30 +0300 (Tue, 19 May 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: SoundTouch.cpp 73 2009-05-19 04:57:30Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <assert.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <math.h>
+#include <stdexcept>
+#include <stdio.h>
+
+#include "SoundTouch.h"
+#include "TDStretch.h"
+#include "RateTransposer.h"
+#include "cpu_detect.h"
+
+using namespace soundtouch;
+
+/// test if two floating point numbers are equal
+#define TEST_FLOAT_EQUAL(a, b) (fabs(a - b) < 1e-10)
+
+
+/// Print library version string for autoconf
+extern "C" void soundtouch_ac_test()
+{
+ printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION);
+}
+
+
+SoundTouch::SoundTouch()
+{
+ // Initialize rate transposer and tempo changer instances
+
+ pRateTransposer = RateTransposer::newInstance();
+ pTDStretch = TDStretch::newInstance();
+
+ setOutPipe(pTDStretch);
+
+ rate = tempo = 0;
+
+ virtualPitch =
+ virtualRate =
+ virtualTempo = 1.0;
+
+ calcEffectiveRateAndTempo();
+
+ channels = 0;
+ bSrateSet = FALSE;
+}
+
+
+
+SoundTouch::~SoundTouch()
+{
+ delete pRateTransposer;
+ delete pTDStretch;
+}
+
+
+
+/// Get SoundTouch library version string
+const char *SoundTouch::getVersionString()
+{
+ static const char *_version = SOUNDTOUCH_VERSION;
+
+ return _version;
+}
+
+
+/// Get SoundTouch library version Id
+uint SoundTouch::getVersionId()
+{
+ return SOUNDTOUCH_VERSION_ID;
+}
+
+
+// Sets the number of channels, 1 = mono, 2 = stereo
+void SoundTouch::setChannels(uint numChannels)
+{
+ if (numChannels != 1 && numChannels != 2)
+ {
+ throw std::runtime_error("Illegal number of channels");
+ }
+ channels = numChannels;
+ pRateTransposer->setChannels((int)numChannels);
+ pTDStretch->setChannels((int)numChannels);
+}
+
+
+
+// Sets new rate control value. Normal rate = 1.0, smaller values
+// represent slower rate, larger faster rates.
+void SoundTouch::setRate(float newRate)
+{
+ virtualRate = newRate;
+ calcEffectiveRateAndTempo();
+}
+
+
+
+// Sets new rate control value as a difference in percents compared
+// to the original rate (-50 .. +100 %)
+void SoundTouch::setRateChange(float newRate)
+{
+ virtualRate = 1.0f + 0.01f * newRate;
+ calcEffectiveRateAndTempo();
+}
+
+
+
+// Sets new tempo control value. Normal tempo = 1.0, smaller values
+// represent slower tempo, larger faster tempo.
+void SoundTouch::setTempo(float newTempo)
+{
+ virtualTempo = newTempo;
+ calcEffectiveRateAndTempo();
+}
+
+
+
+// Sets new tempo control value as a difference in percents compared
+// to the original tempo (-50 .. +100 %)
+void SoundTouch::setTempoChange(float newTempo)
+{
+ virtualTempo = 1.0f + 0.01f * newTempo;
+ calcEffectiveRateAndTempo();
+}
+
+
+
+// Sets new pitch control value. Original pitch = 1.0, smaller values
+// represent lower pitches, larger values higher pitch.
+void SoundTouch::setPitch(float newPitch)
+{
+ virtualPitch = newPitch;
+ calcEffectiveRateAndTempo();
+}
+
+
+
+// Sets pitch change in octaves compared to the original pitch
+// (-1.00 .. +1.00)
+void SoundTouch::setPitchOctaves(float newPitch)
+{
+ virtualPitch = (float)exp(0.69314718056f * newPitch);
+ calcEffectiveRateAndTempo();
+}
+
+
+
+// Sets pitch change in semi-tones compared to the original pitch
+// (-12 .. +12)
+void SoundTouch::setPitchSemiTones(int newPitch)
+{
+ setPitchOctaves((float)newPitch / 12.0f);
+}
+
+
+
+void SoundTouch::setPitchSemiTones(float newPitch)
+{
+ setPitchOctaves(newPitch / 12.0f);
+}
+
+
+// Calculates 'effective' rate and tempo values from the
+// nominal control values.
+void SoundTouch::calcEffectiveRateAndTempo()
+{
+ float oldTempo = tempo;
+ float oldRate = rate;
+
+ tempo = virtualTempo / virtualPitch;
+ rate = virtualPitch * virtualRate;
+
+ if (!TEST_FLOAT_EQUAL(rate,oldRate)) pRateTransposer->setRate(rate);
+ if (!TEST_FLOAT_EQUAL(tempo, oldTempo)) pTDStretch->setTempo(tempo);
+
+#ifndef PREVENT_CLICK_AT_RATE_CROSSOVER
+ if (rate <= 1.0f)
+ {
+ if (output != pTDStretch)
+ {
+ FIFOSamplePipe *tempoOut;
+
+ assert(output == pRateTransposer);
+ // move samples in the current output buffer to the output of pTDStretch
+ tempoOut = pTDStretch->getOutput();
+ tempoOut->moveSamples(*output);
+ // move samples in pitch transposer's store buffer to tempo changer's input
+ pTDStretch->moveSamples(*pRateTransposer->getStore());
+
+ output = pTDStretch;
+ }
+ }
+ else
+#endif
+ {
+ if (output != pRateTransposer)
+ {
+ FIFOSamplePipe *transOut;
+
+ assert(output == pTDStretch);
+ // move samples in the current output buffer to the output of pRateTransposer
+ transOut = pRateTransposer->getOutput();
+ transOut->moveSamples(*output);
+ // move samples in tempo changer's input to pitch transposer's input
+ pRateTransposer->moveSamples(*pTDStretch->getInput());
+
+ output = pRateTransposer;
+ }
+ }
+}
+
+
+// Sets sample rate.
+void SoundTouch::setSampleRate(uint srate)
+{
+ bSrateSet = TRUE;
+ // set sample rate, leave other tempo changer parameters as they are.
+ pTDStretch->setParameters((int)srate);
+}
+
+
+// Adds 'numSamples' pcs of samples from the 'samples' memory position into
+// the input of the object.
+void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples)
+{
+ if (bSrateSet == FALSE)
+ {
+ throw std::runtime_error("SoundTouch : Sample rate not defined");
+ }
+ else if (channels == 0)
+ {
+ throw std::runtime_error("SoundTouch : Number of channels not defined");
+ }
+
+ // Transpose the rate of the new samples if necessary
+ /* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value...
+ if (rate == 1.0f)
+ {
+ // The rate value is same as the original, simply evaluate the tempo changer.
+ assert(output == pTDStretch);
+ if (pRateTransposer->isEmpty() == 0)
+ {
+ // yet flush the last samples in the pitch transposer buffer
+ // (may happen if 'rate' changes from a non-zero value to zero)
+ pTDStretch->moveSamples(*pRateTransposer);
+ }
+ pTDStretch->putSamples(samples, nSamples);
+ }
+ */
+#ifndef PREVENT_CLICK_AT_RATE_CROSSOVER
+ else if (rate <= 1.0f)
+ {
+ // transpose the rate down, output the transposed sound to tempo changer buffer
+ assert(output == pTDStretch);
+ pRateTransposer->putSamples(samples, nSamples);
+ pTDStretch->moveSamples(*pRateTransposer);
+ }
+ else
+#endif
+ {
+ // evaluate the tempo changer, then transpose the rate up,
+ assert(output == pRateTransposer);
+ pTDStretch->putSamples(samples, nSamples);
+ pRateTransposer->moveSamples(*pTDStretch);
+ }
+}
+
+
+// Flushes the last samples from the processing pipeline to the output.
+// Clears also the internal processing buffers.
+//
+// Note: This function is meant for extracting the last samples of a sound
+// stream. This function may introduce additional blank samples in the end
+// of the sound stream, and thus it's not recommended to call this function
+// in the middle of a sound stream.
+void SoundTouch::flush()
+{
+ int i;
+ uint nOut;
+ SAMPLETYPE buff[128];
+
+ nOut = numSamples();
+
+ memset(buff, 0, 128 * sizeof(SAMPLETYPE));
+ // "Push" the last active samples out from the processing pipeline by
+ // feeding blank samples into the processing pipeline until new,
+ // processed samples appear in the output (not however, more than
+ // 8ksamples in any case)
+ for (i = 0; i < 128; i ++)
+ {
+ putSamples(buff, 64);
+ if (numSamples() != nOut) break; // new samples have appeared in the output!
+ }
+
+ // Clear working buffers
+ pRateTransposer->clear();
+ pTDStretch->clearInput();
+ // yet leave the 'tempoChanger' output intouched as that's where the
+ // flushed samples are!
+}
+
+
+// Changes a setting controlling the processing system behaviour. See the
+// 'SETTING_...' defines for available setting ID's.
+BOOL SoundTouch::setSetting(int settingId, int value)
+{
+ int sampleRate, sequenceMs, seekWindowMs, overlapMs;
+
+ // read current tdstretch routine parameters
+ pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs);
+
+ switch (settingId)
+ {
+ case SETTING_USE_AA_FILTER :
+ // enables / disabless anti-alias filter
+ pRateTransposer->enableAAFilter((value != 0) ? TRUE : FALSE);
+ return TRUE;
+
+ case SETTING_AA_FILTER_LENGTH :
+ // sets anti-alias filter length
+ pRateTransposer->getAAFilter()->setLength(value);
+ return TRUE;
+
+ case SETTING_USE_QUICKSEEK :
+ // enables / disables tempo routine quick seeking algorithm
+ pTDStretch->enableQuickSeek((value != 0) ? TRUE : FALSE);
+ return TRUE;
+
+ case SETTING_SEQUENCE_MS:
+ // change time-stretch sequence duration parameter
+ pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs);
+ return TRUE;
+
+ case SETTING_SEEKWINDOW_MS:
+ // change time-stretch seek window length parameter
+ pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs);
+ return TRUE;
+
+ case SETTING_OVERLAP_MS:
+ // change time-stretch overlap length parameter
+ pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value);
+ return TRUE;
+
+ default :
+ return FALSE;
+ }
+}
+
+
+// Reads a setting controlling the processing system behaviour. See the
+// 'SETTING_...' defines for available setting ID's.
+//
+// Returns the setting value.
+int SoundTouch::getSetting(int settingId) const
+{
+ int temp;
+
+ switch (settingId)
+ {
+ case SETTING_USE_AA_FILTER :
+ return (uint)pRateTransposer->isAAFilterEnabled();
+
+ case SETTING_AA_FILTER_LENGTH :
+ return pRateTransposer->getAAFilter()->getLength();
+
+ case SETTING_USE_QUICKSEEK :
+ return (uint) pTDStretch->isQuickSeekEnabled();
+
+ case SETTING_SEQUENCE_MS:
+ pTDStretch->getParameters(NULL, &temp, NULL, NULL);
+ return temp;
+
+ case SETTING_SEEKWINDOW_MS:
+ pTDStretch->getParameters(NULL, NULL, &temp, NULL);
+ return temp;
+
+ case SETTING_OVERLAP_MS:
+ pTDStretch->getParameters(NULL, NULL, NULL, &temp);
+ return temp;
+
+ default :
+ return 0;
+ }
+}
+
+
+// Clears all the samples in the object's output and internal processing
+// buffers.
+void SoundTouch::clear()
+{
+ pRateTransposer->clear();
+ pTDStretch->clear();
+}
+
+
+
+/// Returns number of samples currently unprocessed.
+uint SoundTouch::numUnprocessedSamples() const
+{
+ FIFOSamplePipe * psp;
+ if (pTDStretch)
+ {
+ psp = pTDStretch->getInput();
+ if (psp)
+ {
+ return psp->numSamples();
+ }
+ }
+ return 0;
+}
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/TDStretch.cpp b/plugins/soundtouch/soundtouch/source/SoundTouch/TDStretch.cpp
new file mode 100644
index 00000000..232133b5
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/TDStretch.cpp
@@ -0,0 +1,1045 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
+/// while maintaining the original pitch by using a time domain WSOLA-like
+/// method with several performance-increasing tweaks.
+///
+/// Note : MMX optimized functions reside in a separate, platform-specific
+/// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-12-28 21:27:04 +0200 (Mon, 28 Dec 2009) $
+// File revision : $Revision: 1.12 $
+//
+// $Id: TDStretch.cpp 77 2009-12-28 19:27:04Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+#include <math.h>
+#include <float.h>
+#include <stdexcept>
+
+#include "STTypes.h"
+#include "cpu_detect.h"
+#include "TDStretch.h"
+
+#include <stdio.h>
+
+using namespace soundtouch;
+
+#define max(x, y) (((x) > (y)) ? (x) : (y))
+
+
+/*****************************************************************************
+ *
+ * Constant definitions
+ *
+ *****************************************************************************/
+
+// Table for the hierarchical mixing position seeking algorithm
+static const short _scanOffsets[5][24]={
+ { 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806,
+ 868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0},
+ {-100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ { -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ { -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 121, 114, 97, 114, 98, 105, 108, 32, 104, 99, 117, 111,
+ 116, 100, 110, 117, 111, 115, 0, 0, 0, 0, 0, 0}};
+
+/*****************************************************************************
+ *
+ * Implementation of the class 'TDStretch'
+ *
+ *****************************************************************************/
+
+
+TDStretch::TDStretch() : FIFOProcessor(&outputBuffer)
+{
+ bQuickSeek = FALSE;
+ channels = 2;
+
+ pMidBuffer = NULL;
+ pRefMidBufferUnaligned = NULL;
+ overlapLength = 0;
+
+ bAutoSeqSetting = TRUE;
+ bAutoSeekSetting = TRUE;
+
+// outDebt = 0;
+ skipFract = 0;
+
+ tempo = 1.0f;
+ setParameters(44100, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS);
+ setTempo(1.0f);
+
+ clear();
+}
+
+
+
+TDStretch::~TDStretch()
+{
+ delete[] pMidBuffer;
+ delete[] pRefMidBufferUnaligned;
+}
+
+
+
+// Sets routine control parameters. These control are certain time constants
+// defining how the sound is stretched to the desired duration.
+//
+// 'sampleRate' = sample rate of the sound
+// 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms)
+// 'seekwindowMS' = seeking window length for scanning the best overlapping
+// position (default = 28 ms)
+// 'overlapMS' = overlapping length (default = 12 ms)
+
+void TDStretch::setParameters(int aSampleRate, int aSequenceMS,
+ int aSeekWindowMS, int aOverlapMS)
+{
+ // accept only positive parameter values - if zero or negative, use old values instead
+ if (aSampleRate > 0) this->sampleRate = aSampleRate;
+ if (aOverlapMS > 0) this->overlapMs = aOverlapMS;
+
+ if (aSequenceMS > 0)
+ {
+ this->sequenceMs = aSequenceMS;
+ bAutoSeqSetting = FALSE;
+ }
+ else if (aSequenceMS == 0)
+ {
+ // if zero, use automatic setting
+ bAutoSeqSetting = TRUE;
+ }
+
+ if (aSeekWindowMS > 0)
+ {
+ this->seekWindowMs = aSeekWindowMS;
+ bAutoSeekSetting = FALSE;
+ }
+ else if (aSeekWindowMS == 0)
+ {
+ // if zero, use automatic setting
+ bAutoSeekSetting = TRUE;
+ }
+
+ calcSeqParameters();
+
+ calculateOverlapLength(overlapMs);
+
+ // set tempo to recalculate 'sampleReq'
+ setTempo(tempo);
+
+}
+
+
+
+/// Get routine control parameters, see setParameters() function.
+/// Any of the parameters to this function can be NULL, in such case corresponding parameter
+/// value isn't returned.
+void TDStretch::getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const
+{
+ if (pSampleRate)
+ {
+ *pSampleRate = sampleRate;
+ }
+
+ if (pSequenceMs)
+ {
+ *pSequenceMs = (bAutoSeqSetting) ? (USE_AUTO_SEQUENCE_LEN) : sequenceMs;
+ }
+
+ if (pSeekWindowMs)
+ {
+ *pSeekWindowMs = (bAutoSeekSetting) ? (USE_AUTO_SEEKWINDOW_LEN) : seekWindowMs;
+ }
+
+ if (pOverlapMs)
+ {
+ *pOverlapMs = overlapMs;
+ }
+}
+
+
+// Overlaps samples in 'midBuffer' with the samples in 'pInput'
+void TDStretch::overlapMono(SAMPLETYPE *pOutput, const SAMPLETYPE *pInput) const
+{
+ int i, itemp;
+
+ for (i = 0; i < overlapLength ; i ++)
+ {
+ itemp = overlapLength - i;
+ pOutput[i] = (pInput[i] * i + pMidBuffer[i] * itemp ) / overlapLength; // >> overlapDividerBits;
+ }
+}
+
+
+
+void TDStretch::clearMidBuffer()
+{
+ memset(pMidBuffer, 0, 2 * sizeof(SAMPLETYPE) * overlapLength);
+}
+
+
+void TDStretch::clearInput()
+{
+ inputBuffer.clear();
+ clearMidBuffer();
+}
+
+
+// Clears the sample buffers
+void TDStretch::clear()
+{
+ outputBuffer.clear();
+ clearInput();
+}
+
+
+
+// Enables/disables the quick position seeking algorithm. Zero to disable, nonzero
+// to enable
+void TDStretch::enableQuickSeek(BOOL enable)
+{
+ bQuickSeek = enable;
+}
+
+
+// Returns nonzero if the quick seeking algorithm is enabled.
+BOOL TDStretch::isQuickSeekEnabled() const
+{
+ return bQuickSeek;
+}
+
+
+// Seeks for the optimal overlap-mixing position.
+int TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos)
+{
+ if (channels == 2)
+ {
+ // stereo sound
+ if (bQuickSeek)
+ {
+ return seekBestOverlapPositionStereoQuick(refPos);
+ }
+ else
+ {
+ return seekBestOverlapPositionStereo(refPos);
+ }
+ }
+ else
+ {
+ // mono sound
+ if (bQuickSeek)
+ {
+ return seekBestOverlapPositionMonoQuick(refPos);
+ }
+ else
+ {
+ return seekBestOverlapPositionMono(refPos);
+ }
+ }
+}
+
+
+
+
+// Overlaps samples in 'midBuffer' with the samples in 'pInputBuffer' at position
+// of 'ovlPos'.
+inline void TDStretch::overlap(SAMPLETYPE *pOutput, const SAMPLETYPE *pInput, uint ovlPos) const
+{
+ if (channels == 2)
+ {
+ // stereo sound
+ overlapStereo(pOutput, pInput + 2 * ovlPos);
+ } else {
+ // mono sound.
+ overlapMono(pOutput, pInput + ovlPos);
+ }
+}
+
+
+
+
+// Seeks for the optimal overlap-mixing position. The 'stereo' version of the
+// routine
+//
+// The best position is determined as the position where the two overlapped
+// sample sequences are 'most alike', in terms of the highest cross-correlation
+// value over the overlapping period
+int TDStretch::seekBestOverlapPositionStereo(const SAMPLETYPE *refPos)
+{
+ int bestOffs;
+ double bestCorr, corr;
+ int i;
+
+ // Slopes the amplitudes of the 'midBuffer' samples
+ precalcCorrReferenceStereo();
+
+ bestCorr = FLT_MIN;
+ bestOffs = 0;
+
+ // Scans for the best correlation value by testing each possible position
+ // over the permitted range.
+ for (i = 0; i < seekLength; i ++)
+ {
+ // Calculates correlation value for the mixing position corresponding
+ // to 'i'
+ corr = (double)calcCrossCorrStereo(refPos + 2 * i, pRefMidBuffer);
+ // heuristic rule to slightly favour values close to mid of the range
+ double tmp = (double)(2 * i - seekLength) / (double)seekLength;
+ corr = ((corr + 0.1) * (1.0 - 0.25 * tmp * tmp));
+
+ // Checks for the highest correlation value
+ if (corr > bestCorr)
+ {
+ bestCorr = corr;
+ bestOffs = i;
+ }
+ }
+ // clear cross correlation routine state if necessary (is so e.g. in MMX routines).
+ clearCrossCorrState();
+
+ return bestOffs;
+}
+
+
+// Seeks for the optimal overlap-mixing position. The 'stereo' version of the
+// routine
+//
+// The best position is determined as the position where the two overlapped
+// sample sequences are 'most alike', in terms of the highest cross-correlation
+// value over the overlapping period
+int TDStretch::seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos)
+{
+ int j;
+ int bestOffs;
+ double bestCorr, corr;
+ int scanCount, corrOffset, tempOffset;
+
+ // Slopes the amplitude of the 'midBuffer' samples
+ precalcCorrReferenceStereo();
+
+ bestCorr = FLT_MIN;
+ bestOffs = _scanOffsets[0][0];
+ corrOffset = 0;
+ tempOffset = 0;
+
+ // Scans for the best correlation value using four-pass hierarchical search.
+ //
+ // The look-up table 'scans' has hierarchical position adjusting steps.
+ // In first pass the routine searhes for the highest correlation with
+ // relatively coarse steps, then rescans the neighbourhood of the highest
+ // correlation with better resolution and so on.
+ for (scanCount = 0;scanCount < 4; scanCount ++)
+ {
+ j = 0;
+ while (_scanOffsets[scanCount][j])
+ {
+ tempOffset = corrOffset + _scanOffsets[scanCount][j];
+ if (tempOffset >= seekLength) break;
+
+ // Calculates correlation value for the mixing position corresponding
+ // to 'tempOffset'
+ corr = (double)calcCrossCorrStereo(refPos + 2 * tempOffset, pRefMidBuffer);
+ // heuristic rule to slightly favour values close to mid of the range
+ double tmp = (double)(2 * tempOffset - seekLength) / seekLength;
+ corr = ((corr + 0.1) * (1.0 - 0.25 * tmp * tmp));
+
+ // Checks for the highest correlation value
+ if (corr > bestCorr)
+ {
+ bestCorr = corr;
+ bestOffs = tempOffset;
+ }
+ j ++;
+ }
+ corrOffset = bestOffs;
+ }
+ // clear cross correlation routine state if necessary (is so e.g. in MMX routines).
+ clearCrossCorrState();
+
+ return bestOffs;
+}
+
+
+
+// Seeks for the optimal overlap-mixing position. The 'mono' version of the
+// routine
+//
+// The best position is determined as the position where the two overlapped
+// sample sequences are 'most alike', in terms of the highest cross-correlation
+// value over the overlapping period
+int TDStretch::seekBestOverlapPositionMono(const SAMPLETYPE *refPos)
+{
+ int bestOffs;
+ double bestCorr, corr;
+ int tempOffset;
+ const SAMPLETYPE *compare;
+
+ // Slopes the amplitude of the 'midBuffer' samples
+ precalcCorrReferenceMono();
+
+ bestCorr = FLT_MIN;
+ bestOffs = 0;
+
+ // Scans for the best correlation value by testing each possible position
+ // over the permitted range.
+ for (tempOffset = 0; tempOffset < seekLength; tempOffset ++)
+ {
+ compare = refPos + tempOffset;
+
+ // Calculates correlation value for the mixing position corresponding
+ // to 'tempOffset'
+ corr = (double)calcCrossCorrMono(pRefMidBuffer, compare);
+ // heuristic rule to slightly favour values close to mid of the range
+ double tmp = (double)(2 * tempOffset - seekLength) / seekLength;
+ corr = ((corr + 0.1) * (1.0 - 0.25 * tmp * tmp));
+
+ // Checks for the highest correlation value
+ if (corr > bestCorr)
+ {
+ bestCorr = corr;
+ bestOffs = tempOffset;
+ }
+ }
+ // clear cross correlation routine state if necessary (is so e.g. in MMX routines).
+ clearCrossCorrState();
+
+ return bestOffs;
+}
+
+
+// Seeks for the optimal overlap-mixing position. The 'mono' version of the
+// routine
+//
+// The best position is determined as the position where the two overlapped
+// sample sequences are 'most alike', in terms of the highest cross-correlation
+// value over the overlapping period
+int TDStretch::seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos)
+{
+ int j;
+ int bestOffs;
+ double bestCorr, corr;
+ int scanCount, corrOffset, tempOffset;
+
+ // Slopes the amplitude of the 'midBuffer' samples
+ precalcCorrReferenceMono();
+
+ bestCorr = FLT_MIN;
+ bestOffs = _scanOffsets[0][0];
+ corrOffset = 0;
+ tempOffset = 0;
+
+ // Scans for the best correlation value using four-pass hierarchical search.
+ //
+ // The look-up table 'scans' has hierarchical position adjusting steps.
+ // In first pass the routine searhes for the highest correlation with
+ // relatively coarse steps, then rescans the neighbourhood of the highest
+ // correlation with better resolution and so on.
+ for (scanCount = 0;scanCount < 4; scanCount ++)
+ {
+ j = 0;
+ while (_scanOffsets[scanCount][j])
+ {
+ tempOffset = corrOffset + _scanOffsets[scanCount][j];
+ if (tempOffset >= seekLength) break;
+
+ // Calculates correlation value for the mixing position corresponding
+ // to 'tempOffset'
+ corr = (double)calcCrossCorrMono(refPos + tempOffset, pRefMidBuffer);
+ // heuristic rule to slightly favour values close to mid of the range
+ double tmp = (double)(2 * tempOffset - seekLength) / seekLength;
+ corr = ((corr + 0.1) * (1.0 - 0.25 * tmp * tmp));
+
+ // Checks for the highest correlation value
+ if (corr > bestCorr)
+ {
+ bestCorr = corr;
+ bestOffs = tempOffset;
+ }
+ j ++;
+ }
+ corrOffset = bestOffs;
+ }
+ // clear cross correlation routine state if necessary (is so e.g. in MMX routines).
+ clearCrossCorrState();
+
+ return bestOffs;
+}
+
+
+/// clear cross correlation routine state if necessary
+void TDStretch::clearCrossCorrState()
+{
+ // default implementation is empty.
+}
+
+
+/// Calculates processing sequence length according to tempo setting
+void TDStretch::calcSeqParameters()
+{
+ // Adjust tempo param according to tempo, so that variating processing sequence length is used
+ // at varius tempo settings, between the given low...top limits
+ #define AUTOSEQ_TEMPO_LOW 0.5 // auto setting low tempo range (-50%)
+ #define AUTOSEQ_TEMPO_TOP 2.0 // auto setting top tempo range (+100%)
+
+ // sequence-ms setting values at above low & top tempo
+ #define AUTOSEQ_AT_MIN 125.0
+ #define AUTOSEQ_AT_MAX 50.0
+ #define AUTOSEQ_K ((AUTOSEQ_AT_MAX - AUTOSEQ_AT_MIN) / (AUTOSEQ_TEMPO_TOP - AUTOSEQ_TEMPO_LOW))
+ #define AUTOSEQ_C (AUTOSEQ_AT_MIN - (AUTOSEQ_K) * (AUTOSEQ_TEMPO_LOW))
+
+ // seek-window-ms setting values at above low & top tempo
+ #define AUTOSEEK_AT_MIN 25.0
+ #define AUTOSEEK_AT_MAX 15.0
+ #define AUTOSEEK_K ((AUTOSEEK_AT_MAX - AUTOSEEK_AT_MIN) / (AUTOSEQ_TEMPO_TOP - AUTOSEQ_TEMPO_LOW))
+ #define AUTOSEEK_C (AUTOSEEK_AT_MIN - (AUTOSEEK_K) * (AUTOSEQ_TEMPO_LOW))
+
+ #define CHECK_LIMITS(x, mi, ma) (((x) < (mi)) ? (mi) : (((x) > (ma)) ? (ma) : (x)))
+
+ double seq, seek;
+
+ if (bAutoSeqSetting)
+ {
+ seq = AUTOSEQ_C + AUTOSEQ_K * tempo;
+ seq = CHECK_LIMITS(seq, AUTOSEQ_AT_MAX, AUTOSEQ_AT_MIN);
+ sequenceMs = (int)(seq + 0.5);
+ }
+
+ if (bAutoSeekSetting)
+ {
+ seek = AUTOSEEK_C + AUTOSEEK_K * tempo;
+ seek = CHECK_LIMITS(seek, AUTOSEEK_AT_MAX, AUTOSEEK_AT_MIN);
+ seekWindowMs = (int)(seek + 0.5);
+ }
+
+ // Update seek window lengths
+ seekWindowLength = (sampleRate * sequenceMs) / 1000;
+ if (seekWindowLength < 2 * overlapLength)
+ {
+ seekWindowLength = 2 * overlapLength;
+ }
+ seekLength = (sampleRate * seekWindowMs) / 1000;
+}
+
+
+
+// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower
+// tempo, larger faster tempo.
+void TDStretch::setTempo(float newTempo)
+{
+ int intskip;
+
+ tempo = newTempo;
+
+ // Calculate new sequence duration
+ calcSeqParameters();
+
+ // Calculate ideal skip length (according to tempo value)
+ nominalSkip = tempo * (seekWindowLength - overlapLength);
+ intskip = (int)(nominalSkip + 0.5f);
+
+ // Calculate how many samples are needed in the 'inputBuffer' to
+ // process another batch of samples
+ //sampleReq = max(intskip + overlapLength, seekWindowLength) + seekLength / 2;
+ sampleReq = max(intskip + overlapLength, seekWindowLength) + seekLength;
+}
+
+
+
+// Sets the number of channels, 1 = mono, 2 = stereo
+void TDStretch::setChannels(int numChannels)
+{
+ assert(numChannels > 0);
+ if (channels == numChannels) return;
+ assert(numChannels == 1 || numChannels == 2);
+
+ channels = numChannels;
+ inputBuffer.setChannels(channels);
+ outputBuffer.setChannels(channels);
+}
+
+
+// nominal tempo, no need for processing, just pass the samples through
+// to outputBuffer
+/*
+void TDStretch::processNominalTempo()
+{
+ assert(tempo == 1.0f);
+
+ if (bMidBufferDirty)
+ {
+ // If there are samples in pMidBuffer waiting for overlapping,
+ // do a single sliding overlapping with them in order to prevent a
+ // clicking distortion in the output sound
+ if (inputBuffer.numSamples() < overlapLength)
+ {
+ // wait until we've got overlapLength input samples
+ return;
+ }
+ // Mix the samples in the beginning of 'inputBuffer' with the
+ // samples in 'midBuffer' using sliding overlapping
+ overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0);
+ outputBuffer.putSamples(overlapLength);
+ inputBuffer.receiveSamples(overlapLength);
+ clearMidBuffer();
+ // now we've caught the nominal sample flow and may switch to
+ // bypass mode
+ }
+
+ // Simply bypass samples from input to output
+ outputBuffer.moveSamples(inputBuffer);
+}
+*/
+
+#include <stdio.h>
+
+// Processes as many processing frames of the samples 'inputBuffer', store
+// the result into 'outputBuffer'
+void TDStretch::processSamples()
+{
+ int ovlSkip, offset;
+ int temp;
+
+ /* Removed this small optimization - can introduce a click to sound when tempo setting
+ crosses the nominal value
+ if (tempo == 1.0f)
+ {
+ // tempo not changed from the original, so bypass the processing
+ processNominalTempo();
+ return;
+ }
+ */
+
+ // Process samples as long as there are enough samples in 'inputBuffer'
+ // to form a processing frame.
+// while ((int)inputBuffer.numSamples() >= sampleReq - (outDebt / 4))
+ while ((int)inputBuffer.numSamples() >= sampleReq)
+ {
+ // If tempo differs from the normal ('SCALE'), scan for the best overlapping
+ // position
+ offset = seekBestOverlapPosition(inputBuffer.ptrBegin());
+
+ // Mix the samples in the 'inputBuffer' at position of 'offset' with the
+ // samples in 'midBuffer' using sliding overlapping
+ // ... first partially overlap with the end of the previous sequence
+ // (that's in 'midBuffer')
+ overlap(outputBuffer.ptrEnd((uint)overlapLength), inputBuffer.ptrBegin(), (uint)offset);
+ outputBuffer.putSamples((uint)overlapLength);
+
+ // ... then copy sequence samples from 'inputBuffer' to output:
+ temp = (seekLength / 2 - offset);
+
+ // compensate cumulated output length diff vs. ideal output
+// temp -= outDebt / 4;
+
+ // update ideal vs. true output difference
+// outDebt += temp;
+
+ // length of sequence
+// temp += (seekWindowLength - 2 * overlapLength);
+ temp = (seekWindowLength - 2 * overlapLength);
+
+ // crosscheck that we don't have buffer overflow...
+ if ((int)inputBuffer.numSamples() < (offset + temp + overlapLength * 2))
+ {
+ continue; // just in case, shouldn't really happen
+ }
+
+ outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), (uint)temp);
+
+ // Copies the end of the current sequence from 'inputBuffer' to
+ // 'midBuffer' for being mixed with the beginning of the next
+ // processing sequence and so on
+ assert((offset + temp + overlapLength * 2) <= (int)inputBuffer.numSamples());
+ memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + temp + overlapLength),
+ channels * sizeof(SAMPLETYPE) * overlapLength);
+
+ // Remove the processed samples from the input buffer. Update
+ // the difference between integer & nominal skip step to 'skipFract'
+ // in order to prevent the error from accumulating over time.
+ skipFract += nominalSkip; // real skip size
+ ovlSkip = (int)skipFract; // rounded to integer skip
+ skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip
+ inputBuffer.receiveSamples((uint)ovlSkip);
+ }
+}
+
+
+// Adds 'numsamples' pcs of samples from the 'samples' memory position into
+// the input of the object.
+void TDStretch::putSamples(const SAMPLETYPE *samples, uint nSamples)
+{
+ // Add the samples into the input buffer
+ inputBuffer.putSamples(samples, nSamples);
+ // Process the samples in input buffer
+ processSamples();
+}
+
+
+
+/// Set new overlap length parameter & reallocate RefMidBuffer if necessary.
+void TDStretch::acceptNewOverlapLength(int newOverlapLength)
+{
+ int prevOvl;
+
+ assert(newOverlapLength >= 0);
+ prevOvl = overlapLength;
+ overlapLength = newOverlapLength;
+
+ if (overlapLength > prevOvl)
+ {
+ delete[] pMidBuffer;
+ delete[] pRefMidBufferUnaligned;
+
+ pMidBuffer = new SAMPLETYPE[overlapLength * 2];
+ clearMidBuffer();
+
+ pRefMidBufferUnaligned = new SAMPLETYPE[2 * overlapLength + 16 / sizeof(SAMPLETYPE)];
+ // ensure that 'pRefMidBuffer' is aligned to 16 byte boundary for efficiency
+ pRefMidBuffer = (SAMPLETYPE *)((((ulong)pRefMidBufferUnaligned) + 15) & (ulong)-16);
+ }
+}
+
+
+// Operator 'new' is overloaded so that it automatically creates a suitable instance
+// depending on if we've a MMX/SSE/etc-capable CPU available or not.
+void * TDStretch::operator new(size_t s)
+{
+ // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead!
+ throw std::runtime_error("Error in TDStretch::new: Don't use 'new TDStretch' directly, use 'newInstance' member instead!");
+ return NULL;
+}
+
+
+TDStretch * TDStretch::newInstance()
+{
+ uint uExtensions;
+
+ uExtensions = detectCPUextensions();
+
+ // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU
+
+#ifdef ALLOW_MMX
+ // MMX routines available only with integer sample types
+ if (uExtensions & SUPPORT_MMX)
+ {
+ return ::new TDStretchMMX;
+ }
+ else
+#endif // ALLOW_MMX
+
+
+#ifdef ALLOW_SSE
+ if (uExtensions & SUPPORT_SSE)
+ {
+ // SSE support
+ return ::new TDStretchSSE;
+ }
+ else
+#endif // ALLOW_SSE
+
+
+#ifdef ALLOW_3DNOW
+ if (uExtensions & SUPPORT_3DNOW)
+ {
+ // 3DNow! support
+ return ::new TDStretch3DNow;
+ }
+ else
+#endif // ALLOW_3DNOW
+
+ {
+ // ISA optimizations not supported, use plain C version
+ return ::new TDStretch;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Integer arithmetics specific algorithm implementations.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#ifdef INTEGER_SAMPLES
+
+// Slopes the amplitude of the 'midBuffer' samples so that cross correlation
+// is faster to calculate
+void TDStretch::precalcCorrReferenceStereo()
+{
+ int i, cnt2;
+ int temp, temp2;
+
+ for (i=0 ; i < (int)overlapLength ;i ++)
+ {
+ temp = i * (overlapLength - i);
+ cnt2 = i * 2;
+
+ temp2 = (pMidBuffer[cnt2] * temp) / slopingDivider;
+ pRefMidBuffer[cnt2] = (short)(temp2);
+ temp2 = (pMidBuffer[cnt2 + 1] * temp) / slopingDivider;
+ pRefMidBuffer[cnt2 + 1] = (short)(temp2);
+ }
+}
+
+
+// Slopes the amplitude of the 'midBuffer' samples so that cross correlation
+// is faster to calculate
+void TDStretch::precalcCorrReferenceMono()
+{
+ int i;
+ long temp;
+ long temp2;
+
+ for (i=0 ; i < (int)overlapLength ;i ++)
+ {
+ temp = i * (overlapLength - i);
+ temp2 = (pMidBuffer[i] * temp) / slopingDivider;
+ pRefMidBuffer[i] = (short)temp2;
+ }
+}
+
+
+// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo'
+// version of the routine.
+void TDStretch::overlapStereo(short *poutput, const short *input) const
+{
+ int i;
+ short temp;
+ int cnt2;
+
+ for (i = 0; i < overlapLength ; i ++)
+ {
+ temp = (short)(overlapLength - i);
+ cnt2 = 2 * i;
+ poutput[cnt2] = (input[cnt2] * i + pMidBuffer[cnt2] * temp ) / overlapLength;
+ poutput[cnt2 + 1] = (input[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength;
+ }
+}
+
+// Calculates the x having the closest 2^x value for the given value
+static int _getClosest2Power(double value)
+{
+ return (int)(log(value) / log(2.0) + 0.5);
+}
+
+
+/// Calculates overlap period length in samples.
+/// Integer version rounds overlap length to closest power of 2
+/// for a divide scaling operation.
+void TDStretch::calculateOverlapLength(int aoverlapMs)
+{
+ int newOvl;
+
+ assert(aoverlapMs >= 0);
+
+ // calculate overlap length so that it's power of 2 - thus it's easy to do
+ // integer division by right-shifting. Term "-1" at end is to account for
+ // the extra most significatnt bit left unused in result by signed multiplication
+ overlapDividerBits = _getClosest2Power((sampleRate * aoverlapMs) / 1000.0) - 1;
+ if (overlapDividerBits > 9) overlapDividerBits = 9;
+ if (overlapDividerBits < 3) overlapDividerBits = 3;
+ newOvl = (int)pow(2.0, (int)overlapDividerBits + 1); // +1 => account for -1 above
+
+ acceptNewOverlapLength(newOvl);
+
+ // calculate sloping divider so that crosscorrelation operation won't
+ // overflow 32-bit register. Max. sum of the crosscorrelation sum without
+ // divider would be 2^30*(N^3-N)/3, where N = overlap length
+ slopingDivider = (newOvl * newOvl - 1) / 3;
+}
+
+
+long TDStretch::calcCrossCorrMono(const short *mixingPos, const short *compare) const
+{
+ long corr;
+ long norm;
+ int i;
+
+ corr = norm = 0;
+ for (i = 1; i < overlapLength; i ++)
+ {
+ corr += (mixingPos[i] * compare[i]) >> overlapDividerBits;
+ norm += (mixingPos[i] * mixingPos[i]) >> overlapDividerBits;
+ }
+
+ // Normalize result by dividing by sqrt(norm) - this step is easiest
+ // done using floating point operation
+ if (norm == 0) norm = 1; // to avoid div by zero
+ return (long)((double)corr * SHRT_MAX / sqrt((double)norm));
+}
+
+
+long TDStretch::calcCrossCorrStereo(const short *mixingPos, const short *compare) const
+{
+ long corr;
+ long norm;
+ int i;
+
+ corr = norm = 0;
+ for (i = 2; i < 2 * overlapLength; i += 2)
+ {
+ corr += (mixingPos[i] * compare[i] +
+ mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBits;
+ norm += (mixingPos[i] * mixingPos[i] + mixingPos[i + 1] * mixingPos[i + 1]) >> overlapDividerBits;
+ }
+
+ // Normalize result by dividing by sqrt(norm) - this step is easiest
+ // done using floating point operation
+ if (norm == 0) norm = 1; // to avoid div by zero
+ return (long)((double)corr * SHRT_MAX / sqrt((double)norm));
+}
+
+#endif // INTEGER_SAMPLES
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Floating point arithmetics specific algorithm implementations.
+//
+
+#ifdef FLOAT_SAMPLES
+
+
+// Slopes the amplitude of the 'midBuffer' samples so that cross correlation
+// is faster to calculate
+void TDStretch::precalcCorrReferenceStereo()
+{
+ int i, cnt2;
+ float temp;
+
+ for (i=0 ; i < (int)overlapLength ;i ++)
+ {
+ temp = (float)i * (float)(overlapLength - i);
+ cnt2 = i * 2;
+ pRefMidBuffer[cnt2] = (float)(pMidBuffer[cnt2] * temp);
+ pRefMidBuffer[cnt2 + 1] = (float)(pMidBuffer[cnt2 + 1] * temp);
+ }
+}
+
+
+// Slopes the amplitude of the 'midBuffer' samples so that cross correlation
+// is faster to calculate
+void TDStretch::precalcCorrReferenceMono()
+{
+ int i;
+ float temp;
+
+ for (i=0 ; i < (int)overlapLength ;i ++)
+ {
+ temp = (float)i * (float)(overlapLength - i);
+ pRefMidBuffer[i] = (float)(pMidBuffer[i] * temp);
+ }
+}
+
+
+// Overlaps samples in 'midBuffer' with the samples in 'pInput'
+void TDStretch::overlapStereo(float *pOutput, const float *pInput) const
+{
+ int i;
+ int cnt2;
+ float fTemp;
+ float fScale;
+ float fi;
+
+ fScale = 1.0f / (float)overlapLength;
+
+ for (i = 0; i < (int)overlapLength ; i ++)
+ {
+ fTemp = (float)(overlapLength - i) * fScale;
+ fi = (float)i * fScale;
+ cnt2 = 2 * i;
+ pOutput[cnt2 + 0] = pInput[cnt2 + 0] * fi + pMidBuffer[cnt2 + 0] * fTemp;
+ pOutput[cnt2 + 1] = pInput[cnt2 + 1] * fi + pMidBuffer[cnt2 + 1] * fTemp;
+ }
+}
+
+
+/// Calculates overlapInMsec period length in samples.
+void TDStretch::calculateOverlapLength(int overlapInMsec)
+{
+ int newOvl;
+
+ assert(overlapInMsec >= 0);
+ newOvl = (sampleRate * overlapInMsec) / 1000;
+ if (newOvl < 16) newOvl = 16;
+
+ // must be divisible by 8
+ newOvl -= newOvl % 8;
+
+ acceptNewOverlapLength(newOvl);
+}
+
+
+
+double TDStretch::calcCrossCorrMono(const float *mixingPos, const float *compare) const
+{
+ double corr;
+ double norm;
+ int i;
+
+ corr = norm = 0;
+ for (i = 1; i < overlapLength; i ++)
+ {
+ corr += mixingPos[i] * compare[i];
+ norm += mixingPos[i] * mixingPos[i];
+ }
+
+ if (norm < 1e-9) norm = 1.0; // to avoid div by zero
+ return corr / sqrt(norm);
+}
+
+
+double TDStretch::calcCrossCorrStereo(const float *mixingPos, const float *compare) const
+{
+ double corr;
+ double norm;
+ int i;
+
+ corr = norm = 0;
+ for (i = 2; i < 2 * overlapLength; i += 2)
+ {
+ corr += mixingPos[i] * compare[i] +
+ mixingPos[i + 1] * compare[i + 1];
+ norm += mixingPos[i] * mixingPos[i] +
+ mixingPos[i + 1] * mixingPos[i + 1];
+ }
+
+ if (norm < 1e-9) norm = 1.0; // to avoid div by zero
+ return corr / sqrt(norm);
+}
+
+#endif // FLOAT_SAMPLES
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/TDStretch.h b/plugins/soundtouch/soundtouch/source/SoundTouch/TDStretch.h
new file mode 100644
index 00000000..00d1f3e3
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/TDStretch.h
@@ -0,0 +1,275 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
+/// while maintaining the original pitch by using a time domain WSOLA-like method
+/// with several performance-increasing tweaks.
+///
+/// Note : MMX/SSE optimized functions reside in separate, platform-specific files
+/// 'mmx_optimized.cpp' and 'sse_optimized.cpp'
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-05-17 14:35:13 +0300 (Sun, 17 May 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: TDStretch.h 71 2009-05-17 11:35:13Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef TDStretch_H
+#define TDStretch_H
+
+#include <stddef.h>
+#include "STTypes.h"
+#include "RateTransposer.h"
+#include "FIFOSamplePipe.h"
+
+namespace soundtouch
+{
+
+/// Default values for sound processing parameters:
+/// Notice that the default parameters are tuned for contemporary popular music
+/// processing. For speech processing applications these parameters suit better:
+/// #define DEFAULT_SEQUENCE_MS 40
+/// #define DEFAULT_SEEKWINDOW_MS 15
+/// #define DEFAULT_OVERLAP_MS 8
+///
+
+/// Default length of a single processing sequence, in milliseconds. This determines to how
+/// long sequences the original sound is chopped in the time-stretch algorithm.
+///
+/// The larger this value is, the lesser sequences are used in processing. In principle
+/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo
+/// and vice versa.
+///
+/// Increasing this value reduces computational burden & vice versa.
+//#define DEFAULT_SEQUENCE_MS 40
+#define DEFAULT_SEQUENCE_MS USE_AUTO_SEQUENCE_LEN
+
+/// Giving this value for the sequence length sets automatic parameter value
+/// according to tempo setting (recommended)
+#define USE_AUTO_SEQUENCE_LEN 0
+
+/// Seeking window default length in milliseconds for algorithm that finds the best possible
+/// overlapping location. This determines from how wide window the algorithm may look for an
+/// optimal joining location when mixing the sound sequences back together.
+///
+/// The bigger this window setting is, the higher the possibility to find a better mixing
+/// position will become, but at the same time large values may cause a "drifting" artifact
+/// because consequent sequences will be taken at more uneven intervals.
+///
+/// If there's a disturbing artifact that sounds as if a constant frequency was drifting
+/// around, try reducing this setting.
+///
+/// Increasing this value increases computational burden & vice versa.
+//#define DEFAULT_SEEKWINDOW_MS 15
+#define DEFAULT_SEEKWINDOW_MS USE_AUTO_SEEKWINDOW_LEN
+
+/// Giving this value for the seek window length sets automatic parameter value
+/// according to tempo setting (recommended)
+#define USE_AUTO_SEEKWINDOW_LEN 0
+
+/// Overlap length in milliseconds. When the chopped sound sequences are mixed back together,
+/// to form a continuous sound stream, this parameter defines over how long period the two
+/// consecutive sequences are let to overlap each other.
+///
+/// This shouldn't be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting
+/// by a large amount, you might wish to try a smaller value on this.
+///
+/// Increasing this value increases computational burden & vice versa.
+#define DEFAULT_OVERLAP_MS 8
+
+
+/// Class that does the time-stretch (tempo change) effect for the processed
+/// sound.
+class TDStretch : public FIFOProcessor
+{
+protected:
+ int channels;
+ int sampleReq;
+ float tempo;
+
+ SAMPLETYPE *pMidBuffer;
+ SAMPLETYPE *pRefMidBuffer;
+ SAMPLETYPE *pRefMidBufferUnaligned;
+ int overlapLength;
+ int seekLength;
+ int seekWindowLength;
+ int overlapDividerBits;
+ int slopingDivider;
+ float nominalSkip;
+ float skipFract;
+ FIFOSampleBuffer outputBuffer;
+ FIFOSampleBuffer inputBuffer;
+ BOOL bQuickSeek;
+// int outDebt;
+// BOOL bMidBufferDirty;
+
+ int sampleRate;
+ int sequenceMs;
+ int seekWindowMs;
+ int overlapMs;
+ BOOL bAutoSeqSetting;
+ BOOL bAutoSeekSetting;
+
+ void acceptNewOverlapLength(int newOverlapLength);
+
+ virtual void clearCrossCorrState();
+ void calculateOverlapLength(int overlapMs);
+
+ virtual LONG_SAMPLETYPE calcCrossCorrStereo(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const;
+ virtual LONG_SAMPLETYPE calcCrossCorrMono(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const;
+
+ virtual int seekBestOverlapPositionStereo(const SAMPLETYPE *refPos);
+ virtual int seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos);
+ virtual int seekBestOverlapPositionMono(const SAMPLETYPE *refPos);
+ virtual int seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos);
+ int seekBestOverlapPosition(const SAMPLETYPE *refPos);
+
+ virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const;
+ virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const;
+
+ void clearMidBuffer();
+ void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const;
+
+ void precalcCorrReferenceMono();
+ void precalcCorrReferenceStereo();
+
+ void calcSeqParameters();
+
+ /// Changes the tempo of the given sound samples.
+ /// Returns amount of samples returned in the "output" buffer.
+ /// The maximum amount of samples that can be returned at a time is set by
+ /// the 'set_returnBuffer_size' function.
+ void processSamples();
+
+public:
+ TDStretch();
+ virtual ~TDStretch();
+
+ /// Operator 'new' is overloaded so that it automatically creates a suitable instance
+ /// depending on if we've a MMX/SSE/etc-capable CPU available or not.
+ static void *operator new(size_t s);
+
+ /// Use this function instead of "new" operator to create a new instance of this class.
+ /// This function automatically chooses a correct feature set depending on if the CPU
+ /// supports MMX/SSE/etc extensions.
+ static TDStretch *newInstance();
+
+ /// Returns the output buffer object
+ FIFOSamplePipe *getOutput() { return &outputBuffer; };
+
+ /// Returns the input buffer object
+ FIFOSamplePipe *getInput() { return &inputBuffer; };
+
+ /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower
+ /// tempo, larger faster tempo.
+ void setTempo(float newTempo);
+
+ /// Returns nonzero if there aren't any samples available for outputting.
+ virtual void clear();
+
+ /// Clears the input buffer
+ void clearInput();
+
+ /// Sets the number of channels, 1 = mono, 2 = stereo
+ void setChannels(int numChannels);
+
+ /// Enables/disables the quick position seeking algorithm. Zero to disable,
+ /// nonzero to enable
+ void enableQuickSeek(BOOL enable);
+
+ /// Returns nonzero if the quick seeking algorithm is enabled.
+ BOOL isQuickSeekEnabled() const;
+
+ /// Sets routine control parameters. These control are certain time constants
+ /// defining how the sound is stretched to the desired duration.
+ //
+ /// 'sampleRate' = sample rate of the sound
+ /// 'sequenceMS' = one processing sequence length in milliseconds
+ /// 'seekwindowMS' = seeking window length for scanning the best overlapping
+ /// position
+ /// 'overlapMS' = overlapping length
+ void setParameters(int sampleRate, ///< Samplerate of sound being processed (Hz)
+ int sequenceMS = -1, ///< Single processing sequence length (ms)
+ int seekwindowMS = -1, ///< Offset seeking window length (ms)
+ int overlapMS = -1 ///< Sequence overlapping length (ms)
+ );
+
+ /// Get routine control parameters, see setParameters() function.
+ /// Any of the parameters to this function can be NULL, in such case corresponding parameter
+ /// value isn't returned.
+ void getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const;
+
+ /// Adds 'numsamples' pcs of samples from the 'samples' memory position into
+ /// the input of the object.
+ virtual void putSamples(
+ const SAMPLETYPE *samples, ///< Input sample data
+ uint numSamples ///< Number of samples in 'samples' so that one sample
+ ///< contains both channels if stereo
+ );
+};
+
+
+
+// Implementation-specific class declarations:
+
+#ifdef ALLOW_MMX
+ /// Class that implements MMX optimized routines for 16bit integer samples type.
+ class TDStretchMMX : public TDStretch
+ {
+ protected:
+ long calcCrossCorrStereo(const short *mixingPos, const short *compare) const;
+ virtual void overlapStereo(short *output, const short *input) const;
+ virtual void clearCrossCorrState();
+ };
+#endif /// ALLOW_MMX
+
+
+#ifdef ALLOW_3DNOW
+ /// Class that implements 3DNow! optimized routines for floating point samples type.
+ class TDStretch3DNow : public TDStretch
+ {
+ protected:
+ double calcCrossCorrStereo(const float *mixingPos, const float *compare) const;
+ };
+#endif /// ALLOW_3DNOW
+
+
+#ifdef ALLOW_SSE
+ /// Class that implements SSE optimized routines for floating point samples type.
+ class TDStretchSSE : public TDStretch
+ {
+ protected:
+ double calcCrossCorrStereo(const float *mixingPos, const float *compare) const;
+ };
+
+#endif /// ALLOW_SSE
+
+}
+#endif /// TDStretch_H
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/cpu_detect.h b/plugins/soundtouch/soundtouch/source/SoundTouch/cpu_detect.h
new file mode 100644
index 00000000..025781da
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/cpu_detect.h
@@ -0,0 +1,62 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// A header file for detecting the Intel MMX instructions set extension.
+///
+/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the
+/// routine implementations for x86 Windows, x86 gnu version and non-x86
+/// platforms, respectively.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2008-02-10 18:26:55 +0200 (Sun, 10 Feb 2008) $
+// File revision : $Revision: 4 $
+//
+// $Id: cpu_detect.h 11 2008-02-10 16:26:55Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef _CPU_DETECT_H_
+#define _CPU_DETECT_H_
+
+#include "STTypes.h"
+
+#define SUPPORT_MMX 0x0001
+#define SUPPORT_3DNOW 0x0002
+#define SUPPORT_ALTIVEC 0x0004
+#define SUPPORT_SSE 0x0008
+#define SUPPORT_SSE2 0x0010
+
+/// Checks which instruction set extensions are supported by the CPU.
+///
+/// \return A bitmask of supported extensions, see SUPPORT_... defines.
+uint detectCPUextensions(void);
+
+/// Disables given set of instruction extensions. See SUPPORT_... defines.
+void disableExtensions(uint wDisableMask);
+
+#endif // _CPU_DETECT_H_
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/cpu_detect_x86_gcc.cpp b/plugins/soundtouch/soundtouch/source/SoundTouch/cpu_detect_x86_gcc.cpp
new file mode 100644
index 00000000..b0d0a693
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/cpu_detect_x86_gcc.cpp
@@ -0,0 +1,135 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Generic version of the x86 CPU extension detection routine.
+///
+/// This file is for GNU & other non-Windows compilers, see 'cpu_detect_x86_win.cpp'
+/// for the Microsoft compiler version.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-02-25 19:13:51 +0200 (Wed, 25 Feb 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: cpu_detect_x86_gcc.cpp 67 2009-02-25 17:13:51Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <stdexcept>
+#include <string>
+#include "cpu_detect.h"
+#include "STTypes.h"
+
+using namespace std;
+
+#include <stdio.h>
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// processor instructions extension detection routines
+//
+//////////////////////////////////////////////////////////////////////////////
+
+// Flag variable indicating whick ISA extensions are disabled (for debugging)
+static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions
+
+// Disables given set of instruction extensions. See SUPPORT_... defines.
+void disableExtensions(uint dwDisableMask)
+{
+ _dwDisabledISA = dwDisableMask;
+}
+
+
+
+/// Checks which instruction set extensions are supported by the CPU.
+uint detectCPUextensions(void)
+{
+#if (!(ALLOW_X86_OPTIMIZATIONS) || !(__GNUC__))
+
+ return 0; // always disable extensions on non-x86 platforms.
+
+#else
+ uint res = 0;
+
+ if (_dwDisabledISA == 0xffffffff) return 0;
+
+ asm volatile(
+ "\n\txor %%esi, %%esi" // clear %%esi = result register
+ // check if 'cpuid' instructions is available by toggling eflags bit 21
+
+ "\n\tpushf" // save eflags to stack
+ "\n\tmovl (%%esp), %%eax" // load eax from stack (with eflags)
+ "\n\tmovl %%eax, %%ecx" // save the original eflags values to ecx
+ "\n\txor $0x00200000, %%eax" // toggle bit 21
+ "\n\tmovl %%eax, (%%esp)" // store toggled eflags to stack
+ "\n\tpopf" // load eflags from stack
+ "\n\tpushf" // save updated eflags to stack
+ "\n\tmovl (%%esp), %%eax" // load eax from stack
+ "\n\tpopf" // pop stack to restore esp
+ "\n\txor %%edx, %%edx" // clear edx for defaulting no mmx
+ "\n\tcmp %%ecx, %%eax" // compare to original eflags values
+ "\n\tjz end" // jumps to 'end' if cpuid not present
+ // cpuid instruction available, test for presence of mmx instructions
+
+ "\n\tmovl $1, %%eax"
+ "\n\tcpuid"
+ "\n\ttest $0x00800000, %%edx"
+ "\n\tjz end" // branch if MMX not available
+
+ "\n\tor $0x01, %%esi" // otherwise add MMX support bit
+
+ "\n\ttest $0x02000000, %%edx"
+ "\n\tjz test3DNow" // branch if SSE not available
+
+ "\n\tor $0x08, %%esi" // otherwise add SSE support bit
+
+ "\n\ttest3DNow:"
+ // test for precense of AMD extensions
+ "\n\tmov $0x80000000, %%eax"
+ "\n\tcpuid"
+ "\n\tcmp $0x80000000, %%eax"
+ "\n\tjbe end" // branch if no AMD extensions detected
+
+ // test for precense of 3DNow! extension
+ "\n\tmov $0x80000001, %%eax"
+ "\n\tcpuid"
+ "\n\ttest $0x80000000, %%edx"
+ "\n\tjz end" // branch if 3DNow! not detected
+
+ "\n\tor $0x02, %%esi" // otherwise add 3DNow support bit
+
+ "\n\tend:"
+
+ "\n\tmov %%esi, %0"
+
+ : "=r" (res)
+ : /* no inputs */
+ : "%edx", "%eax", "%ecx", "%esi" );
+
+ return res & ~_dwDisabledISA;
+#endif
+}
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/cpu_detect_x86_win.cpp b/plugins/soundtouch/soundtouch/source/SoundTouch/cpu_detect_x86_win.cpp
new file mode 100644
index 00000000..c6c54246
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/cpu_detect_x86_win.cpp
@@ -0,0 +1,129 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Win32 version of the x86 CPU detect routine.
+///
+/// This file is to be compiled in Windows platform with Microsoft Visual C++
+/// Compiler. Please see 'cpu_detect_x86_gcc.cpp' for the gcc compiler version
+/// for all GNU platforms.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-02-13 18:22:48 +0200 (Fri, 13 Feb 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: cpu_detect_x86_win.cpp 62 2009-02-13 16:22:48Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include "cpu_detect.h"
+
+#ifndef WIN32
+#error wrong platform - this source code file is exclusively for Win32 platform
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// processor instructions extension detection routines
+//
+//////////////////////////////////////////////////////////////////////////////
+
+// Flag variable indicating whick ISA extensions are disabled (for debugging)
+static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions
+
+
+// Disables given set of instruction extensions. See SUPPORT_... defines.
+void disableExtensions(uint dwDisableMask)
+{
+ _dwDisabledISA = dwDisableMask;
+}
+
+
+
+/// Checks which instruction set extensions are supported by the CPU.
+uint detectCPUextensions(void)
+{
+ uint res = 0;
+
+ if (_dwDisabledISA == 0xffffffff) return 0;
+
+ _asm
+ {
+ ; check if 'cpuid' instructions is available by toggling eflags bit 21
+ ;
+ xor esi, esi ; clear esi = result register
+
+ pushfd ; save eflags to stack
+ mov eax,dword ptr [esp] ; load eax from stack (with eflags)
+ mov ecx, eax ; save the original eflags values to ecx
+ xor eax, 0x00200000 ; toggle bit 21
+ mov dword ptr [esp],eax ; store toggled eflags to stack
+ popfd ; load eflags from stack
+
+ pushfd ; save updated eflags to stack
+ mov eax,dword ptr [esp] ; load eax from stack
+ popfd ; pop stack to restore stack pointer
+
+ xor edx, edx ; clear edx for defaulting no mmx
+ cmp eax, ecx ; compare to original eflags values
+ jz end ; jumps to 'end' if cpuid not present
+
+ ; cpuid instruction available, test for presence of mmx instructions
+ mov eax, 1
+ cpuid
+ test edx, 0x00800000
+ jz end ; branch if MMX not available
+
+ or esi, SUPPORT_MMX ; otherwise add MMX support bit
+
+ test edx, 0x02000000
+ jz test3DNow ; branch if SSE not available
+
+ or esi, SUPPORT_SSE ; otherwise add SSE support bit
+
+ test3DNow:
+ ; test for precense of AMD extensions
+ mov eax, 0x80000000
+ cpuid
+ cmp eax, 0x80000000
+ jbe end ; branch if no AMD extensions detected
+
+ ; test for precense of 3DNow! extension
+ mov eax, 0x80000001
+ cpuid
+ test edx, 0x80000000
+ jz end ; branch if 3DNow! not detected
+
+ or esi, SUPPORT_3DNOW ; otherwise add 3DNow support bit
+
+ end:
+
+ mov res, esi
+ }
+
+ return res & ~_dwDisabledISA;
+}
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/mmx_optimized.cpp b/plugins/soundtouch/soundtouch/source/SoundTouch/mmx_optimized.cpp
new file mode 100644
index 00000000..539ee57c
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/mmx_optimized.cpp
@@ -0,0 +1,320 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// MMX optimized routines. All MMX optimized functions have been gathered into
+/// this single source code file, regardless to their class or original source
+/// code file, in order to ease porting the library to other compiler and
+/// processor platforms.
+///
+/// The MMX-optimizations are programmed using MMX compiler intrinsics that
+/// are supported both by Microsoft Visual C++ and GCC compilers, so this file
+/// should compile with both toolsets.
+///
+/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++
+/// 6.0 processor pack" update to support compiler intrinsic syntax. The update
+/// is available for download at Microsoft Developers Network, see here:
+/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-10-31 16:53:23 +0200 (Sat, 31 Oct 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: mmx_optimized.cpp 75 2009-10-31 14:53:23Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include "STTypes.h"
+
+#ifdef ALLOW_MMX
+// MMX routines available only with integer sample type
+
+#if !(WIN32 || __i386__ || __x86_64__)
+#error "wrong platform - this source code file is exclusively for x86 platforms"
+#endif
+
+using namespace soundtouch;
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// implementation of MMX optimized functions of class 'TDStretchMMX'
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include "TDStretch.h"
+#include <mmintrin.h>
+#include <limits.h>
+#include <math.h>
+
+
+// Calculates cross correlation of two buffers
+long TDStretchMMX::calcCrossCorrStereo(const short *pV1, const short *pV2) const
+{
+ const __m64 *pVec1, *pVec2;
+ __m64 shifter;
+ __m64 accu, normaccu;
+ long corr, norm;
+ int i;
+
+ pVec1 = (__m64*)pV1;
+ pVec2 = (__m64*)pV2;
+
+ shifter = _m_from_int(overlapDividerBits);
+ normaccu = accu = _mm_setzero_si64();
+
+ // Process 4 parallel sets of 2 * stereo samples each during each
+ // round to improve CPU-level parallellization.
+ for (i = 0; i < overlapLength / 8; i ++)
+ {
+ __m64 temp, temp2;
+
+ // dictionary of instructions:
+ // _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3]
+ // _mm_add_pi32 : 2*32bit add
+ // _m_psrad : 32bit right-shift
+
+ temp = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]),
+ _mm_madd_pi16(pVec1[1], pVec2[1]));
+ temp2 = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec1[0]),
+ _mm_madd_pi16(pVec1[1], pVec1[1]));
+ accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter));
+ normaccu = _mm_add_pi32(normaccu, _mm_sra_pi32(temp2, shifter));
+
+ temp = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]),
+ _mm_madd_pi16(pVec1[3], pVec2[3]));
+ temp2 = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec1[2]),
+ _mm_madd_pi16(pVec1[3], pVec1[3]));
+ accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter));
+ normaccu = _mm_add_pi32(normaccu, _mm_sra_pi32(temp2, shifter));
+
+ pVec1 += 4;
+ pVec2 += 4;
+ }
+
+ // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1
+ // and finally store the result into the variable "corr"
+
+ accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32));
+ corr = _m_to_int(accu);
+
+ normaccu = _mm_add_pi32(normaccu, _mm_srli_si64(normaccu, 32));
+ norm = _m_to_int(normaccu);
+
+ // Clear MMS state
+ _m_empty();
+
+ // Normalize result by dividing by sqrt(norm) - this step is easiest
+ // done using floating point operation
+ if (norm == 0) norm = 1; // to avoid div by zero
+ return (long)((double)corr * USHRT_MAX / sqrt((double)norm));
+ // Note: Warning about the missing EMMS instruction is harmless
+ // as it'll be called elsewhere.
+}
+
+
+
+void TDStretchMMX::clearCrossCorrState()
+{
+ // Clear MMS state
+ _m_empty();
+ //_asm EMMS;
+}
+
+
+
+// MMX-optimized version of the function overlapStereo
+void TDStretchMMX::overlapStereo(short *output, const short *input) const
+{
+ const __m64 *pVinput, *pVMidBuf;
+ __m64 *pVdest;
+ __m64 mix1, mix2, adder, shifter;
+ int i;
+
+ pVinput = (const __m64*)input;
+ pVMidBuf = (const __m64*)pMidBuffer;
+ pVdest = (__m64*)output;
+
+ // mix1 = mixer values for 1st stereo sample
+ // mix1 = mixer values for 2nd stereo sample
+ // adder = adder for updating mixer values after each round
+
+ mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength);
+ adder = _mm_set_pi16(1, -1, 1, -1);
+ mix2 = _mm_add_pi16(mix1, adder);
+ adder = _mm_add_pi16(adder, adder);
+
+ // Overlaplength-division by shifter. "+1" is to account for "-1" deduced in
+ // overlapDividerBits calculation earlier.
+ shifter = _m_from_int(overlapDividerBits + 1);
+
+ for (i = 0; i < overlapLength / 4; i ++)
+ {
+ __m64 temp1, temp2;
+
+ // load & shuffle data so that input & mixbuffer data samples are paired
+ temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r
+ temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r
+
+ // temp = (temp .* mix) >> shifter
+ temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter);
+ temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter);
+ pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit
+
+ // update mix += adder
+ mix1 = _mm_add_pi16(mix1, adder);
+ mix2 = _mm_add_pi16(mix2, adder);
+
+ // --- second round begins here ---
+
+ // load & shuffle data so that input & mixbuffer data samples are paired
+ temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r
+ temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r
+
+ // temp = (temp .* mix) >> shifter
+ temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter);
+ temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter);
+ pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit
+
+ // update mix += adder
+ mix1 = _mm_add_pi16(mix1, adder);
+ mix2 = _mm_add_pi16(mix2, adder);
+
+ pVinput += 2;
+ pVMidBuf += 2;
+ pVdest += 2;
+ }
+
+ _m_empty(); // clear MMS state
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// implementation of MMX optimized functions of class 'FIRFilter'
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include "FIRFilter.h"
+
+
+FIRFilterMMX::FIRFilterMMX() : FIRFilter()
+{
+ filterCoeffsUnalign = NULL;
+}
+
+
+FIRFilterMMX::~FIRFilterMMX()
+{
+ delete[] filterCoeffsUnalign;
+}
+
+
+// (overloaded) Calculates filter coefficients for MMX routine
+void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor)
+{
+ uint i;
+ FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor);
+
+ // Ensure that filter coeffs array is aligned to 16-byte boundary
+ delete[] filterCoeffsUnalign;
+ filterCoeffsUnalign = new short[2 * newLength + 8];
+ filterCoeffsAlign = (short *)(((ulong)filterCoeffsUnalign + 15) & -16);
+
+ // rearrange the filter coefficients for mmx routines
+ for (i = 0;i < length; i += 4)
+ {
+ filterCoeffsAlign[2 * i + 0] = coeffs[i + 0];
+ filterCoeffsAlign[2 * i + 1] = coeffs[i + 2];
+ filterCoeffsAlign[2 * i + 2] = coeffs[i + 0];
+ filterCoeffsAlign[2 * i + 3] = coeffs[i + 2];
+
+ filterCoeffsAlign[2 * i + 4] = coeffs[i + 1];
+ filterCoeffsAlign[2 * i + 5] = coeffs[i + 3];
+ filterCoeffsAlign[2 * i + 6] = coeffs[i + 1];
+ filterCoeffsAlign[2 * i + 7] = coeffs[i + 3];
+ }
+}
+
+
+
+// mmx-optimized version of the filter routine for stereo sound
+uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numSamples) const
+{
+ // Create stack copies of the needed member variables for asm routines :
+ uint i, j;
+ __m64 *pVdest = (__m64*)dest;
+
+ if (length < 2) return 0;
+
+ for (i = 0; i < (numSamples - length) / 2; i ++)
+ {
+ __m64 accu1;
+ __m64 accu2;
+ const __m64 *pVsrc = (const __m64*)src;
+ const __m64 *pVfilter = (const __m64*)filterCoeffsAlign;
+
+ accu1 = accu2 = _mm_setzero_si64();
+ for (j = 0; j < lengthDiv8 * 2; j ++)
+ {
+ __m64 temp1, temp2;
+
+ temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0
+ temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]); // = l3 l1 r3 r1
+
+ accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0])); // += l2*f2+l0*f0 r2*f2+r0*f0
+ accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1])); // += l3*f3+l1*f1 r3*f3+r1*f1
+
+ temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]); // = l4 l2 r4 r2
+
+ accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0])); // += l3*f2+l1*f0 r3*f2+r1*f0
+ accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1])); // += l4*f3+l2*f1 r4*f3+r2*f1
+
+ // accu1 += l2*f2+l0*f0 r2*f2+r0*f0
+ // += l3*f3+l1*f1 r3*f3+r1*f1
+
+ // accu2 += l3*f2+l1*f0 r3*f2+r1*f0
+ // l4*f3+l2*f1 r4*f3+r2*f1
+
+ pVfilter += 2;
+ pVsrc += 2;
+ }
+ // accu >>= resultDivFactor
+ accu1 = _mm_srai_pi32(accu1, resultDivFactor);
+ accu2 = _mm_srai_pi32(accu2, resultDivFactor);
+
+ // pack 2*2*32bits => 4*16 bits
+ pVdest[0] = _mm_packs_pi32(accu1, accu2);
+ src += 4;
+ pVdest ++;
+ }
+
+ _m_empty(); // clear emms state
+
+ return (numSamples & 0xfffffffe) - length;
+}
+
+#endif // ALLOW_MMX
diff --git a/plugins/soundtouch/soundtouch/source/SoundTouch/sse_optimized.cpp b/plugins/soundtouch/soundtouch/source/SoundTouch/sse_optimized.cpp
new file mode 100644
index 00000000..7659be68
--- /dev/null
+++ b/plugins/soundtouch/soundtouch/source/SoundTouch/sse_optimized.cpp
@@ -0,0 +1,510 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE
+/// optimized functions have been gathered into this single source
+/// code file, regardless to their class or original source code file, in order
+/// to ease porting the library to other compiler and processor platforms.
+///
+/// The SSE-optimizations are programmed using SSE compiler intrinsics that
+/// are supported both by Microsoft Visual C++ and GCC compilers, so this file
+/// should compile with both toolsets.
+///
+/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++
+/// 6.0 processor pack" update to support SSE instruction set. The update is
+/// available for download at Microsoft Developers Network, see here:
+/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx
+///
+/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and
+/// perform a search with keywords "processor pack".
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2009-12-28 22:32:57 +0200 (Mon, 28 Dec 2009) $
+// File revision : $Revision: 4 $
+//
+// $Id: sse_optimized.cpp 80 2009-12-28 20:32:57Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include "cpu_detect.h"
+#include "STTypes.h"
+
+using namespace soundtouch;
+
+#ifdef ALLOW_SSE
+
+// SSE routines available only with float sample type
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// implementation of SSE optimized functions of class 'TDStretchSSE'
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include "TDStretch.h"
+#include <xmmintrin.h>
+#include <math.h>
+
+// Calculates cross correlation of two buffers
+double TDStretchSSE::calcCrossCorrStereo(const float *pV1, const float *pV2) const
+{
+ int i;
+ const float *pVec1;
+ const __m128 *pVec2;
+ __m128 vSum, vNorm;
+
+ // Note. It means a major slow-down if the routine needs to tolerate
+ // unaligned __m128 memory accesses. It's way faster if we can skip
+ // unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps.
+ // This can mean up to ~ 10-fold difference (incl. part of which is
+ // due to skipping every second round for stereo sound though).
+ //
+ // Compile-time define ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided
+ // for choosing if this little cheating is allowed.
+
+#ifdef ALLOW_NONEXACT_SIMD_OPTIMIZATION
+ // Little cheating allowed, return valid correlation only for
+ // aligned locations, meaning every second round for stereo sound.
+
+ #define _MM_LOAD _mm_load_ps
+
+ if (((ulong)pV1) & 15) return -1e50; // skip unaligned locations
+
+#else
+ // No cheating allowed, use unaligned load & take the resulting
+ // performance hit.
+ #define _MM_LOAD _mm_loadu_ps
+#endif
+
+ // ensure overlapLength is divisible by 8
+ assert((overlapLength % 8) == 0);
+
+ // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
+ // Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not.
+ pVec1 = (const float*)pV1;
+ pVec2 = (const __m128*)pV2;
+ vSum = vNorm = _mm_setzero_ps();
+
+ // Unroll the loop by factor of 4 * 4 operations
+ for (i = 0; i < overlapLength / 8; i ++)
+ {
+ __m128 vTemp;
+ // vSum += pV1[0..3] * pV2[0..3]
+ vTemp = _MM_LOAD(pVec1);
+ vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp ,pVec2[0]));
+ vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
+
+ // vSum += pV1[4..7] * pV2[4..7]
+ vTemp = _MM_LOAD(pVec1 + 4);
+ vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[1]));
+ vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
+
+ // vSum += pV1[8..11] * pV2[8..11]
+ vTemp = _MM_LOAD(pVec1 + 8);
+ vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[2]));
+ vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
+
+ // vSum += pV1[12..15] * pV2[12..15]
+ vTemp = _MM_LOAD(pVec1 + 12);
+ vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[3]));
+ vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
+
+ pVec1 += 16;
+ pVec2 += 4;
+ }
+
+ // return value = vSum[0] + vSum[1] + vSum[2] + vSum[3]
+ float *pvNorm = (float*)&vNorm;
+ double norm = sqrt(pvNorm[0] + pvNorm[1] + pvNorm[2] + pvNorm[3]);
+ if (norm < 1e-9) norm = 1.0; // to avoid div by zero
+
+ float *pvSum = (float*)&vSum;
+ return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]) / norm;
+
+ /* This is approximately corresponding routine in C-language yet without normalization:
+ double corr, norm;
+ uint i;
+
+ // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
+ corr = norm = 0.0;
+ for (i = 0; i < overlapLength / 8; i ++)
+ {
+ corr += pV1[0] * pV2[0] +
+ pV1[1] * pV2[1] +
+ pV1[2] * pV2[2] +
+ pV1[3] * pV2[3] +
+ pV1[4] * pV2[4] +
+ pV1[5] * pV2[5] +
+ pV1[6] * pV2[6] +
+ pV1[7] * pV2[7] +
+ pV1[8] * pV2[8] +
+ pV1[9] * pV2[9] +
+ pV1[10] * pV2[10] +
+ pV1[11] * pV2[11] +
+ pV1[12] * pV2[12] +
+ pV1[13] * pV2[13] +
+ pV1[14] * pV2[14] +
+ pV1[15] * pV2[15];
+
+ for (j = 0; j < 15; j ++) norm += pV1[j] * pV1[j];
+
+ pV1 += 16;
+ pV2 += 16;
+ }
+ return corr / sqrt(norm);
+ */
+
+ /* This is a bit outdated, corresponding routine in assembler. This may be teeny-weeny bit
+ faster than intrinsic version, but more difficult to maintain & get compiled on multiple
+ platforms.
+
+ uint overlapLengthLocal = overlapLength;
+ float corr;
+
+ _asm
+ {
+ // Very important note: data in 'pV2' _must_ be aligned to
+ // 16-byte boundary!
+
+ // give prefetch hints to CPU of what data are to be needed soonish
+ // give more aggressive hints on pV1 as that changes while pV2 stays
+ // same between runs
+ prefetcht0 [pV1]
+ prefetcht0 [pV2]
+ prefetcht0 [pV1 + 32]
+
+ mov eax, dword ptr pV1
+ mov ebx, dword ptr pV2
+
+ xorps xmm0, xmm0
+
+ mov ecx, overlapLengthLocal
+ shr ecx, 3 // div by eight
+
+ loop1:
+ prefetcht0 [eax + 64] // give a prefetch hint to CPU what data are to be needed soonish
+ prefetcht0 [ebx + 32] // give a prefetch hint to CPU what data are to be needed soonish
+ movups xmm1, [eax]
+ mulps xmm1, [ebx]
+ addps xmm0, xmm1
+
+ movups xmm2, [eax + 16]
+ mulps xmm2, [ebx + 16]
+ addps xmm0, xmm2
+
+ prefetcht0 [eax + 96] // give a prefetch hint to CPU what data are to be needed soonish
+ prefetcht0 [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish
+
+ movups xmm3, [eax + 32]
+ mulps xmm3, [ebx + 32]
+ addps xmm0, xmm3
+
+ movups xmm4, [eax + 48]
+ mulps xmm4, [ebx + 48]
+ addps xmm0, xmm4
+
+ add eax, 64
+ add ebx, 64
+
+ dec ecx
+ jnz loop1
+
+ // add the four floats of xmm0 together and return the result.
+
+ movhlps xmm1, xmm0 // move 3 & 4 of xmm0 to 1 & 2 of xmm1
+ addps xmm1, xmm0
+ movaps xmm2, xmm1
+ shufps xmm2, xmm2, 0x01 // move 2 of xmm2 as 1 of xmm2
+ addss xmm2, xmm1
+ movss corr, xmm2
+ }
+
+ return (double)corr;
+ */
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// implementation of SSE optimized functions of class 'FIRFilter'
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include "FIRFilter.h"
+
+FIRFilterSSE::FIRFilterSSE() : FIRFilter()
+{
+ filterCoeffsAlign = NULL;
+ filterCoeffsUnalign = NULL;
+}
+
+
+FIRFilterSSE::~FIRFilterSSE()
+{
+ delete[] filterCoeffsUnalign;
+ filterCoeffsAlign = NULL;
+ filterCoeffsUnalign = NULL;
+}
+
+
+// (overloaded) Calculates filter coefficients for SSE routine
+void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor)
+{
+ uint i;
+ float fDivider;
+
+ FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor);
+
+ // Scale the filter coefficients so that it won't be necessary to scale the filtering result
+ // also rearrange coefficients suitably for 3DNow!
+ // Ensure that filter coeffs array is aligned to 16-byte boundary
+ delete[] filterCoeffsUnalign;
+ filterCoeffsUnalign = new float[2 * newLength + 4];
+ filterCoeffsAlign = (float *)(((unsigned long)filterCoeffsUnalign + 15) & (ulong)-16);
+
+ fDivider = (float)resultDivider;
+
+ // rearrange the filter coefficients for mmx routines
+ for (i = 0; i < newLength; i ++)
+ {
+ filterCoeffsAlign[2 * i + 0] =
+ filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider;
+ }
+}
+
+
+
+// SSE-optimized version of the filter routine for stereo sound
+uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const
+{
+ int count = (int)((numSamples - length) & (uint)-2);
+ int j;
+
+ assert(count % 2 == 0);
+
+ if (count < 2) return 0;
+
+ assert(source != NULL);
+ assert(dest != NULL);
+ assert((length % 8) == 0);
+ assert(filterCoeffsAlign != NULL);
+ assert(((ulong)filterCoeffsAlign) % 16 == 0);
+
+ // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2'
+ for (j = 0; j < count; j += 2)
+ {
+ const float *pSrc;
+ const __m128 *pFil;
+ __m128 sum1, sum2;
+ uint i;
+
+ pSrc = (const float*)source; // source audio data
+ pFil = (const __m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients
+ // are aligned to 16-byte boundary
+ sum1 = sum2 = _mm_setzero_ps();
+
+ for (i = 0; i < length / 8; i ++)
+ {
+ // Unroll loop for efficiency & calculate filter for 2*2 stereo samples
+ // at each pass
+
+ // sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset
+ // sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset.
+
+ sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0]));
+ sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0]));
+
+ sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1]));
+ sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1]));
+
+ sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2]));
+ sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2]));
+
+ sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3]));
+ sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3]));
+
+ pSrc += 16;
+ pFil += 4;
+ }
+
+ // Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need
+ // to sum the two hi- and lo-floats of these registers together.
+
+ // post-shuffle & add the filtered values and store to dest.
+ _mm_storeu_ps(dest, _mm_add_ps(
+ _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2
+ _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0
+ ));
+ source += 4;
+ dest += 4;
+ }
+
+ // Ideas for further improvement:
+ // 1. If it could be guaranteed that 'source' were always aligned to 16-byte
+ // boundary, a faster aligned '_mm_load_ps' instruction could be used.
+ // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte
+ // boundary, a faster '_mm_store_ps' instruction could be used.
+
+ return (uint)count;
+
+ /* original routine in C-language. please notice the C-version has differently
+ organized coefficients though.
+ double suml1, suml2;
+ double sumr1, sumr2;
+ uint i, j;
+
+ for (j = 0; j < count; j += 2)
+ {
+ const float *ptr;
+ const float *pFil;
+
+ suml1 = sumr1 = 0.0;
+ suml2 = sumr2 = 0.0;
+ ptr = src;
+ pFil = filterCoeffs;
+ for (i = 0; i < lengthLocal; i ++)
+ {
+ // unroll loop for efficiency.
+
+ suml1 += ptr[0] * pFil[0] +
+ ptr[2] * pFil[2] +
+ ptr[4] * pFil[4] +
+ ptr[6] * pFil[6];
+
+ sumr1 += ptr[1] * pFil[1] +
+ ptr[3] * pFil[3] +
+ ptr[5] * pFil[5] +
+ ptr[7] * pFil[7];
+
+ suml2 += ptr[8] * pFil[0] +
+ ptr[10] * pFil[2] +
+ ptr[12] * pFil[4] +
+ ptr[14] * pFil[6];
+
+ sumr2 += ptr[9] * pFil[1] +
+ ptr[11] * pFil[3] +
+ ptr[13] * pFil[5] +
+ ptr[15] * pFil[7];
+
+ ptr += 16;
+ pFil += 8;
+ }
+ dest[0] = (float)suml1;
+ dest[1] = (float)sumr1;
+ dest[2] = (float)suml2;
+ dest[3] = (float)sumr2;
+
+ src += 4;
+ dest += 4;
+ }
+ */
+
+
+ /* Similar routine in assembly, again obsoleted due to maintainability
+ _asm
+ {
+ // Very important note: data in 'src' _must_ be aligned to
+ // 16-byte boundary!
+ mov edx, count
+ mov ebx, dword ptr src
+ mov eax, dword ptr dest
+ shr edx, 1
+
+ loop1:
+ // "outer loop" : during each round 2*2 output samples are calculated
+
+ // give prefetch hints to CPU of what data are to be needed soonish
+ prefetcht0 [ebx]
+ prefetcht0 [filterCoeffsLocal]
+
+ mov esi, ebx
+ mov edi, filterCoeffsLocal
+ xorps xmm0, xmm0
+ xorps xmm1, xmm1
+ mov ecx, lengthLocal
+
+ loop2:
+ // "inner loop" : during each round eight FIR filter taps are evaluated for 2*2 samples
+ prefetcht0 [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish
+ prefetcht0 [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish
+
+ movups xmm2, [esi] // possibly unaligned load
+ movups xmm3, [esi + 8] // possibly unaligned load
+ mulps xmm2, [edi]
+ mulps xmm3, [edi]
+ addps xmm0, xmm2
+ addps xmm1, xmm3
+
+ movups xmm4, [esi + 16] // possibly unaligned load
+ movups xmm5, [esi + 24] // possibly unaligned load
+ mulps xmm4, [edi + 16]
+ mulps xmm5, [edi + 16]
+ addps xmm0, xmm4
+ addps xmm1, xmm5
+
+ prefetcht0 [esi + 64] // give a prefetch hint to CPU what data are to be needed soonish
+ prefetcht0 [edi + 64] // give a prefetch hint to CPU what data are to be needed soonish
+
+ movups xmm6, [esi + 32] // possibly unaligned load
+ movups xmm7, [esi + 40] // possibly unaligned load
+ mulps xmm6, [edi + 32]
+ mulps xmm7, [edi + 32]
+ addps xmm0, xmm6
+ addps xmm1, xmm7
+
+ movups xmm4, [esi + 48] // possibly unaligned load
+ movups xmm5, [esi + 56] // possibly unaligned load
+ mulps xmm4, [edi + 48]
+ mulps xmm5, [edi + 48]
+ addps xmm0, xmm4
+ addps xmm1, xmm5
+
+ add esi, 64
+ add edi, 64
+ dec ecx
+ jnz loop2
+
+ // Now xmm0 and xmm1 both have a filtered 2-channel sample each, but we still need
+ // to sum the two hi- and lo-floats of these registers together.
+
+ movhlps xmm2, xmm0 // xmm2 = xmm2_3 xmm2_2 xmm0_3 xmm0_2
+ movlhps xmm2, xmm1 // xmm2 = xmm1_1 xmm1_0 xmm0_3 xmm0_2
+ shufps xmm0, xmm1, 0xe4 // xmm0 = xmm1_3 xmm1_2 xmm0_1 xmm0_0
+ addps xmm0, xmm2
+
+ movaps [eax], xmm0
+ add ebx, 16
+ add eax, 16
+
+ dec edx
+ jnz loop1
+ }
+ */
+}
+
+#endif // ALLOW_SSE
diff --git a/plugins/soundtouch/st.cpp b/plugins/soundtouch/st.cpp
new file mode 100644
index 00000000..458a5b44
--- /dev/null
+++ b/plugins/soundtouch/st.cpp
@@ -0,0 +1,112 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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 <SoundTouch.h>
+#include "st.h"
+
+using namespace soundtouch;
+
+void*
+st_alloc (void) {
+ return new SoundTouch ();
+}
+
+void
+st_free (void *st) {
+ delete (SoundTouch *)st;
+}
+
+void
+st_set_rate (void *st, float r) {
+ ((SoundTouch *)st)->setRate (r);
+}
+
+void
+st_set_tempo (void *st, float t) {
+ ((SoundTouch *)st)->setTempo (t);
+}
+
+void
+st_set_rate_change (void *st, float r) {
+ ((SoundTouch *)st)->setRateChange (r);
+}
+
+void
+st_set_tempo_change (void *st, float t) {
+ ((SoundTouch *)st)->setTempoChange (t);
+}
+
+void
+st_set_pitch (void *st, float p) {
+ ((SoundTouch *)st)->setPitch (p);
+}
+
+void
+st_set_pitch_octaves (void *st, float po) {
+ ((SoundTouch *)st)->setPitchOctaves (po);
+}
+
+void
+st_set_pitch_semi_tones (void *st, float p) {
+ ((SoundTouch *)st)->setPitchSemiTones (p);
+}
+
+void
+st_set_channels (void *st, int c) {
+ ((SoundTouch *)st)->setChannels (c);
+}
+
+void
+st_set_sample_rate (void *st, int r) {
+ ((SoundTouch *)st)->setSampleRate (r);
+}
+
+void
+st_flush (void *st) {
+ ((SoundTouch *)st)->flush ();
+}
+
+void
+st_put_samples (void *st, float *samples, int nsamples) {
+ ((SoundTouch *)st)->putSamples (samples, nsamples);
+}
+
+void
+st_clear (void *st) {
+ ((SoundTouch *)st)->clear ();
+}
+
+void
+st_set_setting (void *st, int id, int value) {
+ ((SoundTouch *)st)->setSetting (id, value);
+}
+
+int
+st_get_setting (void *st, int id) {
+ return ((SoundTouch *)st)->getSetting (id);
+}
+
+unsigned int
+st_num_unprocessed_samples (void *st) {
+ return ((SoundTouch *)st)->numUnprocessedSamples ();
+}
+
+unsigned int
+st_receive_samples (void *st, float *out, unsigned int max_samples) {
+ return ((SoundTouch *)st)->receiveSamples (out, max_samples);
+}
diff --git a/plugins/soundtouch/st.h b/plugins/soundtouch/st.h
new file mode 100644
index 00000000..ae1f4f05
--- /dev/null
+++ b/plugins/soundtouch/st.h
@@ -0,0 +1,115 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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.
+*/
+#ifndef __ST_H
+#define __ST_H
+
+//////////////////////////////////
+// C-wrapper for soundtouch class
+
+/// Enable/disable anti-alias filter in pitch transposer (0 = disable)
+#define SETTING_USE_AA_FILTER 0
+
+/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32)
+#define SETTING_AA_FILTER_LENGTH 1
+
+/// Enable/disable quick seeking algorithm in tempo changer routine
+/// (enabling quick seeking lowers CPU utilization but causes a minor sound
+/// quality compromising)
+#define SETTING_USE_QUICKSEEK 2
+
+/// Time-stretch algorithm single processing sequence length in milliseconds. This determines
+/// to how long sequences the original sound is chopped in the time-stretch algorithm.
+/// See "STTypes.h" or README for more information.
+#define SETTING_SEQUENCE_MS 3
+
+/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the
+/// best possible overlapping location. This determines from how wide window the algorithm
+/// may look for an optimal joining location when mixing the sound sequences back together.
+/// See "STTypes.h" or README for more information.
+#define SETTING_SEEKWINDOW_MS 4
+
+/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences
+/// are mixed back together, to form a continuous sound stream, this parameter defines over
+/// how long period the two consecutive sequences are let to overlap each other.
+/// See "STTypes.h" or README for more information.
+#define SETTING_OVERLAP_MS 5
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void*
+st_alloc (void);
+
+void
+st_free (void *st);
+
+void
+st_set_rate (void *st, float r);
+
+void
+st_set_tempo (void *st, float t);
+
+void
+st_set_rate_change (void *st, float r);
+
+void
+st_set_tempo_change (void *st, float t);
+
+void
+st_set_pitch (void *st, float p);
+
+void
+st_set_pitch_octaves (void *st, float po);
+
+void
+st_set_pitch_semi_tones (void *st, float p);
+
+void
+st_set_channels (void *st, int c);
+
+void
+st_set_sample_rate (void *st, int r);
+
+void
+st_flush (void *st);
+
+void
+st_put_samples (void *st, float *samples, int nsamples);
+
+void
+st_clear (void *st);
+
+void
+st_set_setting (void *st, int id, int value);
+
+int
+st_get_setting (void *st, int id);
+
+unsigned int
+st_num_unprocessed_samples (void *st);
+
+unsigned int
+st_receive_samples (void *st, float *out, unsigned int max_samples);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/plugins/supereq/Equ.cpp b/plugins/supereq/Equ.cpp
index f53b99d1..0aff4f8a 100644
--- a/plugins/supereq/Equ.cpp
+++ b/plugins/supereq/Equ.cpp
@@ -1,37 +1,92 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>
+ Original SuperEQ code (C) Naoki Shibata <shibatch@users.sf.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 <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include "paramlist.hpp"
+#include "Equ.h"
+
+int _Unwind_Resume_or_Rethrow;
+int _Unwind_RaiseException;
+int _Unwind_GetLanguageSpecificData;
+int _Unwind_Resume;
+int _Unwind_DeleteException;
+int _Unwind_GetTextRelBase;
+int _Unwind_SetIP;
+int _Unwind_GetDataRelBase;
+int _Unwind_GetRegionStart;
+int _Unwind_SetGR;
+int _Unwind_GetIPInfo;
+
+#ifdef USE_OOURA
+extern "C" void rdft(int, int, REAL *, int *, REAL *);
+void rfft(int n,int isign,REAL *x)
+{
+ static int ipsize = 0,wsize=0;
+ static int *ip = NULL;
+ static REAL *w = NULL;
+ int newipsize,newwsize;
+ if (n == 0) {
+ free(ip); ip = NULL; ipsize = 0;
+ free(w); w = NULL; wsize = 0;
+ return;
+ }
-typedef float REAL;
-void rfft(int n,int isign,REAL x[]);
+ n = 1 << n;
-#define M 15
-#define PI 3.1415926535897932384626433832795
+ newipsize = 2+sqrt(n/2);
+ if (newipsize > ipsize) {
+ ipsize = newipsize;
+ ip = (int *)realloc(ip,sizeof(int)*ipsize);
+ ip[0] = 0;
+ }
-#define RINT(x) ((x) >= 0 ? ((int)((x) + 0.5)) : ((int)((x) - 0.5)))
+ newwsize = n/2;
+ if (newwsize > wsize) {
+ wsize = newwsize;
+ w = (REAL *)realloc(w,sizeof(REAL)*wsize);
+ }
-#define DITHERLEN 65536
+ rdft(n,isign,x,ip,w);
+}
+#elif defined(USE_FFMPEG) || defined(USE_SHIBATCH)
+extern "C" void rfft(int n,int isign,REAL *x);
+#endif
-// play -c 2 -r 44100 -fs -sw
+#if defined(USE_SHIBATCH)
+extern "C" {
+#include "SIMDBase.h"
+}
+#endif
+
+
+#define PI 3.1415926535897932384626433832795
+
+#define DITHERLEN 65536
+#define M 15
static REAL fact[M+1];
static REAL aa = 96;
-static REAL iza;
-static REAL *lires,*lires1,*lires2,*rires,*rires1,*rires2,*irest;
-static REAL *fsamples;
-static REAL *ditherbuf;
-static int ditherptr = 0;
-static volatile int chg_ires,cur_ires;
-static int winlen,winlenbit,tabsize,nbufsamples;
-static short *inbuf;
-static REAL *outbuf;
-static int maxamp;
-int enable = 1, dither = 0;
-
-#define NCH 2
+static REAL iza = 0;
#define NBANDS 17
static REAL bands[] = {
@@ -62,49 +117,75 @@ static REAL izero(REAL x)
return ret;
}
-extern "C" void equ_init(int wb)
+void *equ_malloc (int size) {
+#ifdef USE_SHIBATCH
+ return SIMDBase_alignedMalloc (size);
+#else
+ return malloc (size);
+#endif
+}
+
+void equ_free (void *mem) {
+#ifdef USE_SHIBATCH
+ SIMDBase_alignedFree (mem);
+#else
+ free (mem);
+#endif
+}
+
+extern "C" void equ_init(SuperEqState *state, int wb, int channels)
{
int i,j;
- if (lires1 != NULL) free(lires1);
- if (lires2 != NULL) free(lires2);
- if (rires1 != NULL) free(rires1);
- if (rires2 != NULL) free(rires2);
- if (irest != NULL) free(irest);
- if (fsamples != NULL) free(fsamples);
- if (inbuf != NULL) free(inbuf);
- if (outbuf != NULL) free(outbuf);
- if (ditherbuf != NULL) free(ditherbuf);
-
- winlen = (1 << (wb-1))-1;
- winlenbit = wb;
- tabsize = 1 << wb;
-
- lires1 = (REAL *)malloc(sizeof(REAL)*tabsize);
- lires2 = (REAL *)malloc(sizeof(REAL)*tabsize);
- rires1 = (REAL *)malloc(sizeof(REAL)*tabsize);
- rires2 = (REAL *)malloc(sizeof(REAL)*tabsize);
- irest = (REAL *)malloc(sizeof(REAL)*tabsize);
- fsamples = (REAL *)malloc(sizeof(REAL)*tabsize);
- inbuf = (short *)calloc(winlen*NCH,sizeof(int));
- outbuf = (REAL *)calloc(tabsize*NCH,sizeof(REAL));
- ditherbuf = (REAL *)malloc(sizeof(REAL)*DITHERLEN);
-
- lires = lires1;
- rires = rires1;
- cur_ires = 1;
- chg_ires = 1;
+ if (state->lires1 != NULL) free(state->lires1);
+ if (state->lires2 != NULL) free(state->lires2);
+ if (state->irest != NULL) free(state->irest);
+ if (state->fsamples != NULL) free(state->fsamples);
+ if (state->finbuf != NULL) free(state->finbuf);
+ if (state->outbuf != NULL) free(state->outbuf);
+ if (state->ditherbuf != NULL) free(state->ditherbuf);
+
+
+ memset (state, 0, sizeof (SuperEqState));
+ state->channels = channels;
+ state->enable = 1;
+
+ state->winlen = (1 << (wb-1))-1;
+ state->winlenbit = wb;
+ state->tabsize = 1 << wb;
+ state->fft_bits = wb;
+
+ state->lires1 = (REAL *)equ_malloc(sizeof(REAL)*state->tabsize * state->channels);
+ state->lires2 = (REAL *)equ_malloc(sizeof(REAL)*state->tabsize * state->channels);
+ state->irest = (REAL *)equ_malloc(sizeof(REAL)*state->tabsize);
+ state->fsamples = (REAL *)equ_malloc(sizeof(REAL)*state->tabsize);
+ state->finbuf = (REAL *)equ_malloc(state->winlen*state->channels*sizeof(REAL));
+ state->outbuf = (REAL *)equ_malloc(state->tabsize*state->channels*sizeof(REAL));
+ state->ditherbuf = (REAL *)equ_malloc(sizeof(REAL)*DITHERLEN);
+
+ memset (state->lires1, 0, sizeof(REAL)*state->tabsize * state->channels);
+ memset (state->lires2, 0, sizeof(REAL)*state->tabsize * state->channels);
+ memset (state->irest, 0, sizeof(REAL)*state->tabsize);
+ memset (state->fsamples, 0, sizeof(REAL)*state->tabsize);
+ memset (state->finbuf, 0, state->winlen*state->channels*sizeof(REAL));
+ memset (state->outbuf, 0, state->tabsize*state->channels*sizeof(REAL));
+ memset (state->ditherbuf, 0, sizeof(REAL)*DITHERLEN);
+
+ state->lires = state->lires1;
+ state->cur_ires = 1;
+ state->chg_ires = 1;
for(i=0;i<DITHERLEN;i++)
- ditherbuf[i] = (float(rand())/RAND_MAX-0.5);
-
- for(i=0;i<=M;i++)
- {
- fact[i] = 1;
- for(j=1;j<=i;j++) fact[i] *= j;
- }
-
- iza = izero(alpha(aa));
+ state->ditherbuf[i] = (float(rand())/RAND_MAX-0.5);
+
+ if (fact[0] < 1) {
+ for(i=0;i<=M;i++)
+ {
+ fact[i] = 1;
+ for(j=1;j<=i;j++) fact[i] *= j;
+ }
+ iza = izero(alpha(aa));
+ }
}
// -(N-1)/2 <= n <= (N-1)/2
@@ -168,7 +249,6 @@ void process_param(REAL *bc,paramlist *param,paramlist &param2,REAL fs,int ch)
for(e = param->elm;e != NULL;e = e->next)
{
- if ((ch == 0 && !e->left) || (ch == 1 && !e->right)) continue;
if (e->lower >= e->upper) continue;
for(p=param2.elm;p != NULL;p = p->next)
@@ -231,414 +311,164 @@ void process_param(REAL *bc,paramlist *param,paramlist &param2,REAL fs,int ch)
}
}
-extern "C" void equ_makeTable(REAL *lbc,REAL *rbc,paramlist *param,REAL fs)
+extern "C" void equ_makeTable(SuperEqState *state, REAL *lbc,void *_param,REAL fs)
{
- int i,cires = cur_ires;
+ paramlist *param = (paramlist *)_param;
+ int i,cires = state->cur_ires;
REAL *nires;
if (fs <= 0) return;
paramlist param2;
- // L
-
- process_param(lbc,param,param2,fs,0);
-
- for(i=0;i<winlen;i++)
- irest[i] = hn(i-winlen/2,param2,fs)*win(i-winlen/2,winlen);
-
- for(;i<tabsize;i++)
- irest[i] = 0;
+ for (int ch = 0; ch < state->channels; ch++) {
+ process_param(lbc,param,param2,fs,ch);
- rfft(tabsize,1,irest);
+ for(i=0;i<state->winlen;i++)
+ state->irest[i] = hn(i-state->winlen/2,param2,fs)*win(i-state->winlen/2,state->winlen);
- nires = cires == 1 ? lires2 : lires1;
+ for(;i<state->tabsize;i++)
+ state->irest[i] = 0;
- for(i=0;i<tabsize;i++)
- nires[i] = irest[i];
+ rfft(state->fft_bits,1,state->irest);
- process_param(rbc,param,param2,fs,1);
-
- // R
-
- for(i=0;i<winlen;i++)
- irest[i] = hn(i-winlen/2,param2,fs)*win(i-winlen/2,winlen);
+ nires = cires == 1 ? state->lires2 : state->lires1;
+ nires += ch * state->tabsize;
- for(;i<tabsize;i++)
- irest[i] = 0;
-
- rfft(tabsize,1,irest);
-
- nires = cires == 1 ? rires2 : rires1;
-
- for(i=0;i<tabsize;i++)
- nires[i] = irest[i];
-
- //
-
- chg_ires = cires == 1 ? 2 : 1;
+ for(i=0;i<state->tabsize;i++)
+ nires[i] = state->irest[i];
+ }
+ state->chg_ires = cires == 1 ? 2 : 1;
}
-extern "C" void equ_quit(void)
+extern "C" void equ_quit(SuperEqState *state)
{
- free(lires1);
- free(lires2);
- free(rires1);
- free(rires2);
- free(irest);
- free(fsamples);
- free(inbuf);
- free(outbuf);
- free(ditherbuf);
-
- lires1 = NULL;
- lires2 = NULL;
- rires1 = NULL;
- rires2 = NULL;
- irest = NULL;
- fsamples = NULL;
- inbuf = NULL;
- outbuf = NULL;
+ equ_free(state->lires1);
+ equ_free(state->lires2);
+ equ_free(state->irest);
+ equ_free(state->fsamples);
+ equ_free(state->finbuf);
+ equ_free(state->outbuf);
+ equ_free(state->ditherbuf);
+
+ state->lires1 = NULL;
+ state->lires2 = NULL;
+ state->irest = NULL;
+ state->fsamples = NULL;
+ state->finbuf = NULL;
+ state->outbuf = NULL;
rfft(0,0,NULL);
}
-extern "C" void equ_clearbuf(int bps,int srate)
+extern "C" void equ_clearbuf(SuperEqState *state)
{
int i;
- nbufsamples = 0;
- for(i=0;i<tabsize*NCH;i++) outbuf[i] = 0;
+ state->nbufsamples = 0;
+ for(i=0;i<state->tabsize*state->channels;i++) state->outbuf[i] = 0;
}
-extern "C" int equ_modifySamples(char *buf,int nsamples,int nch,int bps)
+extern "C" int equ_modifySamples_float (SuperEqState *state, char *buf,int nsamples,int nch)
{
int i,p,ch;
REAL *ires;
- int amax = (1 << (bps-1))-1;
- int amin = -(1 << (bps-1));
+ float amax = 1.0f;
+ float amin = -1.0f;
static float hm1 = 0, hm2 = 0;
- if (chg_ires) {
- cur_ires = chg_ires;
- lires = cur_ires == 1 ? lires1 : lires2;
- rires = cur_ires == 1 ? rires1 : rires2;
- chg_ires = 0;
+ if (state->chg_ires) {
+ state->cur_ires = state->chg_ires;
+ state->lires = state->cur_ires == 1 ? state->lires1 : state->lires2;
+ state->chg_ires = 0;
}
p = 0;
- while(nbufsamples+nsamples >= winlen)
+ while(state->nbufsamples+nsamples >= state->winlen)
{
- switch(bps)
- {
- case 8:
- for(i=0;i<(winlen-nbufsamples)*nch;i++)
- {
- inbuf[nbufsamples*nch+i] = ((unsigned char *)buf)[i+p*nch] - 0x80;
- float s = outbuf[nbufsamples*nch+i];
- if (dither) {
- float u;
- s -= hm1;
- u = s;
- s += ditherbuf[(ditherptr++) & (DITHERLEN-1)];
- if (s < amin) s = amin;
- if (amax < s) s = amax;
- s = RINT(s);
- hm1 = s - u;
- ((unsigned char *)buf)[i+p*nch] = s + 0x80;
- } else {
- if (s < amin) s = amin;
- if (amax < s) s = amax;
- ((unsigned char *)buf)[i+p*nch] = RINT(s) + 0x80;
- }
- }
- for(i=winlen*nch;i<tabsize*nch;i++)
- outbuf[i-winlen*nch] = outbuf[i];
-
- break;
-
- case 16:
- for(i=0;i<(winlen-nbufsamples)*nch;i++)
+ for(i=0;i<(state->winlen-state->nbufsamples)*nch;i++)
{
- inbuf[nbufsamples*nch+i] = ((short *)buf)[i+p*nch];
- float s = outbuf[nbufsamples*nch+i];
- if (dither) {
- float u;
- s -= hm1;
- u = s;
- s += ditherbuf[(ditherptr++) & (DITHERLEN-1)];
- if (s < amin) s = amin;
- if (amax < s) s = amax;
- s = RINT(s);
- hm1 = s - u;
- ((short *)buf)[i+p*nch] = s;
- } else {
- if (s < amin) s = amin;
- if (amax < s) s = amax;
- ((short *)buf)[i+p*nch] = RINT(s);
- }
- }
- for(i=winlen*nch;i<tabsize*nch;i++)
- outbuf[i-winlen*nch] = outbuf[i];
-
- break;
-
- case 24:
- for(i=0;i<(winlen-nbufsamples)*nch;i++)
- {
- ((int *)inbuf)[nbufsamples*nch+i] =
- (((unsigned char *)buf)[(i+p*nch)*3 ] ) +
- (((unsigned char *)buf)[(i+p*nch)*3+1] << 8) +
- ((( signed char *)buf)[(i+p*nch)*3+2] << 16) ;
-
- float s = outbuf[nbufsamples*nch+i];
+ state->finbuf[state->nbufsamples*nch+i] = ((float *)buf)[i+p*nch];
+ float s = state->outbuf[state->nbufsamples*nch+i];
//if (dither) s += ditherbuf[(ditherptr++) & (DITHERLEN-1)];
if (s < amin) s = amin;
if (amax < s) s = amax;
- int s2 = RINT(s);
- ((signed char *)buf)[(i+p*nch)*3 ] = s2 & 255; s2 >>= 8;
- ((signed char *)buf)[(i+p*nch)*3+1] = s2 & 255; s2 >>= 8;
- ((signed char *)buf)[(i+p*nch)*3+2] = s2 & 255;
+ ((float *)buf)[i+p*nch] = s;
}
- for(i=winlen*nch;i<tabsize*nch;i++)
- outbuf[i-winlen*nch] = outbuf[i];
+ for(i=state->winlen*nch;i<state->tabsize*nch;i++)
+ state->outbuf[i-state->winlen*nch] = state->outbuf[i];
- break;
- default:
- assert(0);
- }
-
- p += winlen-nbufsamples;
- nsamples -= winlen-nbufsamples;
- nbufsamples = 0;
+ p += state->winlen-state->nbufsamples;
+ nsamples -= state->winlen-state->nbufsamples;
+ state->nbufsamples = 0;
for(ch=0;ch<nch;ch++)
{
- ires = ch == 0 ? lires : rires;
+ ires = state->lires + ch * state->tabsize;
- if (bps == 24) {
- for(i=0;i<winlen;i++)
- fsamples[i] = ((int *)inbuf)[nch*i+ch];
- } else {
- for(i=0;i<winlen;i++)
- fsamples[i] = inbuf[nch*i+ch];
- }
+ for(i=0;i<state->winlen;i++)
+ state->fsamples[i] = state->finbuf[nch*i+ch];
- for(i=winlen;i<tabsize;i++)
- fsamples[i] = 0;
+ for(i=state->winlen;i<state->tabsize;i++)
+ state->fsamples[i] = 0;
- if (enable) {
- rfft(tabsize,1,fsamples);
+ if (state->enable) {
+ rfft(state->fft_bits,1,state->fsamples);
- fsamples[0] = ires[0]*fsamples[0];
- fsamples[1] = ires[1]*fsamples[1];
+ state->fsamples[0] = ires[0]*state->fsamples[0];
+ state->fsamples[1] = ires[1]*state->fsamples[1];
- for(i=1;i<tabsize/2;i++)
+ for(i=1;i<state->tabsize/2;i++)
{
REAL re,im;
- re = ires[i*2 ]*fsamples[i*2] - ires[i*2+1]*fsamples[i*2+1];
- im = ires[i*2+1]*fsamples[i*2] + ires[i*2 ]*fsamples[i*2+1];
+ re = ires[i*2 ]*state->fsamples[i*2] - ires[i*2+1]*state->fsamples[i*2+1];
+ im = ires[i*2+1]*state->fsamples[i*2] + ires[i*2 ]*state->fsamples[i*2+1];
- fsamples[i*2 ] = re;
- fsamples[i*2+1] = im;
+ state->fsamples[i*2 ] = re;
+ state->fsamples[i*2+1] = im;
}
- rfft(tabsize,-1,fsamples);
+ rfft(state->fft_bits,-1,state->fsamples);
} else {
- for(i=winlen-1+winlen/2;i>=winlen/2;i--) fsamples[i] = fsamples[i-winlen/2]*tabsize/2;
- for(;i>=0;i--) fsamples[i] = 0;
+ for(i=state->winlen-1+state->winlen/2;i>=state->winlen/2;i--) state->fsamples[i] = state->fsamples[i-state->winlen/2]*state->tabsize/2;
+ for(;i>=0;i--) state->fsamples[i] = 0;
}
- for(i=0;i<winlen;i++) outbuf[i*nch+ch] += fsamples[i]/tabsize*2;
+ for(i=0;i<state->winlen;i++) state->outbuf[i*nch+ch] += state->fsamples[i]/state->tabsize*2;
- for(i=winlen;i<tabsize;i++) outbuf[i*nch+ch] = fsamples[i]/tabsize*2;
+ for(i=state->winlen;i<state->tabsize;i++) state->outbuf[i*nch+ch] = state->fsamples[i]/state->tabsize*2;
}
}
- switch(bps)
- {
- case 8:
- for(i=0;i<nsamples*nch;i++)
- {
- inbuf[nbufsamples*nch+i] = ((unsigned char *)buf)[i+p*nch] - 0x80;
- float s = outbuf[nbufsamples*nch+i];
- if (dither) {
- float u;
- s -= hm1;
- u = s;
- s += ditherbuf[(ditherptr++) & (DITHERLEN-1)];
- if (s < amin) s = amin;
- if (amax < s) s = amax;
- s = RINT(s);
- hm1 = s - u;
- ((unsigned char *)buf)[i+p*nch] = s + 0x80;
- } else {
- if (s < amin) s = amin;
- if (amax < s) s = amax;
- ((unsigned char *)buf)[i+p*nch] = RINT(s) + 0x80;
- }
- }
- break;
-
- case 16:
for(i=0;i<nsamples*nch;i++)
{
- inbuf[nbufsamples*nch+i] = ((short *)buf)[i+p*nch];
- float s = outbuf[nbufsamples*nch+i];
- if (dither) {
+ state->finbuf[state->nbufsamples*nch+i] = ((float *)buf)[i+p*nch];
+ float s = state->outbuf[state->nbufsamples*nch+i];
+ if (state->dither) {
float u;
s -= hm1;
u = s;
- s += ditherbuf[(ditherptr++) & (DITHERLEN-1)];
+// s += ditherbuf[(ditherptr++) & (DITHERLEN-1)];
if (s < amin) s = amin;
if (amax < s) s = amax;
- s = RINT(s);
hm1 = s - u;
- ((short *)buf)[i+p*nch] = s;
+ ((float *)buf)[i+p*nch] = s;
} else {
if (s < amin) s = amin;
if (amax < s) s = amax;
- ((short *)buf)[i+p*nch] = RINT(s);
+ ((float *)buf)[i+p*nch] = s;
}
}
- break;
-
- case 24:
- for(i=0;i<nsamples*nch;i++)
- {
- ((int *)inbuf)[nbufsamples*nch+i] =
- (((unsigned char *)buf)[(i+p*nch)*3 ] ) +
- (((unsigned char *)buf)[(i+p*nch)*3+1] << 8) +
- ((( signed char *)buf)[(i+p*nch)*3+2] << 16) ;
-
- float s = outbuf[nbufsamples*nch+i];
- //if (dither) s += ditherbuf[(ditherptr++) & (DITHERLEN-1)];
- if (s < amin) s = amin;
- if (amax < s) s = amax;
- int s2 = RINT(s);
- ((signed char *)buf)[(i+p*nch)*3 ] = s2 & 255; s2 >>= 8;
- ((signed char *)buf)[(i+p*nch)*3+1] = s2 & 255; s2 >>= 8;
- ((signed char *)buf)[(i+p*nch)*3+2] = s2 & 255;
- }
- break;
-
- default:
- assert(0);
- }
p += nsamples;
- nbufsamples += nsamples;
+ state->nbufsamples += nsamples;
return p;
}
-#if 0
-void usage(void)
-{
- fprintf(stderr,"Ouch!\n");
-}
-
-int main(int argc,char **argv)
-{
- FILE *fpi,*fpo;
- char buf[576*2*2];
-
- static REAL bc[] =
- {1.0, 0,1.0, 0,1.0, 0,1.0, 0,1.0, 0,1.0, 0,1.0, 0,1.0, 0,1.0, 0};
-
- init(14);
- makeTable(bc,44100);
-
- if (argc != 3 && argc != 4) exit(-1);
-
- fpi = fopen(argv[1],"r");
- fpo = fopen(argv[2],"w");
-
- if (!fpi || !fpo) exit(-1);
-
- /* generate wav header */
-
- {
- short word;
- int dword;
-
- fwrite("RIFF",4,1,fpo);
- dword = 0;
- fwrite(&dword,4,1,fpo);
-
- fwrite("WAVEfmt ",8,1,fpo);
- dword = 16;
- fwrite(&dword,4,1,fpo);
- word = 1;
- fwrite(&word,2,1,fpo); /* format category, PCM */
- word = 2;
- fwrite(&word,2,1,fpo); /* channels */
- dword = 44100;
- fwrite(&dword,4,1,fpo); /* sampling rate */
- dword = 44100*2*2;
- fwrite(&dword,4,1,fpo); /* bytes per sec */
- word = 4;
- fwrite(&word,2,1,fpo); /* block alignment */
- word = 16;
- fwrite(&word,2,1,fpo); /* ??? */
-
- fwrite("data",4,1,fpo);
- dword = 0;
- fwrite(&dword,4,1,fpo);
- }
-
- preamp = 65536;
- maxamp = 0;
-
- if (argc == 4) {
- preamp = 32767*65536/atoi(argv[3]);
- fprintf(stderr,"preamp = %d\n",preamp);
- }
-
- for(;;)
- {
- int n,m;
-
- n = fread(buf,1,576*2*2,fpi);
- if (n <= 0) break;
- m = modifySamples((short *)buf,n/4,2);
- fwrite(buf,4,m,fpo);
- }
-
-#if 0
- for(;;)
- {
- int n = flushbuf((short *)buf,576);
- if (n == 0) break;
- fwrite(buf,4,n,fpo);
- }
-#endif
-
- {
- short word;
- int dword;
- int len = ftell(fpo);
-
- fseek(fpo,4,SEEK_SET);
- dword = len-8;
- fwrite(&dword,4,1,fpo);
-
- fseek(fpo,40,SEEK_SET);
- dword = len-44;
- fwrite(&dword,4,1,fpo);
- }
-
- if (maxamp != 0) {
- fprintf(stderr,"maxamp = %d\n",maxamp);
- }
-
- quit();
-}
-#endif
-
extern "C" void *paramlist_alloc (void) {
return (void *)(new paramlist);
}
diff --git a/plugins/supereq/Equ.h b/plugins/supereq/Equ.h
new file mode 100644
index 00000000..a315741a
--- /dev/null
+++ b/plugins/supereq/Equ.h
@@ -0,0 +1,56 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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.
+*/
+#ifndef __EQU_H
+#define __EQU_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef float REAL;
+typedef struct {
+ REAL *lires,*lires1,*lires2;
+ REAL *irest;
+ REAL *fsamples;
+ REAL *ditherbuf;
+ int ditherptr;
+ volatile int chg_ires,cur_ires;
+ int winlen,winlenbit,tabsize,nbufsamples;
+ REAL *finbuf;
+ REAL *outbuf;
+ int dither;
+ int channels;
+ int enable;
+ int fft_bits;
+} SuperEqState;
+
+void *paramlist_alloc (void);
+void paramlist_free (void *);
+void equ_makeTable(SuperEqState *state, float *lbc,void *param,float fs);
+int equ_modifySamples(SuperEqState *state, char *buf,int nsamples,int nch,int bps);
+int equ_modifySamples_float (SuperEqState *state, char *buf,int nsamples,int nch);
+void equ_clearbuf(SuperEqState *state);
+void equ_init(SuperEqState *state, int wb, int channels);
+void equ_quit(SuperEqState *state);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/plugins/supereq/Fftsg_fl.cpp b/plugins/supereq/Fftsg_fl.cpp
index d48debfe..636f8b8a 100644
--- a/plugins/supereq/Fftsg_fl.cpp
+++ b/plugins/supereq/Fftsg_fl.cpp
@@ -285,6 +285,7 @@ Appendix :
w[] and ip[] are compatible with all routines.
*/
+extern "C" {
void cdft(int n, int isgn, REAL *a, int *ip, REAL *w)
{
@@ -2649,32 +2650,4 @@ void dstsub(int n, REAL *a, int nc, REAL *c)
}
a[m] *= c[0];
}
-
-void rfft(int n,int isign,REAL x[])
-{
- static int ipsize = 0,wsize=0;
- static int *ip = NULL;
- static REAL *w = NULL;
- int newipsize,newwsize;
-
- if (n == 0) {
- free(ip); ip = NULL; ipsize = 0;
- free(w); w = NULL; wsize = 0;
- return;
- }
-
- newipsize = 2+sqrt(n/2);
- if (newipsize > ipsize) {
- ipsize = newipsize;
- ip = (int *)realloc(ip,sizeof(int)*ipsize);
- ip[0] = 0;
- }
-
- newwsize = n/2;
- if (newwsize > wsize) {
- wsize = newwsize;
- w = (REAL *)realloc(w,sizeof(REAL)*wsize);
- }
-
- rdft(n,isign,x,ip,w);
}
diff --git a/plugins/supereq/Makefile.am b/plugins/supereq/Makefile.am
index 0fffd6d6..45010ec8 100644
--- a/plugins/supereq/Makefile.am
+++ b/plugins/supereq/Makefile.am
@@ -3,8 +3,51 @@ supereqdir = $(libdir)/$(PACKAGE)
pkglib_LTLIBRARIES = supereq.la
supereq_la_SOURCES = supereq.c supereq.h Equ.cpp Fftsg_fl.cpp paramlist.hpp
-supereq_la_LDFLAGS = -module
+#nsfft-1.00/simd/SIMDBaseUndiff.c\
+#nsfft-1.00/simd/SIMDBase.c\
+#nsfft-1.00/dft/DFT.c\
+#nsfft-1.00/dft/DFTUndiff.c\
+#nsfft-1.00/simd/SIMDBase.h\
+#nsfft-1.00/simd/SIMDBaseUndiff.h\
+#nsfft-1.00/dft/DFTUndiff.h\
+#nsfft-1.00/dft/DFT.h\
+#shibatch_rdft.c
+
+#ffmpeg_fft/libavutil/mem.c\
+#ffmpeg_fft/libavutil/mathematics.c\
+#ffmpeg_fft/libavutil/rational.c\
+#ffmpeg_fft/libavutil/intfloat_readwrite.c\
+#ffmpeg_fft/libavcodec/dct.c\
+#ffmpeg_fft/libavcodec/avfft.c\
+#ffmpeg_fft/libavcodec/fft.c\
+#ffmpeg_fft/libavcodec/dct32.c\
+#ffmpeg_fft/libavcodec/rdft.c\
+#ffmpeg_fft/libavutil/intfloat_readwrite.h\
+#ffmpeg_fft/libavutil/avutil.h\
+#ffmpeg_fft/libavutil/common.h\
+#ffmpeg_fft/libavutil/attributes.h\
+#ffmpeg_fft/libavutil/mem.h\
+#ffmpeg_fft/libavutil/avconfig.h\
+#ffmpeg_fft/libavutil/mathematics.h\
+#ffmpeg_fft/libavutil/rational.h\
+#ffmpeg_fft/publik.h\
+#ffmpeg_fft/ffmpeg_fft.h\
+#ffmpeg_fft/libavcodec/dct32.h\
+#ffmpeg_fft/libavcodec/fft.h\
+#ffmpeg_fft/libavcodec/avfft.h\
+#ffmpeg_fft/config.h\
+#ff_rdft.c
+
+#AM_CFLAGS = $(CFLAGS) -I ffmpeg_fft -I ffmpeg_fft/libavcodec -I ffmpeg_fft/libavutil -std=c99
+#AM_CPPFLAGS = $(CXXFLAGS) -fno-exceptions -fno-rtti -nostdlib -fno-unwind-tables -I ffmpeg_fft -I ffmpeg_fft/libavcodec -I ffmpeg_fft/libavutil
+
+#AM_CFLAGS = $(CFLAGS) -I nsfft-1.00/dft -I nsfft-1.00/simd -std=c99 -msse -DENABLE_SSE_FLOAT -DUSE_SHIBATCH
+#AM_CPPFLAGS = $(CXXFLAGS) -fno-exceptions -fno-rtti -nostdlib -fno-unwind-tables -I nsfft-1.00/dft -I nsfft-1.00/simd -msse -DENABLE_SSE_FLOAT -DUSE_SHIBATCH
+
+AM_CFLAGS = $(CFLAGS) -std=c99 -DUSE_OOURA
+AM_CPPFLAGS = $(CXXFLAGS) -fno-exceptions -fno-rtti -nostdlib -fno-unwind-tables -DUSE_OOURA
+
+supereq_la_LDFLAGS = -module -nostdlib -lsupc++
supereq_la_LIBADD = $(LDADD)
-AM_CFLAGS = -std=c99
endif
diff --git a/plugins/supereq/ff_rdft.c b/plugins/supereq/ff_rdft.c
new file mode 100644
index 00000000..70a09350
--- /dev/null
+++ b/plugins/supereq/ff_rdft.c
@@ -0,0 +1,63 @@
+#include <stdint.h>
+#include <complex.h>
+#include "libavcodec/avfft.h"
+#include "libavutil/avutil.h"
+
+void rfft(int n,int isign,float *x)
+{
+ static int wsize=0;
+ static float *w = NULL;
+ static RDFTContext *s = NULL;
+ static RDFTContext *si = NULL;
+ int newwsize;
+
+ if (n == 0) {
+ if (w) {
+ av_free(w);
+ w = NULL;
+ wsize = 0;
+ }
+ if (s) {
+ av_rdft_end (s);
+ s = NULL;
+ }
+ if (si) {
+ av_rdft_end (si);
+ si = NULL;
+ }
+ return;
+ }
+
+ newwsize = n/2;
+ if (newwsize > wsize) {
+ wsize = newwsize;
+ if (s) {
+ av_rdft_end (s);
+ s = NULL;
+ }
+ if (si) {
+ av_rdft_end (si);
+ si = NULL;
+ }
+ if (w) {
+ av_free (w);
+ w = NULL;
+ }
+ w = (float *)av_malloc(sizeof(float)*wsize);
+ }
+
+ if (!s) {
+ s = av_rdft_init(n,DFT_R2C);
+ }
+ if (!si) {
+ si = av_rdft_init(n,IDFT_C2R);
+ }
+
+ if (isign == 1) {
+ av_rdft_calc (s, x);
+ }
+ else {
+ av_rdft_calc (si, x);
+ }
+}
+
diff --git a/plugins/supereq/ffmpeg_fft/README b/plugins/supereq/ffmpeg_fft/README
new file mode 100644
index 00000000..f53b2447
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/README
@@ -0,0 +1,9 @@
+purpose:
+
+* compare fftw and ffmpeg fourier transforms using benchfft and / or libbench
+* note: this is very specifically for neon. if you want to use ffmpeg_fft with
+ some other arch / fpu, then you will need to do some reorganization
+
+todo:
+
+1) fix benchees/ffmpeg/doitr.c
diff --git a/plugins/supereq/ffmpeg_fft/config.h b/plugins/supereq/ffmpeg_fft/config.h
new file mode 100644
index 00000000..0f36b47c
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/config.h
@@ -0,0 +1,904 @@
+/* Automatically generated by configure - do not modify! */
+#ifndef FFMPEG_CONFIG_H
+#define FFMPEG_CONFIG_H
+#define FFMPEG_CONFIGURATION "--prefix=/usr --enable-neon --enable-pic --cpu=cortex-a8 --arch=arm --cross-prefix=arm-none-linux-gnueabi- --enable-cross-compile --target-os=linux --extra-cflags='-mfpu=neon -mcpu=cortex-a8 -mfloat-abi=softfp' --enable-shared --disable-debug"
+#define FFMPEG_LICENSE "LGPL version 2.1 or later"
+#define FFMPEG_DATADIR "/usr/share/ffmpeg"
+#define CC_TYPE "gcc"
+#define CC_VERSION __VERSION__
+#define restrict restrict
+#define ASMALIGN(ZEROBITS) ".p2align " #ZEROBITS "\n\t"
+#define EXTERN_PREFIX ""
+#define EXTERN_ASM
+#define ARCH_ALPHA 0
+#define ARCH_ARM 0
+#define ARCH_AVR32 0
+#define ARCH_AVR32_AP 0
+#define ARCH_AVR32_UC 0
+#define ARCH_BFIN 0
+#define ARCH_IA64 0
+#define ARCH_M68K 0
+#define ARCH_MIPS 0
+#define ARCH_MIPS64 0
+#define ARCH_PARISC 0
+#define ARCH_PPC 0
+#define ARCH_PPC64 0
+#define ARCH_S390 0
+#define ARCH_SH4 0
+#define ARCH_SPARC 0
+#define ARCH_SPARC64 0
+#define ARCH_TOMI 0
+#define ARCH_X86 1
+#define ARCH_X86_32 1
+#define ARCH_X86_64 0
+#define HAVE_ALTIVEC 0
+#define HAVE_AMD3DNOW 0
+#define HAVE_AMD3DNOWEXT 0
+#define HAVE_ARMV5TE 1
+#define HAVE_ARMV6 1
+#define HAVE_ARMV6T2 1
+#define HAVE_ARMVFP 1
+#define HAVE_IWMMXT 0
+#define HAVE_MMI 0
+#define HAVE_MMX 0
+#define HAVE_MMX2 0
+#define HAVE_NEON 1
+#define HAVE_PPC4XX 0
+#define HAVE_SSE 1
+#define HAVE_SSSE3 1
+#define HAVE_VIS 0
+#define HAVE_BIGENDIAN 0
+#define HAVE_PTHREADS 1
+#define HAVE_W32THREADS 0
+#define HAVE_ALSA_ASOUNDLIB_H 0
+#define HAVE_ALTIVEC_H 0
+#define HAVE_ARPA_INET_H 1
+#define HAVE_ATTRIBUTE_MAY_ALIAS 1
+#define HAVE_ATTRIBUTE_PACKED 1
+#define HAVE_BSWAP 0
+#define HAVE_CLOSESOCKET 0
+#define HAVE_CMOV 0
+#define HAVE_CONIO_H 0
+#define HAVE_DCBZL 0
+#define HAVE_DEV_BKTR_IOCTL_BT848_H 0
+#define HAVE_DEV_BKTR_IOCTL_METEOR_H 0
+#define HAVE_DEV_IC_BT8XX_H 0
+#define HAVE_DEV_VIDEO_METEOR_IOCTL_METEOR_H 0
+#define HAVE_DEV_VIDEO_BKTR_IOCTL_BT848_H 0
+#define HAVE_DLFCN_H 1
+#define HAVE_DLOPEN 1
+#define HAVE_DOS_PATHS 0
+#define HAVE_EBP_AVAILABLE 0
+#define HAVE_EBX_AVAILABLE 0
+#define HAVE_EXP2 1
+#define HAVE_EXP2F 1
+#define HAVE_FAST_64BIT 0
+#define HAVE_FAST_CLZ 1
+#define HAVE_FAST_CMOV 0
+#define HAVE_FAST_UNALIGNED 1
+#define HAVE_FCNTL 1
+#define HAVE_FORK 1
+#define HAVE_GETADDRINFO 1
+#define HAVE_GETHRTIME 0
+#define HAVE_GETPROCESSMEMORYINFO 0
+#define HAVE_GETPROCESSTIMES 0
+#define HAVE_GETRUSAGE 1
+#define HAVE_GNU_AS 1
+#define HAVE_STRUCT_RUSAGE_RU_MAXRSS 1
+#define HAVE_IBM_ASM 0
+#define HAVE_INET_ATON 1
+#define HAVE_INLINE_ASM 1
+#define HAVE_ISATTY 1
+#define HAVE_LDBRX 0
+#define HAVE_LIBDC1394_1 0
+#define HAVE_LIBDC1394_2 0
+#define HAVE_LLRINT 1
+#define HAVE_LLRINTF 1
+#define HAVE_LOCAL_ALIGNED_16 0
+#define HAVE_LOCAL_ALIGNED_8 0
+#define HAVE_LOG2 1
+#define HAVE_LOG2F 1
+#define HAVE_LOONGSON 0
+#define HAVE_LRINT 1
+#define HAVE_LRINTF 1
+#define HAVE_LZO1X_999_COMPRESS 0
+#define HAVE_MACHINE_IOCTL_BT848_H 0
+#define HAVE_MACHINE_IOCTL_METEOR_H 0
+#define HAVE_MALLOC_H 1
+#define HAVE_MEMALIGN 1
+#define HAVE_MKSTEMP 1
+#define HAVE_PLD 1
+#define HAVE_POSIX_MEMALIGN 1
+#define HAVE_ROUND 1
+#define HAVE_ROUNDF 1
+#define HAVE_SDL 0
+#define HAVE_SDL_VIDEO_SIZE 0
+#define HAVE_SETMODE 0
+#define HAVE_SOCKLEN_T 1
+#define HAVE_SOUNDCARD_H 0
+#define HAVE_POLL_H 1
+#define HAVE_SETRLIMIT 1
+#define HAVE_STRERROR_R 1
+#define HAVE_STRUCT_ADDRINFO 1
+#define HAVE_STRUCT_IPV6_MREQ 1
+#define HAVE_STRUCT_SOCKADDR_IN6 1
+#define HAVE_STRUCT_SOCKADDR_SA_LEN 0
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+#define HAVE_SYMVER 1
+#define HAVE_SYMVER_GNU_ASM 1
+#define HAVE_SYMVER_ASM_LABEL 0
+#define HAVE_SYS_MMAN_H 1
+#define HAVE_SYS_RESOURCE_H 1
+#define HAVE_SYS_SELECT_H 1
+#define HAVE_SYS_SOUNDCARD_H 1
+#define HAVE_SYS_VIDEOIO_H 0
+#define HAVE_TEN_OPERANDS 0
+#define HAVE_TERMIOS_H 1
+#define HAVE_THREADS 1
+#define HAVE_TRUNCF 1
+#define HAVE_VFP_ARGS 0
+#define HAVE_VIRTUALALLOC 0
+#define HAVE_WINSOCK2_H 0
+#define HAVE_XFORM_ASM 0
+#define HAVE_YASM 0
+#define CONFIG_BSFS 1
+#define CONFIG_DECODERS 1
+#define CONFIG_DEMUXERS 1
+#define CONFIG_ENCODERS 1
+#define CONFIG_FILTERS 1
+#define CONFIG_HWACCELS 0
+#define CONFIG_INDEVS 1
+#define CONFIG_MUXERS 1
+#define CONFIG_OUTDEVS 1
+#define CONFIG_PARSERS 1
+#define CONFIG_PROTOCOLS 1
+#define CONFIG_AANDCT 1
+#define CONFIG_AVCODEC 1
+#define CONFIG_AVDEVICE 1
+#define CONFIG_AVFILTER 1
+#define CONFIG_AVFILTER_LAVF 0
+#define CONFIG_AVFORMAT 1
+#define CONFIG_AVISYNTH 0
+#define CONFIG_BZLIB 0
+#define CONFIG_DCT 1
+#define CONFIG_DOC 0
+#define CONFIG_DWT 1
+#define CONFIG_DXVA2 0
+#define CONFIG_FASTDIV 1
+#define CONFIG_FFMPEG 1
+#define CONFIG_FFPLAY 0
+#define CONFIG_FFPROBE 1
+#define CONFIG_FFSERVER 1
+#define CONFIG_FFT 1
+#define CONFIG_GOLOMB 1
+#define CONFIG_GPL 0
+#define CONFIG_GRAY 0
+#define CONFIG_H264DSP 1
+#define CONFIG_HARDCODED_TABLES 0
+#define CONFIG_LIBDC1394 0
+#define CONFIG_LIBDIRAC 0
+#define CONFIG_LIBFAAC 0
+#define CONFIG_LIBGSM 0
+#define CONFIG_LIBMP3LAME 0
+#define CONFIG_LIBNUT 0
+#define CONFIG_LIBOPENCORE_AMRNB 0
+#define CONFIG_LIBOPENCORE_AMRWB 0
+#define CONFIG_LIBOPENJPEG 0
+#define CONFIG_LIBRTMP 0
+#define CONFIG_LIBSCHROEDINGER 0
+#define CONFIG_LIBSPEEX 0
+#define CONFIG_LIBTHEORA 0
+#define CONFIG_LIBVORBIS 0
+#define CONFIG_LIBVPX 0
+#define CONFIG_LIBX264 0
+#define CONFIG_LIBXVID 0
+#define CONFIG_LPC 1
+#define CONFIG_LSP 1
+//#define CONFIG_MDCT 1
+#define CONFIG_MEMALIGN_HACK 0
+#define CONFIG_MLIB 0
+#define CONFIG_MPEGAUDIO_HP 1
+#define CONFIG_NETWORK 1
+#define CONFIG_NONFREE 0
+#define CONFIG_PIC 1
+#define CONFIG_POSTPROC 0
+#define CONFIG_RDFT 1
+#define CONFIG_RUNTIME_CPUDETECT 0
+#define CONFIG_SHARED 1
+#define CONFIG_SMALL 0
+#define CONFIG_SRAM 0
+#define CONFIG_STATIC 1
+#define CONFIG_SWSCALE 1
+#define CONFIG_SWSCALE_ALPHA 1
+#define CONFIG_VAAPI 0
+#define CONFIG_VDPAU 0
+#define CONFIG_VERSION3 0
+#define CONFIG_X11GRAB 0
+#define CONFIG_ZLIB 0
+#define CONFIG_AVUTIL 1
+#define CONFIG_GPLV3 0
+#define CONFIG_LGPLV3 0
+#define CONFIG_AASC_DECODER 1
+#define CONFIG_AMV_DECODER 1
+#define CONFIG_ANM_DECODER 1
+#define CONFIG_ASV1_DECODER 1
+#define CONFIG_ASV2_DECODER 1
+#define CONFIG_AURA_DECODER 1
+#define CONFIG_AURA2_DECODER 1
+#define CONFIG_AVS_DECODER 1
+#define CONFIG_BETHSOFTVID_DECODER 1
+#define CONFIG_BFI_DECODER 1
+#define CONFIG_BINK_DECODER 1
+#define CONFIG_BMP_DECODER 1
+#define CONFIG_C93_DECODER 1
+#define CONFIG_CAVS_DECODER 1
+#define CONFIG_CDGRAPHICS_DECODER 1
+#define CONFIG_CINEPAK_DECODER 1
+#define CONFIG_CLJR_DECODER 1
+#define CONFIG_CSCD_DECODER 1
+#define CONFIG_CYUV_DECODER 1
+#define CONFIG_DNXHD_DECODER 1
+#define CONFIG_DPX_DECODER 1
+#define CONFIG_DSICINVIDEO_DECODER 1
+#define CONFIG_DVVIDEO_DECODER 1
+#define CONFIG_DXA_DECODER 0
+#define CONFIG_EACMV_DECODER 1
+#define CONFIG_EAMAD_DECODER 1
+#define CONFIG_EATGQ_DECODER 1
+#define CONFIG_EATGV_DECODER 1
+#define CONFIG_EATQI_DECODER 1
+#define CONFIG_EIGHTBPS_DECODER 1
+#define CONFIG_EIGHTSVX_EXP_DECODER 1
+#define CONFIG_EIGHTSVX_FIB_DECODER 1
+#define CONFIG_ESCAPE124_DECODER 1
+#define CONFIG_FFV1_DECODER 1
+#define CONFIG_FFVHUFF_DECODER 1
+#define CONFIG_FLASHSV_DECODER 0
+#define CONFIG_FLIC_DECODER 1
+#define CONFIG_FLV_DECODER 1
+#define CONFIG_FOURXM_DECODER 1
+#define CONFIG_FRAPS_DECODER 1
+#define CONFIG_FRWU_DECODER 1
+#define CONFIG_GIF_DECODER 1
+#define CONFIG_H261_DECODER 1
+#define CONFIG_H263_DECODER 1
+#define CONFIG_H263I_DECODER 1
+#define CONFIG_H264_DECODER 1
+#define CONFIG_H264_VDPAU_DECODER 0
+#define CONFIG_HUFFYUV_DECODER 1
+#define CONFIG_IDCIN_DECODER 1
+#define CONFIG_IFF_BYTERUN1_DECODER 1
+#define CONFIG_IFF_ILBM_DECODER 1
+#define CONFIG_INDEO2_DECODER 1
+#define CONFIG_INDEO3_DECODER 1
+#define CONFIG_INDEO5_DECODER 1
+#define CONFIG_INTERPLAY_VIDEO_DECODER 1
+#define CONFIG_JPEGLS_DECODER 1
+#define CONFIG_KGV1_DECODER 1
+#define CONFIG_KMVC_DECODER 1
+#define CONFIG_LOCO_DECODER 1
+#define CONFIG_MDEC_DECODER 1
+#define CONFIG_MIMIC_DECODER 1
+#define CONFIG_MJPEG_DECODER 1
+#define CONFIG_MJPEGB_DECODER 1
+#define CONFIG_MMVIDEO_DECODER 1
+#define CONFIG_MOTIONPIXELS_DECODER 1
+#define CONFIG_MPEG_XVMC_DECODER 0
+#define CONFIG_MPEG1VIDEO_DECODER 1
+#define CONFIG_MPEG2VIDEO_DECODER 1
+#define CONFIG_MPEG4_DECODER 1
+#define CONFIG_MPEG4_VDPAU_DECODER 0
+#define CONFIG_MPEGVIDEO_DECODER 1
+#define CONFIG_MPEG_VDPAU_DECODER 0
+#define CONFIG_MPEG1_VDPAU_DECODER 0
+#define CONFIG_MSMPEG4V1_DECODER 1
+#define CONFIG_MSMPEG4V2_DECODER 1
+#define CONFIG_MSMPEG4V3_DECODER 1
+#define CONFIG_MSRLE_DECODER 1
+#define CONFIG_MSVIDEO1_DECODER 1
+#define CONFIG_MSZH_DECODER 1
+#define CONFIG_NUV_DECODER 1
+#define CONFIG_PAM_DECODER 1
+#define CONFIG_PBM_DECODER 1
+#define CONFIG_PCX_DECODER 1
+#define CONFIG_PGM_DECODER 1
+#define CONFIG_PGMYUV_DECODER 1
+#define CONFIG_PICTOR_DECODER 1
+#define CONFIG_PNG_DECODER 0
+#define CONFIG_PPM_DECODER 1
+#define CONFIG_PTX_DECODER 1
+#define CONFIG_QDRAW_DECODER 1
+#define CONFIG_QPEG_DECODER 1
+#define CONFIG_QTRLE_DECODER 1
+#define CONFIG_R210_DECODER 1
+#define CONFIG_RAWVIDEO_DECODER 1
+#define CONFIG_RL2_DECODER 1
+#define CONFIG_ROQ_DECODER 1
+#define CONFIG_RPZA_DECODER 1
+#define CONFIG_RV10_DECODER 1
+#define CONFIG_RV20_DECODER 1
+#define CONFIG_RV30_DECODER 1
+#define CONFIG_RV40_DECODER 1
+#define CONFIG_SGI_DECODER 1
+#define CONFIG_SMACKER_DECODER 1
+#define CONFIG_SMC_DECODER 1
+#define CONFIG_SNOW_DECODER 1
+#define CONFIG_SP5X_DECODER 1
+#define CONFIG_SUNRAST_DECODER 1
+#define CONFIG_SVQ1_DECODER 1
+#define CONFIG_SVQ3_DECODER 1
+#define CONFIG_TARGA_DECODER 1
+#define CONFIG_THEORA_DECODER 1
+#define CONFIG_THP_DECODER 1
+#define CONFIG_TIERTEXSEQVIDEO_DECODER 1
+#define CONFIG_TIFF_DECODER 1
+#define CONFIG_TMV_DECODER 1
+#define CONFIG_TRUEMOTION1_DECODER 1
+#define CONFIG_TRUEMOTION2_DECODER 1
+#define CONFIG_TSCC_DECODER 0
+#define CONFIG_TXD_DECODER 1
+#define CONFIG_ULTI_DECODER 1
+#define CONFIG_V210_DECODER 1
+#define CONFIG_V210X_DECODER 1
+#define CONFIG_VB_DECODER 1
+#define CONFIG_VC1_DECODER 1
+#define CONFIG_VC1_VDPAU_DECODER 0
+#define CONFIG_VCR1_DECODER 1
+#define CONFIG_VMDVIDEO_DECODER 1
+#define CONFIG_VMNC_DECODER 1
+#define CONFIG_VP3_DECODER 1
+#define CONFIG_VP5_DECODER 1
+#define CONFIG_VP6_DECODER 1
+#define CONFIG_VP6A_DECODER 1
+#define CONFIG_VP6F_DECODER 1
+#define CONFIG_VP8_DECODER 1
+#define CONFIG_VQA_DECODER 1
+#define CONFIG_WMV1_DECODER 1
+#define CONFIG_WMV2_DECODER 1
+#define CONFIG_WMV3_DECODER 1
+#define CONFIG_WMV3_VDPAU_DECODER 0
+#define CONFIG_WNV1_DECODER 1
+#define CONFIG_XAN_WC3_DECODER 1
+#define CONFIG_XL_DECODER 1
+#define CONFIG_YOP_DECODER 1
+#define CONFIG_ZLIB_DECODER 0
+#define CONFIG_ZMBV_DECODER 0
+#define CONFIG_AAC_DECODER 1
+#define CONFIG_AC3_DECODER 1
+#define CONFIG_ALAC_DECODER 1
+#define CONFIG_ALS_DECODER 1
+#define CONFIG_AMRNB_DECODER 1
+#define CONFIG_APE_DECODER 1
+#define CONFIG_ATRAC1_DECODER 1
+#define CONFIG_ATRAC3_DECODER 1
+#define CONFIG_BINKAUDIO_DCT_DECODER 1
+#define CONFIG_BINKAUDIO_RDFT_DECODER 1
+#define CONFIG_COOK_DECODER 1
+/* #define CONFIG_DCA_DECODER 1 */
+#define CONFIG_DSICINAUDIO_DECODER 1
+#define CONFIG_EAC3_DECODER 1
+#define CONFIG_FLAC_DECODER 1
+#define CONFIG_GSM_DECODER 1
+#define CONFIG_GSM_MS_DECODER 1
+#define CONFIG_IMC_DECODER 1
+#define CONFIG_MACE3_DECODER 1
+#define CONFIG_MACE6_DECODER 1
+#define CONFIG_MLP_DECODER 1
+#define CONFIG_MP1_DECODER 1
+#define CONFIG_MP1FLOAT_DECODER 1
+#define CONFIG_MP2_DECODER 1
+#define CONFIG_MP2FLOAT_DECODER 1
+#define CONFIG_MP3_DECODER 1
+#define CONFIG_MP3FLOAT_DECODER 1
+#define CONFIG_MP3ADU_DECODER 1
+#define CONFIG_MP3ADUFLOAT_DECODER 1
+#define CONFIG_MP3ON4_DECODER 1
+#define CONFIG_MP3ON4FLOAT_DECODER 1
+#define CONFIG_MPC7_DECODER 1
+#define CONFIG_MPC8_DECODER 1
+#define CONFIG_NELLYMOSER_DECODER 1
+#define CONFIG_QCELP_DECODER 1
+#define CONFIG_QDM2_DECODER 1
+#define CONFIG_RA_144_DECODER 1
+#define CONFIG_RA_288_DECODER 1
+#define CONFIG_SHORTEN_DECODER 1
+#define CONFIG_SIPR_DECODER 1
+#define CONFIG_SMACKAUD_DECODER 1
+#define CONFIG_SONIC_DECODER 1
+#define CONFIG_TRUEHD_DECODER 1
+#define CONFIG_TRUESPEECH_DECODER 1
+#define CONFIG_TTA_DECODER 1
+#define CONFIG_TWINVQ_DECODER 1
+#define CONFIG_VMDAUDIO_DECODER 1
+#define CONFIG_VORBIS_DECODER 1
+#define CONFIG_WAVPACK_DECODER 1
+#define CONFIG_WMAPRO_DECODER 1
+#define CONFIG_WMAV1_DECODER 1
+#define CONFIG_WMAV2_DECODER 1
+#define CONFIG_WMAVOICE_DECODER 1
+#define CONFIG_WS_SND1_DECODER 1
+#define CONFIG_PCM_ALAW_DECODER 1
+#define CONFIG_PCM_BLURAY_DECODER 1
+#define CONFIG_PCM_DVD_DECODER 1
+#define CONFIG_PCM_F32BE_DECODER 1
+#define CONFIG_PCM_F32LE_DECODER 1
+#define CONFIG_PCM_F64BE_DECODER 1
+#define CONFIG_PCM_F64LE_DECODER 1
+#define CONFIG_PCM_MULAW_DECODER 1
+#define CONFIG_PCM_S8_DECODER 1
+#define CONFIG_PCM_S16BE_DECODER 1
+#define CONFIG_PCM_S16LE_DECODER 1
+#define CONFIG_PCM_S16LE_PLANAR_DECODER 1
+#define CONFIG_PCM_S24BE_DECODER 1
+#define CONFIG_PCM_S24DAUD_DECODER 1
+#define CONFIG_PCM_S24LE_DECODER 1
+#define CONFIG_PCM_S32BE_DECODER 1
+#define CONFIG_PCM_S32LE_DECODER 1
+#define CONFIG_PCM_U8_DECODER 1
+#define CONFIG_PCM_U16BE_DECODER 1
+#define CONFIG_PCM_U16LE_DECODER 1
+#define CONFIG_PCM_U24BE_DECODER 1
+#define CONFIG_PCM_U24LE_DECODER 1
+#define CONFIG_PCM_U32BE_DECODER 1
+#define CONFIG_PCM_U32LE_DECODER 1
+#define CONFIG_PCM_ZORK_DECODER 1
+#define CONFIG_INTERPLAY_DPCM_DECODER 1
+#define CONFIG_ROQ_DPCM_DECODER 1
+#define CONFIG_SOL_DPCM_DECODER 1
+#define CONFIG_XAN_DPCM_DECODER 1
+#define CONFIG_ADPCM_4XM_DECODER 1
+#define CONFIG_ADPCM_ADX_DECODER 1
+#define CONFIG_ADPCM_CT_DECODER 1
+#define CONFIG_ADPCM_EA_DECODER 1
+#define CONFIG_ADPCM_EA_MAXIS_XA_DECODER 1
+#define CONFIG_ADPCM_EA_R1_DECODER 1
+#define CONFIG_ADPCM_EA_R2_DECODER 1
+#define CONFIG_ADPCM_EA_R3_DECODER 1
+#define CONFIG_ADPCM_EA_XAS_DECODER 1
+#define CONFIG_ADPCM_G726_DECODER 1
+#define CONFIG_ADPCM_IMA_AMV_DECODER 1
+#define CONFIG_ADPCM_IMA_DK3_DECODER 1
+#define CONFIG_ADPCM_IMA_DK4_DECODER 1
+#define CONFIG_ADPCM_IMA_EA_EACS_DECODER 1
+#define CONFIG_ADPCM_IMA_EA_SEAD_DECODER 1
+#define CONFIG_ADPCM_IMA_ISS_DECODER 1
+#define CONFIG_ADPCM_IMA_QT_DECODER 1
+#define CONFIG_ADPCM_IMA_SMJPEG_DECODER 1
+#define CONFIG_ADPCM_IMA_WAV_DECODER 1
+#define CONFIG_ADPCM_IMA_WS_DECODER 1
+#define CONFIG_ADPCM_MS_DECODER 1
+#define CONFIG_ADPCM_SBPRO_2_DECODER 1
+#define CONFIG_ADPCM_SBPRO_3_DECODER 1
+#define CONFIG_ADPCM_SBPRO_4_DECODER 1
+#define CONFIG_ADPCM_SWF_DECODER 1
+#define CONFIG_ADPCM_THP_DECODER 1
+#define CONFIG_ADPCM_XA_DECODER 1
+#define CONFIG_ADPCM_YAMAHA_DECODER 1
+#define CONFIG_DVBSUB_DECODER 1
+#define CONFIG_DVDSUB_DECODER 1
+#define CONFIG_PGSSUB_DECODER 1
+#define CONFIG_XSUB_DECODER 1
+#define CONFIG_LIBDIRAC_DECODER 0
+#define CONFIG_LIBGSM_DECODER 0
+#define CONFIG_LIBGSM_MS_DECODER 0
+#define CONFIG_LIBOPENCORE_AMRNB_DECODER 0
+#define CONFIG_LIBOPENCORE_AMRWB_DECODER 0
+#define CONFIG_LIBOPENJPEG_DECODER 0
+#define CONFIG_LIBSCHROEDINGER_DECODER 0
+#define CONFIG_LIBSPEEX_DECODER 0
+#define CONFIG_LIBVPX_DECODER 0
+#define CONFIG_ASV1_ENCODER 1
+#define CONFIG_ASV2_ENCODER 1
+#define CONFIG_BMP_ENCODER 1
+#define CONFIG_DNXHD_ENCODER 1
+#define CONFIG_DVVIDEO_ENCODER 1
+#define CONFIG_FFV1_ENCODER 1
+#define CONFIG_FFVHUFF_ENCODER 1
+#define CONFIG_FLASHSV_ENCODER 0
+#define CONFIG_FLV_ENCODER 1
+#define CONFIG_GIF_ENCODER 1
+#define CONFIG_H261_ENCODER 1
+#define CONFIG_H263_ENCODER 1
+#define CONFIG_H263P_ENCODER 1
+#define CONFIG_HUFFYUV_ENCODER 1
+#define CONFIG_JPEGLS_ENCODER 1
+#define CONFIG_LJPEG_ENCODER 1
+#define CONFIG_MJPEG_ENCODER 1
+#define CONFIG_MPEG1VIDEO_ENCODER 1
+#define CONFIG_MPEG2VIDEO_ENCODER 1
+#define CONFIG_MPEG4_ENCODER 1
+#define CONFIG_MSMPEG4V1_ENCODER 1
+#define CONFIG_MSMPEG4V2_ENCODER 1
+#define CONFIG_MSMPEG4V3_ENCODER 1
+#define CONFIG_PAM_ENCODER 1
+#define CONFIG_PBM_ENCODER 1
+#define CONFIG_PCX_ENCODER 1
+#define CONFIG_PGM_ENCODER 1
+#define CONFIG_PGMYUV_ENCODER 1
+#define CONFIG_PNG_ENCODER 0
+#define CONFIG_PPM_ENCODER 1
+#define CONFIG_QTRLE_ENCODER 1
+#define CONFIG_RAWVIDEO_ENCODER 1
+#define CONFIG_ROQ_ENCODER 1
+#define CONFIG_RV10_ENCODER 1
+#define CONFIG_RV20_ENCODER 1
+#define CONFIG_SGI_ENCODER 1
+#define CONFIG_SNOW_ENCODER 1
+#define CONFIG_SVQ1_ENCODER 1
+#define CONFIG_TARGA_ENCODER 1
+#define CONFIG_TIFF_ENCODER 1
+#define CONFIG_V210_ENCODER 1
+#define CONFIG_WMV1_ENCODER 1
+#define CONFIG_WMV2_ENCODER 1
+#define CONFIG_ZLIB_ENCODER 0
+#define CONFIG_ZMBV_ENCODER 0
+#define CONFIG_AAC_ENCODER 1
+#define CONFIG_AC3_ENCODER 1
+#define CONFIG_ALAC_ENCODER 1
+#define CONFIG_FLAC_ENCODER 1
+#define CONFIG_MP2_ENCODER 1
+#define CONFIG_NELLYMOSER_ENCODER 1
+#define CONFIG_RA_144_ENCODER 1
+#define CONFIG_SONIC_ENCODER 1
+#define CONFIG_SONIC_LS_ENCODER 1
+#define CONFIG_VORBIS_ENCODER 1
+#define CONFIG_WMAV1_ENCODER 1
+#define CONFIG_WMAV2_ENCODER 1
+#define CONFIG_PCM_ALAW_ENCODER 1
+#define CONFIG_PCM_F32BE_ENCODER 1
+#define CONFIG_PCM_F32LE_ENCODER 1
+#define CONFIG_PCM_F64BE_ENCODER 1
+#define CONFIG_PCM_F64LE_ENCODER 1
+#define CONFIG_PCM_MULAW_ENCODER 1
+#define CONFIG_PCM_S8_ENCODER 1
+#define CONFIG_PCM_S16BE_ENCODER 1
+#define CONFIG_PCM_S16LE_ENCODER 1
+#define CONFIG_PCM_S24BE_ENCODER 1
+#define CONFIG_PCM_S24DAUD_ENCODER 1
+#define CONFIG_PCM_S24LE_ENCODER 1
+#define CONFIG_PCM_S32BE_ENCODER 1
+#define CONFIG_PCM_S32LE_ENCODER 1
+#define CONFIG_PCM_U8_ENCODER 1
+#define CONFIG_PCM_U16BE_ENCODER 1
+#define CONFIG_PCM_U16LE_ENCODER 1
+#define CONFIG_PCM_U24BE_ENCODER 1
+#define CONFIG_PCM_U24LE_ENCODER 1
+#define CONFIG_PCM_U32BE_ENCODER 1
+#define CONFIG_PCM_U32LE_ENCODER 1
+#define CONFIG_PCM_ZORK_ENCODER 1
+#define CONFIG_ROQ_DPCM_ENCODER 1
+#define CONFIG_ADPCM_ADX_ENCODER 1
+#define CONFIG_ADPCM_G726_ENCODER 1
+#define CONFIG_ADPCM_IMA_QT_ENCODER 1
+#define CONFIG_ADPCM_IMA_WAV_ENCODER 1
+#define CONFIG_ADPCM_MS_ENCODER 1
+#define CONFIG_ADPCM_SWF_ENCODER 1
+#define CONFIG_ADPCM_YAMAHA_ENCODER 1
+#define CONFIG_DVBSUB_ENCODER 1
+#define CONFIG_DVDSUB_ENCODER 1
+#define CONFIG_XSUB_ENCODER 1
+#define CONFIG_LIBDIRAC_ENCODER 0
+#define CONFIG_LIBFAAC_ENCODER 0
+#define CONFIG_LIBGSM_ENCODER 0
+#define CONFIG_LIBGSM_MS_ENCODER 0
+#define CONFIG_LIBMP3LAME_ENCODER 0
+#define CONFIG_LIBOPENCORE_AMRNB_ENCODER 0
+#define CONFIG_LIBSCHROEDINGER_ENCODER 0
+#define CONFIG_LIBTHEORA_ENCODER 0
+#define CONFIG_LIBVORBIS_ENCODER 0
+#define CONFIG_LIBVPX_ENCODER 0
+#define CONFIG_LIBX264_ENCODER 0
+#define CONFIG_LIBXVID_ENCODER 0
+#define CONFIG_H263_VAAPI_HWACCEL 0
+#define CONFIG_H264_DXVA2_HWACCEL 0
+#define CONFIG_H264_VAAPI_HWACCEL 0
+#define CONFIG_MPEG2_DXVA2_HWACCEL 0
+#define CONFIG_MPEG2_VAAPI_HWACCEL 0
+#define CONFIG_MPEG4_VAAPI_HWACCEL 0
+#define CONFIG_VC1_DXVA2_HWACCEL 0
+#define CONFIG_VC1_VAAPI_HWACCEL 0
+#define CONFIG_WMV3_DXVA2_HWACCEL 0
+#define CONFIG_WMV3_VAAPI_HWACCEL 0
+#define CONFIG_AAC_PARSER 1
+#define CONFIG_AC3_PARSER 1
+#define CONFIG_CAVSVIDEO_PARSER 1
+#define CONFIG_DCA_PARSER 1
+#define CONFIG_DIRAC_PARSER 1
+#define CONFIG_DNXHD_PARSER 1
+#define CONFIG_DVBSUB_PARSER 1
+#define CONFIG_DVDSUB_PARSER 1
+#define CONFIG_H261_PARSER 1
+#define CONFIG_H263_PARSER 1
+#define CONFIG_H264_PARSER 1
+#define CONFIG_MJPEG_PARSER 1
+#define CONFIG_MLP_PARSER 1
+#define CONFIG_MPEG4VIDEO_PARSER 1
+#define CONFIG_MPEGAUDIO_PARSER 1
+#define CONFIG_MPEGVIDEO_PARSER 1
+#define CONFIG_PNM_PARSER 1
+#define CONFIG_VC1_PARSER 1
+#define CONFIG_VP3_PARSER 1
+#define CONFIG_VP8_PARSER 1
+#define CONFIG_AAC_ADTSTOASC_BSF 1
+#define CONFIG_CHOMP_BSF 1
+#define CONFIG_DUMP_EXTRADATA_BSF 1
+#define CONFIG_H264_MP4TOANNEXB_BSF 1
+#define CONFIG_IMX_DUMP_HEADER_BSF 1
+#define CONFIG_MJPEGA_DUMP_HEADER_BSF 1
+#define CONFIG_MP3_HEADER_COMPRESS_BSF 1
+#define CONFIG_MP3_HEADER_DECOMPRESS_BSF 1
+#define CONFIG_MOV2TEXTSUB_BSF 1
+#define CONFIG_NOISE_BSF 1
+#define CONFIG_REMOVE_EXTRADATA_BSF 1
+#define CONFIG_TEXT2MOVSUB_BSF 1
+#define CONFIG_AAC_DEMUXER 1
+#define CONFIG_AC3_DEMUXER 1
+#define CONFIG_AEA_DEMUXER 1
+#define CONFIG_AIFF_DEMUXER 1
+#define CONFIG_AMR_DEMUXER 1
+#define CONFIG_ANM_DEMUXER 1
+#define CONFIG_APC_DEMUXER 1
+#define CONFIG_APE_DEMUXER 1
+#define CONFIG_ASF_DEMUXER 1
+#define CONFIG_ASS_DEMUXER 1
+#define CONFIG_AU_DEMUXER 1
+#define CONFIG_AVI_DEMUXER 1
+#define CONFIG_AVISYNTH_DEMUXER 0
+#define CONFIG_AVS_DEMUXER 1
+#define CONFIG_BETHSOFTVID_DEMUXER 1
+#define CONFIG_BFI_DEMUXER 1
+#define CONFIG_BINK_DEMUXER 1
+#define CONFIG_C93_DEMUXER 1
+#define CONFIG_CAF_DEMUXER 1
+#define CONFIG_CAVSVIDEO_DEMUXER 1
+#define CONFIG_CDG_DEMUXER 1
+#define CONFIG_DAUD_DEMUXER 1
+#define CONFIG_DIRAC_DEMUXER 1
+#define CONFIG_DNXHD_DEMUXER 1
+#define CONFIG_DSICIN_DEMUXER 1
+#define CONFIG_DTS_DEMUXER 1
+#define CONFIG_DV_DEMUXER 1
+#define CONFIG_DXA_DEMUXER 1
+#define CONFIG_EA_DEMUXER 1
+#define CONFIG_EA_CDATA_DEMUXER 1
+#define CONFIG_EAC3_DEMUXER 1
+#define CONFIG_FFM_DEMUXER 1
+#define CONFIG_FILMSTRIP_DEMUXER 1
+#define CONFIG_FLAC_DEMUXER 1
+#define CONFIG_FLIC_DEMUXER 1
+#define CONFIG_FLV_DEMUXER 1
+#define CONFIG_FOURXM_DEMUXER 1
+#define CONFIG_GSM_DEMUXER 1
+#define CONFIG_GXF_DEMUXER 1
+#define CONFIG_H261_DEMUXER 1
+#define CONFIG_H263_DEMUXER 1
+#define CONFIG_H264_DEMUXER 1
+#define CONFIG_IDCIN_DEMUXER 1
+#define CONFIG_IFF_DEMUXER 1
+#define CONFIG_IMAGE2_DEMUXER 1
+#define CONFIG_IMAGE2PIPE_DEMUXER 1
+#define CONFIG_INGENIENT_DEMUXER 1
+#define CONFIG_IPMOVIE_DEMUXER 1
+#define CONFIG_ISS_DEMUXER 1
+#define CONFIG_IV8_DEMUXER 1
+#define CONFIG_IVF_DEMUXER 1
+#define CONFIG_LMLM4_DEMUXER 1
+#define CONFIG_M4V_DEMUXER 1
+#define CONFIG_MATROSKA_DEMUXER 1
+#define CONFIG_MJPEG_DEMUXER 1
+#define CONFIG_MLP_DEMUXER 1
+#define CONFIG_MM_DEMUXER 1
+#define CONFIG_MMF_DEMUXER 1
+#define CONFIG_MOV_DEMUXER 1
+#define CONFIG_MP3_DEMUXER 1
+#define CONFIG_MPC_DEMUXER 1
+#define CONFIG_MPC8_DEMUXER 1
+#define CONFIG_MPEGPS_DEMUXER 1
+#define CONFIG_MPEGTS_DEMUXER 1
+#define CONFIG_MPEGTSRAW_DEMUXER 1
+#define CONFIG_MPEGVIDEO_DEMUXER 1
+#define CONFIG_MSNWC_TCP_DEMUXER 1
+#define CONFIG_MTV_DEMUXER 1
+#define CONFIG_MVI_DEMUXER 1
+#define CONFIG_MXF_DEMUXER 1
+#define CONFIG_NC_DEMUXER 1
+#define CONFIG_NSV_DEMUXER 1
+#define CONFIG_NUT_DEMUXER 1
+#define CONFIG_NUV_DEMUXER 1
+#define CONFIG_OGG_DEMUXER 1
+#define CONFIG_OMA_DEMUXER 1
+#define CONFIG_PCM_ALAW_DEMUXER 1
+#define CONFIG_PCM_MULAW_DEMUXER 1
+#define CONFIG_PCM_F64BE_DEMUXER 1
+#define CONFIG_PCM_F64LE_DEMUXER 1
+#define CONFIG_PCM_F32BE_DEMUXER 1
+#define CONFIG_PCM_F32LE_DEMUXER 1
+#define CONFIG_PCM_S32BE_DEMUXER 1
+#define CONFIG_PCM_S32LE_DEMUXER 1
+#define CONFIG_PCM_S24BE_DEMUXER 1
+#define CONFIG_PCM_S24LE_DEMUXER 1
+#define CONFIG_PCM_S16BE_DEMUXER 1
+#define CONFIG_PCM_S16LE_DEMUXER 1
+#define CONFIG_PCM_S8_DEMUXER 1
+#define CONFIG_PCM_U32BE_DEMUXER 1
+#define CONFIG_PCM_U32LE_DEMUXER 1
+#define CONFIG_PCM_U24BE_DEMUXER 1
+#define CONFIG_PCM_U24LE_DEMUXER 1
+#define CONFIG_PCM_U16BE_DEMUXER 1
+#define CONFIG_PCM_U16LE_DEMUXER 1
+#define CONFIG_PCM_U8_DEMUXER 1
+#define CONFIG_PVA_DEMUXER 1
+#define CONFIG_QCP_DEMUXER 1
+#define CONFIG_R3D_DEMUXER 1
+#define CONFIG_RAWVIDEO_DEMUXER 1
+#define CONFIG_RL2_DEMUXER 1
+#define CONFIG_RM_DEMUXER 1
+#define CONFIG_ROQ_DEMUXER 1
+#define CONFIG_RPL_DEMUXER 1
+#define CONFIG_RTSP_DEMUXER 1
+#define CONFIG_SDP_DEMUXER 1
+#define CONFIG_SEGAFILM_DEMUXER 1
+#define CONFIG_SHORTEN_DEMUXER 1
+#define CONFIG_SIFF_DEMUXER 1
+#define CONFIG_SMACKER_DEMUXER 1
+#define CONFIG_SOL_DEMUXER 1
+#define CONFIG_SOX_DEMUXER 1
+#define CONFIG_STR_DEMUXER 1
+#define CONFIG_SWF_DEMUXER 1
+#define CONFIG_THP_DEMUXER 1
+#define CONFIG_TIERTEXSEQ_DEMUXER 1
+#define CONFIG_TMV_DEMUXER 1
+#define CONFIG_TRUEHD_DEMUXER 1
+#define CONFIG_TTA_DEMUXER 1
+#define CONFIG_TXD_DEMUXER 1
+#define CONFIG_VC1_DEMUXER 1
+#define CONFIG_VC1T_DEMUXER 1
+#define CONFIG_VMD_DEMUXER 1
+#define CONFIG_VOC_DEMUXER 1
+#define CONFIG_VQF_DEMUXER 1
+#define CONFIG_W64_DEMUXER 1
+#define CONFIG_WAV_DEMUXER 1
+#define CONFIG_WC3_DEMUXER 1
+#define CONFIG_WSAUD_DEMUXER 1
+#define CONFIG_WSVQA_DEMUXER 1
+#define CONFIG_WV_DEMUXER 1
+#define CONFIG_XA_DEMUXER 1
+#define CONFIG_YOP_DEMUXER 1
+#define CONFIG_YUV4MPEGPIPE_DEMUXER 1
+#define CONFIG_LIBNUT_DEMUXER 0
+#define CONFIG_AC3_MUXER 1
+#define CONFIG_ADTS_MUXER 1
+#define CONFIG_AIFF_MUXER 1
+#define CONFIG_AMR_MUXER 1
+#define CONFIG_ASF_MUXER 1
+#define CONFIG_ASS_MUXER 1
+#define CONFIG_ASF_STREAM_MUXER 1
+#define CONFIG_AU_MUXER 1
+#define CONFIG_AVI_MUXER 1
+#define CONFIG_AVM2_MUXER 1
+#define CONFIG_CRC_MUXER 1
+#define CONFIG_DAUD_MUXER 1
+#define CONFIG_DIRAC_MUXER 1
+#define CONFIG_DNXHD_MUXER 1
+#define CONFIG_DTS_MUXER 1
+#define CONFIG_DV_MUXER 1
+#define CONFIG_EAC3_MUXER 1
+#define CONFIG_FFM_MUXER 1
+#define CONFIG_FILMSTRIP_MUXER 1
+#define CONFIG_FLAC_MUXER 1
+#define CONFIG_FLV_MUXER 1
+#define CONFIG_FRAMECRC_MUXER 1
+#define CONFIG_FRAMEMD5_MUXER 1
+#define CONFIG_GIF_MUXER 1
+#define CONFIG_GXF_MUXER 1
+#define CONFIG_H261_MUXER 1
+#define CONFIG_H263_MUXER 1
+#define CONFIG_H264_MUXER 1
+#define CONFIG_IMAGE2_MUXER 1
+#define CONFIG_IMAGE2PIPE_MUXER 1
+#define CONFIG_IPOD_MUXER 1
+#define CONFIG_M4V_MUXER 1
+#define CONFIG_MD5_MUXER 1
+#define CONFIG_MATROSKA_MUXER 1
+#define CONFIG_MATROSKA_AUDIO_MUXER 1
+#define CONFIG_MJPEG_MUXER 1
+#define CONFIG_MLP_MUXER 1
+#define CONFIG_MMF_MUXER 1
+#define CONFIG_MOV_MUXER 1
+#define CONFIG_MP2_MUXER 1
+#define CONFIG_MP3_MUXER 1
+#define CONFIG_MP4_MUXER 1
+#define CONFIG_MPEG1SYSTEM_MUXER 1
+#define CONFIG_MPEG1VCD_MUXER 1
+#define CONFIG_MPEG1VIDEO_MUXER 1
+#define CONFIG_MPEG2DVD_MUXER 1
+#define CONFIG_MPEG2SVCD_MUXER 1
+#define CONFIG_MPEG2VIDEO_MUXER 1
+#define CONFIG_MPEG2VOB_MUXER 1
+#define CONFIG_MPEGTS_MUXER 1
+#define CONFIG_MPJPEG_MUXER 1
+#define CONFIG_MXF_MUXER 1
+#define CONFIG_MXF_D10_MUXER 1
+#define CONFIG_NULL_MUXER 1
+#define CONFIG_NUT_MUXER 1
+#define CONFIG_OGG_MUXER 1
+#define CONFIG_PCM_ALAW_MUXER 1
+#define CONFIG_PCM_MULAW_MUXER 1
+#define CONFIG_PCM_F64BE_MUXER 1
+#define CONFIG_PCM_F64LE_MUXER 1
+#define CONFIG_PCM_F32BE_MUXER 1
+#define CONFIG_PCM_F32LE_MUXER 1
+#define CONFIG_PCM_S32BE_MUXER 1
+#define CONFIG_PCM_S32LE_MUXER 1
+#define CONFIG_PCM_S24BE_MUXER 1
+#define CONFIG_PCM_S24LE_MUXER 1
+#define CONFIG_PCM_S16BE_MUXER 1
+#define CONFIG_PCM_S16LE_MUXER 1
+#define CONFIG_PCM_S8_MUXER 1
+#define CONFIG_PCM_U32BE_MUXER 1
+#define CONFIG_PCM_U32LE_MUXER 1
+#define CONFIG_PCM_U24BE_MUXER 1
+#define CONFIG_PCM_U24LE_MUXER 1
+#define CONFIG_PCM_U16BE_MUXER 1
+#define CONFIG_PCM_U16LE_MUXER 1
+#define CONFIG_PCM_U8_MUXER 1
+#define CONFIG_PSP_MUXER 1
+#define CONFIG_RAWVIDEO_MUXER 1
+#define CONFIG_RM_MUXER 1
+#define CONFIG_ROQ_MUXER 1
+#define CONFIG_RTP_MUXER 1
+#define CONFIG_RTSP_MUXER 1
+#define CONFIG_SOX_MUXER 1
+#define CONFIG_SPDIF_MUXER 1
+#define CONFIG_SWF_MUXER 1
+#define CONFIG_TG2_MUXER 1
+#define CONFIG_TGP_MUXER 1
+#define CONFIG_TRUEHD_MUXER 1
+#define CONFIG_VC1T_MUXER 1
+#define CONFIG_VOC_MUXER 1
+#define CONFIG_WAV_MUXER 1
+#define CONFIG_WEBM_MUXER 1
+#define CONFIG_YUV4MPEGPIPE_MUXER 1
+#define CONFIG_LIBNUT_MUXER 0
+#define CONFIG_ASPECT_FILTER 1
+#define CONFIG_CROP_FILTER 1
+#define CONFIG_FORMAT_FILTER 1
+#define CONFIG_NOFORMAT_FILTER 1
+#define CONFIG_NULL_FILTER 1
+#define CONFIG_PAD_FILTER 1
+#define CONFIG_PIXDESCTEST_FILTER 1
+#define CONFIG_PIXELASPECT_FILTER 1
+#define CONFIG_SCALE_FILTER 1
+#define CONFIG_SLICIFY_FILTER 1
+#define CONFIG_UNSHARP_FILTER 1
+#define CONFIG_VFLIP_FILTER 1
+#define CONFIG_BUFFER_FILTER 1
+#define CONFIG_NULLSRC_FILTER 1
+#define CONFIG_NULLSINK_FILTER 1
+#define CONFIG_FILE_PROTOCOL 1
+#define CONFIG_GOPHER_PROTOCOL 1
+#define CONFIG_HTTP_PROTOCOL 1
+#define CONFIG_MMST_PROTOCOL 1
+#define CONFIG_PIPE_PROTOCOL 1
+#define CONFIG_RTMP_PROTOCOL 1
+#define CONFIG_RTMPT_PROTOCOL 1
+#define CONFIG_RTMPE_PROTOCOL 1
+#define CONFIG_RTMPTE_PROTOCOL 1
+#define CONFIG_RTMPS_PROTOCOL 1
+#define CONFIG_RTP_PROTOCOL 1
+#define CONFIG_TCP_PROTOCOL 1
+#define CONFIG_UDP_PROTOCOL 1
+#define CONFIG_CONCAT_PROTOCOL 1
+#define CONFIG_ALSA_INDEV 0
+#define CONFIG_BKTR_INDEV 0
+#define CONFIG_DV1394_INDEV 1
+#define CONFIG_JACK_INDEV 0
+#define CONFIG_OSS_INDEV 1
+#define CONFIG_V4L2_INDEV 1
+#define CONFIG_V4L_INDEV 1
+#define CONFIG_VFWCAP_INDEV 0
+#define CONFIG_X11_GRAB_DEVICE_INDEV 0
+#define CONFIG_LIBDC1394_INDEV 0
+#define CONFIG_ALSA_OUTDEV 0
+#define CONFIG_OSS_OUTDEV 1
+#endif /* FFMPEG_CONFIG_H */
diff --git a/plugins/supereq/ffmpeg_fft/ffmpeg_fft.h b/plugins/supereq/ffmpeg_fft/ffmpeg_fft.h
new file mode 100644
index 00000000..b98313d2
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/ffmpeg_fft.h
@@ -0,0 +1,95 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_AVFFT_H
+#define AVCODEC_AVFFT_H
+
+typedef float FFTSample;
+
+typedef struct FFTComplex {
+ FFTSample re, im;
+} FFTComplex;
+
+//#define FFTC_SZ 32
+typedef struct FFTContext FFTContext;
+
+/**
+ * Set up a complex FFT.
+ * @param nbits log2 of the length of the input array
+ * @param inverse if 0 perform the forward transform, if 1 perform the inverse
+ */
+FFTContext *av_fft_init(int nbits, int inverse);
+
+/**
+ * Do the permutation needed BEFORE calling ff_fft_calc().
+ */
+void av_fft_permute(FFTContext *s, FFTComplex *z);
+
+/**
+ * Do a complex FFT with the parameters defined in av_fft_init(). The
+ * input data must be permuted before. No 1.0/sqrt(n) normalization is done.
+ */
+void av_fft_calc(FFTContext *s, FFTComplex *z);
+
+void av_fft_end(FFTContext *s);
+
+/* Real Discrete Fourier Transform */
+
+enum RDFTransformType {
+ DFT_R2C,
+ IDFT_C2R,
+ IDFT_R2C,
+ DFT_C2R,
+};
+
+//#define RDFTC_SZ 56
+typedef struct RDFTContext RDFTContext;
+
+/**
+ * Set up a real FFT.
+ * @param nbits log2 of the length of the input array
+ * @param trans the type of transform
+ */
+RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans);
+void av_rdft_calc(RDFTContext *s, FFTSample *data);
+void av_rdft_end(RDFTContext *s);
+
+/* Discrete Cosine Transform */
+
+typedef struct DCTContext DCTContext;
+
+enum DCTTransformType {
+ DCT_II = 0,
+ DCT_III,
+ DCT_I,
+ DST_I,
+};
+
+/**
+ * Set up DCT.
+ * @param nbits size of the input array:
+ * (1 << nbits) for DCT-II, DCT-III and DST-I
+ * (1 << nbits) + 1 for DCT-I
+ *
+ * @note the first element of the input of DST-I is ignored
+ */
+DCTContext *av_dct_init(int nbits, enum DCTTransformType type);
+void av_dct_calc(DCTContext *s, FFTSample *data);
+void av_dct_end (DCTContext *s);
+
+#endif /* AVCODEC_AVFFT_H */
diff --git a/plugins/supereq/ffmpeg_fft/libavcodec/arm/asm.S b/plugins/supereq/ffmpeg_fft/libavcodec/arm/asm.S
new file mode 100644
index 00000000..6860f1cf
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavcodec/arm/asm.S
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#ifdef __ELF__
+# define ELF
+#else
+# define ELF @
+#endif
+
+.macro require8 val=1
+ELF .eabi_attribute 24, \val
+.endm
+
+.macro preserve8 val=1
+ELF .eabi_attribute 25, \val
+.endm
+
+/*
+.macro function name, export=0
+ .macro endfunc
+ELF .size \name, . - \name
+ .endfunc
+ .purgem endfunc
+ .endm
+ .text
+ .if \export
+ .global EXTERN_ASM\name
+EXTERN_ASM\name:
+ .endif
+ELF .type \name, %function
+ .func \name
+\name:
+.endm
+*/
+
+.macro function name, export=0
+ .macro endfunc
+ELF .size \name, . - \name
+ .endfunc
+ .purgem endfunc
+ .endm
+ .text
+ .if \export
+ .hidden EXTERN_ASM\name
+ .global EXTERN_ASM\name
+EXTERN_ASM\name:
+ .endif
+ELF .type \name, %function
+ .func \name
+\name:
+.endm
+
+.macro mov32 rd, val
+#if HAVE_ARMV6T2
+ movw \rd, #(\val) & 0xffff
+ .if (\val) >> 16
+ movt \rd, #(\val) >> 16
+ .endif
+#else
+ ldr \rd, =\val
+#endif
+.endm
+
+.macro movrel rd, val
+#if HAVE_ARMV6T2 && !CONFIG_PIC
+ movw \rd, #:lower16:\val
+ movt \rd, #:upper16:\val
+#else
+ ldr \rd, =\val
+#endif
+.endm
+
+#if HAVE_VFP_ARGS
+ .eabi_attribute 28, 1
+# define VFP
+# define NOVFP @
+#else
+# define VFP @
+# define NOVFP
+#endif
+
+#define GLUE(a, b) a ## b
+#define JOIN(a, b) GLUE(a, b)
+#define X(s) JOIN(EXTERN_ASM, s)
+
diff --git a/plugins/supereq/ffmpeg_fft/libavcodec/arm/fft_init_arm.c b/plugins/supereq/ffmpeg_fft/libavcodec/arm/fft_init_arm.c
new file mode 100644
index 00000000..28148e92
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavcodec/arm/fft_init_arm.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavcodec/fft.h"
+#if CONFIG_DCA_DECODER
+#include "libavcodec/synth_filter.h"
+#endif
+
+void ff_fft_permute_neon(FFTContext *s, FFTComplex *z);
+void ff_fft_calc_neon(FFTContext *s, FFTComplex *z);
+
+#if 0
+void ff_imdct_calc_neon(FFTContext *s, FFTSample *output, const FFTSample *input);
+void ff_imdct_half_neon(FFTContext *s, FFTSample *output, const FFTSample *input);
+void ff_mdct_calc_neon(FFTContext *s, FFTSample *output, const FFTSample *input);
+#endif
+
+void ff_rdft_calc_neon(struct RDFTContext *s, FFTSample *z);
+
+void ff_synth_filter_float_neon(FFTContext *imdct,
+ float *synth_buf_ptr, int *synth_buf_offset,
+ float synth_buf2[32], const float window[512],
+ float out[32], const float in[32],
+ float scale, float bias);
+
+av_cold void ff_fft_init_arm(FFTContext *s)
+{
+ if (HAVE_NEON) {
+ s->fft_permute = ff_fft_permute_neon;
+ s->fft_calc = ff_fft_calc_neon;
+#if 0
+ s->imdct_calc = ff_imdct_calc_neon;
+ s->imdct_half = ff_imdct_half_neon;
+ s->mdct_calc = ff_mdct_calc_neon;
+ s->permutation = FF_MDCT_PERM_INTERLEAVE;
+#endif
+ }
+}
+
+#if CONFIG_RDFT
+av_cold void ff_rdft_init_arm(RDFTContext *s)
+{
+ if (HAVE_NEON)
+ s->rdft_calc = ff_rdft_calc_neon;
+}
+#endif
+
+#if CONFIG_DCA_DECODER
+av_cold void ff_synth_filter_init_arm(SynthFilterContext *s)
+{
+ if (HAVE_NEON)
+ s->synth_filter_float = ff_synth_filter_float_neon;
+}
+#endif
diff --git a/plugins/supereq/ffmpeg_fft/libavcodec/arm/fft_neon.S b/plugins/supereq/ffmpeg_fft/libavcodec/arm/fft_neon.S
new file mode 100644
index 00000000..117f4fee
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavcodec/arm/fft_neon.S
@@ -0,0 +1,372 @@
+/*
+ * ARM NEON optimised FFT
+ *
+ * Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
+ * Copyright (c) 2009 Naotoshi Nojiri
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "asm.S"
+
+#define M_SQRT1_2 0.70710678118654752440
+
+ .text
+
+function fft4_neon
+ vld1.32 {d0-d3}, [r0,:128]
+
+ vext.32 q8, q1, q1, #1 @ i2,r3 d3=i3,r2
+ vsub.f32 d6, d0, d1 @ r0-r1,i0-i1
+ vsub.f32 d7, d16, d17 @ r3-r2,i2-i3
+ vadd.f32 d4, d0, d1 @ r0+r1,i0+i1
+ vadd.f32 d5, d2, d3 @ i2+i3,r2+r3
+ vadd.f32 d1, d6, d7
+ vsub.f32 d3, d6, d7
+ vadd.f32 d0, d4, d5
+ vsub.f32 d2, d4, d5
+
+ vst1.32 {d0-d3}, [r0,:128]
+
+ bx lr
+endfunc
+
+function fft8_neon
+ mov r1, r0
+ vld1.32 {d0-d3}, [r1,:128]!
+ vld1.32 {d16-d19}, [r1,:128]
+
+ movw r2, #0x04f3 @ sqrt(1/2)
+ movt r2, #0x3f35
+ eor r3, r2, #1<<31
+ vdup.32 d31, r2
+
+ vext.32 q11, q1, q1, #1 @ i2,r3,i3,r2
+ vadd.f32 d4, d16, d17 @ r4+r5,i4+i5
+ vmov d28, r3, r2
+ vadd.f32 d5, d18, d19 @ r6+r7,i6+i7
+ vsub.f32 d17, d16, d17 @ r4-r5,i4-i5
+ vsub.f32 d19, d18, d19 @ r6-r7,i6-i7
+ vrev64.32 d29, d28
+ vadd.f32 d20, d0, d1 @ r0+r1,i0+i1
+ vadd.f32 d21, d2, d3 @ r2+r3,i2+i3
+ vmul.f32 d26, d17, d28 @ -a2r*w,a2i*w
+ vext.32 q3, q2, q2, #1
+ vmul.f32 d27, d19, d29 @ a3r*w,-a3i*w
+ vsub.f32 d23, d22, d23 @ i2-i3,r3-r2
+ vsub.f32 d22, d0, d1 @ r0-r1,i0-i1
+ vmul.f32 d24, d17, d31 @ a2r*w,a2i*w
+ vmul.f32 d25, d19, d31 @ a3r*w,a3i*w
+ vadd.f32 d0, d20, d21
+ vsub.f32 d2, d20, d21
+ vadd.f32 d1, d22, d23
+ vrev64.32 q13, q13
+ vsub.f32 d3, d22, d23
+ vsub.f32 d6, d6, d7
+ vadd.f32 d24, d24, d26 @ a2r+a2i,a2i-a2r t1,t2
+ vadd.f32 d25, d25, d27 @ a3r-a3i,a3i+a3r t5,t6
+ vadd.f32 d7, d4, d5
+ vsub.f32 d18, d2, d6
+ vext.32 q13, q12, q12, #1
+ vadd.f32 d2, d2, d6
+ vsub.f32 d16, d0, d7
+ vadd.f32 d5, d25, d24
+ vsub.f32 d4, d26, d27
+ vadd.f32 d0, d0, d7
+ vsub.f32 d17, d1, d5
+ vsub.f32 d19, d3, d4
+ vadd.f32 d3, d3, d4
+ vadd.f32 d1, d1, d5
+
+ vst1.32 {d16-d19}, [r1,:128]
+ vst1.32 {d0-d3}, [r0,:128]
+
+ bx lr
+endfunc
+
+function fft16_neon
+ movrel r1, mppm
+ vld1.32 {d16-d19}, [r0,:128]! @ q8{r0,i0,r1,i1} q9{r2,i2,r3,i3}
+ pld [r0, #32]
+ vld1.32 {d2-d3}, [r1,:128]
+ vext.32 q13, q9, q9, #1
+ vld1.32 {d22-d25}, [r0,:128]! @ q11{r4,i4,r5,i5} q12{r6,i5,r7,i7}
+ vadd.f32 d4, d16, d17
+ vsub.f32 d5, d16, d17
+ vadd.f32 d18, d18, d19
+ vsub.f32 d19, d26, d27
+
+ vadd.f32 d20, d22, d23
+ vsub.f32 d22, d22, d23
+ vsub.f32 d23, d24, d25
+ vadd.f32 q8, q2, q9 @ {r0,i0,r1,i1}
+ vadd.f32 d21, d24, d25
+ vmul.f32 d24, d22, d2
+ vsub.f32 q9, q2, q9 @ {r2,i2,r3,i3}
+ vmul.f32 d25, d23, d3
+ vuzp.32 d16, d17 @ {r0,r1,i0,i1}
+ vmul.f32 q1, q11, d2[1]
+ vuzp.32 d18, d19 @ {r2,r3,i2,i3}
+ vrev64.32 q12, q12
+ vadd.f32 q11, q12, q1 @ {t1a,t2a,t5,t6}
+ vld1.32 {d24-d27}, [r0,:128]! @ q12{r8,i8,r9,i9} q13{r10,i10,r11,i11}
+ vzip.32 q10, q11
+ vld1.32 {d28-d31}, [r0,:128] @ q14{r12,i12,r13,i13} q15{r14,i14,r15,i15}
+ vadd.f32 d0, d22, d20
+ vadd.f32 d1, d21, d23
+ vsub.f32 d2, d21, d23
+ vsub.f32 d3, d22, d20
+ sub r0, r0, #96
+ vext.32 q13, q13, q13, #1
+ vsub.f32 q10, q8, q0 @ {r4,r5,i4,i5}
+ vadd.f32 q8, q8, q0 @ {r0,r1,i0,i1}
+ vext.32 q15, q15, q15, #1
+ vsub.f32 q11, q9, q1 @ {r6,r7,i6,i7}
+ vswp d25, d26 @ q12{r8,i8,i10,r11} q13{r9,i9,i11,r10}
+ vadd.f32 q9, q9, q1 @ {r2,r3,i2,i3}
+ vswp d29, d30 @ q14{r12,i12,i14,r15} q15{r13,i13,i15,r14}
+ vadd.f32 q0, q12, q13 @ {t1,t2,t5,t6}
+ vadd.f32 q1, q14, q15 @ {t1a,t2a,t5a,t6a}
+ movrel r2, X(ff_cos_16)
+ vsub.f32 q13, q12, q13 @ {t3,t4,t7,t8}
+ vrev64.32 d1, d1
+ vsub.f32 q15, q14, q15 @ {t3a,t4a,t7a,t8a}
+ vrev64.32 d3, d3
+ movrel r3, pmmp
+ vswp d1, d26 @ q0{t1,t2,t3,t4} q13{t6,t5,t7,t8}
+ vswp d3, d30 @ q1{t1a,t2a,t3a,t4a} q15{t6a,t5a,t7a,t8a}
+ vadd.f32 q12, q0, q13 @ {r8,i8,r9,i9}
+ vadd.f32 q14, q1, q15 @ {r12,i12,r13,i13}
+ vld1.32 {d4-d5}, [r2,:64]
+ vsub.f32 q13, q0, q13 @ {r10,i10,r11,i11}
+ vsub.f32 q15, q1, q15 @ {r14,i14,r15,i15}
+ vswp d25, d28 @ q12{r8,i8,r12,i12} q14{r9,i9,r13,i13}
+ vld1.32 {d6-d7}, [r3,:128]
+ vrev64.32 q1, q14
+ vmul.f32 q14, q14, d4[1]
+ vmul.f32 q1, q1, q3
+ vmla.f32 q14, q1, d5[1] @ {t1a,t2a,t5a,t6a}
+ vswp d27, d30 @ q13{r10,i10,r14,i14} q15{r11,i11,r15,i15}
+ vzip.32 q12, q14
+ vadd.f32 d0, d28, d24
+ vadd.f32 d1, d25, d29
+ vsub.f32 d2, d25, d29
+ vsub.f32 d3, d28, d24
+ vsub.f32 q12, q8, q0 @ {r8,r9,i8,i9}
+ vadd.f32 q8, q8, q0 @ {r0,r1,i0,i1}
+ vsub.f32 q14, q10, q1 @ {r12,r13,i12,i13}
+ mov r1, #32
+ vadd.f32 q10, q10, q1 @ {r4,r5,i4,i5}
+ vrev64.32 q0, q13
+ vmul.f32 q13, q13, d5[0]
+ vrev64.32 q1, q15
+ vmul.f32 q15, q15, d5[1]
+ vst2.32 {d16-d17},[r0,:128], r1
+ vmul.f32 q0, q0, q3
+ vst2.32 {d20-d21},[r0,:128], r1
+ vmul.f32 q1, q1, q3
+ vmla.f32 q13, q0, d5[0] @ {t1,t2,t5,t6}
+ vmla.f32 q15, q1, d4[1] @ {t1a,t2a,t5a,t6a}
+ vst2.32 {d24-d25},[r0,:128], r1
+ vst2.32 {d28-d29},[r0,:128]
+ vzip.32 q13, q15
+ sub r0, r0, #80
+ vadd.f32 d0, d30, d26
+ vadd.f32 d1, d27, d31
+ vsub.f32 d2, d27, d31
+ vsub.f32 d3, d30, d26
+ vsub.f32 q13, q9, q0 @ {r10,r11,i10,i11}
+ vadd.f32 q9, q9, q0 @ {r2,r3,i2,i3}
+ vsub.f32 q15, q11, q1 @ {r14,r15,i14,i15}
+ vadd.f32 q11, q11, q1 @ {r6,r7,i6,i7}
+ vst2.32 {d18-d19},[r0,:128], r1
+ vst2.32 {d22-d23},[r0,:128], r1
+ vst2.32 {d26-d27},[r0,:128], r1
+ vst2.32 {d30-d31},[r0,:128]
+ bx lr
+endfunc
+
+function fft_pass_neon
+ push {r4-r6,lr}
+ mov r6, r2 @ n
+ lsl r5, r2, #3 @ 2 * n * sizeof FFTSample
+ lsl r4, r2, #4 @ 2 * n * sizeof FFTComplex
+ lsl r2, r2, #5 @ 4 * n * sizeof FFTComplex
+ add r3, r2, r4
+ add r4, r4, r0 @ &z[o1]
+ add r2, r2, r0 @ &z[o2]
+ add r3, r3, r0 @ &z[o3]
+ vld1.32 {d20-d21},[r2,:128] @ {z[o2],z[o2+1]}
+ movrel r12, pmmp
+ vld1.32 {d22-d23},[r3,:128] @ {z[o3],z[o3+1]}
+ add r5, r5, r1 @ wim
+ vld1.32 {d6-d7}, [r12,:128] @ pmmp
+ vswp d21, d22
+ vld1.32 {d4}, [r1,:64]! @ {wre[0],wre[1]}
+ sub r5, r5, #4 @ wim--
+ vrev64.32 q1, q11
+ vmul.f32 q11, q11, d4[1]
+ vmul.f32 q1, q1, q3
+ vld1.32 {d5[0]}, [r5,:32] @ d5[0] = wim[-1]
+ vmla.f32 q11, q1, d5[0] @ {t1a,t2a,t5a,t6a}
+ vld2.32 {d16-d17},[r0,:128] @ {z[0],z[1]}
+ sub r6, r6, #1 @ n--
+ vld2.32 {d18-d19},[r4,:128] @ {z[o1],z[o1+1]}
+ vzip.32 q10, q11
+ vadd.f32 d0, d22, d20
+ vadd.f32 d1, d21, d23
+ vsub.f32 d2, d21, d23
+ vsub.f32 d3, d22, d20
+ vsub.f32 q10, q8, q0
+ vadd.f32 q8, q8, q0
+ vsub.f32 q11, q9, q1
+ vadd.f32 q9, q9, q1
+ vst2.32 {d20-d21},[r2,:128]! @ {z[o2],z[o2+1]}
+ vst2.32 {d16-d17},[r0,:128]! @ {z[0],z[1]}
+ vst2.32 {d22-d23},[r3,:128]! @ {z[o3],z[o3+1]}
+ vst2.32 {d18-d19},[r4,:128]! @ {z[o1],z[o1+1]}
+ sub r5, r5, #8 @ wim -= 2
+1:
+ vld1.32 {d20-d21},[r2,:128] @ {z[o2],z[o2+1]}
+ vld1.32 {d22-d23},[r3,:128] @ {z[o3],z[o3+1]}
+ vswp d21, d22
+ vld1.32 {d4}, [r1]! @ {wre[0],wre[1]}
+ vrev64.32 q0, q10
+ vmul.f32 q10, q10, d4[0]
+ vrev64.32 q1, q11
+ vmul.f32 q11, q11, d4[1]
+ vld1.32 {d5}, [r5] @ {wim[-1],wim[0]}
+ vmul.f32 q0, q0, q3
+ sub r5, r5, #8 @ wim -= 2
+ vmul.f32 q1, q1, q3
+ vmla.f32 q10, q0, d5[1] @ {t1,t2,t5,t6}
+ vmla.f32 q11, q1, d5[0] @ {t1a,t2a,t5a,t6a}
+ vld2.32 {d16-d17},[r0,:128] @ {z[0],z[1]}
+ subs r6, r6, #1 @ n--
+ vld2.32 {d18-d19},[r4,:128] @ {z[o1],z[o1+1]}
+ vzip.32 q10, q11
+ vadd.f32 d0, d22, d20
+ vadd.f32 d1, d21, d23
+ vsub.f32 d2, d21, d23
+ vsub.f32 d3, d22, d20
+ vsub.f32 q10, q8, q0
+ vadd.f32 q8, q8, q0
+ vsub.f32 q11, q9, q1
+ vadd.f32 q9, q9, q1
+ vst2.32 {d20-d21}, [r2,:128]! @ {z[o2],z[o2+1]}
+ vst2.32 {d16-d17}, [r0,:128]! @ {z[0],z[1]}
+ vst2.32 {d22-d23}, [r3,:128]! @ {z[o3],z[o3+1]}
+ vst2.32 {d18-d19}, [r4,:128]! @ {z[o1],z[o1+1]}
+ bne 1b
+
+ pop {r4-r6,pc}
+endfunc
+
+.macro def_fft n, n2, n4
+ .align 6
+function fft\n\()_neon
+ push {r4, lr}
+ mov r4, r0
+ bl fft\n2\()_neon
+ add r0, r4, #\n4*2*8
+ bl fft\n4\()_neon
+ add r0, r4, #\n4*3*8
+ bl fft\n4\()_neon
+ mov r0, r4
+ pop {r4, lr}
+ movrel r1, X(ff_cos_\n)
+ mov r2, #\n4/2
+ b fft_pass_neon
+endfunc
+.endm
+
+ def_fft 32, 16, 8
+ def_fft 64, 32, 16
+ def_fft 128, 64, 32
+ def_fft 256, 128, 64
+ def_fft 512, 256, 128
+ def_fft 1024, 512, 256
+ def_fft 2048, 1024, 512
+ def_fft 4096, 2048, 1024
+ def_fft 8192, 4096, 2048
+ def_fft 16384, 8192, 4096
+ def_fft 32768, 16384, 8192
+ def_fft 65536, 32768, 16384
+
+function ff_fft_calc_neon, export=1
+ ldr r2, [r0]
+ sub r2, r2, #2
+ movrel r3, fft_tab_neon
+ ldr r3, [r3, r2, lsl #2]
+ mov r0, r1
+ bx r3
+endfunc
+
+function ff_fft_permute_neon, export=1
+ push {r4,lr}
+ mov r12, #1
+ ldr r2, [r0] @ nbits
+ ldr r3, [r0, #12] @ tmp_buf
+ ldr r0, [r0, #8] @ revtab
+ lsl r12, r12, r2
+ mov r2, r12
+1:
+ vld1.32 {d0-d1}, [r1,:128]!
+ ldr r4, [r0], #4
+ uxth lr, r4
+ uxth r4, r4, ror #16
+ add lr, r3, lr, lsl #3
+ add r4, r3, r4, lsl #3
+ vst1.32 {d0}, [lr,:64]
+ vst1.32 {d1}, [r4,:64]
+ subs r12, r12, #2
+ bgt 1b
+
+ sub r1, r1, r2, lsl #3
+1:
+ vld1.32 {d0-d3}, [r3,:128]!
+ vst1.32 {d0-d3}, [r1,:128]!
+ subs r2, r2, #4
+ bgt 1b
+
+ pop {r4,pc}
+endfunc
+
+ .section .rodata
+ .align 4
+fft_tab_neon:
+ .word fft4_neon
+ .word fft8_neon
+ .word fft16_neon
+ .word fft32_neon
+ .word fft64_neon
+ .word fft128_neon
+ .word fft256_neon
+ .word fft512_neon
+ .word fft1024_neon
+ .word fft2048_neon
+ .word fft4096_neon
+ .word fft8192_neon
+ .word fft16384_neon
+ .word fft32768_neon
+ .word fft65536_neon
+ELF .size fft_tab_neon, . - fft_tab_neon
+
+ .align 4
+pmmp: .float +1.0, -1.0, -1.0, +1.0
+mppm: .float -M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2
+
diff --git a/plugins/supereq/ffmpeg_fft/libavcodec/arm/rdft_neon.S b/plugins/supereq/ffmpeg_fft/libavcodec/arm/rdft_neon.S
new file mode 100644
index 00000000..4f8a1032
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavcodec/arm/rdft_neon.S
@@ -0,0 +1,151 @@
+/*
+ * ARM NEON optimised RDFT
+ * Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "asm.S"
+
+ preserve8
+
+function ff_rdft_calc_neon, export=1
+ push {r4-r8,lr}
+
+ ldr r6, [r0, #4] @ inverse
+ mov r4, r0
+ mov r5, r1
+
+ lsls r6, r6, #31
+ bne 1f
+ add r0, r4, #20
+ bl X(ff_fft_permute_neon)
+ add r0, r4, #20
+ mov r1, r5
+ bl X(ff_fft_calc_neon)
+1:
+ ldr r12, [r4, #0] @ nbits
+ mov r2, #1
+ lsl r12, r2, r12
+ add r0, r5, #8
+ add r1, r5, r12, lsl #2
+ lsr r12, r12, #2
+ ldr r2, [r4, #12] @ tcos
+ sub r12, r12, #2
+ ldr r3, [r4, #16] @ tsin
+ mov r7, r0
+ sub r1, r1, #8
+ mov lr, r1
+ mov r8, #-8
+ vld1.32 {d0}, [r0,:64]! @ d1[0,1]
+ vld1.32 {d1}, [r1,:64], r8 @ d2[0,1]
+ vld1.32 {d4}, [r2,:64]! @ tcos[i]
+ vld1.32 {d5}, [r3,:64]! @ tsin[i]
+ vmov.f32 d18, #0.5 @ k1
+ vdup.32 d19, r6
+ pld [r0, #32]
+ veor d19, d18, d19 @ k2
+ vmov.i32 d16, #0
+ vmov.i32 d17, #1<<31
+ pld [r1, #-32]
+ vtrn.32 d16, d17
+ pld [r2, #32]
+ vrev64.32 d16, d16 @ d16=1,0 d17=0,1
+ pld [r3, #32]
+2:
+ veor q1, q0, q8 @ -d1[0],d1[1], d2[0],-d2[1]
+ vld1.32 {d24}, [r0,:64]! @ d1[0,1]
+ vadd.f32 d0, d0, d3 @ d1[0]+d2[0], d1[1]-d2[1]
+ vld1.32 {d25}, [r1,:64], r8 @ d2[0,1]
+ vadd.f32 d1, d2, d1 @ -d1[0]+d2[0], d1[1]+d2[1]
+ veor q3, q12, q8 @ -d1[0],d1[1], d2[0],-d2[1]
+ pld [r0, #32]
+ vmul.f32 q10, q0, q9 @ ev.re, ev.im, od.im, od.re
+ pld [r1, #-32]
+ vadd.f32 d0, d24, d7 @ d1[0]+d2[0], d1[1]-d2[1]
+ vadd.f32 d1, d6, d25 @ -d1[0]+d2[0], d1[1]+d2[1]
+ vmul.f32 q11, q0, q9 @ ev.re, ev.im, od.im, od.re
+ veor d7, d21, d16 @ -od.im, od.re
+ vrev64.32 d3, d21 @ od.re, od.im
+ veor d6, d20, d17 @ ev.re,-ev.im
+ veor d2, d3, d16 @ -od.re, od.im
+ vmla.f32 d20, d3, d4[1]
+ vmla.f32 d20, d7, d5[1]
+ vmla.f32 d6, d2, d4[1]
+ vmla.f32 d6, d21, d5[1]
+ vld1.32 {d4}, [r2,:64]! @ tcos[i]
+ veor d7, d23, d16 @ -od.im, od.re
+ vld1.32 {d5}, [r3,:64]! @ tsin[i]
+ veor d24, d22, d17 @ ev.re,-ev.im
+ vrev64.32 d3, d23 @ od.re, od.im
+ pld [r2, #32]
+ veor d2, d3, d16 @ -od.re, od.im
+ pld [r3, #32]
+ vmla.f32 d22, d3, d4[0]
+ vmla.f32 d22, d7, d5[0]
+ vmla.f32 d24, d2, d4[0]
+ vmla.f32 d24, d23, d5[0]
+ vld1.32 {d0}, [r0,:64]! @ d1[0,1]
+ vld1.32 {d1}, [r1,:64], r8 @ d2[0,1]
+ vst1.32 {d20}, [r7,:64]!
+ vst1.32 {d6}, [lr,:64], r8
+ vst1.32 {d22}, [r7,:64]!
+ vst1.32 {d24}, [lr,:64], r8
+ subs r12, r12, #2
+ bgt 2b
+
+ veor q1, q0, q8 @ -d1[0],d1[1], d2[0],-d2[1]
+ vadd.f32 d0, d0, d3 @ d1[0]+d2[0], d1[1]-d2[1]
+ vadd.f32 d1, d2, d1 @ -d1[0]+d2[0], d1[1]+d2[1]
+ ldr r2, [r4, #8] @ sign_convention
+ vmul.f32 q10, q0, q9 @ ev.re, ev.im, od.im, od.re
+ add r0, r0, #4
+ bfc r2, #0, #31
+ vld1.32 {d0[0]}, [r0,:32]
+ veor d7, d21, d16 @ -od.im, od.re
+ vrev64.32 d3, d21 @ od.re, od.im
+ veor d6, d20, d17 @ ev.re,-ev.im
+ vld1.32 {d22}, [r5,:64]
+ vdup.32 d1, r2
+ vmov d23, d22
+ veor d2, d3, d16 @ -od.re, od.im
+ vtrn.32 d22, d23
+ veor d0, d0, d1
+ veor d23, d23, d17
+ vmla.f32 d20, d3, d4[1]
+ vmla.f32 d20, d7, d5[1]
+ vmla.f32 d6, d2, d4[1]
+ vmla.f32 d6, d21, d5[1]
+ vadd.f32 d22, d22, d23
+ vst1.32 {d20}, [r7,:64]
+ vst1.32 {d6}, [lr,:64]
+ vst1.32 {d0[0]}, [r0,:32]
+ vst1.32 {d22}, [r5,:64]
+
+ cmp r6, #0
+ popeq {r4-r8,pc}
+
+ vmul.f32 d22, d22, d18
+ vst1.32 {d22}, [r5,:64]
+ add r0, r4, #20
+ mov r1, r5
+ bl X(ff_fft_permute_neon)
+ add r0, r4, #20
+ mov r1, r5
+ pop {r4-r8,lr}
+ b X(ff_fft_calc_neon)
+endfunc
diff --git a/plugins/supereq/ffmpeg_fft/libavcodec/arm/simple_idct_neon.S b/plugins/supereq/ffmpeg_fft/libavcodec/arm/simple_idct_neon.S
new file mode 100644
index 00000000..17cde583
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavcodec/arm/simple_idct_neon.S
@@ -0,0 +1,372 @@
+/*
+ * ARM NEON IDCT
+ *
+ * Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
+ *
+ * Based on Simple IDCT
+ * Copyright (c) 2001 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "asm.S"
+
+#define W1 22725 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
+#define W2 21407 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
+#define W3 19266 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
+#define W4 16383 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
+#define W5 12873 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
+#define W6 8867 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
+#define W7 4520 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
+#define W4c ((1<<(COL_SHIFT-1))/W4)
+#define ROW_SHIFT 11
+#define COL_SHIFT 20
+
+#define w1 d0[0]
+#define w2 d0[1]
+#define w3 d0[2]
+#define w4 d0[3]
+#define w5 d1[0]
+#define w6 d1[1]
+#define w7 d1[2]
+#define w4c d1[3]
+
+ .macro idct_col4_top
+ vmull.s16 q7, d6, w2 /* q9 = W2 * col[2] */
+ vmull.s16 q8, d6, w6 /* q10 = W6 * col[2] */
+ vmull.s16 q9, d4, w1 /* q9 = W1 * col[1] */
+ vadd.i32 q11, q15, q7
+ vmull.s16 q10, d4, w3 /* q10 = W3 * col[1] */
+ vadd.i32 q12, q15, q8
+ vmull.s16 q5, d4, w5 /* q5 = W5 * col[1] */
+ vsub.i32 q13, q15, q8
+ vmull.s16 q6, d4, w7 /* q6 = W7 * col[1] */
+ vsub.i32 q14, q15, q7
+
+ vmlal.s16 q9, d8, w3 /* q9 += W3 * col[3] */
+ vmlsl.s16 q10, d8, w7 /* q10 -= W7 * col[3] */
+ vmlsl.s16 q5, d8, w1 /* q5 -= W1 * col[3] */
+ vmlsl.s16 q6, d8, w5 /* q6 -= W5 * col[3] */
+ .endm
+
+ .text
+ .align 6
+
+function idct_row4_pld_neon
+ pld [r0]
+ add r3, r0, r1, lsl #2
+ pld [r0, r1]
+ pld [r0, r1, lsl #1]
+ pld [r3, -r1]
+ pld [r3]
+ pld [r3, r1]
+ add r3, r3, r1, lsl #1
+ pld [r3]
+ pld [r3, r1]
+endfunc
+
+function idct_row4_neon
+ vmov.i32 q15, #(1<<(ROW_SHIFT-1))
+ vld1.64 {d2-d5}, [r2,:128]!
+ vmlal.s16 q15, d2, w4 /* q15 += W4 * col[0] */
+ vld1.64 {d6,d7}, [r2,:128]!
+ vorr d10, d3, d5
+ vld1.64 {d8,d9}, [r2,:128]!
+ add r2, r2, #-64
+
+ vorr d11, d7, d9
+ vorr d10, d10, d11
+ vmov r3, r4, d10
+
+ idct_col4_top
+
+ orrs r3, r3, r4
+ beq 1f
+
+ vmull.s16 q7, d3, w4 /* q7 = W4 * col[4] */
+ vmlal.s16 q9, d5, w5 /* q9 += W5 * col[5] */
+ vmlsl.s16 q10, d5, w1 /* q10 -= W1 * col[5] */
+ vmull.s16 q8, d7, w2 /* q8 = W2 * col[6] */
+ vmlal.s16 q5, d5, w7 /* q5 += W7 * col[5] */
+ vadd.i32 q11, q11, q7
+ vsub.i32 q12, q12, q7
+ vsub.i32 q13, q13, q7
+ vadd.i32 q14, q14, q7
+ vmlal.s16 q6, d5, w3 /* q6 += W3 * col[5] */
+ vmull.s16 q7, d7, w6 /* q7 = W6 * col[6] */
+ vmlal.s16 q9, d9, w7
+ vmlsl.s16 q10, d9, w5
+ vmlal.s16 q5, d9, w3
+ vmlsl.s16 q6, d9, w1
+ vadd.i32 q11, q11, q7
+ vsub.i32 q12, q12, q8
+ vadd.i32 q13, q13, q8
+ vsub.i32 q14, q14, q7
+
+1: vadd.i32 q3, q11, q9
+ vadd.i32 q4, q12, q10
+ vshrn.i32 d2, q3, #ROW_SHIFT
+ vshrn.i32 d4, q4, #ROW_SHIFT
+ vadd.i32 q7, q13, q5
+ vadd.i32 q8, q14, q6
+ vtrn.16 d2, d4
+ vshrn.i32 d6, q7, #ROW_SHIFT
+ vshrn.i32 d8, q8, #ROW_SHIFT
+ vsub.i32 q14, q14, q6
+ vsub.i32 q11, q11, q9
+ vtrn.16 d6, d8
+ vsub.i32 q13, q13, q5
+ vshrn.i32 d3, q14, #ROW_SHIFT
+ vtrn.32 d2, d6
+ vsub.i32 q12, q12, q10
+ vtrn.32 d4, d8
+ vshrn.i32 d5, q13, #ROW_SHIFT
+ vshrn.i32 d7, q12, #ROW_SHIFT
+ vshrn.i32 d9, q11, #ROW_SHIFT
+
+ vtrn.16 d3, d5
+ vtrn.16 d7, d9
+ vtrn.32 d3, d7
+ vtrn.32 d5, d9
+
+ vst1.64 {d2-d5}, [r2,:128]!
+ vst1.64 {d6-d9}, [r2,:128]!
+
+ bx lr
+endfunc
+
+function idct_col4_neon
+ mov ip, #16
+ vld1.64 {d2}, [r2,:64], ip /* d2 = col[0] */
+ vdup.16 d30, w4c
+ vld1.64 {d4}, [r2,:64], ip /* d3 = col[1] */
+ vadd.i16 d30, d30, d2
+ vld1.64 {d6}, [r2,:64], ip /* d4 = col[2] */
+ vmull.s16 q15, d30, w4 /* q15 = W4*(col[0]+(1<<COL_SHIFT-1)/W4)*/
+ vld1.64 {d8}, [r2,:64], ip /* d5 = col[3] */
+
+ ldrd r4, [r2]
+ ldrd r6, [r2, #16]
+ orrs r4, r4, r5
+
+ idct_col4_top
+ addeq r2, r2, #16
+ beq 1f
+
+ vld1.64 {d3}, [r2,:64], ip /* d6 = col[4] */
+ vmull.s16 q7, d3, w4 /* q7 = W4 * col[4] */
+ vadd.i32 q11, q11, q7
+ vsub.i32 q12, q12, q7
+ vsub.i32 q13, q13, q7
+ vadd.i32 q14, q14, q7
+
+1: orrs r6, r6, r7
+ ldrd r4, [r2, #16]
+ addeq r2, r2, #16
+ beq 2f
+
+ vld1.64 {d5}, [r2,:64], ip /* d7 = col[5] */
+ vmlal.s16 q9, d5, w5 /* q9 += W5 * col[5] */
+ vmlsl.s16 q10, d5, w1 /* q10 -= W1 * col[5] */
+ vmlal.s16 q5, d5, w7 /* q5 += W7 * col[5] */
+ vmlal.s16 q6, d5, w3 /* q6 += W3 * col[5] */
+
+2: orrs r4, r4, r5
+ ldrd r4, [r2, #16]
+ addeq r2, r2, #16
+ beq 3f
+
+ vld1.64 {d7}, [r2,:64], ip /* d8 = col[6] */
+ vmull.s16 q7, d7, w6 /* q7 = W6 * col[6] */
+ vmull.s16 q8, d7, w2 /* q8 = W2 * col[6] */
+ vadd.i32 q11, q11, q7
+ vsub.i32 q14, q14, q7
+ vsub.i32 q12, q12, q8
+ vadd.i32 q13, q13, q8
+
+3: orrs r4, r4, r5
+ addeq r2, r2, #16
+ beq 4f
+
+ vld1.64 {d9}, [r2,:64], ip /* d9 = col[7] */
+ vmlal.s16 q9, d9, w7
+ vmlsl.s16 q10, d9, w5
+ vmlal.s16 q5, d9, w3
+ vmlsl.s16 q6, d9, w1
+
+4: vaddhn.i32 d2, q11, q9
+ vaddhn.i32 d3, q12, q10
+ vaddhn.i32 d4, q13, q5
+ vaddhn.i32 d5, q14, q6
+ vsubhn.i32 d9, q11, q9
+ vsubhn.i32 d8, q12, q10
+ vsubhn.i32 d7, q13, q5
+ vsubhn.i32 d6, q14, q6
+
+ bx lr
+endfunc
+
+ .align 6
+
+function idct_col4_st8_neon
+ vqshrun.s16 d2, q1, #COL_SHIFT-16
+ vqshrun.s16 d3, q2, #COL_SHIFT-16
+ vqshrun.s16 d4, q3, #COL_SHIFT-16
+ vqshrun.s16 d5, q4, #COL_SHIFT-16
+ vst1.32 {d2[0]}, [r0,:32], r1
+ vst1.32 {d2[1]}, [r0,:32], r1
+ vst1.32 {d3[0]}, [r0,:32], r1
+ vst1.32 {d3[1]}, [r0,:32], r1
+ vst1.32 {d4[0]}, [r0,:32], r1
+ vst1.32 {d4[1]}, [r0,:32], r1
+ vst1.32 {d5[0]}, [r0,:32], r1
+ vst1.32 {d5[1]}, [r0,:32], r1
+
+ bx lr
+endfunc
+
+ .section .rodata
+ .align 4
+idct_coeff_neon:
+ .short W1, W2, W3, W4, W5, W6, W7, W4c
+
+ .macro idct_start data
+ push {r4-r7, lr}
+ pld [\data]
+ pld [\data, #64]
+ vpush {d8-d15}
+ movrel r3, idct_coeff_neon
+ vld1.64 {d0,d1}, [r3,:128]
+ .endm
+
+ .macro idct_end
+ vpop {d8-d15}
+ pop {r4-r7, pc}
+ .endm
+
+/* void ff_simple_idct_put_neon(uint8_t *dst, int line_size, DCTELEM *data); */
+function ff_simple_idct_put_neon, export=1
+ idct_start r2
+
+ bl idct_row4_pld_neon
+ bl idct_row4_neon
+ add r2, r2, #-128
+ bl idct_col4_neon
+ bl idct_col4_st8_neon
+ sub r0, r0, r1, lsl #3
+ add r0, r0, #4
+ add r2, r2, #-120
+ bl idct_col4_neon
+ bl idct_col4_st8_neon
+
+ idct_end
+endfunc
+
+ .align 6
+
+function idct_col4_add8_neon
+ mov ip, r0
+
+ vld1.32 {d10[0]}, [r0,:32], r1
+ vshr.s16 q1, q1, #COL_SHIFT-16
+ vld1.32 {d10[1]}, [r0,:32], r1
+ vshr.s16 q2, q2, #COL_SHIFT-16
+ vld1.32 {d11[0]}, [r0,:32], r1
+ vshr.s16 q3, q3, #COL_SHIFT-16
+ vld1.32 {d11[1]}, [r0,:32], r1
+ vshr.s16 q4, q4, #COL_SHIFT-16
+ vld1.32 {d12[0]}, [r0,:32], r1
+ vaddw.u8 q1, q1, d10
+ vld1.32 {d12[1]}, [r0,:32], r1
+ vaddw.u8 q2, q2, d11
+ vld1.32 {d13[0]}, [r0,:32], r1
+ vqmovun.s16 d2, q1
+ vld1.32 {d13[1]}, [r0,:32], r1
+ vaddw.u8 q3, q3, d12
+ vst1.32 {d2[0]}, [ip,:32], r1
+ vqmovun.s16 d3, q2
+ vst1.32 {d2[1]}, [ip,:32], r1
+ vaddw.u8 q4, q4, d13
+ vst1.32 {d3[0]}, [ip,:32], r1
+ vqmovun.s16 d4, q3
+ vst1.32 {d3[1]}, [ip,:32], r1
+ vqmovun.s16 d5, q4
+ vst1.32 {d4[0]}, [ip,:32], r1
+ vst1.32 {d4[1]}, [ip,:32], r1
+ vst1.32 {d5[0]}, [ip,:32], r1
+ vst1.32 {d5[1]}, [ip,:32], r1
+
+ bx lr
+endfunc
+
+/* void ff_simple_idct_add_neon(uint8_t *dst, int line_size, DCTELEM *data); */
+function ff_simple_idct_add_neon, export=1
+ idct_start r2
+
+ bl idct_row4_pld_neon
+ bl idct_row4_neon
+ add r2, r2, #-128
+ bl idct_col4_neon
+ bl idct_col4_add8_neon
+ sub r0, r0, r1, lsl #3
+ add r0, r0, #4
+ add r2, r2, #-120
+ bl idct_col4_neon
+ bl idct_col4_add8_neon
+
+ idct_end
+endfunc
+
+ .align 6
+
+function idct_col4_st16_neon
+ mov ip, #16
+
+ vshr.s16 q1, q1, #COL_SHIFT-16
+ vshr.s16 q2, q2, #COL_SHIFT-16
+ vst1.64 {d2}, [r2,:64], ip
+ vshr.s16 q3, q3, #COL_SHIFT-16
+ vst1.64 {d3}, [r2,:64], ip
+ vshr.s16 q4, q4, #COL_SHIFT-16
+ vst1.64 {d4}, [r2,:64], ip
+ vst1.64 {d5}, [r2,:64], ip
+ vst1.64 {d6}, [r2,:64], ip
+ vst1.64 {d7}, [r2,:64], ip
+ vst1.64 {d8}, [r2,:64], ip
+ vst1.64 {d9}, [r2,:64], ip
+
+ bx lr
+endfunc
+
+/* void ff_simple_idct_neon(DCTELEM *data); */
+function ff_simple_idct_neon, export=1
+ idct_start r0
+
+ mov r2, r0
+ bl idct_row4_neon
+ bl idct_row4_neon
+ add r2, r2, #-128
+ bl idct_col4_neon
+ add r2, r2, #-128
+ bl idct_col4_st16_neon
+ add r2, r2, #-120
+ bl idct_col4_neon
+ add r2, r2, #-128
+ bl idct_col4_st16_neon
+
+ idct_end
+endfunc
diff --git a/plugins/supereq/ffmpeg_fft/libavcodec/avfft.c b/plugins/supereq/ffmpeg_fft/libavcodec/avfft.c
new file mode 100644
index 00000000..25fc4e09
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavcodec/avfft.c
@@ -0,0 +1,142 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/mem.h"
+#include "avfft.h"
+#include "fft.h"
+
+/* FFT */
+
+FFTContext *av_fft_init(int nbits, int inverse)
+{
+ FFTContext *s = av_malloc(sizeof(*s));
+
+ if (s)
+ ff_fft_init(s, nbits, inverse);
+
+ return s;
+}
+
+void av_fft_permute(FFTContext *s, FFTComplex *z)
+{
+ s->fft_permute(s, z);
+}
+
+void av_fft_calc(FFTContext *s, FFTComplex *z)
+{
+ s->fft_calc(s, z);
+}
+
+void av_fft_end(FFTContext *s)
+{
+ if (s) {
+ ff_fft_end(s);
+ av_free(s);
+ }
+}
+
+#if CONFIG_MDCT
+
+FFTContext *av_mdct_init(int nbits, int inverse, double scale)
+{
+ FFTContext *s = av_malloc(sizeof(*s));
+
+ if (s)
+ ff_mdct_init(s, nbits, inverse, scale);
+
+ return s;
+}
+
+void av_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input)
+{
+ s->imdct_calc(s, output, input);
+}
+
+void av_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input)
+{
+ s->imdct_half(s, output, input);
+}
+
+void av_mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input)
+{
+ s->mdct_calc(s, output, input);
+}
+
+void av_mdct_end(FFTContext *s)
+{
+ if (s) {
+ ff_mdct_end(s);
+ av_free(s);
+ }
+}
+
+#endif /* CONFIG_MDCT */
+
+#if CONFIG_RDFT
+
+RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans)
+{
+ RDFTContext *s = av_malloc(sizeof(*s));
+
+ if (s)
+ ff_rdft_init(s, nbits, trans);
+
+ return s;
+}
+
+void av_rdft_calc(RDFTContext *s, FFTSample *data)
+{
+ ff_rdft_calc(s, data);
+}
+
+void av_rdft_end(RDFTContext *s)
+{
+ if (s) {
+ ff_rdft_end(s);
+ av_free(s);
+ }
+}
+
+#endif /* CONFIG_RDFT */
+
+#if CONFIG_DCT
+
+DCTContext *av_dct_init(int nbits, enum DCTTransformType inverse)
+{
+ DCTContext *s = av_malloc(sizeof(*s));
+
+ if (s)
+ ff_dct_init(s, nbits, inverse);
+
+ return s;
+}
+
+void av_dct_calc(DCTContext *s, FFTSample *data)
+{
+ ff_dct_calc(s, data);
+}
+
+void av_dct_end(DCTContext *s)
+{
+ if (s) {
+ ff_dct_end(s);
+ av_free(s);
+ }
+}
+
+#endif /* CONFIG_DCT */
diff --git a/plugins/supereq/ffmpeg_fft/libavcodec/avfft.h b/plugins/supereq/ffmpeg_fft/libavcodec/avfft.h
new file mode 100644
index 00000000..fdf30237
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavcodec/avfft.h
@@ -0,0 +1,103 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_AVFFT_H
+#define AVCODEC_AVFFT_H
+
+#include "publik.h"
+
+typedef float FFTSample;
+
+typedef struct FFTComplex {
+ FFTSample re, im;
+} FFTComplex;
+
+typedef struct FFTContext FFTContext;
+
+/**
+ * Set up a complex FFT.
+ * @param nbits log2 of the length of the input array
+ * @param inverse if 0 perform the forward transform, if 1 perform the inverse
+ */
+PUBLIK FFTContext *av_fft_init(int nbits, int inverse);
+
+/**
+ * Do the permutation needed BEFORE calling ff_fft_calc().
+ */
+PUBLIK void av_fft_permute(FFTContext *s, FFTComplex *z);
+
+/**
+ * Do a complex FFT with the parameters defined in av_fft_init(). The
+ * input data must be permuted before. No 1.0/sqrt(n) normalization is done.
+ */
+PUBLIK void av_fft_calc(FFTContext *s, FFTComplex *z);
+
+PUBLIK void av_fft_end(FFTContext *s);
+
+#if 0
+FFTContext *av_mdct_init(int nbits, int inverse, double scale);
+void av_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input);
+void av_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input);
+void av_mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input);
+void av_mdct_end(FFTContext *s);
+#endif
+
+/* Real Discrete Fourier Transform */
+
+enum RDFTransformType {
+ DFT_R2C,
+ IDFT_C2R,
+ IDFT_R2C,
+ DFT_C2R,
+};
+
+typedef struct RDFTContext RDFTContext;
+
+/**
+ * Set up a real FFT.
+ * @param nbits log2 of the length of the input array
+ * @param trans the type of transform
+ */
+PUBLIK RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans);
+PUBLIK void av_rdft_calc(RDFTContext *s, FFTSample *data);
+PUBLIK void av_rdft_end(RDFTContext *s);
+
+/* Discrete Cosine Transform */
+
+typedef struct DCTContext DCTContext;
+
+enum DCTTransformType {
+ DCT_II = 0,
+ DCT_III,
+ DCT_I,
+ DST_I,
+};
+
+/**
+ * Set up DCT.
+ * @param nbits size of the input array:
+ * (1 << nbits) for DCT-II, DCT-III and DST-I
+ * (1 << nbits) + 1 for DCT-I
+ *
+ * @note the first element of the input of DST-I is ignored
+ */
+PUBLIK DCTContext *av_dct_init(int nbits, enum DCTTransformType type);
+PUBLIK void av_dct_calc(DCTContext *s, FFTSample *data);
+PUBLIK void av_dct_end (DCTContext *s);
+
+#endif /* AVCODEC_AVFFT_H */
diff --git a/plugins/supereq/ffmpeg_fft/libavcodec/dct.c b/plugins/supereq/ffmpeg_fft/libavcodec/dct.c
new file mode 100644
index 00000000..6ea1936e
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavcodec/dct.c
@@ -0,0 +1,228 @@
+/*
+ * (I)DCT Transforms
+ * Copyright (c) 2009 Peter Ross <pross@xvid.org>
+ * Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
+ * Copyright (c) 2010 Vitor Sessak
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * (Inverse) Discrete Cosine Transforms. These are also known as the
+ * type II and type III DCTs respectively.
+ */
+
+#include <math.h>
+#include "libavutil/mathematics.h"
+#include "fft.h"
+#ifndef ARCH_ARM
+#include "x86/fft.h"
+#endif
+
+#define DCT32_FLOAT
+#include "dct32.h"
+
+/* sin((M_PI * x / (2*n)) */
+#define SIN(s,n,x) (s->costab[(n) - (x)])
+
+/* cos((M_PI * x / (2*n)) */
+#define COS(s,n,x) (s->costab[x])
+
+static void ff_dst_calc_I_c(DCTContext *ctx, FFTSample *data)
+{
+ int n = 1 << ctx->nbits;
+ int i;
+
+ data[0] = 0;
+ for(i = 1; i < n/2; i++) {
+ float tmp1 = data[i ];
+ float tmp2 = data[n - i];
+ float s = SIN(ctx, n, 2*i);
+
+ s *= tmp1 + tmp2;
+ tmp1 = (tmp1 - tmp2) * 0.5f;
+ data[i ] = s + tmp1;
+ data[n - i] = s - tmp1;
+ }
+
+ data[n/2] *= 2;
+ ff_rdft_calc(&ctx->rdft, data);
+
+ data[0] *= 0.5f;
+
+ for(i = 1; i < n-2; i += 2) {
+ data[i + 1] += data[i - 1];
+ data[i ] = -data[i + 2];
+ }
+
+ data[n-1] = 0;
+}
+
+static void ff_dct_calc_I_c(DCTContext *ctx, FFTSample *data)
+{
+ int n = 1 << ctx->nbits;
+ int i;
+ float next = -0.5f * (data[0] - data[n]);
+
+ for(i = 0; i < n/2; i++) {
+ float tmp1 = data[i ];
+ float tmp2 = data[n - i];
+ float s = SIN(ctx, n, 2*i);
+ float c = COS(ctx, n, 2*i);
+
+ c *= tmp1 - tmp2;
+ s *= tmp1 - tmp2;
+
+ next += c;
+
+ tmp1 = (tmp1 + tmp2) * 0.5f;
+ data[i ] = tmp1 - s;
+ data[n - i] = tmp1 + s;
+ }
+
+ ff_rdft_calc(&ctx->rdft, data);
+ data[n] = data[1];
+ data[1] = next;
+
+ for(i = 3; i <= n; i += 2)
+ data[i] = data[i - 2] - data[i];
+}
+
+static void ff_dct_calc_III_c(DCTContext *ctx, FFTSample *data)
+{
+ int n = 1 << ctx->nbits;
+ int i;
+
+ float next = data[n - 1];
+ float inv_n = 1.0f / n;
+
+ for (i = n - 2; i >= 2; i -= 2) {
+ float val1 = data[i ];
+ float val2 = data[i - 1] - data[i + 1];
+ float c = COS(ctx, n, i);
+ float s = SIN(ctx, n, i);
+
+ data[i ] = c * val1 + s * val2;
+ data[i + 1] = s * val1 - c * val2;
+ }
+
+ data[1] = 2 * next;
+
+ ff_rdft_calc(&ctx->rdft, data);
+
+ for (i = 0; i < n / 2; i++) {
+ float tmp1 = data[i ] * inv_n;
+ float tmp2 = data[n - i - 1] * inv_n;
+ float csc = ctx->csc2[i] * (tmp1 - tmp2);
+
+ tmp1 += tmp2;
+ data[i ] = tmp1 + csc;
+ data[n - i - 1] = tmp1 - csc;
+ }
+}
+
+static void ff_dct_calc_II_c(DCTContext *ctx, FFTSample *data)
+{
+ int n = 1 << ctx->nbits;
+ int i;
+ float next;
+
+ for (i=0; i < n/2; i++) {
+ float tmp1 = data[i ];
+ float tmp2 = data[n - i - 1];
+ float s = SIN(ctx, n, 2*i + 1);
+
+ s *= tmp1 - tmp2;
+ tmp1 = (tmp1 + tmp2) * 0.5f;
+
+ data[i ] = tmp1 + s;
+ data[n-i-1] = tmp1 - s;
+ }
+
+ ff_rdft_calc(&ctx->rdft, data);
+
+ next = data[1] * 0.5;
+ data[1] *= -1;
+
+ for (i = n - 2; i >= 0; i -= 2) {
+ float inr = data[i ];
+ float ini = data[i + 1];
+ float c = COS(ctx, n, i);
+ float s = SIN(ctx, n, i);
+
+ data[i ] = c * inr + s * ini;
+
+ data[i+1] = next;
+
+ next += s * inr - c * ini;
+ }
+}
+
+static void dct32_func(DCTContext *ctx, FFTSample *data)
+{
+ ctx->dct32(data, data);
+}
+
+void ff_dct_calc(DCTContext *s, FFTSample *data)
+{
+ s->dct_calc(s, data);
+}
+
+av_cold int ff_dct_init(DCTContext *s, int nbits, enum DCTTransformType inverse)
+{
+ int n = 1 << nbits;
+ int i;
+
+ s->nbits = nbits;
+ s->inverse = inverse;
+
+ ff_init_ff_cos_tabs(nbits+2);
+
+ s->costab = ff_cos_tabs[nbits+2];
+
+ s->csc2 = av_malloc(n/2 * sizeof(FFTSample));
+
+ if (ff_rdft_init(&s->rdft, nbits, inverse == DCT_III) < 0) {
+ av_free(s->csc2);
+ return -1;
+ }
+
+ for (i = 0; i < n/2; i++)
+ s->csc2[i] = 0.5 / sin((M_PI / (2*n) * (2*i + 1)));
+
+ switch(inverse) {
+ case DCT_I : s->dct_calc = ff_dct_calc_I_c; break;
+ case DCT_II : s->dct_calc = ff_dct_calc_II_c ; break;
+ case DCT_III: s->dct_calc = ff_dct_calc_III_c; break;
+ case DST_I : s->dct_calc = ff_dst_calc_I_c; break;
+ }
+
+ if (inverse == DCT_II && nbits == 5)
+ s->dct_calc = dct32_func;
+
+ s->dct32 = dct32;
+ if (HAVE_MMX) ff_dct_init_mmx(s);
+
+ return 0;
+}
+
+av_cold void ff_dct_end(DCTContext *s)
+{
+ ff_rdft_end(&s->rdft);
+ av_free(s->csc2);
+}
diff --git a/plugins/supereq/ffmpeg_fft/libavcodec/dct32.c b/plugins/supereq/ffmpeg_fft/libavcodec/dct32.c
new file mode 100644
index 00000000..3e6ad78d
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavcodec/dct32.c
@@ -0,0 +1,262 @@
+/*
+ * Template for the Discrete Cosine Transform for 32 samples
+ * Copyright (c) 2001, 2002 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dct32.h"
+
+/* tab[i][j] = 1.0 / (2.0 * cos(pi*(2*k+1) / 2^(6 - j))) */
+
+/* cos(i*pi/64) */
+
+#define COS0_0 FIXHR(0.50060299823519630134/2)
+#define COS0_1 FIXHR(0.50547095989754365998/2)
+#define COS0_2 FIXHR(0.51544730992262454697/2)
+#define COS0_3 FIXHR(0.53104259108978417447/2)
+#define COS0_4 FIXHR(0.55310389603444452782/2)
+#define COS0_5 FIXHR(0.58293496820613387367/2)
+#define COS0_6 FIXHR(0.62250412303566481615/2)
+#define COS0_7 FIXHR(0.67480834145500574602/2)
+#define COS0_8 FIXHR(0.74453627100229844977/2)
+#define COS0_9 FIXHR(0.83934964541552703873/2)
+#define COS0_10 FIXHR(0.97256823786196069369/2)
+#define COS0_11 FIXHR(1.16943993343288495515/4)
+#define COS0_12 FIXHR(1.48416461631416627724/4)
+#define COS0_13 FIXHR(2.05778100995341155085/8)
+#define COS0_14 FIXHR(3.40760841846871878570/8)
+#define COS0_15 FIXHR(10.19000812354805681150/32)
+
+#define COS1_0 FIXHR(0.50241928618815570551/2)
+#define COS1_1 FIXHR(0.52249861493968888062/2)
+#define COS1_2 FIXHR(0.56694403481635770368/2)
+#define COS1_3 FIXHR(0.64682178335999012954/2)
+#define COS1_4 FIXHR(0.78815462345125022473/2)
+#define COS1_5 FIXHR(1.06067768599034747134/4)
+#define COS1_6 FIXHR(1.72244709823833392782/4)
+#define COS1_7 FIXHR(5.10114861868916385802/16)
+
+#define COS2_0 FIXHR(0.50979557910415916894/2)
+#define COS2_1 FIXHR(0.60134488693504528054/2)
+#define COS2_2 FIXHR(0.89997622313641570463/2)
+#define COS2_3 FIXHR(2.56291544774150617881/8)
+
+#define COS3_0 FIXHR(0.54119610014619698439/2)
+#define COS3_1 FIXHR(1.30656296487637652785/4)
+
+#define COS4_0 FIXHR(0.70710678118654752439/2)
+
+/* butterfly operator */
+#define BF(a, b, c, s)\
+{\
+ tmp0 = val##a + val##b;\
+ tmp1 = val##a - val##b;\
+ val##a = tmp0;\
+ val##b = MULH3(tmp1, c, 1<<(s));\
+}
+
+#define BF0(a, b, c, s)\
+{\
+ tmp0 = tab[a] + tab[b];\
+ tmp1 = tab[a] - tab[b];\
+ val##a = tmp0;\
+ val##b = MULH3(tmp1, c, 1<<(s));\
+}
+
+#define BF1(a, b, c, d)\
+{\
+ BF(a, b, COS4_0, 1);\
+ BF(c, d,-COS4_0, 1);\
+ val##c += val##d;\
+}
+
+#define BF2(a, b, c, d)\
+{\
+ BF(a, b, COS4_0, 1);\
+ BF(c, d,-COS4_0, 1);\
+ val##c += val##d;\
+ val##a += val##c;\
+ val##c += val##b;\
+ val##b += val##d;\
+}
+
+#define ADD(a, b) val##a += val##b
+
+/* DCT32 without 1/sqrt(2) coef zero scaling. */
+void dct32(INTFLOAT *out, const INTFLOAT *tab)
+{
+ INTFLOAT tmp0, tmp1;
+
+ INTFLOAT val0 , val1 , val2 , val3 , val4 , val5 , val6 , val7 ,
+ val8 , val9 , val10, val11, val12, val13, val14, val15,
+ val16, val17, val18, val19, val20, val21, val22, val23,
+ val24, val25, val26, val27, val28, val29, val30, val31;
+
+ /* pass 1 */
+ BF0( 0, 31, COS0_0 , 1);
+ BF0(15, 16, COS0_15, 5);
+ /* pass 2 */
+ BF( 0, 15, COS1_0 , 1);
+ BF(16, 31,-COS1_0 , 1);
+ /* pass 1 */
+ BF0( 7, 24, COS0_7 , 1);
+ BF0( 8, 23, COS0_8 , 1);
+ /* pass 2 */
+ BF( 7, 8, COS1_7 , 4);
+ BF(23, 24,-COS1_7 , 4);
+ /* pass 3 */
+ BF( 0, 7, COS2_0 , 1);
+ BF( 8, 15,-COS2_0 , 1);
+ BF(16, 23, COS2_0 , 1);
+ BF(24, 31,-COS2_0 , 1);
+ /* pass 1 */
+ BF0( 3, 28, COS0_3 , 1);
+ BF0(12, 19, COS0_12, 2);
+ /* pass 2 */
+ BF( 3, 12, COS1_3 , 1);
+ BF(19, 28,-COS1_3 , 1);
+ /* pass 1 */
+ BF0( 4, 27, COS0_4 , 1);
+ BF0(11, 20, COS0_11, 2);
+ /* pass 2 */
+ BF( 4, 11, COS1_4 , 1);
+ BF(20, 27,-COS1_4 , 1);
+ /* pass 3 */
+ BF( 3, 4, COS2_3 , 3);
+ BF(11, 12,-COS2_3 , 3);
+ BF(19, 20, COS2_3 , 3);
+ BF(27, 28,-COS2_3 , 3);
+ /* pass 4 */
+ BF( 0, 3, COS3_0 , 1);
+ BF( 4, 7,-COS3_0 , 1);
+ BF( 8, 11, COS3_0 , 1);
+ BF(12, 15,-COS3_0 , 1);
+ BF(16, 19, COS3_0 , 1);
+ BF(20, 23,-COS3_0 , 1);
+ BF(24, 27, COS3_0 , 1);
+ BF(28, 31,-COS3_0 , 1);
+
+
+
+ /* pass 1 */
+ BF0( 1, 30, COS0_1 , 1);
+ BF0(14, 17, COS0_14, 3);
+ /* pass 2 */
+ BF( 1, 14, COS1_1 , 1);
+ BF(17, 30,-COS1_1 , 1);
+ /* pass 1 */
+ BF0( 6, 25, COS0_6 , 1);
+ BF0( 9, 22, COS0_9 , 1);
+ /* pass 2 */
+ BF( 6, 9, COS1_6 , 2);
+ BF(22, 25,-COS1_6 , 2);
+ /* pass 3 */
+ BF( 1, 6, COS2_1 , 1);
+ BF( 9, 14,-COS2_1 , 1);
+ BF(17, 22, COS2_1 , 1);
+ BF(25, 30,-COS2_1 , 1);
+
+ /* pass 1 */
+ BF0( 2, 29, COS0_2 , 1);
+ BF0(13, 18, COS0_13, 3);
+ /* pass 2 */
+ BF( 2, 13, COS1_2 , 1);
+ BF(18, 29,-COS1_2 , 1);
+ /* pass 1 */
+ BF0( 5, 26, COS0_5 , 1);
+ BF0(10, 21, COS0_10, 1);
+ /* pass 2 */
+ BF( 5, 10, COS1_5 , 2);
+ BF(21, 26,-COS1_5 , 2);
+ /* pass 3 */
+ BF( 2, 5, COS2_2 , 1);
+ BF(10, 13,-COS2_2 , 1);
+ BF(18, 21, COS2_2 , 1);
+ BF(26, 29,-COS2_2 , 1);
+ /* pass 4 */
+ BF( 1, 2, COS3_1 , 2);
+ BF( 5, 6,-COS3_1 , 2);
+ BF( 9, 10, COS3_1 , 2);
+ BF(13, 14,-COS3_1 , 2);
+ BF(17, 18, COS3_1 , 2);
+ BF(21, 22,-COS3_1 , 2);
+ BF(25, 26, COS3_1 , 2);
+ BF(29, 30,-COS3_1 , 2);
+
+ /* pass 5 */
+ BF1( 0, 1, 2, 3);
+ BF2( 4, 5, 6, 7);
+ BF1( 8, 9, 10, 11);
+ BF2(12, 13, 14, 15);
+ BF1(16, 17, 18, 19);
+ BF2(20, 21, 22, 23);
+ BF1(24, 25, 26, 27);
+ BF2(28, 29, 30, 31);
+
+ /* pass 6 */
+
+ ADD( 8, 12);
+ ADD(12, 10);
+ ADD(10, 14);
+ ADD(14, 9);
+ ADD( 9, 13);
+ ADD(13, 11);
+ ADD(11, 15);
+
+ out[ 0] = val0;
+ out[16] = val1;
+ out[ 8] = val2;
+ out[24] = val3;
+ out[ 4] = val4;
+ out[20] = val5;
+ out[12] = val6;
+ out[28] = val7;
+ out[ 2] = val8;
+ out[18] = val9;
+ out[10] = val10;
+ out[26] = val11;
+ out[ 6] = val12;
+ out[22] = val13;
+ out[14] = val14;
+ out[30] = val15;
+
+ ADD(24, 28);
+ ADD(28, 26);
+ ADD(26, 30);
+ ADD(30, 25);
+ ADD(25, 29);
+ ADD(29, 27);
+ ADD(27, 31);
+
+ out[ 1] = val16 + val24;
+ out[17] = val17 + val25;
+ out[ 9] = val18 + val26;
+ out[25] = val19 + val27;
+ out[ 5] = val20 + val28;
+ out[21] = val21 + val29;
+ out[13] = val22 + val30;
+ out[29] = val23 + val31;
+ out[ 3] = val24 + val20;
+ out[19] = val25 + val21;
+ out[11] = val26 + val22;
+ out[27] = val27 + val23;
+ out[ 7] = val28 + val18;
+ out[23] = val29 + val19;
+ out[15] = val30 + val17;
+ out[31] = val31;
+}
diff --git a/plugins/supereq/ffmpeg_fft/libavcodec/dct32.h b/plugins/supereq/ffmpeg_fft/libavcodec/dct32.h
new file mode 100644
index 00000000..dc2d847a
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavcodec/dct32.h
@@ -0,0 +1,10 @@
+#ifndef DCT_32_H
+#define DCT_32_H
+
+#define FIXHR(x) ((float)(x))
+#define MULH3(x, y, s) ((s)*(y)*(x))
+#define INTFLOAT float
+
+void dct32(INTFLOAT *out, const INTFLOAT *tab);
+
+#endif
diff --git a/plugins/supereq/ffmpeg_fft/libavcodec/fft.c b/plugins/supereq/ffmpeg_fft/libavcodec/fft.c
new file mode 100644
index 00000000..04082bf4
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavcodec/fft.c
@@ -0,0 +1,300 @@
+/*
+ * FFT/IFFT transforms
+ * Copyright (c) 2008 Loren Merritt
+ * Copyright (c) 2002 Fabrice Bellard
+ * Partly based on libdjbfft by D. J. Bernstein
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * FFT/IFFT transforms.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "libavutil/mathematics.h"
+#include "fft.h"
+
+/* cos(2*pi*x/n) for 0<=x<=n/4, followed by its reverse */
+#if !CONFIG_HARDCODED_TABLES
+COSTABLE(16);
+COSTABLE(32);
+COSTABLE(64);
+COSTABLE(128);
+COSTABLE(256);
+COSTABLE(512);
+COSTABLE(1024);
+COSTABLE(2048);
+COSTABLE(4096);
+COSTABLE(8192);
+COSTABLE(16384);
+COSTABLE(32768);
+COSTABLE(65536);
+#endif
+COSTABLE_CONST FFTSample * const ff_cos_tabs[] = {
+ NULL, NULL, NULL, NULL,
+ ff_cos_16, ff_cos_32, ff_cos_64, ff_cos_128, ff_cos_256, ff_cos_512, ff_cos_1024,
+ ff_cos_2048, ff_cos_4096, ff_cos_8192, ff_cos_16384, ff_cos_32768, ff_cos_65536,
+};
+
+static int split_radix_permutation(int i, int n, int inverse)
+{
+ int m;
+ if(n <= 2) return i&1;
+ m = n >> 1;
+ if(!(i&m)) return split_radix_permutation(i, m, inverse)*2;
+ m >>= 1;
+ if(inverse == !(i&m)) return split_radix_permutation(i, m, inverse)*4 + 1;
+ else return split_radix_permutation(i, m, inverse)*4 - 1;
+}
+
+av_cold void ff_init_ff_cos_tabs(int index)
+{
+#if !CONFIG_HARDCODED_TABLES
+ int i;
+ int m = 1<<index;
+ double freq = 2*M_PI/m;
+ FFTSample *tab = ff_cos_tabs[index];
+ for(i=0; i<=m/4; i++)
+ tab[i] = cos(i*freq);
+ for(i=1; i<m/4; i++)
+ tab[m/2-i] = tab[i];
+#endif
+}
+
+av_cold int ff_fft_init(FFTContext *s, int nbits, int inverse)
+{
+ int i, j, n;
+
+ if (nbits < 2 || nbits > 16)
+ goto fail;
+ s->nbits = nbits;
+ n = 1 << nbits;
+
+ s->revtab = av_malloc(n * sizeof(uint16_t));
+ if (!s->revtab)
+ goto fail;
+ s->tmp_buf = av_malloc(n * sizeof(FFTComplex));
+ if (!s->tmp_buf)
+ goto fail;
+ s->inverse = inverse;
+
+ s->fft_permute = ff_fft_permute_c;
+ s->fft_calc = ff_fft_calc_c;
+#if CONFIG_MDCT
+ s->imdct_calc = ff_imdct_calc_c;
+ s->imdct_half = ff_imdct_half_c;
+ s->mdct_calc = ff_mdct_calc_c;
+#endif
+
+#if ARCH_ARM
+ ff_fft_init_arm(s);
+#elif HAVE_ALTIVEC
+ if (HAVE_ALTIVEC) ff_fft_init_altivec(s);
+#elif HAVE_MMX
+ if (HAVE_MMX) ff_fft_init_mmx(s);
+#endif
+
+ for(j=4; j<=nbits; j++) {
+ ff_init_ff_cos_tabs(j);
+ }
+ for(i=0; i<n; i++)
+ s->revtab[-split_radix_permutation(i, n, s->inverse) & (n-1)] = i;
+
+ return 0;
+ fail:
+ av_freep(&s->revtab);
+ av_freep(&s->tmp_buf);
+ return -1;
+}
+
+void ff_fft_permute_c(FFTContext *s, FFTComplex *z)
+{
+ int j, np;
+ const uint16_t *revtab = s->revtab;
+ np = 1 << s->nbits;
+ /* TODO: handle split-radix permute in a more optimal way, probably in-place */
+ for(j=0;j<np;j++) s->tmp_buf[revtab[j]] = z[j];
+ memcpy(z, s->tmp_buf, np * sizeof(FFTComplex));
+}
+
+av_cold void ff_fft_end(FFTContext *s)
+{
+ av_freep(&s->revtab);
+ av_freep(&s->tmp_buf);
+}
+
+#define sqrthalf (float)M_SQRT1_2
+
+#define BF(x,y,a,b) {\
+ x = a - b;\
+ y = a + b;\
+}
+
+#define BUTTERFLIES(a0,a1,a2,a3) {\
+ BF(t3, t5, t5, t1);\
+ BF(a2.re, a0.re, a0.re, t5);\
+ BF(a3.im, a1.im, a1.im, t3);\
+ BF(t4, t6, t2, t6);\
+ BF(a3.re, a1.re, a1.re, t4);\
+ BF(a2.im, a0.im, a0.im, t6);\
+}
+
+// force loading all the inputs before storing any.
+// this is slightly slower for small data, but avoids store->load aliasing
+// for addresses separated by large powers of 2.
+#define BUTTERFLIES_BIG(a0,a1,a2,a3) {\
+ FFTSample r0=a0.re, i0=a0.im, r1=a1.re, i1=a1.im;\
+ BF(t3, t5, t5, t1);\
+ BF(a2.re, a0.re, r0, t5);\
+ BF(a3.im, a1.im, i1, t3);\
+ BF(t4, t6, t2, t6);\
+ BF(a3.re, a1.re, r1, t4);\
+ BF(a2.im, a0.im, i0, t6);\
+}
+
+#define TRANSFORM(a0,a1,a2,a3,wre,wim) {\
+ t1 = a2.re * wre + a2.im * wim;\
+ t2 = a2.im * wre - a2.re * wim;\
+ t5 = a3.re * wre - a3.im * wim;\
+ t6 = a3.im * wre + a3.re * wim;\
+ BUTTERFLIES(a0,a1,a2,a3)\
+}
+
+#define TRANSFORM_ZERO(a0,a1,a2,a3) {\
+ t1 = a2.re;\
+ t2 = a2.im;\
+ t5 = a3.re;\
+ t6 = a3.im;\
+ BUTTERFLIES(a0,a1,a2,a3)\
+}
+
+/* z[0...8n-1], w[1...2n-1] */
+#define PASS(name)\
+static void name(FFTComplex *z, const FFTSample *wre, unsigned int n)\
+{\
+ FFTSample t1, t2, t3, t4, t5, t6;\
+ int o1 = 2*n;\
+ int o2 = 4*n;\
+ int o3 = 6*n;\
+ const FFTSample *wim = wre+o1;\
+ n--;\
+\
+ TRANSFORM_ZERO(z[0],z[o1],z[o2],z[o3]);\
+ TRANSFORM(z[1],z[o1+1],z[o2+1],z[o3+1],wre[1],wim[-1]);\
+ do {\
+ z += 2;\
+ wre += 2;\
+ wim -= 2;\
+ TRANSFORM(z[0],z[o1],z[o2],z[o3],wre[0],wim[0]);\
+ TRANSFORM(z[1],z[o1+1],z[o2+1],z[o3+1],wre[1],wim[-1]);\
+ } while(--n);\
+}
+
+PASS(pass)
+#undef BUTTERFLIES
+#define BUTTERFLIES BUTTERFLIES_BIG
+PASS(pass_big)
+
+#define DECL_FFT(n,n2,n4)\
+static void fft##n(FFTComplex *z)\
+{\
+ fft##n2(z);\
+ fft##n4(z+n4*2);\
+ fft##n4(z+n4*3);\
+ pass(z,ff_cos_##n,n4/2);\
+}
+
+static void fft4(FFTComplex *z)
+{
+ FFTSample t1, t2, t3, t4, t5, t6, t7, t8;
+
+ BF(t3, t1, z[0].re, z[1].re);
+ BF(t8, t6, z[3].re, z[2].re);
+ BF(z[2].re, z[0].re, t1, t6);
+ BF(t4, t2, z[0].im, z[1].im);
+ BF(t7, t5, z[2].im, z[3].im);
+ BF(z[3].im, z[1].im, t4, t8);
+ BF(z[3].re, z[1].re, t3, t7);
+ BF(z[2].im, z[0].im, t2, t5);
+}
+
+static void fft8(FFTComplex *z)
+{
+ FFTSample t1, t2, t3, t4, t5, t6, t7, t8;
+
+ fft4(z);
+
+ BF(t1, z[5].re, z[4].re, -z[5].re);
+ BF(t2, z[5].im, z[4].im, -z[5].im);
+ BF(t3, z[7].re, z[6].re, -z[7].re);
+ BF(t4, z[7].im, z[6].im, -z[7].im);
+ BF(t8, t1, t3, t1);
+ BF(t7, t2, t2, t4);
+ BF(z[4].re, z[0].re, z[0].re, t1);
+ BF(z[4].im, z[0].im, z[0].im, t2);
+ BF(z[6].re, z[2].re, z[2].re, t7);
+ BF(z[6].im, z[2].im, z[2].im, t8);
+
+ TRANSFORM(z[1],z[3],z[5],z[7],sqrthalf,sqrthalf);
+}
+
+#if !CONFIG_SMALL
+static void fft16(FFTComplex *z)
+{
+ FFTSample t1, t2, t3, t4, t5, t6;
+
+ fft8(z);
+ fft4(z+8);
+ fft4(z+12);
+
+ TRANSFORM_ZERO(z[0],z[4],z[8],z[12]);
+ TRANSFORM(z[2],z[6],z[10],z[14],sqrthalf,sqrthalf);
+ TRANSFORM(z[1],z[5],z[9],z[13],ff_cos_16[1],ff_cos_16[3]);
+ TRANSFORM(z[3],z[7],z[11],z[15],ff_cos_16[3],ff_cos_16[1]);
+}
+#else
+DECL_FFT(16,8,4)
+#endif
+DECL_FFT(32,16,8)
+DECL_FFT(64,32,16)
+DECL_FFT(128,64,32)
+DECL_FFT(256,128,64)
+DECL_FFT(512,256,128)
+#if !CONFIG_SMALL
+#define pass pass_big
+#endif
+DECL_FFT(1024,512,256)
+DECL_FFT(2048,1024,512)
+DECL_FFT(4096,2048,1024)
+DECL_FFT(8192,4096,2048)
+DECL_FFT(16384,8192,4096)
+DECL_FFT(32768,16384,8192)
+DECL_FFT(65536,32768,16384)
+
+static void (* const fft_dispatch[])(FFTComplex*) = {
+ fft4, fft8, fft16, fft32, fft64, fft128, fft256, fft512, fft1024,
+ fft2048, fft4096, fft8192, fft16384, fft32768, fft65536,
+};
+
+void ff_fft_calc_c(FFTContext *s, FFTComplex *z)
+{
+ fft_dispatch[s->nbits-2](z);
+}
+
diff --git a/plugins/supereq/ffmpeg_fft/libavcodec/fft.h b/plugins/supereq/ffmpeg_fft/libavcodec/fft.h
new file mode 100644
index 00000000..b2e0f540
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavcodec/fft.h
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
+ * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_FFT_H
+#define AVCODEC_FFT_H
+
+#include <stdint.h>
+#include "../config.h"
+#include "libavutil/mem.h"
+#include "avfft.h"
+
+/* FFT computation */
+
+struct FFTContext {
+ int nbits;
+ int inverse;
+ uint16_t *revtab;
+ FFTComplex *tmp_buf;
+ int mdct_size; /* size of MDCT (i.e. number of input data * 2) */
+ int mdct_bits; /* n = 2^nbits */
+ /* pre/post rotation tables */
+ FFTSample *tcos;
+ FFTSample *tsin;
+ void (*fft_permute)(struct FFTContext *s, FFTComplex *z);
+ void (*fft_calc)(struct FFTContext *s, FFTComplex *z);
+ void (*imdct_calc)(struct FFTContext *s, FFTSample *output, const FFTSample *input);
+ void (*imdct_half)(struct FFTContext *s, FFTSample *output, const FFTSample *input);
+ void (*mdct_calc)(struct FFTContext *s, FFTSample *output, const FFTSample *input);
+ int permutation;
+#define FF_MDCT_PERM_NONE 0
+#define FF_MDCT_PERM_INTERLEAVE 1
+};
+
+#if CONFIG_HARDCODED_TABLES
+#define COSTABLE_CONST const
+#define SINTABLE_CONST const
+#define SINETABLE_CONST const
+#else
+#define COSTABLE_CONST
+#define SINTABLE_CONST
+#define SINETABLE_CONST
+#endif
+
+#define COSTABLE(size) \
+ COSTABLE_CONST DECLARE_ALIGNED(16, FFTSample, ff_cos_##size)[size/2]
+#define SINTABLE(size) \
+ SINTABLE_CONST DECLARE_ALIGNED(16, FFTSample, ff_sin_##size)[size/2]
+#define SINETABLE(size) \
+ SINETABLE_CONST DECLARE_ALIGNED(16, float, ff_sine_##size)[size]
+extern COSTABLE(16);
+extern COSTABLE(32);
+extern COSTABLE(64);
+extern COSTABLE(128);
+extern COSTABLE(256);
+extern COSTABLE(512);
+extern COSTABLE(1024);
+extern COSTABLE(2048);
+extern COSTABLE(4096);
+extern COSTABLE(8192);
+extern COSTABLE(16384);
+extern COSTABLE(32768);
+extern COSTABLE(65536);
+extern COSTABLE_CONST FFTSample* const ff_cos_tabs[17];
+
+/**
+ * Initialize the cosine table in ff_cos_tabs[index]
+ * \param index index in ff_cos_tabs array of the table to initialize
+ */
+void ff_init_ff_cos_tabs(int index);
+
+extern SINTABLE(16);
+extern SINTABLE(32);
+extern SINTABLE(64);
+extern SINTABLE(128);
+extern SINTABLE(256);
+extern SINTABLE(512);
+extern SINTABLE(1024);
+extern SINTABLE(2048);
+extern SINTABLE(4096);
+extern SINTABLE(8192);
+extern SINTABLE(16384);
+extern SINTABLE(32768);
+extern SINTABLE(65536);
+
+/**
+ * Set up a complex FFT.
+ * @param nbits log2 of the length of the input array
+ * @param inverse if 0 perform the forward transform, if 1 perform the inverse
+ */
+int ff_fft_init(FFTContext *s, int nbits, int inverse);
+void ff_fft_permute_c(FFTContext *s, FFTComplex *z);
+void ff_fft_calc_c(FFTContext *s, FFTComplex *z);
+
+void ff_fft_init_altivec(FFTContext *s);
+void ff_fft_init_mmx(FFTContext *s);
+void ff_fft_init_arm(FFTContext *s);
+void ff_dct_init_mmx(DCTContext *s);
+
+/**
+ * Do the permutation needed BEFORE calling ff_fft_calc().
+ */
+static inline void ff_fft_permute(FFTContext *s, FFTComplex *z)
+{
+ s->fft_permute(s, z);
+}
+/**
+ * Do a complex FFT with the parameters defined in ff_fft_init(). The
+ * input data must be permuted before. No 1.0/sqrt(n) normalization is done.
+ */
+static inline void ff_fft_calc(FFTContext *s, FFTComplex *z)
+{
+ s->fft_calc(s, z);
+}
+void ff_fft_end(FFTContext *s);
+
+/* MDCT computation */
+
+static inline void ff_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input)
+{
+ s->imdct_calc(s, output, input);
+}
+static inline void ff_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input)
+{
+ s->imdct_half(s, output, input);
+}
+
+static inline void ff_mdct_calc(FFTContext *s, FFTSample *output,
+ const FFTSample *input)
+{
+ s->mdct_calc(s, output, input);
+}
+
+/**
+ * Maximum window size for ff_kbd_window_init.
+ */
+#define FF_KBD_WINDOW_MAX 1024
+
+/**
+ * Generate a Kaiser-Bessel Derived Window.
+ * @param window pointer to half window
+ * @param alpha determines window shape
+ * @param n size of half window, max FF_KBD_WINDOW_MAX
+ */
+void ff_kbd_window_init(float *window, float alpha, int n);
+
+/**
+ * Generate a sine window.
+ * @param window pointer to half window
+ * @param n size of half window
+ */
+void ff_sine_window_init(float *window, int n);
+
+/**
+ * initialize the specified entry of ff_sine_windows
+ */
+void ff_init_ff_sine_windows(int index);
+extern SINETABLE( 32);
+extern SINETABLE( 64);
+extern SINETABLE( 128);
+extern SINETABLE( 256);
+extern SINETABLE( 512);
+extern SINETABLE(1024);
+extern SINETABLE(2048);
+extern SINETABLE(4096);
+extern SINETABLE_CONST float * const ff_sine_windows[13];
+
+int ff_mdct_init(FFTContext *s, int nbits, int inverse, double scale);
+void ff_imdct_calc_c(FFTContext *s, FFTSample *output, const FFTSample *input);
+void ff_imdct_half_c(FFTContext *s, FFTSample *output, const FFTSample *input);
+void ff_mdct_calc_c(FFTContext *s, FFTSample *output, const FFTSample *input);
+void ff_mdct_end(FFTContext *s);
+
+/* Real Discrete Fourier Transform */
+
+struct RDFTContext {
+ int nbits;
+ int inverse;
+ int sign_convention;
+
+ /* pre/post rotation tables */
+ const FFTSample *tcos;
+ SINTABLE_CONST FFTSample *tsin;
+ FFTContext fft;
+ void (*rdft_calc)(struct RDFTContext *s, FFTSample *z);
+};
+
+/**
+ * Set up a real FFT.
+ * @param nbits log2 of the length of the input array
+ * @param trans the type of transform
+ */
+int ff_rdft_init(RDFTContext *s, int nbits, enum RDFTransformType trans);
+void ff_rdft_end(RDFTContext *s);
+
+void ff_rdft_init_arm(RDFTContext *s);
+
+static av_always_inline void ff_rdft_calc(RDFTContext *s, FFTSample *data)
+{
+ s->rdft_calc(s, data);
+}
+
+/* Discrete Cosine Transform */
+
+struct DCTContext {
+ int nbits;
+ int inverse;
+ RDFTContext rdft;
+ const float *costab;
+ FFTSample *csc2;
+ void (*dct_calc)(struct DCTContext *s, FFTSample *data);
+ void (*dct32)(FFTSample *out, const FFTSample *in);
+};
+
+/**
+ * Set up DCT.
+ * @param nbits size of the input array:
+ * (1 << nbits) for DCT-II, DCT-III and DST-I
+ * (1 << nbits) + 1 for DCT-I
+ *
+ * @note the first element of the input of DST-I is ignored
+ */
+int ff_dct_init(DCTContext *s, int nbits, enum DCTTransformType type);
+void ff_dct_calc(DCTContext *s, FFTSample *data);
+void ff_dct_end (DCTContext *s);
+
+#endif /* AVCODEC_FFT_H */
diff --git a/plugins/supereq/ffmpeg_fft/libavcodec/rdft.c b/plugins/supereq/ffmpeg_fft/libavcodec/rdft.c
new file mode 100644
index 00000000..fe6014fb
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavcodec/rdft.c
@@ -0,0 +1,137 @@
+/*
+ * (I)RDFT transforms
+ * Copyright (c) 2009 Alex Converse <alex dot converse at gmail dot com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <stdlib.h>
+#include <math.h>
+#include "libavutil/mathematics.h"
+#include "fft.h"
+
+/**
+ * @file
+ * (Inverse) Real Discrete Fourier Transforms.
+ */
+
+/* sin(2*pi*x/n) for 0<=x<n/4, followed by n/2<=x<3n/4 */
+#if !CONFIG_HARDCODED_TABLES
+SINTABLE(16);
+SINTABLE(32);
+SINTABLE(64);
+SINTABLE(128);
+SINTABLE(256);
+SINTABLE(512);
+SINTABLE(1024);
+SINTABLE(2048);
+SINTABLE(4096);
+SINTABLE(8192);
+SINTABLE(16384);
+SINTABLE(32768);
+SINTABLE(65536);
+#endif
+SINTABLE_CONST FFTSample * const ff_sin_tabs[] = {
+ NULL, NULL, NULL, NULL,
+ ff_sin_16, ff_sin_32, ff_sin_64, ff_sin_128, ff_sin_256, ff_sin_512, ff_sin_1024,
+ ff_sin_2048, ff_sin_4096, ff_sin_8192, ff_sin_16384, ff_sin_32768, ff_sin_65536,
+};
+
+/** Map one real FFT into two parallel real even and odd FFTs. Then interleave
+ * the two real FFTs into one complex FFT. Unmangle the results.
+ * ref: http://www.engineeringproductivitytools.com/stuff/T0001/PT10.HTM
+ */
+static void ff_rdft_calc_c(RDFTContext* s, FFTSample* data)
+{
+ int i, i1, i2;
+ FFTComplex ev, od;
+ const int n = 1 << s->nbits;
+ const float k1 = 0.5;
+ const float k2 = 0.5 - s->inverse;
+ const FFTSample *tcos = s->tcos;
+ const FFTSample *tsin = s->tsin;
+
+ if (!s->inverse) {
+ ff_fft_permute(&s->fft, (FFTComplex*)data);
+ ff_fft_calc(&s->fft, (FFTComplex*)data);
+ }
+ /* i=0 is a special case because of packing, the DC term is real, so we
+ are going to throw the N/2 term (also real) in with it. */
+ ev.re = data[0];
+ data[0] = ev.re+data[1];
+ data[1] = ev.re-data[1];
+ for (i = 1; i < (n>>2); i++) {
+ i1 = 2*i;
+ i2 = n-i1;
+ /* Separate even and odd FFTs */
+ ev.re = k1*(data[i1 ]+data[i2 ]);
+ od.im = -k2*(data[i1 ]-data[i2 ]);
+ ev.im = k1*(data[i1+1]-data[i2+1]);
+ od.re = k2*(data[i1+1]+data[i2+1]);
+ /* Apply twiddle factors to the odd FFT and add to the even FFT */
+ data[i1 ] = ev.re + od.re*tcos[i] - od.im*tsin[i];
+ data[i1+1] = ev.im + od.im*tcos[i] + od.re*tsin[i];
+ data[i2 ] = ev.re - od.re*tcos[i] + od.im*tsin[i];
+ data[i2+1] = -ev.im + od.im*tcos[i] + od.re*tsin[i];
+ }
+ data[2*i+1]=s->sign_convention*data[2*i+1];
+ if (s->inverse) {
+ data[0] *= k1;
+ data[1] *= k1;
+ ff_fft_permute(&s->fft, (FFTComplex*)data);
+ ff_fft_calc(&s->fft, (FFTComplex*)data);
+ }
+}
+
+av_cold int ff_rdft_init(RDFTContext *s, int nbits, enum RDFTransformType trans)
+{
+ int n = 1 << nbits;
+ int i;
+ const double theta = (trans == DFT_R2C || trans == DFT_C2R ? -1 : 1)*2*M_PI/n;
+
+ s->nbits = nbits;
+ s->inverse = trans == IDFT_C2R || trans == DFT_C2R;
+ s->sign_convention = trans == IDFT_R2C || trans == DFT_C2R ? 1 : -1;
+
+ if (nbits < 4 || nbits > 16) {
+ return -1;
+ }
+
+ if (ff_fft_init(&s->fft, nbits-1, trans == IDFT_C2R || trans == IDFT_R2C) < 0) {
+ return -1;
+ }
+
+ ff_init_ff_cos_tabs(nbits);
+ s->tcos = ff_cos_tabs[nbits];
+ s->tsin = ff_sin_tabs[nbits]+(trans == DFT_R2C || trans == DFT_C2R)*(n>>2);
+#if !CONFIG_HARDCODED_TABLES
+ for (i = 0; i < (n>>2); i++) {
+ s->tsin[i] = sin(i*theta);
+ }
+#endif
+ s->rdft_calc = ff_rdft_calc_c;
+
+#if ARCH_ARM
+ ff_rdft_init_arm(s);
+#endif
+
+ return 0;
+}
+
+av_cold void ff_rdft_end(RDFTContext *s)
+{
+ ff_fft_end(&s->fft);
+}
diff --git a/plugins/supereq/ffmpeg_fft/libavutil/attributes.h b/plugins/supereq/ffmpeg_fft/libavutil/attributes.h
new file mode 100644
index 00000000..50fbfc31
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavutil/attributes.h
@@ -0,0 +1,122 @@
+/*
+ * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Macro definitions for various function/variable attributes
+ */
+
+#ifndef AVUTIL_ATTRIBUTES_H
+#define AVUTIL_ATTRIBUTES_H
+
+#ifdef __GNUC__
+# define AV_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > x || __GNUC__ == x && __GNUC_MINOR__ >= y)
+#else
+# define AV_GCC_VERSION_AT_LEAST(x,y) 0
+#endif
+
+#ifndef av_always_inline
+#if AV_GCC_VERSION_AT_LEAST(3,1)
+# define av_always_inline __attribute__((always_inline)) inline
+#else
+# define av_always_inline inline
+#endif
+#endif
+
+#ifndef av_noinline
+#if AV_GCC_VERSION_AT_LEAST(3,1)
+# define av_noinline __attribute__((noinline))
+#else
+# define av_noinline
+#endif
+#endif
+
+#ifndef av_pure
+#if AV_GCC_VERSION_AT_LEAST(3,1)
+# define av_pure __attribute__((pure))
+#else
+# define av_pure
+#endif
+#endif
+
+#ifndef av_const
+#if AV_GCC_VERSION_AT_LEAST(2,6)
+# define av_const __attribute__((const))
+#else
+# define av_const
+#endif
+#endif
+
+#ifndef av_cold
+#if (!defined(__ICC) || __ICC > 1110) && AV_GCC_VERSION_AT_LEAST(4,3)
+# define av_cold __attribute__((cold))
+#else
+# define av_cold
+#endif
+#endif
+
+#ifndef av_flatten
+#if (!defined(__ICC) || __ICC > 1110) && AV_GCC_VERSION_AT_LEAST(4,1)
+# define av_flatten __attribute__((flatten))
+#else
+# define av_flatten
+#endif
+#endif
+
+#ifndef attribute_deprecated
+#if AV_GCC_VERSION_AT_LEAST(3,1)
+# define attribute_deprecated __attribute__((deprecated))
+#else
+# define attribute_deprecated
+#endif
+#endif
+
+#ifndef av_unused
+#if defined(__GNUC__)
+# define av_unused __attribute__((unused))
+#else
+# define av_unused
+#endif
+#endif
+
+#ifndef av_alias
+#if (!defined(__ICC) || __ICC > 1110) && AV_GCC_VERSION_AT_LEAST(3,3)
+# define av_alias __attribute__((may_alias))
+#else
+# define av_alias
+#endif
+#endif
+
+#ifndef av_uninit
+#if defined(__GNUC__) && !defined(__ICC)
+# define av_uninit(x) x=x
+#else
+# define av_uninit(x) x
+#endif
+#endif
+
+#ifdef __GNUC__
+# define av_builtin_constant_p __builtin_constant_p
+#else
+# define av_builtin_constant_p(x) 0
+#endif
+
+#endif /* AVUTIL_ATTRIBUTES_H */
+
diff --git a/plugins/supereq/ffmpeg_fft/libavutil/avconfig.h b/plugins/supereq/ffmpeg_fft/libavutil/avconfig.h
new file mode 100644
index 00000000..b028bb4f
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavutil/avconfig.h
@@ -0,0 +1,5 @@
+/* Generated by ffconf */
+#ifndef AVUTIL_AVCONFIG_H
+#define AVUTIL_AVCONFIG_H
+#define AV_HAVE_BIGENDIAN 0
+#endif /* AVUTIL_AVCONFIG_H */
diff --git a/plugins/supereq/ffmpeg_fft/libavutil/avutil.h b/plugins/supereq/ffmpeg_fft/libavutil/avutil.h
new file mode 100644
index 00000000..f5d364be
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavutil/avutil.h
@@ -0,0 +1,90 @@
+/*
+ * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_AVUTIL_H
+#define AVUTIL_AVUTIL_H
+
+/**
+ * @file
+ * external API header
+ */
+
+
+#define AV_STRINGIFY(s) AV_TOSTRING(s)
+#define AV_TOSTRING(s) #s
+
+#define AV_GLUE(a, b) a ## b
+#define AV_JOIN(a, b) AV_GLUE(a, b)
+
+#define AV_PRAGMA(s) _Pragma(#s)
+
+#define AV_VERSION_INT(a, b, c) (a<<16 | b<<8 | c)
+#define AV_VERSION_DOT(a, b, c) a ##.## b ##.## c
+#define AV_VERSION(a, b, c) AV_VERSION_DOT(a, b, c)
+
+#define LIBAVUTIL_VERSION_MAJOR 50
+#define LIBAVUTIL_VERSION_MINOR 21
+#define LIBAVUTIL_VERSION_MICRO 0
+
+#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
+ LIBAVUTIL_VERSION_MINOR, \
+ LIBAVUTIL_VERSION_MICRO)
+#define LIBAVUTIL_VERSION AV_VERSION(LIBAVUTIL_VERSION_MAJOR, \
+ LIBAVUTIL_VERSION_MINOR, \
+ LIBAVUTIL_VERSION_MICRO)
+#define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT
+
+#define LIBAVUTIL_IDENT "Lavu" AV_STRINGIFY(LIBAVUTIL_VERSION)
+
+/**
+ * Return the LIBAVUTIL_VERSION_INT constant.
+ */
+unsigned avutil_version(void);
+
+/**
+ * Return the libavutil build-time configuration.
+ */
+const char *avutil_configuration(void);
+
+/**
+ * Return the libavutil license.
+ */
+const char *avutil_license(void);
+
+enum AVMediaType {
+ AVMEDIA_TYPE_UNKNOWN = -1,
+ AVMEDIA_TYPE_VIDEO,
+ AVMEDIA_TYPE_AUDIO,
+ AVMEDIA_TYPE_DATA,
+ AVMEDIA_TYPE_SUBTITLE,
+ AVMEDIA_TYPE_ATTACHMENT,
+ AVMEDIA_TYPE_NB
+};
+
+#include "common.h"
+/* #include "error.h" */
+#include "mathematics.h"
+#include "rational.h"
+#include "intfloat_readwrite.h"
+/* #include "log.h" */
+/* #include "pixfmt.h" */
+
+#endif /* AVUTIL_AVUTIL_H */
+
diff --git a/plugins/supereq/ffmpeg_fft/libavutil/common.h b/plugins/supereq/ffmpeg_fft/libavutil/common.h
new file mode 100644
index 00000000..9dff1435
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavutil/common.h
@@ -0,0 +1,347 @@
+/*
+ * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * common internal and external API header
+ */
+
+#ifndef AVUTIL_COMMON_H
+#define AVUTIL_COMMON_H
+
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "attributes.h"
+
+//rounded division & shift
+#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b))
+/* assume b>0 */
+#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b))
+#define FFABS(a) ((a) >= 0 ? (a) : (-(a)))
+#define FFSIGN(a) ((a) > 0 ? 1 : -1)
+
+#define FFMAX(a,b) ((a) > (b) ? (a) : (b))
+#define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c)
+#define FFMIN(a,b) ((a) > (b) ? (b) : (a))
+#define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c)
+
+#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0)
+#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
+#define FFALIGN(x, a) (((x)+(a)-1)&~((a)-1))
+
+/* misc math functions */
+extern const uint8_t ff_log2_tab[256];
+
+extern const uint8_t av_reverse[256];
+
+static inline av_const int av_log2_c(unsigned int v)
+{
+ int n = 0;
+ if (v & 0xffff0000) {
+ v >>= 16;
+ n += 16;
+ }
+ if (v & 0xff00) {
+ v >>= 8;
+ n += 8;
+ }
+ n += ff_log2_tab[v];
+
+ return n;
+}
+
+static inline av_const int av_log2_16bit_c(unsigned int v)
+{
+ int n = 0;
+ if (v & 0xff00) {
+ v >>= 8;
+ n += 8;
+ }
+ n += ff_log2_tab[v];
+
+ return n;
+}
+
+#ifdef HAVE_AV_CONFIG_H
+# include "config.h"
+# include "intmath.h"
+#endif
+
+/* Pull in unguarded fallback defines at the end of this file. */
+#include "common.h"
+
+/**
+ * Clip a signed integer value into the amin-amax range.
+ * @param a value to clip
+ * @param amin minimum value of the clip range
+ * @param amax maximum value of the clip range
+ * @return clipped value
+ */
+static inline av_const int av_clip_c(int a, int amin, int amax)
+{
+ if (a < amin) return amin;
+ else if (a > amax) return amax;
+ else return a;
+}
+
+/**
+ * Clip a signed integer value into the 0-255 range.
+ * @param a value to clip
+ * @return clipped value
+ */
+static inline av_const uint8_t av_clip_uint8_c(int a)
+{
+ if (a&(~0xFF)) return (-a)>>31;
+ else return a;
+}
+
+/**
+ * Clip a signed integer value into the -128,127 range.
+ * @param a value to clip
+ * @return clipped value
+ */
+static inline av_const int8_t av_clip_int8_c(int a)
+{
+ if ((a+0x80) & ~0xFF) return (a>>31) ^ 0x7F;
+ else return a;
+}
+
+/**
+ * Clip a signed integer value into the 0-65535 range.
+ * @param a value to clip
+ * @return clipped value
+ */
+static inline av_const uint16_t av_clip_uint16_c(int a)
+{
+ if (a&(~0xFFFF)) return (-a)>>31;
+ else return a;
+}
+
+/**
+ * Clip a signed integer value into the -32768,32767 range.
+ * @param a value to clip
+ * @return clipped value
+ */
+static inline av_const int16_t av_clip_int16_c(int a)
+{
+ if ((a+0x8000) & ~0xFFFF) return (a>>31) ^ 0x7FFF;
+ else return a;
+}
+
+/**
+ * Clip a signed 64-bit integer value into the -2147483648,2147483647 range.
+ * @param a value to clip
+ * @return clipped value
+ */
+static inline av_const int32_t av_clipl_int32_c(int64_t a)
+{
+ if ((a+0x80000000u) & ~UINT64_C(0xFFFFFFFF)) return (a>>63) ^ 0x7FFFFFFF;
+ else return a;
+}
+
+/**
+ * Clip a float value into the amin-amax range.
+ * @param a value to clip
+ * @param amin minimum value of the clip range
+ * @param amax maximum value of the clip range
+ * @return clipped value
+ */
+static inline av_const float av_clipf_c(float a, float amin, float amax)
+{
+ if (a < amin) return amin;
+ else if (a > amax) return amax;
+ else return a;
+}
+
+/** Compute ceil(log2(x)).
+ * @param x value used to compute ceil(log2(x))
+ * @return computed ceiling of log2(x)
+ */
+static inline av_const int av_ceil_log2_c(int x)
+{
+ return av_log2((x - 1) << 1);
+}
+
+#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
+#define MKBETAG(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((a) << 24))
+
+/**
+ * Convert a UTF-8 character (up to 4 bytes) to its 32-bit UCS-4 encoded form.
+ *
+ * @param val Output value, must be an lvalue of type uint32_t.
+ * @param GET_BYTE Expression reading one byte from the input.
+ * Evaluated up to 7 times (4 for the currently
+ * assigned Unicode range). With a memory buffer
+ * input, this could be *ptr++.
+ * @param ERROR Expression to be evaluated on invalid input,
+ * typically a goto statement.
+ */
+#define GET_UTF8(val, GET_BYTE, ERROR)\
+ val= GET_BYTE;\
+ {\
+ int ones= 7 - av_log2(val ^ 255);\
+ if(ones==1)\
+ ERROR\
+ val&= 127>>ones;\
+ while(--ones > 0){\
+ int tmp= GET_BYTE - 128;\
+ if(tmp>>6)\
+ ERROR\
+ val= (val<<6) + tmp;\
+ }\
+ }
+
+/**
+ * Convert a UTF-16 character (2 or 4 bytes) to its 32-bit UCS-4 encoded form.
+ *
+ * @param val Output value, must be an lvalue of type uint32_t.
+ * @param GET_16BIT Expression returning two bytes of UTF-16 data converted
+ * to native byte order. Evaluated one or two times.
+ * @param ERROR Expression to be evaluated on invalid input,
+ * typically a goto statement.
+ */
+#define GET_UTF16(val, GET_16BIT, ERROR)\
+ val = GET_16BIT;\
+ {\
+ unsigned int hi = val - 0xD800;\
+ if (hi < 0x800) {\
+ val = GET_16BIT - 0xDC00;\
+ if (val > 0x3FFU || hi > 0x3FFU)\
+ ERROR\
+ val += (hi<<10) + 0x10000;\
+ }\
+ }\
+
+/*!
+ * \def PUT_UTF8(val, tmp, PUT_BYTE)
+ * Convert a 32-bit Unicode character to its UTF-8 encoded form (up to 4 bytes long).
+ * \param val is an input-only argument and should be of type uint32_t. It holds
+ * a UCS-4 encoded Unicode character that is to be converted to UTF-8. If
+ * val is given as a function it is executed only once.
+ * \param tmp is a temporary variable and should be of type uint8_t. It
+ * represents an intermediate value during conversion that is to be
+ * output by PUT_BYTE.
+ * \param PUT_BYTE writes the converted UTF-8 bytes to any proper destination.
+ * It could be a function or a statement, and uses tmp as the input byte.
+ * For example, PUT_BYTE could be "*output++ = tmp;" PUT_BYTE will be
+ * executed up to 4 times for values in the valid UTF-8 range and up to
+ * 7 times in the general case, depending on the length of the converted
+ * Unicode character.
+ */
+#define PUT_UTF8(val, tmp, PUT_BYTE)\
+ {\
+ int bytes, shift;\
+ uint32_t in = val;\
+ if (in < 0x80) {\
+ tmp = in;\
+ PUT_BYTE\
+ } else {\
+ bytes = (av_log2(in) + 4) / 5;\
+ shift = (bytes - 1) * 6;\
+ tmp = (256 - (256 >> bytes)) | (in >> shift);\
+ PUT_BYTE\
+ while (shift >= 6) {\
+ shift -= 6;\
+ tmp = 0x80 | ((in >> shift) & 0x3f);\
+ PUT_BYTE\
+ }\
+ }\
+ }
+
+/*!
+ * \def PUT_UTF16(val, tmp, PUT_16BIT)
+ * Convert a 32-bit Unicode character to its UTF-16 encoded form (2 or 4 bytes).
+ * \param val is an input-only argument and should be of type uint32_t. It holds
+ * a UCS-4 encoded Unicode character that is to be converted to UTF-16. If
+ * val is given as a function it is executed only once.
+ * \param tmp is a temporary variable and should be of type uint16_t. It
+ * represents an intermediate value during conversion that is to be
+ * output by PUT_16BIT.
+ * \param PUT_16BIT writes the converted UTF-16 data to any proper destination
+ * in desired endianness. It could be a function or a statement, and uses tmp
+ * as the input byte. For example, PUT_BYTE could be "*output++ = tmp;"
+ * PUT_BYTE will be executed 1 or 2 times depending on input character.
+ */
+#define PUT_UTF16(val, tmp, PUT_16BIT)\
+ {\
+ uint32_t in = val;\
+ if (in < 0x10000) {\
+ tmp = in;\
+ PUT_16BIT\
+ } else {\
+ tmp = 0xD800 | ((in - 0x10000) >> 10);\
+ PUT_16BIT\
+ tmp = 0xDC00 | ((in - 0x10000) & 0x3FF);\
+ PUT_16BIT\
+ }\
+ }\
+
+
+
+#include "mem.h"
+
+#ifdef HAVE_AV_CONFIG_H
+# include "internal.h"
+#endif /* HAVE_AV_CONFIG_H */
+
+#endif /* AVUTIL_COMMON_H */
+
+/*
+ * The following definitions are outside the multiple inclusion guard
+ * to ensure they are immediately available in intmath.h.
+ */
+
+#ifndef av_log2
+# define av_log2 av_log2_c
+#endif
+#ifndef av_log2_16bit
+# define av_log2_16bit av_log2_16bit_c
+#endif
+#ifndef av_ceil_log2
+# define av_ceil_log2 av_ceil_log2_c
+#endif
+#ifndef av_clip
+# define av_clip av_clip_c
+#endif
+#ifndef av_clip_uint8
+# define av_clip_uint8 av_clip_uint8_c
+#endif
+#ifndef av_clip_int8
+# define av_clip_int8 av_clip_int8_c
+#endif
+#ifndef av_clip_uint16
+# define av_clip_uint16 av_clip_uint16_c
+#endif
+#ifndef av_clip_int16
+# define av_clip_int16 av_clip_int16_c
+#endif
+#ifndef av_clipl_int32
+# define av_clipl_int32 av_clipl_int32_c
+#endif
+#ifndef av_clipf
+# define av_clipf av_clipf_c
+#endif
+
diff --git a/plugins/supereq/ffmpeg_fft/libavutil/intfloat_readwrite.c b/plugins/supereq/ffmpeg_fft/libavutil/intfloat_readwrite.c
new file mode 100644
index 00000000..79fe1867
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavutil/intfloat_readwrite.c
@@ -0,0 +1,98 @@
+/*
+ * portable IEEE float/double read/write functions
+ *
+ * Copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * portable IEEE float/double read/write functions
+ */
+
+#include <stdint.h>
+#include <math.h>
+#include "intfloat_readwrite.h"
+
+double av_int2dbl(int64_t v){
+ if(v+v > 0xFFEULL<<52)
+ return 0.0/0.0;
+ return ldexp(((v&((1LL<<52)-1)) + (1LL<<52)) * (v>>63|1), (v>>52&0x7FF)-1075);
+}
+
+float av_int2flt(int32_t v){
+ if(v+v > 0xFF000000U)
+ return 0.0/0.0;
+ return ldexp(((v&0x7FFFFF) + (1<<23)) * (v>>31|1), (v>>23&0xFF)-150);
+}
+
+double av_ext2dbl(const AVExtFloat ext){
+ uint64_t m = 0;
+ int e, i;
+
+ for (i = 0; i < 8; i++)
+ m = (m<<8) + ext.mantissa[i];
+ e = (((int)ext.exponent[0]&0x7f)<<8) | ext.exponent[1];
+ if (e == 0x7fff && m)
+ return 0.0/0.0;
+ e -= 16383 + 63; /* In IEEE 80 bits, the whole (i.e. 1.xxxx)
+ * mantissa bit is written as opposed to the
+ * single and double precision formats. */
+ if (ext.exponent[0]&0x80)
+ m= -m;
+ return ldexp(m, e);
+}
+
+int64_t av_dbl2int(double d){
+ int e;
+ if ( !d) return 0;
+ else if(d-d) return 0x7FF0000000000000LL + ((int64_t)(d<0)<<63) + (d!=d);
+ d= frexp(d, &e);
+ return (int64_t)(d<0)<<63 | (e+1022LL)<<52 | (int64_t)((fabs(d)-0.5)*(1LL<<53));
+}
+
+int32_t av_flt2int(float d){
+ int e;
+ if ( !d) return 0;
+ else if(d-d) return 0x7F800000 + ((d<0)<<31) + (d!=d);
+ d= frexp(d, &e);
+ return (d<0)<<31 | (e+126)<<23 | (int64_t)((fabs(d)-0.5)*(1<<24));
+}
+
+AVExtFloat av_dbl2ext(double d){
+ struct AVExtFloat ext= {{0}};
+ int e, i; double f; uint64_t m;
+
+ f = fabs(frexp(d, &e));
+ if (f >= 0.5 && f < 1) {
+ e += 16382;
+ ext.exponent[0] = e>>8;
+ ext.exponent[1] = e;
+ m = (uint64_t)ldexp(f, 64);
+ for (i=0; i < 8; i++)
+ ext.mantissa[i] = m>>(56-(i<<3));
+ } else if (f != 0.0) {
+ ext.exponent[0] = 0x7f; ext.exponent[1] = 0xff;
+ if (f != 1/0.0)
+ ext.mantissa[0] = ~0;
+ }
+ if (d < 0)
+ ext.exponent[0] |= 0x80;
+ return ext;
+}
+
diff --git a/plugins/supereq/ffmpeg_fft/libavutil/intfloat_readwrite.h b/plugins/supereq/ffmpeg_fft/libavutil/intfloat_readwrite.h
new file mode 100644
index 00000000..644b3e64
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavutil/intfloat_readwrite.h
@@ -0,0 +1,41 @@
+/*
+ * copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_INTFLOAT_READWRITE_H
+#define AVUTIL_INTFLOAT_READWRITE_H
+
+#include <stdint.h>
+#include "attributes.h"
+
+/* IEEE 80 bits extended float */
+typedef struct AVExtFloat {
+ uint8_t exponent[2];
+ uint8_t mantissa[8];
+} AVExtFloat;
+
+double av_int2dbl(int64_t v) av_const;
+float av_int2flt(int32_t v) av_const;
+double av_ext2dbl(const AVExtFloat ext) av_const;
+int64_t av_dbl2int(double d) av_const;
+int32_t av_flt2int(float d) av_const;
+AVExtFloat av_dbl2ext(double d) av_const;
+
+#endif /* AVUTIL_INTFLOAT_READWRITE_H */
+
diff --git a/plugins/supereq/ffmpeg_fft/libavutil/mathematics.c b/plugins/supereq/ffmpeg_fft/libavutil/mathematics.c
new file mode 100644
index 00000000..c6851cb7
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavutil/mathematics.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * miscellaneous math routines and tables
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <limits.h>
+#include "mathematics.h"
+
+const uint8_t ff_sqrt_tab[256]={
+ 0, 16, 23, 28, 32, 36, 40, 43, 46, 48, 51, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 77, 79, 80, 82, 84, 85, 87, 88, 90,
+ 91, 92, 94, 95, 96, 98, 99,100,102,103,104,105,107,108,109,110,111,112,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
+128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,144,145,146,147,148,149,150,151,151,152,153,154,155,156,156,
+157,158,159,160,160,161,162,163,164,164,165,166,167,168,168,169,170,171,171,172,173,174,174,175,176,176,177,178,179,179,180,181,
+182,182,183,184,184,185,186,186,187,188,188,189,190,190,191,192,192,193,194,194,195,196,196,197,198,198,199,200,200,201,202,202,
+203,204,204,205,205,206,207,207,208,208,209,210,210,211,212,212,213,213,214,215,215,216,216,217,218,218,219,219,220,220,221,222,
+222,223,223,224,224,225,226,226,227,227,228,228,229,230,230,231,231,232,232,233,233,234,235,235,236,236,237,237,238,238,239,239,
+240,240,241,242,242,243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,251,252,252,253,253,254,254,255,255,255
+};
+
+const uint8_t ff_log2_tab[256]={
+ 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
+};
+
+const uint8_t av_reverse[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,
+};
+
+int64_t av_gcd(int64_t a, int64_t b){
+ if(b) return av_gcd(b, a%b);
+ else return a;
+}
+
+int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd){
+ int64_t r=0;
+ assert(c > 0);
+ assert(b >=0);
+ assert((unsigned)rnd<=5 && rnd!=4);
+
+ if(a<0 && a != INT64_MIN) return -av_rescale_rnd(-a, b, c, rnd ^ ((rnd>>1)&1));
+
+ if(rnd==AV_ROUND_NEAR_INF) r= c/2;
+ else if(rnd&1) r= c-1;
+
+ if(b<=INT_MAX && c<=INT_MAX){
+ if(a<=INT_MAX)
+ return (a * b + r)/c;
+ else
+ return a/c*b + (a%c*b + r)/c;
+ }else{
+#if 1
+ uint64_t a0= a&0xFFFFFFFF;
+ uint64_t a1= a>>32;
+ uint64_t b0= b&0xFFFFFFFF;
+ uint64_t b1= b>>32;
+ uint64_t t1= a0*b1 + a1*b0;
+ uint64_t t1a= t1<<32;
+ int i;
+
+ a0 = a0*b0 + t1a;
+ a1 = a1*b1 + (t1>>32) + (a0<t1a);
+ a0 += r;
+ a1 += a0<r;
+
+ for(i=63; i>=0; i--){
+// int o= a1 & 0x8000000000000000ULL;
+ a1+= a1 + ((a0>>i)&1);
+ t1+=t1;
+ if(/*o || */c <= a1){
+ a1 -= c;
+ t1++;
+ }
+ }
+ return t1;
+ }
+#else
+ AVInteger ai;
+ ai= av_mul_i(av_int2i(a), av_int2i(b));
+ ai= av_add_i(ai, av_int2i(r));
+
+ return av_i2int(av_div_i(ai, av_int2i(c)));
+ }
+#endif
+}
+
+int64_t av_rescale(int64_t a, int64_t b, int64_t c){
+ return av_rescale_rnd(a, b, c, AV_ROUND_NEAR_INF);
+}
+
+int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq){
+ int64_t b= bq.num * (int64_t)cq.den;
+ int64_t c= cq.num * (int64_t)bq.den;
+ return av_rescale_rnd(a, b, c, AV_ROUND_NEAR_INF);
+}
+
+int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b){
+ int64_t a= tb_a.num * (int64_t)tb_b.den;
+ int64_t b= tb_b.num * (int64_t)tb_a.den;
+ if (av_rescale_rnd(ts_a, a, b, AV_ROUND_DOWN) < ts_b) return -1;
+ if (av_rescale_rnd(ts_b, b, a, AV_ROUND_DOWN) < ts_a) return 1;
+ return 0;
+}
+
+int64_t av_compare_mod(uint64_t a, uint64_t b, uint64_t mod){
+ int64_t c= (a-b) & (mod-1);
+ if(c > (mod>>1))
+ c-= mod;
+ return c;
+}
+
+#ifdef TEST
+#include "integer.h"
+#undef printf
+int main(void){
+ int64_t a,b,c,d,e;
+
+ for(a=7; a<(1LL<<62); a+=a/3+1){
+ for(b=3; b<(1LL<<62); b+=b/4+1){
+ for(c=9; c<(1LL<<62); c+=(c*2)/5+3){
+ int64_t r= c/2;
+ AVInteger ai;
+ ai= av_mul_i(av_int2i(a), av_int2i(b));
+ ai= av_add_i(ai, av_int2i(r));
+
+ d= av_i2int(av_div_i(ai, av_int2i(c)));
+
+ e= av_rescale(a,b,c);
+
+ if((double)a * (double)b / (double)c > (1LL<<63))
+ continue;
+
+ if(d!=e) printf("%"PRId64"*%"PRId64"/%"PRId64"= %"PRId64"=%"PRId64"\n", a, b, c, d, e);
+ }
+ }
+ }
+ return 0;
+}
+#endif
diff --git a/plugins/supereq/ffmpeg_fft/libavutil/mathematics.h b/plugins/supereq/ffmpeg_fft/libavutil/mathematics.h
new file mode 100644
index 00000000..06d36e09
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavutil/mathematics.h
@@ -0,0 +1,110 @@
+/*
+ * copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_MATHEMATICS_H
+#define AVUTIL_MATHEMATICS_H
+
+#include <stdint.h>
+#include <math.h>
+#include "attributes.h"
+#include "rational.h"
+
+#ifndef M_E
+#define M_E 2.7182818284590452354 /* e */
+#endif
+#ifndef M_LN2
+#define M_LN2 0.69314718055994530942 /* log_e 2 */
+#endif
+#ifndef M_LN10
+#define M_LN10 2.30258509299404568402 /* log_e 10 */
+#endif
+#ifndef M_LOG2_10
+#define M_LOG2_10 3.32192809488736234787 /* log_2 10 */
+#endif
+#ifndef M_PI
+#define M_PI 3.14159265358979323846 /* pi */
+#endif
+#ifndef M_SQRT1_2
+#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */
+#endif
+#ifndef M_SQRT2
+#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
+#endif
+#ifndef NAN
+#define NAN (0.0/0.0)
+#endif
+#ifndef INFINITY
+#define INFINITY (1.0/0.0)
+#endif
+
+enum AVRounding {
+ AV_ROUND_ZERO = 0, ///< Round toward zero.
+ AV_ROUND_INF = 1, ///< Round away from zero.
+ AV_ROUND_DOWN = 2, ///< Round toward -infinity.
+ AV_ROUND_UP = 3, ///< Round toward +infinity.
+ AV_ROUND_NEAR_INF = 5, ///< Round to nearest and halfway cases away from zero.
+};
+
+/**
+ * Return the greatest common divisor of a and b.
+ * If both a and b are 0 or either or both are <0 then behavior is
+ * undefined.
+ */
+int64_t av_const av_gcd(int64_t a, int64_t b);
+
+/**
+ * Rescale a 64-bit integer with rounding to nearest.
+ * A simple a*b/c isn't possible as it can overflow.
+ */
+int64_t av_rescale(int64_t a, int64_t b, int64_t c) av_const;
+
+/**
+ * Rescale a 64-bit integer with specified rounding.
+ * A simple a*b/c isn't possible as it can overflow.
+ */
+int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding) av_const;
+
+/**
+ * Rescale a 64-bit integer by 2 rational numbers.
+ */
+int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const;
+
+/**
+ * Compare 2 timestamps each in its own timebases.
+ * The result of the function is undefined if one of the timestamps
+ * is outside the int64_t range when represented in the others timebase.
+ * @return -1 if ts_a is before ts_b, 1 if ts_a is after ts_b or 0 if they represent the same position
+ */
+int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b);
+
+/**
+ * Compare 2 integers modulo mod.
+ * That is we compare integers a and b for which only the least
+ * significant log2(mod) bits are known.
+ *
+ * @param mod must be a power of 2
+ * @return a negative value if a is smaller than b
+ * a positive value if a is greater than b
+ * 0 if a equals b
+ */
+int64_t av_compare_mod(uint64_t a, uint64_t b, uint64_t mod);
+
+#endif /* AVUTIL_MATHEMATICS_H */
+
diff --git a/plugins/supereq/ffmpeg_fft/libavutil/mem.c b/plugins/supereq/ffmpeg_fft/libavutil/mem.c
new file mode 100644
index 00000000..8cad089a
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavutil/mem.c
@@ -0,0 +1,176 @@
+/*
+ * default memory allocator for libavutil
+ * Copyright (c) 2002 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * default memory allocator for libavutil
+ */
+
+#include "config.h"
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#if HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+#include "avutil.h"
+#include "mem.h"
+
+/* here we can use OS-dependent allocation functions */
+#undef free
+#undef malloc
+#undef realloc
+
+#ifdef MALLOC_PREFIX
+
+#define malloc AV_JOIN(MALLOC_PREFIX, malloc)
+#define memalign AV_JOIN(MALLOC_PREFIX, memalign)
+#define posix_memalign AV_JOIN(MALLOC_PREFIX, posix_memalign)
+#define realloc AV_JOIN(MALLOC_PREFIX, realloc)
+#define free AV_JOIN(MALLOC_PREFIX, free)
+
+void *malloc(size_t size);
+void *memalign(size_t align, size_t size);
+int posix_memalign(void **ptr, size_t align, size_t size);
+void *realloc(void *ptr, size_t size);
+void free(void *ptr);
+
+#endif /* MALLOC_PREFIX */
+
+/* You can redefine av_malloc and av_free in your project to use your
+ memory allocator. You do not need to suppress this file because the
+ linker will do it automatically. */
+
+void *av_malloc(unsigned int size)
+{
+ void *ptr = NULL;
+#if CONFIG_MEMALIGN_HACK
+ long diff;
+#endif
+
+ /* let's disallow possible ambiguous cases */
+ if(size > (INT_MAX-16) )
+ return NULL;
+
+#if CONFIG_MEMALIGN_HACK
+ ptr = malloc(size+16);
+ if(!ptr)
+ return ptr;
+ diff= ((-(long)ptr - 1)&15) + 1;
+ ptr = (char*)ptr + diff;
+ ((char*)ptr)[-1]= diff;
+#elif HAVE_POSIX_MEMALIGN
+ if (posix_memalign(&ptr,16,size))
+ ptr = NULL;
+#elif HAVE_MEMALIGN
+ ptr = memalign(16,size);
+ /* Why 64?
+ Indeed, we should align it:
+ on 4 for 386
+ on 16 for 486
+ on 32 for 586, PPro - K6-III
+ on 64 for K7 (maybe for P3 too).
+ Because L1 and L2 caches are aligned on those values.
+ But I don't want to code such logic here!
+ */
+ /* Why 16?
+ Because some CPUs need alignment, for example SSE2 on P4, & most RISC CPUs
+ it will just trigger an exception and the unaligned load will be done in the
+ exception handler or it will just segfault (SSE2 on P4).
+ Why not larger? Because I did not see a difference in benchmarks ...
+ */
+ /* benchmarks with P3
+ memalign(64)+1 3071,3051,3032
+ memalign(64)+2 3051,3032,3041
+ memalign(64)+4 2911,2896,2915
+ memalign(64)+8 2545,2554,2550
+ memalign(64)+16 2543,2572,2563
+ memalign(64)+32 2546,2545,2571
+ memalign(64)+64 2570,2533,2558
+
+ BTW, malloc seems to do 8-byte alignment by default here.
+ */
+#else
+ ptr = malloc(size);
+#endif
+ return ptr;
+}
+
+void *av_realloc(void *ptr, unsigned int size)
+{
+#if CONFIG_MEMALIGN_HACK
+ int diff;
+#endif
+
+ /* let's disallow possible ambiguous cases */
+ if(size > (INT_MAX-16) )
+ return NULL;
+
+#if CONFIG_MEMALIGN_HACK
+ //FIXME this isn't aligned correctly, though it probably isn't needed
+ if(!ptr) return av_malloc(size);
+ diff= ((char*)ptr)[-1];
+ return (char*)realloc((char*)ptr - diff, size + diff) + diff;
+#else
+ return realloc(ptr, size);
+#endif
+}
+
+void av_free(void *ptr)
+{
+ /* XXX: this test should not be needed on most libcs */
+ if (ptr)
+#if CONFIG_MEMALIGN_HACK
+ free((char*)ptr - ((char*)ptr)[-1]);
+#else
+ free(ptr);
+#endif
+}
+
+void av_freep(void *arg)
+{
+ void **ptr= (void**)arg;
+ av_free(*ptr);
+ *ptr = NULL;
+}
+
+void *av_mallocz(unsigned int size)
+{
+ void *ptr = av_malloc(size);
+ if (ptr)
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+char *av_strdup(const char *s)
+{
+ char *ptr= NULL;
+ if(s){
+ int len = strlen(s) + 1;
+ ptr = av_malloc(len);
+ if (ptr)
+ memcpy(ptr, s, len);
+ }
+ return ptr;
+}
+
diff --git a/plugins/supereq/ffmpeg_fft/libavutil/mem.h b/plugins/supereq/ffmpeg_fft/libavutil/mem.h
new file mode 100644
index 00000000..7da0a15f
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavutil/mem.h
@@ -0,0 +1,128 @@
+/*
+ * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * memory handling functions
+ */
+
+#ifndef AVUTIL_MEM_H
+#define AVUTIL_MEM_H
+
+#include "attributes.h"
+#include "avutil.h"
+#include "publik.h"
+
+#if defined(__ICC) && _ICC < 1200 || defined(__SUNPRO_C)
+ #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v
+ #define DECLARE_ASM_CONST(n,t,v) const t __attribute__ ((aligned (n))) v
+#elif defined(__TI_COMPILER_VERSION__)
+ #define DECLARE_ALIGNED(n,t,v) \
+ AV_PRAGMA(DATA_ALIGN(v,n)) \
+ t __attribute__((aligned(n))) v
+ #define DECLARE_ASM_CONST(n,t,v) \
+ AV_PRAGMA(DATA_ALIGN(v,n)) \
+ static const t __attribute__((aligned(n))) v
+#elif defined(__GNUC__)
+ #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v
+ #define DECLARE_ASM_CONST(n,t,v) static const t attribute_used __attribute__ ((aligned (n))) v
+#elif defined(_MSC_VER)
+ #define DECLARE_ALIGNED(n,t,v) __declspec(align(n)) t v
+ #define DECLARE_ASM_CONST(n,t,v) __declspec(align(n)) static const t v
+#else
+ #define DECLARE_ALIGNED(n,t,v) t v
+ #define DECLARE_ASM_CONST(n,t,v) static const t v
+#endif
+
+#if AV_GCC_VERSION_AT_LEAST(3,1)
+ #define av_malloc_attrib __attribute__((__malloc__))
+#else
+ #define av_malloc_attrib
+#endif
+
+#if (!defined(__ICC) || __ICC > 1110) && AV_GCC_VERSION_AT_LEAST(4,3)
+ #define av_alloc_size(n) __attribute__((alloc_size(n)))
+#else
+ #define av_alloc_size(n)
+#endif
+
+/**
+ * Allocate a block of size bytes with alignment suitable for all
+ * memory accesses (including vectors if available on the CPU).
+ * @param size Size in bytes for the memory block to be allocated.
+ * @return Pointer to the allocated block, NULL if the block cannot
+ * be allocated.
+ * @see av_mallocz()
+ */
+PUBLIK void *av_malloc(unsigned int size) av_malloc_attrib av_alloc_size(1);
+
+/**
+ * Allocate or reallocate a block of memory.
+ * If ptr is NULL and size > 0, allocate a new block. If
+ * size is zero, free the memory block pointed to by ptr.
+ * @param size Size in bytes for the memory block to be allocated or
+ * reallocated.
+ * @param ptr Pointer to a memory block already allocated with
+ * av_malloc(z)() or av_realloc() or NULL.
+ * @return Pointer to a newly reallocated block or NULL if the block
+ * cannot be reallocated or the function is used to free the memory block.
+ * @see av_fast_realloc()
+ */
+void *av_realloc(void *ptr, unsigned int size) av_alloc_size(2);
+
+/**
+ * Free a memory block which has been allocated with av_malloc(z)() or
+ * av_realloc().
+ * @param ptr Pointer to the memory block which should be freed.
+ * @note ptr = NULL is explicitly allowed.
+ * @note It is recommended that you use av_freep() instead.
+ * @see av_freep()
+ */
+PUBLIK void av_free(void *ptr);
+
+/**
+ * Allocate a block of size bytes with alignment suitable for all
+ * memory accesses (including vectors if available on the CPU) and
+ * zero all the bytes of the block.
+ * @param size Size in bytes for the memory block to be allocated.
+ * @return Pointer to the allocated block, NULL if it cannot be allocated.
+ * @see av_malloc()
+ */
+void *av_mallocz(unsigned int size) av_malloc_attrib av_alloc_size(1);
+
+/**
+ * Duplicate the string s.
+ * @param s string to be duplicated
+ * @return Pointer to a newly allocated string containing a
+ * copy of s or NULL if the string cannot be allocated.
+ */
+char *av_strdup(const char *s) av_malloc_attrib;
+
+/**
+ * Free a memory block which has been allocated with av_malloc(z)() or
+ * av_realloc() and set the pointer pointing to it to NULL.
+ * @param ptr Pointer to the pointer to the memory block which should
+ * be freed.
+ * @see av_free()
+ */
+void av_freep(void *ptr);
+
+#endif /* AVUTIL_MEM_H */
+
diff --git a/plugins/supereq/ffmpeg_fft/libavutil/rational.c b/plugins/supereq/ffmpeg_fft/libavutil/rational.c
new file mode 100644
index 00000000..3e8b885d
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavutil/rational.c
@@ -0,0 +1,131 @@
+/*
+ * rational numbers
+ * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * rational numbers
+ * @author Michael Niedermayer <michaelni@gmx.at>
+ */
+
+#include <assert.h>
+//#include <math.h>
+#include <limits.h>
+
+#include "common.h"
+#include "mathematics.h"
+#include "rational.h"
+
+int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max){
+ AVRational a0={0,1}, a1={1,0};
+ int sign= (num<0) ^ (den<0);
+ int64_t gcd= av_gcd(FFABS(num), FFABS(den));
+
+ if(gcd){
+ num = FFABS(num)/gcd;
+ den = FFABS(den)/gcd;
+ }
+ if(num<=max && den<=max){
+ a1= (AVRational){num, den};
+ den=0;
+ }
+
+ while(den){
+ uint64_t x = num / den;
+ int64_t next_den= num - den*x;
+ int64_t a2n= x*a1.num + a0.num;
+ int64_t a2d= x*a1.den + a0.den;
+
+ if(a2n > max || a2d > max){
+ if(a1.num) x= (max - a0.num) / a1.num;
+ if(a1.den) x= FFMIN(x, (max - a0.den) / a1.den);
+
+ if (den*(2*x*a1.den + a0.den) > num*a1.den)
+ a1 = (AVRational){x*a1.num + a0.num, x*a1.den + a0.den};
+ break;
+ }
+
+ a0= a1;
+ a1= (AVRational){a2n, a2d};
+ num= den;
+ den= next_den;
+ }
+ assert(av_gcd(a1.num, a1.den) <= 1U);
+
+ *dst_num = sign ? -a1.num : a1.num;
+ *dst_den = a1.den;
+
+ return den==0;
+}
+
+AVRational av_mul_q(AVRational b, AVRational c){
+ av_reduce(&b.num, &b.den, b.num * (int64_t)c.num, b.den * (int64_t)c.den, INT_MAX);
+ return b;
+}
+
+AVRational av_div_q(AVRational b, AVRational c){
+ return av_mul_q(b, (AVRational){c.den, c.num});
+}
+
+AVRational av_add_q(AVRational b, AVRational c){
+ av_reduce(&b.num, &b.den, b.num * (int64_t)c.den + c.num * (int64_t)b.den, b.den * (int64_t)c.den, INT_MAX);
+ return b;
+}
+
+AVRational av_sub_q(AVRational b, AVRational c){
+ return av_add_q(b, (AVRational){-c.num, c.den});
+}
+
+AVRational av_d2q(double d, int max){
+ AVRational a;
+#define LOG2 0.69314718055994530941723212145817656807550013436025
+ int exponent= FFMAX( (int)(log(fabs(d) + 1e-20)/LOG2), 0);
+ int64_t den= 1LL << (61 - exponent);
+ if (isnan(d))
+ return (AVRational){0,0};
+ av_reduce(&a.num, &a.den, (int64_t)(d * den + 0.5), den, max);
+
+ return a;
+}
+
+int av_nearer_q(AVRational q, AVRational q1, AVRational q2)
+{
+ /* n/d is q, a/b is the median between q1 and q2 */
+ int64_t a = q1.num * (int64_t)q2.den + q2.num * (int64_t)q1.den;
+ int64_t b = 2 * (int64_t)q1.den * q2.den;
+
+ /* rnd_up(a*d/b) > n => a*d/b > n */
+ int64_t x_up = av_rescale_rnd(a, q.den, b, AV_ROUND_UP);
+
+ /* rnd_down(a*d/b) < n => a*d/b < n */
+ int64_t x_down = av_rescale_rnd(a, q.den, b, AV_ROUND_DOWN);
+
+ return ((x_up > q.num) - (x_down < q.num)) * av_cmp_q(q2, q1);
+}
+
+int av_find_nearest_q_idx(AVRational q, const AVRational* q_list)
+{
+ int i, nearest_q_idx = 0;
+ for(i=0; q_list[i].den; i++)
+ if (av_nearer_q(q, q_list[i], q_list[nearest_q_idx]) > 0)
+ nearest_q_idx = i;
+
+ return nearest_q_idx;
+}
diff --git a/plugins/supereq/ffmpeg_fft/libavutil/rational.h b/plugins/supereq/ffmpeg_fft/libavutil/rational.h
new file mode 100644
index 00000000..cd0a945a
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libavutil/rational.h
@@ -0,0 +1,130 @@
+/*
+ * rational numbers
+ * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * rational numbers
+ * @author Michael Niedermayer <michaelni@gmx.at>
+ */
+
+#ifndef AVUTIL_RATIONAL_H
+#define AVUTIL_RATIONAL_H
+
+#include <stdint.h>
+#include "attributes.h"
+
+/**
+ * rational number numerator/denominator
+ */
+typedef struct AVRational{
+ int num; ///< numerator
+ int den; ///< denominator
+} AVRational;
+
+/**
+ * Compare two rationals.
+ * @param a first rational
+ * @param b second rational
+ * @return 0 if a==b, 1 if a>b and -1 if a<b
+ */
+static inline int av_cmp_q(AVRational a, AVRational b){
+ const int64_t tmp= a.num * (int64_t)b.den - b.num * (int64_t)a.den;
+
+ if(tmp) return (tmp>>63)|1;
+ else return 0;
+}
+
+/**
+ * Convert rational to double.
+ * @param a rational to convert
+ * @return (double) a
+ */
+static inline double av_q2d(AVRational a){
+ return a.num / (double) a.den;
+}
+
+/**
+ * Reduce a fraction.
+ * This is useful for framerate calculations.
+ * @param dst_num destination numerator
+ * @param dst_den destination denominator
+ * @param num source numerator
+ * @param den source denominator
+ * @param max the maximum allowed for dst_num & dst_den
+ * @return 1 if exact, 0 otherwise
+ */
+int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max);
+
+/**
+ * Multiply two rationals.
+ * @param b first rational
+ * @param c second rational
+ * @return b*c
+ */
+AVRational av_mul_q(AVRational b, AVRational c) av_const;
+
+/**
+ * Divide one rational by another.
+ * @param b first rational
+ * @param c second rational
+ * @return b/c
+ */
+AVRational av_div_q(AVRational b, AVRational c) av_const;
+
+/**
+ * Add two rationals.
+ * @param b first rational
+ * @param c second rational
+ * @return b+c
+ */
+AVRational av_add_q(AVRational b, AVRational c) av_const;
+
+/**
+ * Subtract one rational from another.
+ * @param b first rational
+ * @param c second rational
+ * @return b-c
+ */
+AVRational av_sub_q(AVRational b, AVRational c) av_const;
+
+/**
+ * Convert a double precision floating point number to a rational.
+ * @param d double to convert
+ * @param max the maximum allowed numerator and denominator
+ * @return (AVRational) d
+ */
+AVRational av_d2q(double d, int max) av_const;
+
+/**
+ * @return 1 if q1 is nearer to q than q2, -1 if q2 is nearer
+ * than q1, 0 if they have the same distance.
+ */
+int av_nearer_q(AVRational q, AVRational q1, AVRational q2);
+
+/**
+ * Find the nearest value in q_list to q.
+ * @param q_list an array of rationals terminated by {0, 0}
+ * @return the index of the nearest value found in the array
+ */
+int av_find_nearest_q_idx(AVRational q, const AVRational* q_list);
+
+#endif /* AVUTIL_RATIONAL_H */
+
diff --git a/plugins/supereq/ffmpeg_fft/libffmpeg_fft.ver b/plugins/supereq/ffmpeg_fft/libffmpeg_fft.ver
new file mode 100644
index 00000000..07b44318
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/libffmpeg_fft.ver
@@ -0,0 +1,4 @@
+LIBFFMPEG_FFT_52 {
+ global: *;
+};
+
diff --git a/plugins/supereq/ffmpeg_fft/publik.h b/plugins/supereq/ffmpeg_fft/publik.h
new file mode 100644
index 00000000..bb044756
--- /dev/null
+++ b/plugins/supereq/ffmpeg_fft/publik.h
@@ -0,0 +1,6 @@
+#ifndef PUBLIK_H_
+#define PUBLIK_H_
+
+#define PUBLIK __attribute__ ((visibility ("default")))
+
+#endif /* PUBLIK_H_ */
diff --git a/plugins/supereq/nsfft-1.00/README b/plugins/supereq/nsfft-1.00/README
new file mode 100644
index 00000000..1ca873b1
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/README
@@ -0,0 +1,15 @@
+
+NSFFT (Nonrestrictive SIMD FFT) is yet another FFT library for
+performing 1-dimensional fast Fourier transforms. NSDFT is a simple,
+small and portable library, and it is efficient since it can utilize
+SIMD instruction sets in modern processors. It performs multiple
+transforms simultaneously, and thus it is especially suitable for
+digital signal processing. It does not need so much computation to
+make a good execution plan. This library is in public domain, so that
+you can incorporate this library into your product without any
+obligation.
+
+Visit http://shibatch.sourceforge.net/ to get the latest version of
+this library.
+
+Contact : Naoki Shibata shibatch@users.sourceforge.net
diff --git a/plugins/supereq/nsfft-1.00/dft/DFT.c b/plugins/supereq/nsfft-1.00/dft/DFT.c
new file mode 100644
index 00000000..d59e6ab8
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/dft/DFT.c
@@ -0,0 +1,327 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <stdint.h>
+#include <sys/time.h>
+
+#include "SIMDBase.h"
+#include "DFT.h"
+#include "DFTUndiff.h"
+
+int32_t getModeParamInt_purec_float(int32_t paramId);
+int32_t getModeParamInt_purec_double(int32_t paramId);
+int32_t getModeParamInt_purec_longdouble(int32_t paramId);
+int32_t getModeParamInt_sse_float(int32_t paramId);
+int32_t getModeParamInt_sse2_double(int32_t paramId);
+int32_t getModeParamInt_neon_float(int32_t paramId);
+int32_t getModeParamInt_avx_float(int32_t paramId);
+int32_t getModeParamInt_avx_double(int32_t paramId);
+int32_t getModeParamInt_altivec_float(int32_t paramId);
+
+char * getModeParamString_purec_float(int32_t paramId);
+char * getModeParamString_purec_double(int32_t paramId);
+char * getModeParamString_purec_longdouble(int32_t paramId);
+char * getModeParamString_sse_float(int32_t paramId);
+char * getModeParamString_sse2_double(int32_t paramId);
+char * getModeParamString_neon_float(int32_t paramId);
+char * getModeParamString_avx_float(int32_t paramId);
+char * getModeParamString_avx_double(int32_t paramId);
+char * getModeParamString_altivec_float(int32_t paramId);
+
+void *makePlan_purec_float(uint64_t n, uint64_t flags);
+void *makePlan_purec_double(uint64_t n, uint64_t flags);
+void *makePlan_purec_longdouble(uint64_t n, uint64_t flags);
+void *makePlan_sse_float(uint64_t n, uint64_t flags);
+void *makePlan_sse2_double(uint64_t n, uint64_t flags);
+void *makePlan_neon_float(uint64_t n, uint64_t flags);
+void *makePlan_avx_float(uint64_t n, uint64_t flags);
+void *makePlan_avx_double(uint64_t n, uint64_t flags);
+void *makePlan_altivec_float(uint64_t n, uint64_t flags);
+
+void *makePlanSub_purec_float(uint64_t n, int32_t radix2thres, int32_t useCobra, uint64_t flags);
+void *makePlanSub_purec_double(uint64_t n, int32_t radix2thres, int32_t useCobra, uint64_t flags);
+void *makePlanSub_purec_longdouble(uint64_t n, int32_t radix2thres, int32_t useCobra, uint64_t flags);
+void *makePlanSub_sse_float(uint64_t n, int32_t radix2thres, int32_t useCobra, uint64_t flags);
+void *makePlanSub_sse2_double(uint64_t n, int32_t radix2thres, int32_t useCobra, uint64_t flags);
+void *makePlanSub_neon_float(uint64_t n, int32_t radix2thres, int32_t useCobra, uint64_t flags);
+void *makePlanSub_avx_float(uint64_t n, int32_t radix2thres, int32_t useCobra, uint64_t flags);
+void *makePlanSub_avx_double(uint64_t n, int32_t radix2thres, int32_t useCobra, uint64_t flags);
+void *makePlanSub_altivec_float(uint64_t n, int32_t radix2thres, int32_t useCobra, uint64_t flags);
+
+void destroyPlan_purec_float(void *p);
+void destroyPlan_purec_double(void *p);
+void destroyPlan_purec_longdouble(void *p);
+void destroyPlan_sse_float(void *p);
+void destroyPlan_sse2_double(void *p);
+void destroyPlan_neon_float(void *p);
+void destroyPlan_avx_float(void *p);
+void destroyPlan_avx_double(void *p);
+void destroyPlan_altivec_float(void *p);
+
+void execute_purec_float(void *p, void *s, int32_t dir);
+void execute_purec_double(void *p, void *s, int32_t dir);
+void execute_purec_longdouble(void *p, void *s, int32_t dir);
+void execute_sse_float(void *p, void *s, int32_t dir);
+void execute_sse2_double(void *p, void *s, int32_t dir);
+void execute_neon_float(void *p, void *s, int32_t dir);
+void execute_avx_float(void *p, void *s, int32_t dir);
+void execute_avx_double(void *p, void *s, int32_t dir);
+void execute_altivec_float(void *p, void *s, int32_t dir);
+
+void *DFT_init(int32_t mode, uint64_t n, uint64_t flags) {
+ switch(mode) {
+#if defined(ENABLE_PUREC_FLOAT)
+ case 1: return makePlan_purec_float(n, flags); break;
+#endif
+#if defined(ENABLE_PUREC_DOUBLE)
+ case 2: return makePlan_purec_double(n, flags); break;
+#endif
+#if defined(ENABLE_PUREC_LONGDOUBLE)
+ case 3: return makePlan_purec_longdouble(n, flags); break;
+#endif
+#if defined(ENABLE_SSE_FLOAT)
+ case 4: return makePlan_sse_float(n, flags); break;
+#endif
+#if defined(ENABLE_SSE2_DOUBLE)
+ case 5: return makePlan_sse2_double(n, flags); break;
+#endif
+#if defined(ENABLE_NEON_FLOAT)
+ case 6: return makePlan_neon_float(n, flags); break;
+#endif
+#if defined(ENABLE_AVX_FLOAT)
+ case 7: return makePlan_avx_float(n, flags); break;
+#endif
+#if defined(ENABLE_AVX_DOUBLE)
+ case 8: return makePlan_avx_double(n, flags); break;
+#endif
+#if defined(ENABLE_ALTIVEC_FLOAT)
+ case 9: return makePlan_altivec_float(n, flags); break;
+#endif
+ default: break;
+ }
+
+ return NULL;
+}
+
+void DFT_dispose(void *p, int32_t mode) {
+ switch(mode) {
+#if defined(ENABLE_PUREC_FLOAT)
+ case 1: destroyPlan_purec_float(p); break;
+#endif
+#if defined(ENABLE_PUREC_DOUBLE)
+ case 2: destroyPlan_purec_double(p); break;
+#endif
+#if defined(ENABLE_PUREC_LONGDOUBLE)
+ case 3: destroyPlan_purec_longdouble(p); break;
+#endif
+#if defined(ENABLE_SSE_FLOAT)
+ case 4: destroyPlan_sse_float(p); break;
+#endif
+#if defined(ENABLE_SSE2_DOUBLE)
+ case 5: destroyPlan_sse2_double(p); break;
+#endif
+#if defined(ENABLE_NEON_FLOAT)
+ case 6: destroyPlan_neon_float(p); break;
+#endif
+#if defined(ENABLE_AVX_FLOAT)
+ case 7: destroyPlan_avx_float(p); break;
+#endif
+#if defined(ENABLE_AVX_DOUBLE)
+ case 8: destroyPlan_avx_double(p); break;
+#endif
+#if defined(ENABLE_ALTIVEC_FLOAT)
+ case 9: destroyPlan_altivec_float(p); break;
+#endif
+ default: break;
+ }
+}
+
+void DFT_execute(void *p, int32_t mode, void *s, int32_t dir) {
+ switch(mode) {
+#if defined(ENABLE_PUREC_FLOAT)
+ case 1: return execute_purec_float(p, s, dir); break;
+#endif
+#if defined(ENABLE_PUREC_DOUBLE)
+ case 2: return execute_purec_double(p, s, dir); break;
+#endif
+#if defined(ENABLE_PUREC_LONGDOUBLE)
+ case 3: return execute_purec_longdouble(p, s, dir); break;
+#endif
+#if defined(ENABLE_SSE_FLOAT)
+ case 4: return execute_sse_float(p, s, dir); break;
+#endif
+#if defined(ENABLE_SSE2_DOUBLE)
+ case 5: return execute_sse2_double(p, s, dir); break;
+#endif
+#if defined(ENABLE_NEON_FLOAT)
+ case 6: return execute_neon_float(p, s, dir); break;
+#endif
+#if defined(ENABLE_AVX_FLOAT)
+ case 7: return execute_avx_float(p, s, dir); break;
+#endif
+#if defined(ENABLE_AVX_DOUBLE)
+ case 8: return execute_avx_double(p, s, dir); break;
+#endif
+#if defined(ENABLE_ALTIVEC_FLOAT)
+ case 9: return execute_altivec_float(p, s, dir); break;
+#endif
+ default: break;
+ }
+}
+
+#define FILE_FORMAT_VERSION 0
+
+int32_t DFT_fwrite(void *p2, FILE *fp) {
+ DFTUndiff *p = (DFTUndiff *)p2;
+ if (p->magic != MAGIC_DFT) abort();
+
+ if (fprintf(fp, "nsfft file format : %d\n", FILE_FORMAT_VERSION) <= 0) return 0;
+ if (fprintf(fp, "arch : %s\n", SIMDBase_getProcessorNameString()) <= 0) return 0;
+ if (fprintf(fp, "computation mode : %d\n", p->mode) <= 0) return 0;
+ if (fprintf(fp, "length : %d\n", ((p->flags & DFT_FLAG_REAL) != 0 || (p->flags & DFT_FLAG_ALT_REAL) != 0)? p->length * 2 : p->length) <= 0) return 0;
+ if (fprintf(fp, "radix2 threshold : %d\n", p->radix2thres) <= 0) return 0;
+ if (fprintf(fp, "transpose : %d\n", p->flagTrans) <= 0) return 0;
+ if (fprintf(fp, "bit reversal : %d\n", p->useCobra) <= 0) return 0;
+ if (fprintf(fp, "flags : %llx\n", (unsigned long long int)p->flags) <= 0) return 0;
+ if (fprintf(fp, "%s\n", "end :") <= 0) return 0;
+
+ return 1;
+}
+
+static char *startsWith(char *str1, char *str2) {
+ if (strncmp(str1, str2, strlen(str2)) == 0) {
+ return str1 + strlen(str2);
+ }
+
+ return NULL;
+}
+
+DFT *DFT_fread(FILE *fp, int32_t *errcode) {
+ int length = -1, radix2thres = -1, flagTrans = -1, useCobra = -1;
+ int mode = -1, formatver = -1;
+ unsigned long long int flags = (1ULL << 63);
+
+ if (errcode != NULL) *errcode = DFT_ERROR_NOERROR;
+
+ for(;;) {
+ char buf[256], *q;
+ if (fgets(buf, 255, fp) == NULL) { if (errcode != NULL) *errcode = DFT_ERROR_UNEXPECTED_EOF; return NULL; }
+
+ if ((q = startsWith(buf, "nsfft file format :")) != NULL) {
+ if (1 != sscanf(q, "%d", &formatver)) { if (errcode != NULL) *errcode = DFT_ERROR_FILE_IO; return NULL; }
+ } else if ((q = startsWith(buf, "computation mode :")) != NULL) {
+ if (1 != sscanf(q, "%d", &mode)) { if (errcode != NULL) *errcode = DFT_ERROR_FILE_IO; return NULL; }
+ } else if ((q = startsWith(buf, "length :")) != NULL) {
+ if (1 != sscanf(q, "%d", &length)) { if (errcode != NULL) *errcode = DFT_ERROR_FILE_IO; return NULL; }
+ } else if ((q = startsWith(buf, "radix2 threshold :")) != NULL) {
+ if (1 != sscanf(q, "%d", &radix2thres)) { if (errcode != NULL) *errcode = DFT_ERROR_FILE_IO; return NULL; }
+ } else if ((q = startsWith(buf, "transpose :")) != NULL) {
+ if (1 != sscanf(q, "%d", &flagTrans)) { if (errcode != NULL) *errcode = DFT_ERROR_FILE_IO; return NULL; }
+ } else if ((q = startsWith(buf, "bit reversal :")) != NULL) {
+ if (1 != sscanf(q, "%d", &useCobra)) { if (errcode != NULL) *errcode = DFT_ERROR_FILE_IO; return NULL; }
+ } else if ((q = startsWith(buf, "flags :")) != NULL) {
+ if (1 != sscanf(q, "%llx", &flags)) { if (errcode != NULL) *errcode = DFT_ERROR_FILE_IO; return NULL; }
+ } else if ((q = startsWith(buf, "end :")) != NULL) {
+ break;
+ }
+ }
+
+ if (formatver > FILE_FORMAT_VERSION) {
+ if (errcode != NULL) *errcode = DFT_ERROR_FILE_VERSION;
+ return NULL;
+ }
+
+ switch(SIMDBase_detect(mode)) {
+ case 1:
+ break;
+ case 0:
+ if (errcode != NULL) *errcode = DFT_ERROR_MODE_NOT_AVAILABLE;
+ return NULL;
+ case -1:
+ if (errcode != NULL) *errcode = DFT_ERROR_MODE_NOT_COMPILED_IN;
+ return NULL;
+ }
+
+ switch(mode) {
+#if defined(ENABLE_PUREC_FLOAT)
+ case 1: return makePlanSub_purec_float(length, radix2thres, useCobra, flags);
+#endif
+#if defined(ENABLE_PUREC_DOUBLE)
+ case 2: return makePlanSub_purec_double(length, radix2thres, useCobra, flags);
+#endif
+#if defined(ENABLE_PUREC_LONGDOUBLE)
+ case 3: return makePlanSub_purec_longdouble(length, radix2thres, useCobra, flags);
+#endif
+#if defined(ENABLE_SSE_FLOAT)
+ case 4: return makePlanSub_sse_float(length, radix2thres, useCobra, flags);
+#endif
+#if defined(ENABLE_SSE2_DOUBLE)
+ case 5: return makePlanSub_sse2_double(length, radix2thres, useCobra, flags);
+#endif
+#if defined(ENABLE_NEON_FLOAT)
+ case 6: return makePlanSub_neon_float(length, radix2thres, useCobra, flags);
+#endif
+#if defined(ENABLE_AVX_FLOAT)
+ case 7: return makePlanSub_avx_float(length, radix2thres, useCobra, flags);
+#endif
+#if defined(ENABLE_AVX_DOUBLE)
+ case 8: return makePlanSub_avx_double(length, radix2thres, useCobra, flags);
+#endif
+#if defined(ENABLE_ALTIVEC_FLOAT)
+ case 9: return makePlanSub_altivec_float(length, radix2thres, useCobra, flags);
+#endif
+ }
+
+ if (errcode != NULL) *errcode = DFT_ERROR_UNKNOWN_MODE;
+
+ return NULL;
+}
+
+int32_t DFT_getPlanParamInt(int32_t paramId, void *p2) {
+ DFTUndiff *p = (DFTUndiff *)p2;
+ if (p->magic != MAGIC_DFT) abort();
+
+ switch(paramId) {
+ case DFT_PARAMID_MODE: return p->mode;
+ case DFT_PARAMID_FFT_LENGTH:
+ if ((p->flags & DFT_FLAG_REAL) != 0) return p->length * 2;
+ if ((p->flags & DFT_FLAG_ALT_REAL) != 0) return p->length * 2;
+ return p->length;
+ case DFT_PARAMID_IS_REAL_TRANSFORM: return (p->flags & DFT_FLAG_REAL) ? 1 : 0;
+ case DFT_PARAMID_IS_ALT_REAL_TRANSFORM: return (p->flags & DFT_FLAG_ALT_REAL) ? 1 : 0;
+ case DFT_PARAMID_NO_BIT_REVERSAL: return (p->flags & DFT_FLAG_NO_BITREVERSAL) ? 1 : 0;
+ case DFT_PARAMID_TEST_RUN: return p->flags & 3;
+ }
+
+ return -1;
+}
+
+#if 0
+char *DFT_getPlanParamString(int32_t paramId, void *p2) {
+ dft_t *p = (dft_t *)p2;
+ if (p->magic != MAGIC_NSDFT) abort();
+
+ return NULL;
+}
+#endif
+
+uint32_t DFT_ilog2(uint32_t q) {
+ static const uint32_t tab[] = {0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4};
+ uint32_t r = 0,qq;
+
+ if (q & 0xffff0000) r = 16;
+
+ q >>= r;
+ qq = q | (q >> 1);
+ qq |= (qq >> 2);
+ qq = ((qq & 0x10) >> 4) | ((qq & 0x100) >> 7) | ((qq & 0x1000) >> 10);
+
+ return r + tab[qq] * 4 + tab[q >> (tab[qq] * 4)] - 1;
+}
+
+double DFT_timeofday(void) {
+ struct timeval tp;
+ gettimeofday(&tp, NULL);
+ return (double)tp.tv_sec+(1e-6)*tp.tv_usec;
+}
diff --git a/plugins/supereq/nsfft-1.00/dft/DFT.h b/plugins/supereq/nsfft-1.00/dft/DFT.h
new file mode 100644
index 00000000..facb701a
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/dft/DFT.h
@@ -0,0 +1,56 @@
+#ifndef __DFT_H__
+#define __DFT_H__
+
+#include <stdio.h>
+#include <stdint.h>
+
+typedef void DFT;
+
+int32_t DFT_getParamInt(int32_t paramId);
+char *DFT_getParamString(int32_t paramId);
+
+int32_t DFT_getModeParamInt(int32_t paramId, int32_t mode);
+char *DFT_getModeParamString(int32_t paramId, int32_t mode);
+
+DFT *DFT_init(int32_t mode, uint64_t n, uint64_t flags);
+void DFT_dispose(DFT *p, int32_t mode);
+
+int32_t DFT_fwrite(DFT *p, FILE *fp);
+DFT *DFT_fread(FILE *fp, int32_t *errcode);
+
+int32_t DFT_getPlanParamInt(int32_t paramId, void *p);
+
+void DFT_execute(DFT *p, int32_t mode, void *s, int32_t dir);
+
+uint32_t DFT_ilog2(uint32_t q);
+double DFT_timeofday(void);
+
+#define DFT_FLAG_NO_TEST_RUN ( 0ULL << 0)
+#define DFT_FLAG_LIGHT_TEST_RUN ( 1ULL << 0)
+#define DFT_FLAG_HEAVY_TEST_RUN ( 2ULL << 0)
+#define DFT_FLAG_EXHAUSTIVE_TEST_RUN ( 3ULL << 0)
+
+#define DFT_FLAG_REAL (1ULL << 2)
+#define DFT_FLAG_ALT_REAL (1ULL << 3)
+#define DFT_FLAG_VERBOSE (1ULL << 4)
+#define DFT_FLAG_NO_BITREVERSAL (1ULL << 5)
+#define DFT_FLAG_FORCE_RECURSIVE (1ULL << 6)
+#define DFT_FLAG_FORCE_COBRA (1ULL << 7)
+
+#define DFT_PARAMID_TYPE ( 1 | ( 3 << 24 ))
+#define DFT_PARAMID_MODE ( 2 | ( 3 << 24 ))
+#define DFT_PARAMID_FFT_LENGTH ( 3 | ( 3 << 24 ))
+#define DFT_PARAMID_IS_REAL_TRANSFORM ( 4 | ( 3 << 24 ))
+#define DFT_PARAMID_IS_ALT_REAL_TRANSFORM ( 5 | ( 3 << 24 ))
+#define DFT_PARAMID_NO_BIT_REVERSAL ( 6 | ( 3 << 24 ))
+#define DFT_PARAMID_TEST_RUN ( 7 | ( 3 << 24 ))
+
+#define DFT_ERROR_NOERROR 0
+#define DFT_ERROR_FILE_VERSION 1
+#define DFT_ERROR_FILE_IO 2
+#define DFT_ERROR_UNEXPECTED_EOF 3
+#define DFT_ERROR_MODE_NOT_COMPILED_IN 4
+#define DFT_ERROR_MODE_NOT_AVAILABLE 5
+#define DFT_ERROR_UNKNOWN_MODE 6
+
+#endif
diff --git a/plugins/supereq/nsfft-1.00/dft/DFTUndiff.c b/plugins/supereq/nsfft-1.00/dft/DFTUndiff.c
new file mode 100644
index 00000000..4985da33
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/dft/DFTUndiff.c
@@ -0,0 +1,1807 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+
+#include "SIMDBase.h"
+#include "SIMDBaseUndiff.h"
+#include "DFT.h"
+#include "DFTUndiff.h"
+
+//
+
+#define SIN(x) sin(x)
+#define COS(x) cos(x)
+
+#define SQRT2_2 .7071067811865475244008443621048490392848359376884740365883398689953L
+
+#ifndef M_PIl
+#define M_PIl 3.141592653589793238462643383279502884197169399375105820974944592307L
+#endif
+
+//
+
+static inline void srBut2(DFTUndiff *p) {
+ SIMDBase_VECT *s = p->s;
+ int32_t o = p->offset1;
+ SIMDBase_VECT t0, t1;
+
+ t0 = SIMDBase_ADDm(&s[o ], &s[o+2]); t1 = SIMDBase_SUBm(&s[o ], &s[o+2]);
+ SIMDBase_STOR(&s[o ], t0); SIMDBase_STOR(&s[o+2], t1);
+ t0 = SIMDBase_ADDm(&s[o+1], &s[o+3]); t1 = SIMDBase_SUBm(&s[o+1], &s[o+3]);
+ SIMDBase_STOR(&s[o+1], t0); SIMDBase_STOR(&s[o+3], t1);
+}
+
+static inline void srButForward4(DFTUndiff *p) {
+ SIMDBase_VECT *s = p->s;
+ int32_t o = p->offset1;
+ SIMDBase_VECT t0r, t0i, t1r, t1i, t2r, t2i, t3r, t3i;
+
+ t0r = SIMDBase_ADDm(&s[o+0], &s[o+4]); t2r = SIMDBase_SUBm(&s[o+0], &s[o+4]);
+ t0i = SIMDBase_ADDm(&s[o+1], &s[o+5]); t2i = SIMDBase_SUBm(&s[o+1], &s[o+5]);
+ t1r = SIMDBase_ADDm(&s[o+2], &s[o+6]); t3i = SIMDBase_SUBm(&s[o+2], &s[o+6]);
+ t1i = SIMDBase_ADDm(&s[o+7], &s[o+3]); t3r = SIMDBase_SUBm(&s[o+7], &s[o+3]);
+
+ SIMDBase_STOR(&s[o+0], SIMDBase_ADDi(t0r, t1r)); SIMDBase_STOR(&s[o+1], SIMDBase_ADDi(t0i, t1i));
+ SIMDBase_STOR(&s[o+2], SIMDBase_SUBi(t0r, t1r)); SIMDBase_STOR(&s[o+3], SIMDBase_SUBi(t0i, t1i));
+ SIMDBase_STOR(&s[o+4], SIMDBase_SUBi(t2r, t3r)); SIMDBase_STOR(&s[o+5], SIMDBase_SUBi(t2i, t3i));
+ SIMDBase_STOR(&s[o+6], SIMDBase_ADDi(t2r, t3r)); SIMDBase_STOR(&s[o+7], SIMDBase_ADDi(t2i, t3i));
+}
+
+static inline void srButBackward4(DFTUndiff *p) {
+ SIMDBase_VECT *s = p->s;
+ int32_t o = p->offset1;
+
+ SIMDBase_VECT t0r, t0i, t1r, t1i;
+ SIMDBase_VECT s0 = SIMDBase_LOAD(&s[o+0]), s1 = SIMDBase_LOAD(&s[o+1]), s2 = SIMDBase_LOAD(&s[o+2]), s3 = SIMDBase_LOAD(&s[o+3]);
+
+ t0r = SIMDBase_ADDi(s0, s2); t0i = SIMDBase_SUBi(s0, s2); s0 = t0r; s2 = t0i;
+ t0r = SIMDBase_ADDi(s1, s3); t0i = SIMDBase_SUBi(s1, s3); s1 = t0r; s3 = t0i;
+ t0r = SIMDBase_ADDm(&s[o+4], &s[o+6]); t1i = SIMDBase_SUBm(&s[o+4], &s[o+6]);
+ t0i = SIMDBase_ADDm(&s[o+7], &s[o+5]); t1r = SIMDBase_SUBm(&s[o+7], &s[o+5]);
+
+ SIMDBase_STOR(&s[o+4], SIMDBase_SUBi(s0, t0r)); SIMDBase_STOR(&s[o+5], SIMDBase_SUBi(s1, t0i));
+ SIMDBase_STOR(&s[o+6], SIMDBase_SUBi(s2, t1r)); SIMDBase_STOR(&s[o+7], SIMDBase_SUBi(s3, t1i));
+ SIMDBase_STOR(&s[o+0], SIMDBase_ADDi(s0, t0r)); SIMDBase_STOR(&s[o+1], SIMDBase_ADDi(s1, t0i));
+ SIMDBase_STOR(&s[o+2], SIMDBase_ADDi(s2, t1r)); SIMDBase_STOR(&s[o+3], SIMDBase_ADDi(s3, t1i));
+}
+
+static inline void srButForward8(DFTUndiff *p) {
+ SIMDBase_VECT *s = p->s;
+ int32_t o = p->offset1;
+ SIMDBase_VECT t0r, t0i, t1r, t1i, t2r, t2i, t3r, t3i;
+
+ SIMDBase_VECT s0 = SIMDBase_LOAD(&s[o+ 0]), s1 = SIMDBase_LOAD(&s[o+ 1]), s2 = SIMDBase_LOAD(&s[o+ 2]), s3 = SIMDBase_LOAD(&s[o+ 3]);
+ SIMDBase_VECT s4 = SIMDBase_LOAD(&s[o+ 4]), s5 = SIMDBase_LOAD(&s[o+ 5]), s6 = SIMDBase_LOAD(&s[o+ 6]), s7 = SIMDBase_LOAD(&s[o+ 7]);
+ SIMDBase_VECT s8 = SIMDBase_LOAD(&s[o+ 8]), s9 = SIMDBase_LOAD(&s[o+ 9]), sa = SIMDBase_LOAD(&s[o+10]) ,sb = SIMDBase_LOAD(&s[o+11]);
+ SIMDBase_VECT sc = SIMDBase_LOAD(&s[o+12]), sd = SIMDBase_LOAD(&s[o+13]), se = SIMDBase_LOAD(&s[o+14]), sf = SIMDBase_LOAD(&s[o+15]);
+
+ t2r = SIMDBase_SUBi(s0, s8); t2i = SIMDBase_SUBi(s1, s9);
+ t3r = SIMDBase_SUBi(sd, s5); t3i = SIMDBase_SUBi(s4, sc);
+
+ s0 = SIMDBase_ADDi(s0, s8); s1 = SIMDBase_ADDi(s1, s9);
+ s4 = SIMDBase_ADDi(s4, sc); s5 = SIMDBase_ADDi(s5, sd);
+
+ s8 = SIMDBase_SUBi(t2r, t3r); s9 = SIMDBase_SUBi(t2i, t3i);
+ sc = SIMDBase_ADDi(t2r, t3r); sd = SIMDBase_ADDi(t2i, t3i);
+
+ t2r = SIMDBase_SUBi(s2, sa); t2i = SIMDBase_SUBi(s3, sb);
+ t3r = SIMDBase_SUBi(sf, s7); t3i = SIMDBase_SUBi(s6, se);
+
+ s2 = SIMDBase_ADDi(s2, sa); s3 = SIMDBase_ADDi(s3, sb);
+ s6 = SIMDBase_ADDi(s6, se); s7 = SIMDBase_ADDi(s7, sf);
+
+ t0r = SIMDBase_SUBi(t2r, t3r); t1r = SIMDBase_ADDi(t2r, t3r);
+ t0i = SIMDBase_SUBi(t2i, t3i); t1i = SIMDBase_ADDi(t2i, t3i);
+
+ sa = SIMDBase_MULi(SIMDBase_ADDi(t0r, t0i), SIMDBase_SET1( SQRT2_2));
+ sb = SIMDBase_MULi(SIMDBase_SUBi(t0i, t0r), SIMDBase_SET1( SQRT2_2));
+ se = SIMDBase_MULi(SIMDBase_SUBi(t1i, t1r), SIMDBase_SET1( SQRT2_2));
+ sf = SIMDBase_MULi(SIMDBase_ADDi(t1r, t1i), SIMDBase_SET1(-SQRT2_2));
+
+ SIMDBase_STOR(&s[o+ 8], SIMDBase_ADDi(s8, sa)); SIMDBase_STOR(&s[o+ 9], SIMDBase_ADDi(s9, sb));
+ SIMDBase_STOR(&s[o+10], SIMDBase_SUBi(s8, sa)); SIMDBase_STOR(&s[o+11], SIMDBase_SUBi(s9, sb));
+
+ SIMDBase_STOR(&s[o+12], SIMDBase_ADDi(sc, se)); SIMDBase_STOR(&s[o+13], SIMDBase_ADDi(sd, sf));
+ SIMDBase_STOR(&s[o+14], SIMDBase_SUBi(sc, se)); SIMDBase_STOR(&s[o+15], SIMDBase_SUBi(sd, sf));
+
+ t0r = SIMDBase_ADDi(s0, s4); t2r = SIMDBase_SUBi(s0, s4);
+ t0i = SIMDBase_ADDi(s1, s5); t2i = SIMDBase_SUBi(s1, s5);
+
+ t1r = SIMDBase_ADDi(s2, s6); t3i = SIMDBase_SUBi(s2, s6);
+ t1i = SIMDBase_ADDi(s3, s7); t3r = SIMDBase_SUBi(s7, s3);
+
+ SIMDBase_STOR(&s[o+0], SIMDBase_ADDi(t0r, t1r)); SIMDBase_STOR(&s[o+1], SIMDBase_ADDi(t0i, t1i));
+ SIMDBase_STOR(&s[o+2], SIMDBase_SUBi(t0r, t1r)); SIMDBase_STOR(&s[o+3], SIMDBase_SUBi(t0i, t1i));
+ SIMDBase_STOR(&s[o+4], SIMDBase_SUBi(t2r, t3r)); SIMDBase_STOR(&s[o+5], SIMDBase_SUBi(t2i, t3i));
+ SIMDBase_STOR(&s[o+6], SIMDBase_ADDi(t2r, t3r)); SIMDBase_STOR(&s[o+7], SIMDBase_ADDi(t2i, t3i));
+}
+
+static void srButBackward8(DFTUndiff *p) {
+ SIMDBase_VECT *s = p->s;
+ int32_t o = p->offset1;
+ SIMDBase_VECT t0r, t0i, t1r, t1i;
+
+ SIMDBase_VECT s0 = SIMDBase_LOAD(&s[o+ 0]), s1 = SIMDBase_LOAD(&s[o+ 1]), s2 = SIMDBase_LOAD(&s[o+ 2]), s3 = SIMDBase_LOAD(&s[o+ 3]);
+ SIMDBase_VECT s4 = SIMDBase_LOAD(&s[o+ 4]), s5 = SIMDBase_LOAD(&s[o+ 5]), s6 = SIMDBase_LOAD(&s[o+ 6]), s7 = SIMDBase_LOAD(&s[o+ 7]);
+ SIMDBase_VECT s8 = SIMDBase_LOAD(&s[o+ 8]), s9 = SIMDBase_LOAD(&s[o+ 9]), sa = SIMDBase_LOAD(&s[o+10]) ,sb = SIMDBase_LOAD(&s[o+11]);
+ SIMDBase_VECT sc = SIMDBase_LOAD(&s[o+12]), sd = SIMDBase_LOAD(&s[o+13]), se = SIMDBase_LOAD(&s[o+14]), sf = SIMDBase_LOAD(&s[o+15]);
+
+ t0r = SIMDBase_ADDi(s8, sa); t0i = SIMDBase_SUBi(s8, sa); s8 = t0r; sa = t0i;
+ t0r = SIMDBase_ADDi(s9, sb); t0i = SIMDBase_SUBi(s9, sb); s9 = t0r; sb = t0i;
+ t0r = SIMDBase_ADDi(sc, se); t0i = SIMDBase_SUBi(sc, se); sc = t0r; se = t0i;
+ t0r = SIMDBase_ADDi(sd, sf); t0i = SIMDBase_SUBi(sd, sf); sd = t0r; sf = t0i;
+ t0r = SIMDBase_ADDi(s0, s2); t0i = SIMDBase_SUBi(s0, s2); s0 = t0r; s2 = t0i;
+ t0r = SIMDBase_ADDi(s1, s3); t0i = SIMDBase_SUBi(s1, s3); s1 = t0r; s3 = t0i;
+
+ t0r = SIMDBase_ADDi(s4, s6); t0i = SIMDBase_ADDi(s7, s5);
+ t1r = SIMDBase_SUBi(s7, s5); t1i = SIMDBase_SUBi(s4, s6);
+
+ s4 = SIMDBase_SUBi(s0, t0r); s5 = SIMDBase_SUBi(s1, t0i);
+ s6 = SIMDBase_SUBi(s2, t1r); s7 = SIMDBase_SUBi(s3, t1i);
+ s0 = SIMDBase_ADDi(s0, t0r); s1 = SIMDBase_ADDi(s1, t0i);
+ s2 = SIMDBase_ADDi(s2, t1r); s3 = SIMDBase_ADDi(s3, t1i);
+
+ t0r = SIMDBase_ADDi(s8, sc); t0i = SIMDBase_ADDi(s9, sd);
+ t1r = SIMDBase_SUBi(sd, s9); t1i = SIMDBase_SUBi(s8, sc);
+
+ s8 = SIMDBase_SUBi(s0, t0r); s9 = SIMDBase_SUBi(s1, t0i);
+ sc = SIMDBase_SUBi(s4, t1r); sd = SIMDBase_SUBi(s5, t1i);
+ s0 = SIMDBase_ADDi(s0, t0r); s1 = SIMDBase_ADDi(s1, t0i);
+ s4 = SIMDBase_ADDi(s4, t1r); s5 = SIMDBase_ADDi(s5, t1i);
+
+ t0r = SIMDBase_MULi(SIMDBase_SUBi(sa, sb), SIMDBase_SET1( SQRT2_2));
+ t0i = SIMDBase_MULi(SIMDBase_ADDi(sa, sb), SIMDBase_SET1( SQRT2_2));
+ t1r = SIMDBase_MULi(SIMDBase_ADDi(se, sf), SIMDBase_SET1(-SQRT2_2));
+ t1i = SIMDBase_MULi(SIMDBase_SUBi(se, sf), SIMDBase_SET1( SQRT2_2));
+
+ sa = t0r; sb = t0i; se = t1r; sf = t1i;
+
+ t0r = SIMDBase_ADDi(sa, se); t0i = SIMDBase_ADDi(sb, sf);
+ t1r = SIMDBase_SUBi(sf, sb); t1i = SIMDBase_SUBi(sa, se);
+
+ sa = SIMDBase_SUBi(s2, t0r); sb = SIMDBase_SUBi(s3, t0i);
+ se = SIMDBase_SUBi(s6, t1r); sf = SIMDBase_SUBi(s7, t1i);
+ s2 = SIMDBase_ADDi(s2, t0r); s3 = SIMDBase_ADDi(s3, t0i);
+ s6 = SIMDBase_ADDi(s6, t1r); s7 = SIMDBase_ADDi(s7, t1i);
+
+ SIMDBase_STOR(&s[o+ 0], s0); SIMDBase_STOR(&s[o+ 1], s1); SIMDBase_STOR(&s[o+ 2], s2); SIMDBase_STOR(&s[o+ 3], s3);
+ SIMDBase_STOR(&s[o+ 4], s4); SIMDBase_STOR(&s[o+ 5], s5); SIMDBase_STOR(&s[o+ 6], s6); SIMDBase_STOR(&s[o+ 7], s7);
+ SIMDBase_STOR(&s[o+ 8], s8); SIMDBase_STOR(&s[o+ 9], s9); SIMDBase_STOR(&s[o+10], sa); SIMDBase_STOR(&s[o+11], sb);
+ SIMDBase_STOR(&s[o+12], sc); SIMDBase_STOR(&s[o+13], sd); SIMDBase_STOR(&s[o+14], se); SIMDBase_STOR(&s[o+15], sf);
+}
+
+#if 0
+static inline void srButForwardSub(DFTUndiff *p) {
+ SIMDBase_VECT *s = p->s;
+ SIMDBase_REAL *tbl = p->ptTable[p->log2butlen];
+
+ int32_t i0 = p->offset1;
+ int32_t i1 = i0 + p->stride;
+ int32_t i2 = i1 + p->stride;
+ int32_t i3 = i2 + p->stride;
+ int32_t im = i1;
+
+ int32_t p0 = p->offset2 & (p->butlen*4-1);
+
+ while(i0 < im) {
+ SIMDBase_VECT t0r, t0i, t1r, t1i;
+ SIMDBase_VECT s00, s01, s10, s11, s20, s21, s30, s31;
+ SIMDBase_VECT a0, a1, a2, a3;
+
+ s00 = SIMDBase_LOAD(&s[i0+0]), s01 = SIMDBase_LOAD(&s[i0+1]);
+ s10 = SIMDBase_LOAD(&s[i1+0]), s11 = SIMDBase_LOAD(&s[i1+1]);
+ s20 = SIMDBase_LOAD(&s[i2+0]), s21 = SIMDBase_LOAD(&s[i2+1]);
+ s30 = SIMDBase_LOAD(&s[i3+0]), s31 = SIMDBase_LOAD(&s[i3+1]);
+
+ t0r = SIMDBase_SUBi(SIMDBase_SUBi(s00, s20), SIMDBase_SUBi(s31, s11));
+ t0i = SIMDBase_SUBi(SIMDBase_SUBi(s01, s21), SIMDBase_SUBi(s10, s30));
+
+ t1r = SIMDBase_ADDi(SIMDBase_SUBi(s00, s20), SIMDBase_SUBi(s31, s11));
+ t1i = SIMDBase_ADDi(SIMDBase_SUBi(s01, s21), SIMDBase_SUBi(s10, s30));
+
+ a0 = SIMDBase_LOAD1(&tbl[p0+0]); a1 = SIMDBase_LOAD1(&tbl[p0+1]);
+ a2 = SIMDBase_LOAD1(&tbl[p0+2]); a3 = SIMDBase_LOAD1(&tbl[p0+3]);
+
+ SIMDBase_STOR(&s[i0 ], SIMDBase_ADDi(s00, s20)); SIMDBase_STOR(&s[i0+1], SIMDBase_ADDi(s01, s21));
+ SIMDBase_STOR(&s[i1 ], SIMDBase_ADDi(s10, s30)); SIMDBase_STOR(&s[i1+1], SIMDBase_ADDi(s11, s31));
+
+#ifndef SIMDBase_FMADD_AVAILABLE
+ SIMDBase_STOR(&s[i2 ], SIMDBase_SUBi(SIMDBase_MULi(t0r, a0), SIMDBase_MULi(t0i, a1)));
+ SIMDBase_STOR(&s[i2+1], SIMDBase_ADDi(SIMDBase_MULi(t0r, a1), SIMDBase_MULi(t0i, a0)));
+ SIMDBase_STOR(&s[i3 ], SIMDBase_SUBi(SIMDBase_MULi(t1r, a2), SIMDBase_MULi(t1i, a3)));
+ SIMDBase_STOR(&s[i3+1], SIMDBase_ADDi(SIMDBase_MULi(t1r, a3), SIMDBase_MULi(t1i, a2)));
+#else
+ SIMDBase_STOR(&s[i2 ], SIMDBase_FMSUBi(t0i, a1, SIMDBase_MULi(t0r, a0)));
+ SIMDBase_STOR(&s[i2+1], SIMDBase_FMADDi(t0r, a1, SIMDBase_MULi(t0i, a0)));
+ SIMDBase_STOR(&s[i3 ], SIMDBase_FMSUBi(t1i, a3, SIMDBase_MULi(t1r, a2)));
+ SIMDBase_STOR(&s[i3+1], SIMDBase_FMADDi(t1r, a3, SIMDBase_MULi(t1i, a2)));
+#endif
+
+ i0 += 2; i1 += 2; i2 += 2; i3 += 2;
+ p0 += 4;
+ }
+}
+#endif
+
+#if 0
+static inline void srButBackwardSub(DFTUndiff *p) {
+ SIMDBase_VECT *s = p->s;
+ SIMDBase_REAL *tbl = p->ptTable[p->log2butlen];
+
+ int32_t i0 = p->offset1;
+ int32_t i1 = i0 + p->stride;
+ int32_t i2 = i1 + p->stride;
+ int32_t i3 = i2 + p->stride;
+ int32_t im = i1;
+
+ int32_t p0 = p->offset2 & (p->butlen*4-1);
+
+ while(i0 < im) {
+ SIMDBase_VECT t0r, t0i, t1r, t1i, u, v;
+ SIMDBase_VECT s00, s01, s10, s11, s20, s21, s30, s31;
+ SIMDBase_VECT a0, a1, a2, a3;
+
+ s20 = SIMDBase_LOAD(&s[i2+0]); s21 = SIMDBase_LOAD(&s[i2+1]);
+ a0 = SIMDBase_LOAD1(&tbl[p0+0]); a1 = SIMDBase_LOAD1(&tbl[p0+1]);
+ u = SIMDBase_ADDi(SIMDBase_MULi(s20, a0), SIMDBase_MULi(s21, a1));
+
+ s30 = SIMDBase_LOAD(&s[i3+0]); s31 = SIMDBase_LOAD(&s[i3+1]);
+ a2 = SIMDBase_LOAD1(&tbl[p0+2]); a3 = SIMDBase_LOAD1(&tbl[p0+3]);
+ v = SIMDBase_ADDi(SIMDBase_MULi(s30, a2), SIMDBase_MULi(s31, a3));
+
+ t0r = SIMDBase_ADDi(u, v); t1i = SIMDBase_SUBi(u, v);
+ u = SIMDBase_SUBi(SIMDBase_MULi(s31, a2), SIMDBase_MULi(s30, a3));
+ v = SIMDBase_SUBi(SIMDBase_MULi(s21, a0), SIMDBase_MULi(s20, a1));
+ t0i = SIMDBase_ADDi(u, v); t1r = SIMDBase_SUBi(u, v);
+
+ s00 = SIMDBase_LOAD(&s[i0+0]); s01 = SIMDBase_LOAD(&s[i0+1]);
+ s10 = SIMDBase_LOAD(&s[i1+0]); s11 = SIMDBase_LOAD(&s[i1+1]);
+
+ SIMDBase_STOR(&s[i2+0], SIMDBase_SUBi(s00, t0r)); SIMDBase_STOR(&s[i0+0], SIMDBase_ADDi(s00, t0r));
+ SIMDBase_STOR(&s[i2+1], SIMDBase_SUBi(s01, t0i)); SIMDBase_STOR(&s[i0+1], SIMDBase_ADDi(s01, t0i));
+ SIMDBase_STOR(&s[i3+0], SIMDBase_SUBi(s10, t1r)); SIMDBase_STOR(&s[i1+0], SIMDBase_ADDi(s10, t1r));
+ SIMDBase_STOR(&s[i3+1], SIMDBase_SUBi(s11, t1i)); SIMDBase_STOR(&s[i1+1], SIMDBase_ADDi(s11, t1i));
+
+ i0 += 2; i1 += 2; i2 += 2; i3 += 2;
+ p0 += 4;
+ }
+}
+
+static void srButBackwardSubUnrolled(DFTUndiff *p) {
+ srButBackwardSub(p);
+}
+#endif
+
+static inline void srButForwardSubUnrolled(DFTUndiff *p) {
+ SIMDBase_VECT *s = p->s;
+ SIMDBase_REAL *tbl = p->ptTable[p->log2butlen];
+
+ int32_t i0 = p->offset1;
+ int32_t i1 = i0 + p->stride;
+ int32_t i2 = i1 + p->stride;
+ int32_t i3 = i2 + p->stride;
+ int32_t im = i1;
+
+ int32_t p0 = p->offset2 & (p->butlen*4-1);
+
+ while(i0 < im) {
+ SIMDBase_VECT t0r, t0i, t1r, t1i;
+ SIMDBase_VECT s00, s01, s10, s11, s20, s21, s30, s31;
+ SIMDBase_VECT a0, a1, a2, a3;
+
+ //
+
+ s00 = SIMDBase_LOAD(&s[i0+0]); s01 = SIMDBase_LOAD(&s[i0+1]);
+ s10 = SIMDBase_LOAD(&s[i1+0]); s11 = SIMDBase_LOAD(&s[i1+1]);
+ s20 = SIMDBase_LOAD(&s[i2+0]); s21 = SIMDBase_LOAD(&s[i2+1]);
+ s30 = SIMDBase_LOAD(&s[i3+0]); s31 = SIMDBase_LOAD(&s[i3+1]);
+
+ t0r = SIMDBase_SUBi(SIMDBase_SUBi(s00, s20), SIMDBase_SUBi(s31, s11));
+ t0i = SIMDBase_SUBi(SIMDBase_SUBi(s01, s21), SIMDBase_SUBi(s10, s30));
+
+ t1r = SIMDBase_ADDi(SIMDBase_SUBi(s00, s20), SIMDBase_SUBi(s31, s11));
+ t1i = SIMDBase_ADDi(SIMDBase_SUBi(s01, s21), SIMDBase_SUBi(s10, s30));
+
+ a0 = SIMDBase_LOAD1(&tbl[p0+0]); a1 = SIMDBase_LOAD1(&tbl[p0+1]);
+ a2 = SIMDBase_LOAD1(&tbl[p0+2]); a3 = SIMDBase_LOAD1(&tbl[p0+3]);
+
+ SIMDBase_STOR(&s[i0 ], SIMDBase_ADDi(s00, s20)); SIMDBase_STOR(&s[i0+1], SIMDBase_ADDi(s01, s21));
+ SIMDBase_STOR(&s[i1 ], SIMDBase_ADDi(s10, s30)); SIMDBase_STOR(&s[i1+1], SIMDBase_ADDi(s11, s31));
+
+#ifndef SIMDBase_FMADD_AVAILABLE
+ SIMDBase_STOR(&s[i2 ], SIMDBase_SUBi(SIMDBase_MULi(t0r, a0), SIMDBase_MULi(t0i, a1)));
+ SIMDBase_STOR(&s[i2+1], SIMDBase_ADDi(SIMDBase_MULi(t0r, a1), SIMDBase_MULi(t0i, a0)));
+ SIMDBase_STOR(&s[i3 ], SIMDBase_SUBi(SIMDBase_MULi(t1r, a2), SIMDBase_MULi(t1i, a3)));
+ SIMDBase_STOR(&s[i3+1], SIMDBase_ADDi(SIMDBase_MULi(t1r, a3), SIMDBase_MULi(t1i, a2)));
+#else
+ SIMDBase_STOR(&s[i2 ], SIMDBase_FMSUBi(t0i, a1, SIMDBase_MULi(t0r, a0)));
+ SIMDBase_STOR(&s[i2+1], SIMDBase_FMADDi(t0r, a1, SIMDBase_MULi(t0i, a0)));
+ SIMDBase_STOR(&s[i3 ], SIMDBase_FMSUBi(t1i, a3, SIMDBase_MULi(t1r, a2)));
+ SIMDBase_STOR(&s[i3+1], SIMDBase_FMADDi(t1r, a3, SIMDBase_MULi(t1i, a2)));
+#endif
+
+ //
+
+ s00 = SIMDBase_LOAD(&s[i0+2]); s01 = SIMDBase_LOAD(&s[i0+3]);
+ s10 = SIMDBase_LOAD(&s[i1+2]); s11 = SIMDBase_LOAD(&s[i1+3]);
+ s20 = SIMDBase_LOAD(&s[i2+2]); s21 = SIMDBase_LOAD(&s[i2+3]);
+ s30 = SIMDBase_LOAD(&s[i3+2]); s31 = SIMDBase_LOAD(&s[i3+3]);
+
+ t0r = SIMDBase_SUBi(SIMDBase_SUBi(s00, s20), SIMDBase_SUBi(s31, s11));
+ t0i = SIMDBase_SUBi(SIMDBase_SUBi(s01, s21), SIMDBase_SUBi(s10, s30));
+
+ t1r = SIMDBase_ADDi(SIMDBase_SUBi(s00, s20), SIMDBase_SUBi(s31, s11));
+ t1i = SIMDBase_ADDi(SIMDBase_SUBi(s01, s21), SIMDBase_SUBi(s10, s30));
+
+ a0 = SIMDBase_LOAD1(&tbl[p0+4]); a1 = SIMDBase_LOAD1(&tbl[p0+5]);
+ a2 = SIMDBase_LOAD1(&tbl[p0+6]); a3 = SIMDBase_LOAD1(&tbl[p0+7]);
+
+ SIMDBase_STOR(&s[i0+2], SIMDBase_ADDi(s00, s20)); SIMDBase_STOR(&s[i0+3], SIMDBase_ADDi(s01, s21));
+ SIMDBase_STOR(&s[i1+2], SIMDBase_ADDi(s10, s30)); SIMDBase_STOR(&s[i1+3], SIMDBase_ADDi(s11, s31));
+
+#ifndef SIMDBase_FMADD_AVAILABLE
+ SIMDBase_STOR(&s[i2+2], SIMDBase_SUBi(SIMDBase_MULi(t0r, a0), SIMDBase_MULi(t0i, a1)));
+ SIMDBase_STOR(&s[i2+3], SIMDBase_ADDi(SIMDBase_MULi(t0r, a1), SIMDBase_MULi(t0i, a0)));
+ SIMDBase_STOR(&s[i3+2], SIMDBase_SUBi(SIMDBase_MULi(t1r, a2), SIMDBase_MULi(t1i, a3)));
+ SIMDBase_STOR(&s[i3+3], SIMDBase_ADDi(SIMDBase_MULi(t1r, a3), SIMDBase_MULi(t1i, a2)));
+#else
+ SIMDBase_STOR(&s[i2+2], SIMDBase_FMSUBi(t0i, a1, SIMDBase_MULi(t0r, a0)));
+ SIMDBase_STOR(&s[i2+3], SIMDBase_FMADDi(t0r, a1, SIMDBase_MULi(t0i, a0)));
+ SIMDBase_STOR(&s[i3+2], SIMDBase_FMSUBi(t1i, a3, SIMDBase_MULi(t1r, a2)));
+ SIMDBase_STOR(&s[i3+3], SIMDBase_FMADDi(t1r, a3, SIMDBase_MULi(t1i, a2)));
+#endif
+
+ //
+
+ s00 = SIMDBase_LOAD(&s[i0+4]); s01 = SIMDBase_LOAD(&s[i0+5]);
+ s10 = SIMDBase_LOAD(&s[i1+4]); s11 = SIMDBase_LOAD(&s[i1+5]);
+ s20 = SIMDBase_LOAD(&s[i2+4]); s21 = SIMDBase_LOAD(&s[i2+5]);
+ s30 = SIMDBase_LOAD(&s[i3+4]); s31 = SIMDBase_LOAD(&s[i3+5]);
+
+ t0r = SIMDBase_SUBi(SIMDBase_SUBi(s00, s20), SIMDBase_SUBi(s31, s11));
+ t0i = SIMDBase_SUBi(SIMDBase_SUBi(s01, s21), SIMDBase_SUBi(s10, s30));
+
+ t1r = SIMDBase_ADDi(SIMDBase_SUBi(s00, s20), SIMDBase_SUBi(s31, s11));
+ t1i = SIMDBase_ADDi(SIMDBase_SUBi(s01, s21), SIMDBase_SUBi(s10, s30));
+
+ a0 = SIMDBase_LOAD1(&tbl[p0+ 8]); a1 = SIMDBase_LOAD1(&tbl[p0+ 9]);
+ a2 = SIMDBase_LOAD1(&tbl[p0+10]); a3 = SIMDBase_LOAD1(&tbl[p0+11]);
+
+ SIMDBase_STOR(&s[i0+4], SIMDBase_ADDi(s00, s20)); SIMDBase_STOR(&s[i0+5], SIMDBase_ADDi(s01, s21));
+ SIMDBase_STOR(&s[i1+4], SIMDBase_ADDi(s10, s30)); SIMDBase_STOR(&s[i1+5], SIMDBase_ADDi(s11, s31));
+
+#ifndef SIMDBase_FMADD_AVAILABLE
+ SIMDBase_STOR(&s[i2+4], SIMDBase_SUBi(SIMDBase_MULi(t0r, a0), SIMDBase_MULi(t0i, a1)));
+ SIMDBase_STOR(&s[i2+5], SIMDBase_ADDi(SIMDBase_MULi(t0r, a1), SIMDBase_MULi(t0i, a0)));
+ SIMDBase_STOR(&s[i3+4], SIMDBase_SUBi(SIMDBase_MULi(t1r, a2), SIMDBase_MULi(t1i, a3)));
+ SIMDBase_STOR(&s[i3+5], SIMDBase_ADDi(SIMDBase_MULi(t1r, a3), SIMDBase_MULi(t1i, a2)));
+#else
+ SIMDBase_STOR(&s[i2+4], SIMDBase_FMSUBi(t0i, a1, SIMDBase_MULi(t0r, a0)));
+ SIMDBase_STOR(&s[i2+5], SIMDBase_FMADDi(t0r, a1, SIMDBase_MULi(t0i, a0)));
+ SIMDBase_STOR(&s[i3+4], SIMDBase_FMSUBi(t1i, a3, SIMDBase_MULi(t1r, a2)));
+ SIMDBase_STOR(&s[i3+5], SIMDBase_FMADDi(t1r, a3, SIMDBase_MULi(t1i, a2)));
+#endif
+
+ //
+
+ s00 = SIMDBase_LOAD(&s[i0+6]); s01 = SIMDBase_LOAD(&s[i0+7]);
+ s10 = SIMDBase_LOAD(&s[i1+6]); s11 = SIMDBase_LOAD(&s[i1+7]);
+ s20 = SIMDBase_LOAD(&s[i2+6]); s21 = SIMDBase_LOAD(&s[i2+7]);
+ s30 = SIMDBase_LOAD(&s[i3+6]); s31 = SIMDBase_LOAD(&s[i3+7]);
+
+ t0r = SIMDBase_SUBi(SIMDBase_SUBi(s00, s20), SIMDBase_SUBi(s31, s11));
+ t0i = SIMDBase_SUBi(SIMDBase_SUBi(s01, s21), SIMDBase_SUBi(s10, s30));
+
+ t1r = SIMDBase_ADDi(SIMDBase_SUBi(s00, s20), SIMDBase_SUBi(s31, s11));
+ t1i = SIMDBase_ADDi(SIMDBase_SUBi(s01, s21), SIMDBase_SUBi(s10, s30));
+
+ a0 = SIMDBase_LOAD1(&tbl[p0+12]); a1 = SIMDBase_LOAD1(&tbl[p0+13]);
+ a2 = SIMDBase_LOAD1(&tbl[p0+14]); a3 = SIMDBase_LOAD1(&tbl[p0+15]);
+
+ SIMDBase_STOR(&s[i0+6], SIMDBase_ADDi(s00, s20)); SIMDBase_STOR(&s[i0+7], SIMDBase_ADDi(s01, s21));
+ SIMDBase_STOR(&s[i1+6], SIMDBase_ADDi(s10, s30)); SIMDBase_STOR(&s[i1+7], SIMDBase_ADDi(s11, s31));
+
+#ifndef SIMDBase_FMADD_AVAILABLE
+ SIMDBase_STOR(&s[i2+6], SIMDBase_SUBi(SIMDBase_MULi(t0r, a0), SIMDBase_MULi(t0i, a1)));
+ SIMDBase_STOR(&s[i2+7], SIMDBase_ADDi(SIMDBase_MULi(t0r, a1), SIMDBase_MULi(t0i, a0)));
+ SIMDBase_STOR(&s[i3+6], SIMDBase_SUBi(SIMDBase_MULi(t1r, a2), SIMDBase_MULi(t1i, a3)));
+ SIMDBase_STOR(&s[i3+7], SIMDBase_ADDi(SIMDBase_MULi(t1r, a3), SIMDBase_MULi(t1i, a2)));
+#else
+ SIMDBase_STOR(&s[i2+6], SIMDBase_FMSUBi(t0i, a1, SIMDBase_MULi(t0r, a0)));
+ SIMDBase_STOR(&s[i2+7], SIMDBase_FMADDi(t0r, a1, SIMDBase_MULi(t0i, a0)));
+ SIMDBase_STOR(&s[i3+6], SIMDBase_FMSUBi(t1i, a3, SIMDBase_MULi(t1r, a2)));
+ SIMDBase_STOR(&s[i3+7], SIMDBase_FMADDi(t1r, a3, SIMDBase_MULi(t1i, a2)));
+#endif
+
+ //
+
+ i0 += 8; i1 += 8; i2 += 8; i3 += 8;
+ p0 += 16;
+ }
+}
+
+#if 1
+static void srButBackwardSubUnrolled(DFTUndiff *p) {
+ SIMDBase_VECT *s = p->s;
+ SIMDBase_REAL *tbl = p->ptTable[p->log2butlen];
+
+ int32_t i0 = p->offset1;
+ int32_t i1 = i0 + p->stride;
+ int32_t i2 = i1 + p->stride;
+ int32_t i3 = i2 + p->stride;
+ int32_t im = i1;
+
+ int32_t p0 = p->offset2 & (p->butlen*4-1);
+
+ while(i0 < im) {
+ SIMDBase_VECT t0r, t0i, t1r, t1i, u, v;
+ SIMDBase_VECT s00, s01, s10, s11, s20, s21, s30, s31;
+ SIMDBase_VECT a0, a1, a2, a3;
+
+ //
+
+ s20 = SIMDBase_LOAD(&s[i2+ 0]); s21 = SIMDBase_LOAD(&s[i2+ 1]);
+ a0 = SIMDBase_LOAD1(&tbl[p0+ 0]); a1 = SIMDBase_LOAD1(&tbl[p0+ 1]);
+#ifndef SIMDBase_FMADD_AVAILABLE
+ u = SIMDBase_ADDi(SIMDBase_MULi(s20, a0), SIMDBase_MULi(s21, a1));
+#else
+ u = SIMDBase_FMADDi(s20, a0, SIMDBase_MULi(s21, a1));
+#endif
+
+ s30 = SIMDBase_LOAD(&s[i3+ 0]); s31 = SIMDBase_LOAD(&s[i3+ 1]);
+ a2 = SIMDBase_LOAD1(&tbl[p0+ 2]); a3 = SIMDBase_LOAD1(&tbl[p0+ 3]);
+#ifndef SIMDBase_FMADD_AVAILABLE
+ v = SIMDBase_ADDi(SIMDBase_MULi(s30, a2), SIMDBase_MULi(s31, a3));
+#else
+ v = SIMDBase_FMADDi(s30, a2, SIMDBase_MULi(s31, a3));
+#endif
+
+ t0r = SIMDBase_ADDi(u, v); t1i = SIMDBase_SUBi(u, v);
+
+#ifndef SIMDBase_FMADD_AVAILABLE
+ u = SIMDBase_SUBi(SIMDBase_MULi(s31, a2), SIMDBase_MULi(s30, a3));
+ v = SIMDBase_SUBi(SIMDBase_MULi(s21, a0), SIMDBase_MULi(s20, a1));
+#else
+ u = SIMDBase_FMSUBi(s30, a3, SIMDBase_MULi(s31, a2));
+ v = SIMDBase_FMSUBi(s20, a1, SIMDBase_MULi(s21, a0));
+#endif
+ t0i = SIMDBase_ADDi(u, v); t1r = SIMDBase_SUBi(u, v);
+
+ s00 = SIMDBase_LOAD(&s[i0+ 0]); s01 = SIMDBase_LOAD(&s[i0+ 1]);
+ s10 = SIMDBase_LOAD(&s[i1+ 0]); s11 = SIMDBase_LOAD(&s[i1+ 1]);
+
+ SIMDBase_STOR(&s[i2+ 0], SIMDBase_SUBi(s00, t0r)); SIMDBase_STOR(&s[i0+ 0], SIMDBase_ADDi(s00, t0r));
+ SIMDBase_STOR(&s[i2+ 1], SIMDBase_SUBi(s01, t0i)); SIMDBase_STOR(&s[i0+ 1], SIMDBase_ADDi(s01, t0i));
+ SIMDBase_STOR(&s[i3+ 0], SIMDBase_SUBi(s10, t1r)); SIMDBase_STOR(&s[i1+ 0], SIMDBase_ADDi(s10, t1r));
+ SIMDBase_STOR(&s[i3+ 1], SIMDBase_SUBi(s11, t1i)); SIMDBase_STOR(&s[i1+ 1], SIMDBase_ADDi(s11, t1i));
+
+ //
+
+ s20 = SIMDBase_LOAD(&s[i2+ 2]); s21 = SIMDBase_LOAD(&s[i2+ 3]);
+ a0 = SIMDBase_LOAD1(&tbl[p0+ 4]); a1 = SIMDBase_LOAD1(&tbl[p0+ 5]);
+#ifndef SIMDBase_FMADD_AVAILABLE
+ u = SIMDBase_ADDi(SIMDBase_MULi(s20, a0), SIMDBase_MULi(s21, a1));
+#else
+ u = SIMDBase_FMADDi(s20, a0, SIMDBase_MULi(s21, a1));
+#endif
+
+ s30 = SIMDBase_LOAD(&s[i3+ 2]); s31 = SIMDBase_LOAD(&s[i3+ 3]);
+ a2 = SIMDBase_LOAD1(&tbl[p0+ 6]); a3 = SIMDBase_LOAD1(&tbl[p0+ 7]);
+#ifndef SIMDBase_FMADD_AVAILABLE
+ v = SIMDBase_ADDi(SIMDBase_MULi(s30, a2), SIMDBase_MULi(s31, a3));
+#else
+ v = SIMDBase_FMADDi(s30, a2, SIMDBase_MULi(s31, a3));
+#endif
+
+ t0r = SIMDBase_ADDi(u, v); t1i = SIMDBase_SUBi(u, v);
+
+#ifndef SIMDBase_FMADD_AVAILABLE
+ u = SIMDBase_SUBi(SIMDBase_MULi(s31, a2), SIMDBase_MULi(s30, a3));
+ v = SIMDBase_SUBi(SIMDBase_MULi(s21, a0), SIMDBase_MULi(s20, a1));
+#else
+ u = SIMDBase_FMSUBi(s30, a3, SIMDBase_MULi(s31, a2));
+ v = SIMDBase_FMSUBi(s20, a1, SIMDBase_MULi(s21, a0));
+#endif
+ t0i = SIMDBase_ADDi(u, v); t1r = SIMDBase_SUBi(u, v);
+
+ s00 = SIMDBase_LOAD(&s[i0+ 2]); s01 = SIMDBase_LOAD(&s[i0+ 3]);
+ s10 = SIMDBase_LOAD(&s[i1+ 2]); s11 = SIMDBase_LOAD(&s[i1+ 3]);
+
+ SIMDBase_STOR(&s[i2+ 2], SIMDBase_SUBi(s00, t0r)); SIMDBase_STOR(&s[i0+ 2], SIMDBase_ADDi(s00, t0r));
+ SIMDBase_STOR(&s[i2+ 3], SIMDBase_SUBi(s01, t0i)); SIMDBase_STOR(&s[i0+ 3], SIMDBase_ADDi(s01, t0i));
+ SIMDBase_STOR(&s[i3+ 2], SIMDBase_SUBi(s10, t1r)); SIMDBase_STOR(&s[i1+ 2], SIMDBase_ADDi(s10, t1r));
+ SIMDBase_STOR(&s[i3+ 3], SIMDBase_SUBi(s11, t1i)); SIMDBase_STOR(&s[i1+ 3], SIMDBase_ADDi(s11, t1i));
+
+ //
+
+ s20 = SIMDBase_LOAD(&s[i2+ 4]); s21 = SIMDBase_LOAD(&s[i2+ 5]);
+ a0 = SIMDBase_LOAD1(&tbl[p0+ 8]); a1 = SIMDBase_LOAD1(&tbl[p0+ 9]);
+#ifndef SIMDBase_FMADD_AVAILABLE
+ u = SIMDBase_ADDi(SIMDBase_MULi(s20, a0), SIMDBase_MULi(s21, a1));
+#else
+ u = SIMDBase_FMADDi(s20, a0, SIMDBase_MULi(s21, a1));
+#endif
+
+ s30 = SIMDBase_LOAD(&s[i3+ 4]); s31 = SIMDBase_LOAD(&s[i3+ 5]);
+ a2 = SIMDBase_LOAD1(&tbl[p0+10]); a3 = SIMDBase_LOAD1(&tbl[p0+11]);
+#ifndef SIMDBase_FMADD_AVAILABLE
+ v = SIMDBase_ADDi(SIMDBase_MULi(s30, a2), SIMDBase_MULi(s31, a3));
+#else
+ v = SIMDBase_FMADDi(s30, a2, SIMDBase_MULi(s31, a3));
+#endif
+
+ t0r = SIMDBase_ADDi(u, v); t1i = SIMDBase_SUBi(u, v);
+
+#ifndef SIMDBase_FMADD_AVAILABLE
+ u = SIMDBase_SUBi(SIMDBase_MULi(s31, a2), SIMDBase_MULi(s30, a3));
+ v = SIMDBase_SUBi(SIMDBase_MULi(s21, a0), SIMDBase_MULi(s20, a1));
+#else
+ u = SIMDBase_FMSUBi(s30, a3, SIMDBase_MULi(s31, a2));
+ v = SIMDBase_FMSUBi(s20, a1, SIMDBase_MULi(s21, a0));
+#endif
+ t0i = SIMDBase_ADDi(u, v); t1r = SIMDBase_SUBi(u, v);
+
+ s00 = SIMDBase_LOAD(&s[i0+ 4]); s01 = SIMDBase_LOAD(&s[i0+ 5]);
+ s10 = SIMDBase_LOAD(&s[i1+ 4]); s11 = SIMDBase_LOAD(&s[i1+ 5]);
+
+ SIMDBase_STOR(&s[i2+ 4], SIMDBase_SUBi(s00, t0r)); SIMDBase_STOR(&s[i0+ 4], SIMDBase_ADDi(s00, t0r));
+ SIMDBase_STOR(&s[i2+ 5], SIMDBase_SUBi(s01, t0i)); SIMDBase_STOR(&s[i0+ 5], SIMDBase_ADDi(s01, t0i));
+ SIMDBase_STOR(&s[i3+ 4], SIMDBase_SUBi(s10, t1r)); SIMDBase_STOR(&s[i1+ 4], SIMDBase_ADDi(s10, t1r));
+ SIMDBase_STOR(&s[i3+ 5], SIMDBase_SUBi(s11, t1i)); SIMDBase_STOR(&s[i1+ 5], SIMDBase_ADDi(s11, t1i));
+
+ //
+
+ s20 = SIMDBase_LOAD(&s[i2+ 6]); s21 = SIMDBase_LOAD(&s[i2+ 7]);
+ a0 = SIMDBase_LOAD1(&tbl[p0+12]); a1 = SIMDBase_LOAD1(&tbl[p0+13]);
+#ifndef SIMDBase_FMADD_AVAILABLE
+ u = SIMDBase_ADDi(SIMDBase_MULi(s20, a0), SIMDBase_MULi(s21, a1));
+#else
+ u = SIMDBase_FMADDi(s20, a0, SIMDBase_MULi(s21, a1));
+#endif
+
+ s30 = SIMDBase_LOAD(&s[i3+ 6]); s31 = SIMDBase_LOAD(&s[i3+ 7]);
+ a2 = SIMDBase_LOAD1(&tbl[p0+14]); a3 = SIMDBase_LOAD1(&tbl[p0+15]);
+#ifndef SIMDBase_FMADD_AVAILABLE
+ v = SIMDBase_ADDi(SIMDBase_MULi(s30, a2), SIMDBase_MULi(s31, a3));
+#else
+ v = SIMDBase_FMADDi(s30, a2, SIMDBase_MULi(s31, a3));
+#endif
+
+ t0r = SIMDBase_ADDi(u, v); t1i = SIMDBase_SUBi(u, v);
+
+#ifndef SIMDBase_FMADD_AVAILABLE
+ u = SIMDBase_SUBi(SIMDBase_MULi(s31, a2), SIMDBase_MULi(s30, a3));
+ v = SIMDBase_SUBi(SIMDBase_MULi(s21, a0), SIMDBase_MULi(s20, a1));
+#else
+ u = SIMDBase_FMSUBi(s30, a3, SIMDBase_MULi(s31, a2));
+ v = SIMDBase_FMSUBi(s20, a1, SIMDBase_MULi(s21, a0));
+#endif
+ t0i = SIMDBase_ADDi(u, v); t1r = SIMDBase_SUBi(u, v);
+
+ s00 = SIMDBase_LOAD(&s[i0+ 6]); s01 = SIMDBase_LOAD(&s[i0+ 7]);
+ s10 = SIMDBase_LOAD(&s[i1+ 6]); s11 = SIMDBase_LOAD(&s[i1+ 7]);
+
+ SIMDBase_STOR(&s[i2+ 6], SIMDBase_SUBi(s00, t0r)); SIMDBase_STOR(&s[i0+ 6], SIMDBase_ADDi(s00, t0r));
+ SIMDBase_STOR(&s[i2+ 7], SIMDBase_SUBi(s01, t0i)); SIMDBase_STOR(&s[i0+ 7], SIMDBase_ADDi(s01, t0i));
+ SIMDBase_STOR(&s[i3+ 6], SIMDBase_SUBi(s10, t1r)); SIMDBase_STOR(&s[i1+ 6], SIMDBase_ADDi(s10, t1r));
+ SIMDBase_STOR(&s[i3+ 7], SIMDBase_SUBi(s11, t1i)); SIMDBase_STOR(&s[i1+ 7], SIMDBase_ADDi(s11, t1i));
+
+ //
+
+ i0 += 8; i1 += 8; i2 += 8; i3 += 8;
+ p0 += 16;
+ }
+}
+#endif
+
+static void r2ButForwardSub(DFTUndiff *p) {
+ SIMDBase_VECT *s = p->s;
+
+ SIMDBase_REAL *tbl = p->ptTable[p->log2butlen];
+
+ int32_t i0 = p->offset1;
+ int32_t i2 = i0 + p->stride*2;
+ int32_t cp = 0, sp = p->butlen/4;
+
+ do {
+ SIMDBase_VECT t0r, t0i, s0, s1, s2, s3, t0, t1;
+
+ s0 = SIMDBase_LOAD(&s[i0+0]); s2 = SIMDBase_LOAD(&s[i0+1]);
+ s1 = SIMDBase_LOAD(&s[i2+0]); s3 = SIMDBase_LOAD(&s[i2+1]);
+ t0 = SIMDBase_LOAD1(&tbl[cp+0]); t1 = SIMDBase_LOAD1(&tbl[sp-0]);
+ t0r = SIMDBase_SUBi(s0, s1); SIMDBase_STOR(&s[i0+0], SIMDBase_ADDi(s0, s1));
+ t0i = SIMDBase_SUBi(s2, s3); SIMDBase_STOR(&s[i0+1], SIMDBase_ADDi(s2, s3));
+ SIMDBase_STOR(&s[i2+0], SIMDBase_ADDi(SIMDBase_MULi(t0r, t0), SIMDBase_MULi(t0i, t1)));
+ SIMDBase_STOR(&s[i2+1], SIMDBase_SUBi(SIMDBase_MULi(t0i, t0), SIMDBase_MULi(t0r, t1)));
+
+ s0 = SIMDBase_LOAD(&s[i0+2]); s2 = SIMDBase_LOAD(&s[i0+3]);
+ s1 = SIMDBase_LOAD(&s[i2+2]); s3 = SIMDBase_LOAD(&s[i2+3]);
+ t0 = SIMDBase_LOAD1(&tbl[cp+1]); t1 = SIMDBase_LOAD1(&tbl[sp-1]);
+ t0r = SIMDBase_SUBi(s0, s1); SIMDBase_STOR(&s[i0+2], SIMDBase_ADDi(s0, s1));
+ t0i = SIMDBase_SUBi(s2, s3); SIMDBase_STOR(&s[i0+3], SIMDBase_ADDi(s2, s3));
+ SIMDBase_STOR(&s[i2+2], SIMDBase_ADDi(SIMDBase_MULi(t0r, t0), SIMDBase_MULi(t0i, t1)));
+ SIMDBase_STOR(&s[i2+3], SIMDBase_SUBi(SIMDBase_MULi(t0i, t0), SIMDBase_MULi(t0r, t1)));
+
+ s0 = SIMDBase_LOAD(&s[i0+4]); s2 = SIMDBase_LOAD(&s[i0+5]);
+ s1 = SIMDBase_LOAD(&s[i2+4]); s3 = SIMDBase_LOAD(&s[i2+5]);
+ t0 = SIMDBase_LOAD1(&tbl[cp+2]); t1 = SIMDBase_LOAD1(&tbl[sp-2]);
+ t0r = SIMDBase_SUBi(s0, s1); SIMDBase_STOR(&s[i0+4], SIMDBase_ADDi(s0, s1));
+ t0i = SIMDBase_SUBi(s2, s3); SIMDBase_STOR(&s[i0+5], SIMDBase_ADDi(s2, s3));
+ SIMDBase_STOR(&s[i2+4], SIMDBase_ADDi(SIMDBase_MULi(t0r, t0), SIMDBase_MULi(t0i, t1)));
+ SIMDBase_STOR(&s[i2+5], SIMDBase_SUBi(SIMDBase_MULi(t0i, t0), SIMDBase_MULi(t0r, t1)));
+
+ s0 = SIMDBase_LOAD(&s[i0+6]); s2 = SIMDBase_LOAD(&s[i0+7]);
+ s1 = SIMDBase_LOAD(&s[i2+6]); s3 = SIMDBase_LOAD(&s[i2+7]);
+ t0 = SIMDBase_LOAD1(&tbl[cp+3]); t1 = SIMDBase_LOAD1(&tbl[sp-3]);
+ t0r = SIMDBase_SUBi(s0, s1); SIMDBase_STOR(&s[i0+6], SIMDBase_ADDi(s0, s1));
+ t0i = SIMDBase_SUBi(s2, s3); SIMDBase_STOR(&s[i0+7], SIMDBase_ADDi(s2, s3));
+ SIMDBase_STOR(&s[i2+6], SIMDBase_ADDi(SIMDBase_MULi(t0r, t0), SIMDBase_MULi(t0i, t1)));
+ SIMDBase_STOR(&s[i2+7], SIMDBase_SUBi(SIMDBase_MULi(t0i, t0), SIMDBase_MULi(t0r, t1)));
+
+ //
+
+ i0 += 8; i2 += 8; cp += 4; sp -= 4;
+ } while(sp > 0);
+
+ do {
+ SIMDBase_VECT t0r, t0i, s0, s1, s2, s3, t0, t1;
+
+ s0 = SIMDBase_LOAD(&s[i0+0]); s2 = SIMDBase_LOAD(&s[i0+1]);
+ s1 = SIMDBase_LOAD(&s[i2+0]); s3 = SIMDBase_LOAD(&s[i2+1]);
+ t0 = SIMDBase_LOAD1(&tbl[cp-0]); t1 = SIMDBase_LOAD1(&tbl[sp+0]);
+ t0r = SIMDBase_SUBi(s0, s1); SIMDBase_STOR(&s[i0+0], SIMDBase_ADDi(s0, s1));
+ t0i = SIMDBase_SUBi(s2, s3); SIMDBase_STOR(&s[i0+1], SIMDBase_ADDi(s2, s3));
+ SIMDBase_STOR(&s[i2+0], SIMDBase_SUBi(SIMDBase_MULi(t0i, t1), SIMDBase_MULi(t0r, t0)));
+ SIMDBase_STOR(&s[i2+1], SIMDBase_NEGi(SIMDBase_ADDi(SIMDBase_MULi(t0i, t0), SIMDBase_MULi(t0r, t1))));
+
+ s0 = SIMDBase_LOAD(&s[i0+2]); s2 = SIMDBase_LOAD(&s[i0+3]);
+ s1 = SIMDBase_LOAD(&s[i2+2]); s3 = SIMDBase_LOAD(&s[i2+3]);
+ t0 = SIMDBase_LOAD1(&tbl[cp-1]); t1 = SIMDBase_LOAD1(&tbl[sp+1]);
+ t0r = SIMDBase_SUBi(s0, s1); SIMDBase_STOR(&s[i0+2], SIMDBase_ADDi(s0, s1));
+ t0i = SIMDBase_SUBi(s2, s3); SIMDBase_STOR(&s[i0+3], SIMDBase_ADDi(s2, s3));
+ SIMDBase_STOR(&s[i2+2], SIMDBase_SUBi(SIMDBase_MULi(t0i, t1), SIMDBase_MULi(t0r, t0)));
+ SIMDBase_STOR(&s[i2+3], SIMDBase_NEGi(SIMDBase_ADDi(SIMDBase_MULi(t0i, t0), SIMDBase_MULi(t0r, t1))));
+
+ s0 = SIMDBase_LOAD(&s[i0+4]); s2 = SIMDBase_LOAD(&s[i0+5]);
+ s1 = SIMDBase_LOAD(&s[i2+4]); s3 = SIMDBase_LOAD(&s[i2+5]);
+ t0 = SIMDBase_LOAD1(&tbl[cp-2]); t1 = SIMDBase_LOAD1(&tbl[sp+2]);
+ t0r = SIMDBase_SUBi(s0, s1); SIMDBase_STOR(&s[i0+4], SIMDBase_ADDi(s0, s1));
+ t0i = SIMDBase_SUBi(s2, s3); SIMDBase_STOR(&s[i0+5], SIMDBase_ADDi(s2, s3));
+ SIMDBase_STOR(&s[i2+4], SIMDBase_SUBi(SIMDBase_MULi(t0i, t1), SIMDBase_MULi(t0r, t0)));
+ SIMDBase_STOR(&s[i2+5], SIMDBase_NEGi(SIMDBase_ADDi(SIMDBase_MULi(t0i, t0), SIMDBase_MULi(t0r, t1))));
+
+ s0 = SIMDBase_LOAD(&s[i0+6]); s2 = SIMDBase_LOAD(&s[i0+7]);
+ s1 = SIMDBase_LOAD(&s[i2+6]); s3 = SIMDBase_LOAD(&s[i2+7]);
+ t0 = SIMDBase_LOAD1(&tbl[cp-3]); t1 = SIMDBase_LOAD1(&tbl[sp+3]);
+ t0r = SIMDBase_SUBi(s0, s1); SIMDBase_STOR(&s[i0+6], SIMDBase_ADDi(s0, s1));
+ t0i = SIMDBase_SUBi(s2, s3); SIMDBase_STOR(&s[i0+7], SIMDBase_ADDi(s2, s3));
+ SIMDBase_STOR(&s[i2+6], SIMDBase_SUBi(SIMDBase_MULi(t0i, t1), SIMDBase_MULi(t0r, t0)));
+ SIMDBase_STOR(&s[i2+7], SIMDBase_NEGi(SIMDBase_ADDi(SIMDBase_MULi(t0i, t0), SIMDBase_MULi(t0r, t1))));
+
+ //
+
+ i0 += 8; i2 += 8; cp -= 4; sp += 4;
+ } while(cp > 0);
+}
+
+static void r2ButBackwardSub(DFTUndiff *p) {
+ SIMDBase_VECT *s = p->s;
+
+ SIMDBase_REAL *tbl = p->ptTable[p->log2butlen];
+
+ int i0 = p->offset1;
+ int i2 = i0 + p->stride*2;
+
+ int cp = 0, sp = p->butlen/4;
+
+ do {
+ SIMDBase_VECT t0r, t0i, s0, s1, s2, s3, t0, t1;
+
+ s0 = SIMDBase_LOAD(&s[i0+0]); s2 = SIMDBase_LOAD(&s[i0+1]);
+ s1 = SIMDBase_LOAD(&s[i2+0]); s3 = SIMDBase_LOAD(&s[i2+1]);
+ t0 = SIMDBase_LOAD1(&tbl[cp+0]); t1 = SIMDBase_LOAD1(&tbl[sp-0]);
+ t0r = SIMDBase_SUBi(SIMDBase_MULi(s1, t0), SIMDBase_MULi(s3, t1));
+ t0i = SIMDBase_ADDi(SIMDBase_MULi(s1, t1), SIMDBase_MULi(s3, t0));
+ SIMDBase_STOR(&s[i2+0], SIMDBase_SUBi(s0, t0r)); SIMDBase_STOR(&s[i0+0], SIMDBase_ADDi(s0, t0r));
+ SIMDBase_STOR(&s[i2+1], SIMDBase_SUBi(s2, t0i)); SIMDBase_STOR(&s[i0+1], SIMDBase_ADDi(s2, t0i));
+
+ s0 = SIMDBase_LOAD(&s[i0+2]); s2 = SIMDBase_LOAD(&s[i0+3]);
+ s1 = SIMDBase_LOAD(&s[i2+2]); s3 = SIMDBase_LOAD(&s[i2+3]);
+ t0 = SIMDBase_LOAD1(&tbl[cp+1]); t1 = SIMDBase_LOAD1(&tbl[sp-1]);
+ t0r = SIMDBase_SUBi(SIMDBase_MULi(s1, t0), SIMDBase_MULi(s3, t1));
+ t0i = SIMDBase_ADDi(SIMDBase_MULi(s1, t1), SIMDBase_MULi(s3, t0));
+ SIMDBase_STOR(&s[i2+2], SIMDBase_SUBi(s0, t0r)); SIMDBase_STOR(&s[i0+2], SIMDBase_ADDi(s0, t0r));
+ SIMDBase_STOR(&s[i2+3], SIMDBase_SUBi(s2, t0i)); SIMDBase_STOR(&s[i0+3], SIMDBase_ADDi(s2, t0i));
+
+ s0 = SIMDBase_LOAD(&s[i0+4]); s2 = SIMDBase_LOAD(&s[i0+5]);
+ s1 = SIMDBase_LOAD(&s[i2+4]); s3 = SIMDBase_LOAD(&s[i2+5]);
+ t0 = SIMDBase_LOAD1(&tbl[cp+2]); t1 = SIMDBase_LOAD1(&tbl[sp-2]);
+ t0r = SIMDBase_SUBi(SIMDBase_MULi(s1, t0), SIMDBase_MULi(s3, t1));
+ t0i = SIMDBase_ADDi(SIMDBase_MULi(s1, t1), SIMDBase_MULi(s3, t0));
+ SIMDBase_STOR(&s[i2+4], SIMDBase_SUBi(s0, t0r)); SIMDBase_STOR(&s[i0+4], SIMDBase_ADDi(s0, t0r));
+ SIMDBase_STOR(&s[i2+5], SIMDBase_SUBi(s2, t0i)); SIMDBase_STOR(&s[i0+5], SIMDBase_ADDi(s2, t0i));
+
+ s0 = SIMDBase_LOAD(&s[i0+6]); s2 = SIMDBase_LOAD(&s[i0+7]);
+ s1 = SIMDBase_LOAD(&s[i2+6]); s3 = SIMDBase_LOAD(&s[i2+7]);
+ t0 = SIMDBase_LOAD1(&tbl[cp+3]); t1 = SIMDBase_LOAD1(&tbl[sp-3]);
+ t0r = SIMDBase_SUBi(SIMDBase_MULi(s1, t0), SIMDBase_MULi(s3, t1));
+ t0i = SIMDBase_ADDi(SIMDBase_MULi(s1, t1), SIMDBase_MULi(s3, t0));
+ SIMDBase_STOR(&s[i2+6], SIMDBase_SUBi(s0, t0r)); SIMDBase_STOR(&s[i0+6], SIMDBase_ADDi(s0, t0r));
+ SIMDBase_STOR(&s[i2+7], SIMDBase_SUBi(s2, t0i)); SIMDBase_STOR(&s[i0+7], SIMDBase_ADDi(s2, t0i));
+
+ i0 += 8; i2 += 8; cp += 4; sp -= 4;
+ } while(sp > 0);
+
+ do {
+ SIMDBase_VECT t0r, t0i, s0, s1, s2, s3, t0, t1;
+
+ s0 = SIMDBase_LOAD(&s[i0+0]); s2 = SIMDBase_LOAD(&s[i0+1]);
+ s1 = SIMDBase_LOAD(&s[i2+0]); s3 = SIMDBase_LOAD(&s[i2+1]);
+ t0 = SIMDBase_LOAD1(&tbl[cp-0]); t1 = SIMDBase_LOAD1(&tbl[sp+0]);
+ t0r = SIMDBase_NEGi(SIMDBase_ADDi(SIMDBase_MULi(s1, t0), SIMDBase_MULi(s3, t1)));
+ t0i = SIMDBase_SUBi(SIMDBase_MULi(s1, t1), SIMDBase_MULi(s3, t0));
+ SIMDBase_STOR(&s[i2+0], SIMDBase_SUBi(s0, t0r)); SIMDBase_STOR(&s[i0+0], SIMDBase_ADDi(s0, t0r));
+ SIMDBase_STOR(&s[i2+1], SIMDBase_SUBi(s2, t0i)); SIMDBase_STOR(&s[i0+1], SIMDBase_ADDi(s2, t0i));
+
+ s0 = SIMDBase_LOAD(&s[i0+2]); s2 = SIMDBase_LOAD(&s[i0+3]);
+ s1 = SIMDBase_LOAD(&s[i2+2]); s3 = SIMDBase_LOAD(&s[i2+3]);
+ t0 = SIMDBase_LOAD1(&tbl[cp-1]); t1 = SIMDBase_LOAD1(&tbl[sp+1]);
+ t0r = SIMDBase_NEGi(SIMDBase_ADDi(SIMDBase_MULi(s1, t0), SIMDBase_MULi(s3, t1)));
+ t0i = SIMDBase_SUBi(SIMDBase_MULi(s1, t1), SIMDBase_MULi(s3, t0));
+ SIMDBase_STOR(&s[i2+2], SIMDBase_SUBi(s0, t0r)); SIMDBase_STOR(&s[i0+2], SIMDBase_ADDi(s0, t0r));
+ SIMDBase_STOR(&s[i2+3], SIMDBase_SUBi(s2, t0i)); SIMDBase_STOR(&s[i0+3], SIMDBase_ADDi(s2, t0i));
+
+ s0 = SIMDBase_LOAD(&s[i0+4]); s2 = SIMDBase_LOAD(&s[i0+5]);
+ s1 = SIMDBase_LOAD(&s[i2+4]); s3 = SIMDBase_LOAD(&s[i2+5]);
+ t0 = SIMDBase_LOAD1(&tbl[cp-2]); t1 = SIMDBase_LOAD1(&tbl[sp+2]);
+ t0r = SIMDBase_NEGi(SIMDBase_ADDi(SIMDBase_MULi(s1, t0), SIMDBase_MULi(s3, t1)));
+ t0i = SIMDBase_SUBi(SIMDBase_MULi(s1, t1), SIMDBase_MULi(s3, t0));
+ SIMDBase_STOR(&s[i2+4], SIMDBase_SUBi(s0, t0r)); SIMDBase_STOR(&s[i0+4], SIMDBase_ADDi(s0, t0r));
+ SIMDBase_STOR(&s[i2+5], SIMDBase_SUBi(s2, t0i)); SIMDBase_STOR(&s[i0+5], SIMDBase_ADDi(s2, t0i));
+
+ s0 = SIMDBase_LOAD(&s[i0+6]); s2 = SIMDBase_LOAD(&s[i0+7]);
+ s1 = SIMDBase_LOAD(&s[i2+6]); s3 = SIMDBase_LOAD(&s[i2+7]);
+ t0 = SIMDBase_LOAD1(&tbl[cp-3]); t1 = SIMDBase_LOAD1(&tbl[sp+3]);
+ t0r = SIMDBase_NEGi(SIMDBase_ADDi(SIMDBase_MULi(s1, t0), SIMDBase_MULi(s3, t1)));
+ t0i = SIMDBase_SUBi(SIMDBase_MULi(s1, t1), SIMDBase_MULi(s3, t0));
+ SIMDBase_STOR(&s[i2+6], SIMDBase_SUBi(s0, t0r)); SIMDBase_STOR(&s[i0+6], SIMDBase_ADDi(s0, t0r));
+ SIMDBase_STOR(&s[i2+7], SIMDBase_SUBi(s2, t0i)); SIMDBase_STOR(&s[i0+7], SIMDBase_ADDi(s2, t0i));
+
+ i0 += 8; i2 += 8; cp -= 4; sp += 4;
+ } while(cp > 0);
+}
+
+static void srButForward16(DFTUndiff *p) {
+ int32_t o = p->offset1;
+
+ p->butlen = 16; p->log2butlen = 4; p->stride = p->butlen/2;
+ srButForwardSubUnrolled(p);
+
+ p->offset1 = o + 16*6/4;
+ srButForward4(p);
+
+ p->offset1 = o + 16*4/4;
+ srButForward4(p);
+
+ p->offset1 = o;
+ srButForward8(p);
+}
+
+static void srButBackward16(DFTUndiff *p) {
+ int32_t o = p->offset1;
+
+ p->offset1 = o + 16*6/4;
+ srButBackward4(p);
+
+ p->offset1 = o + 16*4/4;
+ srButBackward4(p);
+
+ p->offset1 = o;
+ srButBackward8(p);
+
+ p->butlen = 16; p->log2butlen = 4; p->stride = p->butlen/2;
+ srButBackwardSubUnrolled(p);
+}
+
+static void srButForward32(DFTUndiff *p) {
+ int32_t o = p->offset1;
+
+ p->butlen = 32; p->log2butlen = 5; p->stride = p->butlen/2;
+ srButForwardSubUnrolled(p);
+
+ p->offset1 = o + 32*6/4;
+ srButForward8 (p);
+
+ p->offset1 = o + 32*4/4;
+ srButForward8 (p);
+
+ p->offset1 = o;
+ srButForward16(p);
+}
+
+static void srButBackward32(DFTUndiff *p) {
+ int32_t o = p->offset1;
+
+ p->offset1 = o + 32*6/4;
+ srButBackward8 (p);
+
+ p->offset1 = o + 32*4/4;
+ srButBackward8 (p);
+
+ p->offset1 = o;
+ srButBackward16(p);
+
+ p->butlen = 32; p->log2butlen = 5; p->stride = p->butlen/2;
+ srButBackwardSubUnrolled(p);
+}
+
+//
+
+#if 1
+static inline void bitReversalUnit(SIMDBase_VECT *p, SIMDBase_VECT *q) {
+ SIMDBase_VECT w, x, y, z;
+
+ w = SIMDBase_LOAD(p); x = SIMDBase_LOAD(p+1);
+ y = SIMDBase_LOAD(q); z = SIMDBase_LOAD(q+1);
+
+ SIMDBase_STOR(q, w); SIMDBase_STOR(q+1, x);
+ SIMDBase_STOR(p, y); SIMDBase_STOR(p+1, z);
+}
+#else
+#define bitReversalUnit(p0, q0) { \
+ SIMDBase_VECT *px = (p0), *qx = (q0); \
+ SIMDBase_VECT wx, xx, yx, zx; \
+ \
+ wx = SIMDBase_LOAD(px); xx = SIMDBase_LOAD(px+1); \
+ yx = SIMDBase_LOAD(qx); zx = SIMDBase_LOAD(qx+1); \
+ \
+ SIMDBase_STOR(qx, wx); SIMDBase_STOR(qx+1, xx); \
+ SIMDBase_STOR(px, yx); SIMDBase_STOR(px+1, zx); \
+}
+#endif
+
+static inline void bitReversal4s(SIMDBase_VECT *s, int32_t sc, int32_t o1, int32_t o2) {
+ SIMDBase_VECT *p = &s[o1*2], *q = &s[o2*2];
+ int b1 = sc*2*1, b2 = b1*2;
+ p += b1; q += b2;
+ bitReversalUnit(p, q);
+}
+
+static inline void bitReversal8s(SIMDBase_VECT *s, int32_t sc, int32_t o1, int32_t o2) {
+ SIMDBase_VECT *p = &s[o1*2], *q = &s[o2*2];
+ int b1 = sc*2*1, b2 = b1*2, b4 = b2*2;
+ p += b1; q += b4;
+ bitReversalUnit(p, q); p += b2; q += b2;
+ bitReversalUnit(p, q);
+}
+
+static inline void bitReversal8d(SIMDBase_VECT *s, int32_t sc, int32_t o1, int32_t o2) {
+ SIMDBase_VECT *p = &s[o1*2], *q = &s[o2*2];
+ int32_t b1 = sc*2*1, b2 = b1*2, b4 = b2*2;
+ bitReversalUnit(p, q); p += b1; q += b4;
+ bitReversalUnit(p, q); p += b2; q += b2;
+ bitReversalUnit(p, q); p -= b1; q -= b4;
+ bitReversalUnit(p, q); p += b4; q += b1;
+ bitReversalUnit(p, q); p += b1; q += b4;
+ bitReversalUnit(p, q); p -= b2; q -= b2;
+ bitReversalUnit(p, q); p -= b1; q -= b4;
+ bitReversalUnit(p, q);
+}
+
+static inline void bitReversal16s(SIMDBase_VECT *s, int32_t sc, int32_t o1, int32_t o2) {
+ SIMDBase_VECT *p = &s[o1*2], *q = &s[o2*2];
+ int32_t b1 = sc*2*1, b2 = b1*2, b4 = b2*2, b8 = b4*2;
+ p += b1; q += b8;
+ bitReversalUnit(p, q); p += b2; q += b4;
+ bitReversalUnit(p, q); p -= b1; q -= b8;
+ bitReversalUnit(p, q); p += b1 + b4; q += b2 + b8;
+ bitReversalUnit(p, q); p -= b2; q -= b4;
+ bitReversalUnit(p, q); p += b2 + b4; q += b1 + b2;
+ bitReversalUnit(p, q);
+}
+
+static inline void bitReversal16d(SIMDBase_VECT *s, int32_t sc, int32_t o1, int32_t o2) {
+ SIMDBase_VECT *p = &s[o1*2], *q = &s[o2*2];
+ int32_t b1 = sc*2*1, b2 = b1*2, b4 = b2*2, b8 = b4*2;
+ bitReversalUnit(p, q); p += b1; q += b8;
+ bitReversalUnit(p, q); p += b2; q += b4;
+ bitReversalUnit(p, q); p -= b1; q -= b8;
+ bitReversalUnit(p, q); p += b4; q += b2;
+ bitReversalUnit(p, q); p += b1; q += b8;
+ bitReversalUnit(p, q); p -= b2; q -= b4;
+ bitReversalUnit(p, q); p -= b1; q -= b8;
+ bitReversalUnit(p, q); p += b8; q += b1;
+ bitReversalUnit(p, q); p += b1; q += b8;
+ bitReversalUnit(p, q); p += b2; q += b4;
+ bitReversalUnit(p, q); p -= b1; q -= b8;
+ bitReversalUnit(p, q); p -= b4; q -= b2;
+ bitReversalUnit(p, q); p += b1; q += b8;
+ bitReversalUnit(p, q); p -= b2; q -= b4;
+ bitReversalUnit(p, q); p -= b1; q -= b8;
+ bitReversalUnit(p, q);
+}
+
+static inline void bitReversal32s(SIMDBase_VECT *s, int32_t sc, int32_t o1, int32_t o2) {
+ SIMDBase_VECT *p = &s[o1*2], *q = &s[o2*2];
+ int32_t b1 = sc*2*1, b2 = b1*2, b4 = b2*2, b8 = b4*2, b16 = b8*2;
+ p += b1; q += b16;
+ bitReversalUnit(p, q); p += b2; q += b8;
+ bitReversalUnit(p, q); p -= b1; q -= b16;
+ bitReversalUnit(p, q); p += b4; q += b4;
+ bitReversalUnit(p, q); p += b1; q += b16;
+ bitReversalUnit(p, q); p -= b2; q -= b8;
+ bitReversalUnit(p, q); p += b8; q += b2;
+ bitReversalUnit(p, q); p += b2; q += b8;
+ bitReversalUnit(p, q); p -= b4; q -= b4;
+ bitReversalUnit(p, q); p -= b2; q -= b8;
+ bitReversalUnit(p, q); p += b16 - b2; q += b1 + b2 + b8;
+ bitReversalUnit(p, q); p -= b4; q -= b4;
+ bitReversalUnit(p, q);
+}
+
+static void bitReversal32d(SIMDBase_VECT *s, int32_t sc, int32_t o1, int32_t o2) {
+ const int32_t k = 32;
+
+ bitReversal8d(s,2*sc, sc*(k/2 )+o1, sc* 1 +o2);
+ bitReversal8d(s,2*sc, sc* 0 +o1, sc* 0 +o2);
+ bitReversal8d(s,2*sc, sc* 1 +o1, sc*(k/2 )+o2);
+ bitReversal8d(s,2*sc, sc*(k/2+1)+o1, sc*(k/2+1)+o2);
+}
+
+static void bitReversalRecursive(SIMDBase_VECT *s, int32_t n, int32_t sc, int32_t o1, int32_t o2) {
+ if (n >= 64) {
+ if (o1 != o2) bitReversalRecursive(s, n/4, 2*sc, sc*(n/2)+o1, sc*1+o2);
+
+ bitReversalRecursive(s, n/4, 2*sc, sc* 0 +o1, sc* 0 +o2);
+ bitReversalRecursive(s, n/4, 2*sc, sc* 1 +o1, sc*(n/2 )+o2);
+ bitReversalRecursive(s, n/4, 2*sc, sc*(n/2+1)+o1, sc*(n/2+1)+o2);
+ } else {
+ if (o1 == o2) {
+ switch(n) {
+ case 4: bitReversal4s (s,sc,o1,o2); return;
+ case 8: bitReversal8s (s,sc,o1,o2); return;
+ case 16: bitReversal16s(s,sc,o1,o2); return;
+ case 32: bitReversal32s(s,sc,o1,o2); return;
+ }
+ } else {
+ switch(n) {
+ case 8: bitReversal8d (s,sc,o1,o2); return;
+ case 16: bitReversal16d(s,sc,o1,o2); return;
+ case 32: bitReversal32d(s,sc,o1,o2); return;
+ }
+ }
+ }
+}
+
+//
+
+static int bitR(int a, int logN) {
+ int ret = 0;
+ int i,j,k;
+ for(i=0,j=1,k=1<<(logN-1);i<logN;i++,j=j<<1,k=k>>1) {
+ if ((a & j) != 0) ret |= k;
+ }
+ return ret;
+}
+
+static void bitReversalCobraInplace(DFTUndiff *p) {
+ SIMDBase_VECT *s = p->s;
+ int cobraQ = p->cobraQ;
+ SIMDBase_VECT *cobraT = p->cobraT;
+ int *cobraR = p->cobraR;
+ int logN = p->log2len;
+
+ int b;
+
+ for(b=0;b<(1 << (logN-2*cobraQ));b++) {
+ int a,c;
+ int b2 = bitR(b, logN-2*cobraQ);
+
+ if (b2 < b) continue;
+
+ if (b2 == b) {
+ for(a=0;a<(1 << cobraQ);a++) {
+ int abc = ((a << (logN-2*cobraQ)) | b) << (cobraQ + 1);
+
+ int a2c = (cobraR[a] << cobraQ) << 1, a2cm = a2c+(1 << cobraQ)*2;
+
+ while(a2c < a2cm) {
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ }
+ }
+
+ for(c=0;c<(1 << cobraQ);c++) {
+ int c2 = cobraR[c];
+ int c2b2a2 = ((c2 << (logN-2*cobraQ)) | b2) << (cobraQ+1);
+
+ int a2c = c << 1;
+ int a2ci = 1 << (cobraQ+1);
+ int c2b2a2m = c2b2a2 + (1 << cobraQ)*2;
+
+ while(c2b2a2 < c2b2a2m) {
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); a2c += a2ci;
+ }
+ }
+ } else {
+ for(a=0;a<(1 << cobraQ);a++) {
+ int a2c = (cobraR[a] << cobraQ) << 1, a2cm = a2c+(1 << cobraQ)*2;
+ int abc = ((a << (logN-2*cobraQ)) | b) << (cobraQ + 1);
+
+ while(a2c < a2cm) {
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++])); SIMDBase_STOR(&cobraT[a2c++], SIMDBase_LOAD(&s[abc++]));
+ }
+ }
+
+ for(c=0;c<(1 << cobraQ);c++) {
+ int c2 = cobraR[c];
+ int c2b2a2 = ((c2 << (logN-2*cobraQ)) | b2) << (cobraQ+1);
+
+ int a2c = c << 1;
+ int a2ci = 1 << (cobraQ+1);
+ int c2b2a2m = c2b2a2 + (1 << cobraQ)*2;
+
+ while(c2b2a2 < c2b2a2m) {
+ SIMDBase_VECT t0, t1, t2, t3, t4, t5, t6, t7;
+
+ t0 = SIMDBase_LOAD(&s[c2b2a2+0]); t1 = SIMDBase_LOAD(&s[c2b2a2+1]);
+ t2 = SIMDBase_LOAD(&s[c2b2a2+2]); t3 = SIMDBase_LOAD(&s[c2b2a2+3]);
+ t4 = SIMDBase_LOAD(&s[c2b2a2+4]); t5 = SIMDBase_LOAD(&s[c2b2a2+5]);
+ t6 = SIMDBase_LOAD(&s[c2b2a2+6]); t7 = SIMDBase_LOAD(&s[c2b2a2+7]);
+
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&cobraT[a2c ], t0);
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); SIMDBase_STOR(&cobraT[a2c+1], t1); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&cobraT[a2c ], t2);
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); SIMDBase_STOR(&cobraT[a2c+1], t3); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&cobraT[a2c ], t4);
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); SIMDBase_STOR(&cobraT[a2c+1], t5); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&cobraT[a2c ], t6);
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); SIMDBase_STOR(&cobraT[a2c+1], t7); a2c += a2ci;
+
+ t0 = SIMDBase_LOAD(&s[c2b2a2+0]); t1 = SIMDBase_LOAD(&s[c2b2a2+1]);
+ t2 = SIMDBase_LOAD(&s[c2b2a2+2]); t3 = SIMDBase_LOAD(&s[c2b2a2+3]);
+ t4 = SIMDBase_LOAD(&s[c2b2a2+4]); t5 = SIMDBase_LOAD(&s[c2b2a2+5]);
+ t6 = SIMDBase_LOAD(&s[c2b2a2+6]); t7 = SIMDBase_LOAD(&s[c2b2a2+7]);
+
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&cobraT[a2c ], t0);
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); SIMDBase_STOR(&cobraT[a2c+1], t1); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&cobraT[a2c ], t2);
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); SIMDBase_STOR(&cobraT[a2c+1], t3); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&cobraT[a2c ], t4);
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); SIMDBase_STOR(&cobraT[a2c+1], t5); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&cobraT[a2c ], t6);
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); SIMDBase_STOR(&cobraT[a2c+1], t7); a2c += a2ci;
+
+ t0 = SIMDBase_LOAD(&s[c2b2a2+0]); t1 = SIMDBase_LOAD(&s[c2b2a2+1]);
+ t2 = SIMDBase_LOAD(&s[c2b2a2+2]); t3 = SIMDBase_LOAD(&s[c2b2a2+3]);
+ t4 = SIMDBase_LOAD(&s[c2b2a2+4]); t5 = SIMDBase_LOAD(&s[c2b2a2+5]);
+ t6 = SIMDBase_LOAD(&s[c2b2a2+6]); t7 = SIMDBase_LOAD(&s[c2b2a2+7]);
+
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&cobraT[a2c ], t0);
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); SIMDBase_STOR(&cobraT[a2c+1], t1); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&cobraT[a2c ], t2);
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); SIMDBase_STOR(&cobraT[a2c+1], t3); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&cobraT[a2c ], t4);
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); SIMDBase_STOR(&cobraT[a2c+1], t5); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&cobraT[a2c ], t6);
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); SIMDBase_STOR(&cobraT[a2c+1], t7); a2c += a2ci;
+
+ t0 = SIMDBase_LOAD(&s[c2b2a2+0]); t1 = SIMDBase_LOAD(&s[c2b2a2+1]);
+ t2 = SIMDBase_LOAD(&s[c2b2a2+2]); t3 = SIMDBase_LOAD(&s[c2b2a2+3]);
+ t4 = SIMDBase_LOAD(&s[c2b2a2+4]); t5 = SIMDBase_LOAD(&s[c2b2a2+5]);
+ t6 = SIMDBase_LOAD(&s[c2b2a2+6]); t7 = SIMDBase_LOAD(&s[c2b2a2+7]);
+
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&cobraT[a2c ], t0);
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); SIMDBase_STOR(&cobraT[a2c+1], t1); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&cobraT[a2c ], t2);
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); SIMDBase_STOR(&cobraT[a2c+1], t3); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&cobraT[a2c ], t4);
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); SIMDBase_STOR(&cobraT[a2c+1], t5); a2c += a2ci;
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c ])); SIMDBase_STOR(&cobraT[a2c ], t6);
+ SIMDBase_STOR(&s[c2b2a2++], SIMDBase_LOAD(&cobraT[a2c+1])); SIMDBase_STOR(&cobraT[a2c+1], t7); a2c += a2ci;
+ }
+ }
+
+ for(a=0;a<(1 << cobraQ);a++) {
+ int a2c = (cobraR[a] << cobraQ) << 1, a2cm = a2c+(1 << cobraQ)*2;
+ int abc = ((a << (logN-2*cobraQ)) | b) << (cobraQ + 1);
+
+ while(a2c < a2cm) {
+ SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++])); SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++]));
+ SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++])); SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++]));
+ SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++])); SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++]));
+ SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++])); SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++]));
+ SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++])); SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++]));
+ SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++])); SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++]));
+ SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++])); SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++]));
+ SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++])); SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++]));
+ SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++])); SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++]));
+ SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++])); SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++]));
+ SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++])); SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++]));
+ SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++])); SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++]));
+ SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++])); SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++]));
+ SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++])); SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++]));
+ SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++])); SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++]));
+ SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++])); SIMDBase_STOR(&s[abc++], SIMDBase_LOAD(&cobraT[a2c++]));
+ }
+ }
+ }
+ }
+}
+
+//
+
+static void srForwardMain2(DFTUndiff *p) {
+ int32_t o = p->offset1;
+ int32_t butlen = p->butlen;
+ int32_t log2butlen = p->log2butlen;
+
+ if (butlen >= p->radix2thres) {
+ p->stride = p->butlen/2;
+ r2ButForwardSub(p);
+
+ p->offset1 = o + butlen*4/4;
+ p->butlen = butlen/2;
+ p->log2butlen = log2butlen-1;
+ srForwardMain2(p);
+
+ p->offset1 = o;
+ p->butlen = butlen/2;
+ p->log2butlen = log2butlen-1;
+ srForwardMain2(p);
+
+ return;
+ }
+
+ if (butlen >= 256) {
+ p->stride = p->butlen/2;
+ srButForwardSubUnrolled(p);
+
+ p->offset1 = o + butlen*6/4;
+ p->butlen = butlen/4;
+ p->log2butlen = log2butlen-2;
+ srForwardMain2(p);
+
+ p->offset1 = o + butlen*4/4;
+ p->butlen = butlen/4;
+ p->log2butlen = log2butlen-2;
+ srForwardMain2(p);
+
+ p->offset1 = o;
+ p->butlen = butlen/2;
+ p->log2butlen = log2butlen-1;
+ srForwardMain2(p);
+
+ return;
+ }
+
+ if (butlen == 128) {
+ p->stride = p->butlen/2;
+ srButForwardSubUnrolled(p);
+
+ p->offset1 = o + butlen*6/4;
+ srButForward32(p);
+
+ p->offset1 = o + butlen*4/4;
+ srButForward32(p);
+
+ p->offset1 = o;
+ p->butlen = butlen/2;
+ p->log2butlen = log2butlen-1;
+ srForwardMain2 (p);
+
+ return;
+ }
+
+ // butlen == 64
+
+ p->stride = p->butlen/2;
+ srButForwardSubUnrolled(p);
+
+ p->offset1 = o + butlen*6/4;
+ srButForward16(p);
+
+ p->offset1 = o + butlen*4/4;
+ srButForward16(p);
+
+ p->offset1 = o;
+ srButForward32(p);
+}
+
+static void srBackwardMain2(DFTUndiff *p) {
+ int32_t o = p->offset1;
+ int32_t butlen = p->butlen;
+ int32_t log2butlen = p->log2butlen;
+
+ if (butlen >= p->radix2thres) {
+ p->offset1 = o + butlen*4/4;
+ p->butlen = butlen/2;
+ p->log2butlen = log2butlen-1;
+ srBackwardMain2(p);
+
+ p->offset1 = o;
+ p->butlen = butlen/2;
+ p->log2butlen = log2butlen-1;
+ srBackwardMain2(p);
+
+ p->butlen = butlen;
+ p->stride = p->butlen/2;
+ p->log2butlen = log2butlen;
+ r2ButBackwardSub(p);
+
+ return;
+ }
+
+ if (butlen >= 256) {
+ p->offset1 = o + butlen*6/4;
+ p->butlen = butlen/4;
+ p->log2butlen = log2butlen-2;
+ srBackwardMain2(p);
+
+ p->offset1 = o + butlen*4/4;
+ p->butlen = butlen/4;
+ p->log2butlen = log2butlen-2;
+ srBackwardMain2(p);
+
+ p->offset1 = o;
+ p->butlen = butlen/2;
+ p->log2butlen = log2butlen-1;
+ srBackwardMain2(p);
+
+ p->butlen = butlen;
+ p->stride = p->butlen/2;
+ p->log2butlen = log2butlen;
+ srButBackwardSubUnrolled(p);
+
+ return;
+ }
+
+ if (butlen == 128) {
+ p->offset1 = o + butlen*6/4;
+ srButBackward32(p);
+
+ p->offset1 = o + butlen*4/4;
+ srButBackward32(p);
+
+ p->offset1 = o;
+ p->butlen = butlen/2;
+ p->log2butlen = log2butlen-1;
+ srBackwardMain2 (p);
+
+ p->butlen = butlen;
+ p->stride = p->butlen/2;
+ p->log2butlen = log2butlen;
+ srButBackwardSubUnrolled(p);
+
+ return;
+ }
+
+ // butlen == 64
+
+ p->offset1 = o + butlen*6/4;
+ srButBackward16(p);
+
+ p->offset1 = o + butlen*4/4;
+ srButBackward16(p);
+
+ p->offset1 = o;
+ srButBackward32(p);
+
+ p->butlen = butlen;
+ p->stride = p->butlen/2;
+ p->log2butlen = log2butlen;
+ srButBackwardSubUnrolled(p);
+}
+
+static void srForwardMain(DFTUndiff *p) {
+ if (p->length >= 64) {
+ p->butlen = p->length;
+ p->log2butlen = p->log2len;
+ p->offset1 = p->offset2 = 0;
+
+ srForwardMain2(p);
+ } else {
+ switch(p->length) {
+ case 32:
+ srButForward32(p);
+ break;
+ case 16:
+ srButForward16(p);
+ break;
+ case 8:
+ srButForward8(p);
+ break;
+ case 4:
+ srButForward4(p);
+ break;
+ case 2:
+ srBut2(p);
+ break;
+ }
+ }
+}
+
+static void srBackwardMain(DFTUndiff *p) {
+ if (p->length >= 64) {
+ p->butlen = p->length;
+ p->log2butlen = p->log2len;
+ p->offset1 = p->offset2 = 0;
+
+ srBackwardMain2(p);
+ } else {
+ switch(p->length) {
+ case 32:
+ srButBackward32(p);
+ break;
+ case 16:
+ srButBackward16(p);
+ break;
+ case 8:
+ srButBackward8(p);
+ break;
+ case 4:
+ srButBackward4(p);
+ break;
+ case 2:
+ srBut2(p);
+ break;
+ }
+ }
+}
+
+static void realSub0(DFTUndiff *p, SIMDBase_VECT *s, int32_t ts) {
+ SIMDBase_VECT tr, ti, ur, ui, mr, mi;
+ int32_t n = p->length*2;
+ int32_t k;
+
+ for(k=1;k<n/4;k++) {
+ SIMDBase_VECT s00 = SIMDBase_LOAD(&s[k*2+0]), s01 = SIMDBase_LOAD(&s[k*2+1]);
+ SIMDBase_VECT s10 = SIMDBase_LOAD(&s[(n/2-k)*2+0]), s11 = SIMDBase_LOAD(&s[(n/2-k)*2+1]);
+
+ tr = SIMDBase_SUBi(s00, s10); ti = SIMDBase_ADDi(s01, s11);
+ ur = SIMDBase_LOAD1(&(p->rtTable[ts][k*2+0]));
+ ui = SIMDBase_LOAD1(&(p->rtTable[ts][k*2+1]));
+ mr = SIMDBase_SUBi(SIMDBase_MULi(tr, ur), SIMDBase_MULi(ti, ui));
+ mi = SIMDBase_ADDi(SIMDBase_MULi(tr, ui), SIMDBase_MULi(ti, ur));
+ SIMDBase_STOR(&s[k*2+0], SIMDBase_SUBi(s00, mr));
+ SIMDBase_STOR(&s[k*2+1], SIMDBase_SUBi(s01, mi));
+ SIMDBase_STOR(&s[(n/2-k)*2+0], SIMDBase_ADDi(s10, mr));
+ SIMDBase_STOR(&s[(n/2-k)*2+1], SIMDBase_SUBi(s11, mi));
+ }
+
+ tr = SIMDBase_LOAD(&s[0]); ti = SIMDBase_LOAD(&s[1]);
+ SIMDBase_STOR(&s[0], SIMDBase_ADDi(tr, ti));
+ SIMDBase_STOR(&s[1], SIMDBase_SUBi(tr, ti));
+}
+
+static void realSub1(DFTUndiff *p, SIMDBase_VECT *s, int32_t ts) {
+ SIMDBase_VECT tr, ti, ur, ui, mr, mi;
+ int32_t n = p->length*2;
+ int32_t k;
+
+ tr = SIMDBase_LOAD(&s[0]); ti = SIMDBase_LOAD(&s[1]);
+ SIMDBase_STOR(&s[0], SIMDBase_MULi(SIMDBase_ADDi(tr, ti), SIMDBase_SET1(0.5)));
+ SIMDBase_STOR(&s[1], SIMDBase_MULi(SIMDBase_SUBi(tr, ti), SIMDBase_SET1(0.5)));
+
+ for(k=1;k<n/4;k++) {
+ SIMDBase_VECT s00 = SIMDBase_LOAD(&s[k*2+0]), s01 = SIMDBase_LOAD(&s[k*2+1]);
+ SIMDBase_VECT s10 = SIMDBase_LOAD(&s[(n/2-k)*2+0]), s11 = SIMDBase_LOAD(&s[(n/2-k)*2+1]);
+
+ tr = SIMDBase_SUBi(s00, s10); ti = SIMDBase_ADDi(s01, s11);
+ ur = SIMDBase_LOAD1(&(p->rtTable[ts][k*2+0]));
+ ui = SIMDBase_LOAD1(&(p->rtTable[ts][k*2+1]));
+ mr = SIMDBase_SUBi(SIMDBase_MULi(tr, ur), SIMDBase_MULi(ti, ui));
+ mi = SIMDBase_ADDi(SIMDBase_MULi(tr, ui), SIMDBase_MULi(ti, ur));
+ tr = SIMDBase_SUBi(s00, mr); ti = SIMDBase_SUBi(mi, s01);
+ SIMDBase_STOR(&s[k*2+0], SIMDBase_ADDi(mr, s10));
+ SIMDBase_STOR(&s[k*2+1], SIMDBase_SUBi(mi, s11));
+ SIMDBase_STOR(&s[(n/2-k)*2+0], tr);
+ SIMDBase_STOR(&s[(n/2-k)*2+1], ti);
+ }
+}
+
+void DFTUndiff_EXECUTE(void *p2, void *s2, int32_t dir) {
+ DFTUndiff *p = (DFTUndiff *)p2;
+ SIMDBase_VECT *s = (SIMDBase_VECT *)s2;
+
+ if (p->magic != MAGIC_DFT) abort();
+
+ p->s = s;
+
+ if (dir == -1) {
+ if ((p->flags & DFT_FLAG_ALT_REAL) != 0) {
+ realSub1(p, s, 0);
+ }
+
+ srForwardMain(p);
+
+ if ((p->flags & DFT_FLAG_NO_BITREVERSAL) == 0) {
+ if (p->useCobra) {
+ bitReversalCobraInplace(p);
+ } else {
+ bitReversalRecursive(p->s, p->length, 1, 0, 0);
+ }
+ }
+
+ if ((p->flags & DFT_FLAG_REAL) != 0) {
+ realSub0(p, s, 0);
+ s[p->length+1] = SIMDBase_NEGi(s[p->length+1]);
+ }
+ } else {
+ if ((p->flags & DFT_FLAG_REAL) != 0) {
+ s[p->length+1] = SIMDBase_NEGi(s[p->length+1]);
+ realSub1(p, s, 1);
+ }
+
+ if ((p->flags & DFT_FLAG_NO_BITREVERSAL) == 0) {
+ if (p->useCobra) {
+ bitReversalCobraInplace(p);
+ } else {
+ bitReversalRecursive(p->s, p->length, 1, 0, 0);
+ }
+ }
+
+ srBackwardMain(p);
+
+ if ((p->flags & DFT_FLAG_ALT_REAL) != 0) {
+ realSub0(p, s, 1);
+ }
+ }
+}
+
+void DFTUndiff_DESTROYPLAN(void *p2) {
+ DFTUndiff *plan = (DFTUndiff *)p2;
+ if (plan->magic != MAGIC_DFT) abort();
+
+ free(*(plan->ptTable));
+ free(plan->ptTable);
+ free(plan->cobraT);
+ free(plan->cobraR);
+ //free(plan->t);
+ if (plan->rtTable != NULL) {
+ free(plan->rtTable[0]);
+ free(plan->rtTable[1]);
+ free(plan->rtTable);
+ }
+
+ plan->magic = 0;
+ free(plan);
+}
+
+DFTUndiff *DFTUndiff_MAKEPLANSUB(uint64_t n, int32_t radix2thres, int32_t useCobra, uint64_t flags) {
+ int32_t i, j, k;
+
+ uint32_t linesize = SIMDBase_sizeOfCachelineInByte();
+ uint32_t cachesize = SIMDBase_sizeOfDataCacheInByte();
+
+ //
+
+ if ((flags & DFT_FLAG_REAL) != 0 || (flags & DFT_FLAG_ALT_REAL) != 0) n /= 2;
+
+ DFTUndiff *d = calloc(1, sizeof(DFTUndiff));
+
+ d->magic = MAGIC_DFT;
+ d->mode = SIMDBase_MODE;
+ d->flags = flags;
+
+ d->radix2thres = radix2thres;
+ d->useCobra = useCobra;
+
+ d->length = (uint32_t) n;
+ d->log2len = DFT_ilog2((uint32_t) n);
+
+ //
+
+ SIMDBase_REAL *trigTable = SIMDBase_alignedMalloc(sizeof(SIMDBase_REAL)*n*2);
+ d->ptTable = malloc(sizeof(SIMDBase_REAL *) * (d->log2len+1));
+
+ SIMDBase_REAL *p = trigTable, **pp = d->ptTable;
+
+ for(j=0;j<(int32_t)d->log2len+1;j++) {
+ *pp++ = p;
+
+ if ((1 << j) >= d->radix2thres) {
+ for(i=0;i<(1 << j)/4+1;i++) {
+ *p++ = (SIMDBase_REAL)COS(-2*M_PIl*i/(1 << j));
+ }
+ const int32_t step = linesize / sizeof(SIMDBase_REAL);
+ p += (step - (p - trigTable) % step) % step;
+ } else {
+ for(i=0;i<(1 << j)/4;i++) {
+ *p++ = (SIMDBase_REAL)COS(-2*M_PIl*i/(1 << j));
+ *p++ = (SIMDBase_REAL)SIN(-2*M_PIl*i/(1 << j));
+ *p++ = (SIMDBase_REAL)COS(-6*M_PIl*i/(1 << j));
+ *p++ = (SIMDBase_REAL)SIN(-6*M_PIl*i/(1 << j));
+ }
+ }
+ }
+
+ //
+
+ int32_t cobraQ;
+
+ cobraQ = linesize / (sizeof(SIMDBase_VECT) * 2);
+
+ for(;;) {
+ if (1 << (cobraQ*2) >
+ (cachesize / (sizeof(SIMDBase_VECT) * 2)/2))
+ break;
+
+ cobraQ++;
+ }
+ cobraQ--;
+
+ d->cobraQ = cobraQ;
+
+ if (cobraQ >= 4 && d->log2len >= 2*cobraQ) {
+ SIMDBase_VECT *cobraT;
+ int32_t *cobraR;
+
+ if (d->log2len <= 2*cobraQ) cobraQ = d->log2len / 2;
+
+ cobraT = SIMDBase_alignedMalloc(sizeof(SIMDBase_VECT)*2 * (1 << (cobraQ*2)));
+ cobraR = (int32_t *)SIMDBase_alignedMalloc(sizeof(int32_t) * (1 << cobraQ));
+
+ for(i=0;i<(1 << cobraQ);i++) cobraR[i] = bitR(i, cobraQ);
+
+ d->cobraT = cobraT; d->cobraR = cobraR;
+ } else {
+ d->useCobra = 0;
+ }
+
+ //
+
+ if ((d->flags & DFT_FLAG_REAL) != 0 || (d->flags & DFT_FLAG_ALT_REAL) != 0) {
+ int32_t m = n*2;
+
+ d->rtTable = malloc(sizeof(SIMDBase_REAL *)*2);
+ d->rtTable[0] = SIMDBase_alignedMalloc(sizeof(SIMDBase_REAL)*m/2);
+ d->rtTable[1] = SIMDBase_alignedMalloc(sizeof(SIMDBase_REAL)*m/2);
+
+ for(k=0;k<m/4;k++) {
+ d->rtTable[0][k*2+0] = 0.5-0.5*SIN(-2*M_PIl*k/m);
+ d->rtTable[0][k*2+1] = 0.5*COS(-2*M_PIl*k/m);
+ d->rtTable[1][k*2+0] = 0.5-0.5*SIN( 2*M_PIl*k/m);
+ d->rtTable[1][k*2+1] = 0.5*COS( 2*M_PIl*k/m);
+ }
+ }
+
+ //
+
+ return (void *)d;
+}
+
+void *DFTUndiff_MAKEPLAN(uint64_t n, uint64_t flags) {
+ if (flags & DFT_FLAG_VERBOSE) {
+ printf("\n--------------------------------\n");
+ printf("Making plan, mode = %s, dft length = %d\n", SIMDBase_NAME, (int)n);
+ printf("Processor : %s\n", SIMDBase_getProcessorNameString());
+ printf("Cache size (L2 + L3) : %d kbytes / thread\n", SIMDBase_sizeOfDataCacheInByte() / 1024);
+ printf("Cache Line Size : %d bytes\n", SIMDBase_sizeOfCachelineInByte());
+ }
+
+ if (n <= 256 || (flags & 3) == 0) {
+ return DFTUndiff_MAKEPLANSUB(n, n*2, (flags & DFT_FLAG_FORCE_COBRA) != 0, flags);
+ }
+
+ SIMDBase_REAL *s1 = SIMDBase_alignedMalloc(sizeof(SIMDBase_VECT)*n*2);
+
+ int32_t i, j, ts, tsbest, useCobra = 0;
+ double tick, tickmin;
+
+ if (flags & DFT_FLAG_VERBOSE) {
+ printf("\nWarming up before calibration ...");
+ fflush(stdout);
+ }
+
+ // warming up
+ tick = DFT_timeofday();
+ while(DFT_timeofday() - tick < 0.5)
+ ;
+
+ if (flags & DFT_FLAG_VERBOSE) {
+ printf(" done\n");
+ }
+
+ int32_t ntimes = 20000000.0 / n / DFT_ilog2(n);
+ if (ntimes == 0) ntimes = 1;
+
+ if (flags & DFT_FLAG_VERBOSE) {
+ printf("nTimes = %d\n", ntimes);
+ }
+
+ //
+
+ DFTUndiff *plan = DFTUndiff_MAKEPLANSUB(n, n*2, 0, flags);
+
+ for(i=0;i<n*2*SIMDBase_VECTLEN;i++) {
+ s1[i] = 0;
+ }
+
+ plan->s = (SIMDBase_VECT *)s1;
+
+ if (plan->cobraT != NULL) {
+ double tcobra = 0, trecur = 0;
+
+ if (flags & DFT_FLAG_VERBOSE) {
+ printf("\nChecking which bit-reversal method is faster\n");
+ }
+
+ //
+
+ bitReversalCobraInplace(plan);
+
+ tick = DFT_timeofday();
+
+ for(j=0;j<ntimes*4;j++) {
+ bitReversalCobraInplace(plan);
+ }
+
+ tcobra += DFT_timeofday() - tick;
+
+ //
+
+ bitReversalRecursive(plan->s, plan->length, 1, 0, 0);
+
+ tick = DFT_timeofday();
+
+ for(j=0;j<ntimes*4;j++) {
+ bitReversalRecursive(plan->s, plan->length, 1, 0, 0);
+ }
+
+ trecur += DFT_timeofday() - tick;
+
+ //
+
+ bitReversalCobraInplace(plan);
+
+ tick = DFT_timeofday();
+
+ for(j=0;j<ntimes*4;j++) {
+ bitReversalCobraInplace(plan);
+ }
+
+ tcobra += DFT_timeofday() - tick;
+
+ //
+
+ bitReversalRecursive(plan->s, plan->length, 1, 0, 0);
+
+ tick = DFT_timeofday();
+
+ for(j=0;j<ntimes*4;j++) {
+ bitReversalRecursive(plan->s, plan->length, 1, 0, 0);
+ }
+
+ trecur += DFT_timeofday() - tick;
+
+ //
+
+ useCobra = tcobra < trecur;
+
+ if ((flags & DFT_FLAG_FORCE_RECURSIVE) != 0) useCobra = 0;
+ if ((flags & DFT_FLAG_FORCE_COBRA) != 0) useCobra = 1;
+
+ if (flags & DFT_FLAG_VERBOSE) {
+ printf("cobra : %g\n", tcobra);
+ printf("recur : %g\n", trecur);
+ if (useCobra) {
+ printf("will use Cobra\n");
+ } else {
+ printf("will use the recursive reverser\n");
+ }
+ }
+ }
+
+ DFTUndiff_DESTROYPLAN(plan);
+
+ //
+
+ if (flags & DFT_FLAG_VERBOSE) {
+ printf("\nDetermining radix 2 threshold\n");
+ }
+
+ plan = DFTUndiff_MAKEPLANSUB(n, n*2, useCobra, flags);
+
+ for(j=0;j<ntimes;j++) {
+ DFTUndiff_EXECUTE(plan, s1, -1);
+ DFTUndiff_EXECUTE(plan, s1, 1);
+ }
+
+ DFTUndiff_DESTROYPLAN(plan);
+
+ tsbest = -1;
+ tickmin = 0;
+
+ for(ts = 1024;ts <= n*2;ts *= 2) {
+ plan = DFTUndiff_MAKEPLANSUB(n, ts, useCobra, flags);
+
+ tick = DFT_timeofday();
+
+ for(j=0;j<ntimes;j++) {
+ DFTUndiff_EXECUTE(plan, s1, -1);
+ DFTUndiff_EXECUTE(plan, s1, 1);
+ }
+
+ tick = DFT_timeofday() - tick;
+
+ DFTUndiff_DESTROYPLAN(plan);
+
+ if (tickmin == 0) tickmin = tick;
+
+ if (flags & DFT_FLAG_VERBOSE) {
+ printf("%d : %g\n",ts, (double)tick);
+ }
+
+ if (tick < tickmin) {
+ tickmin = tick;
+ tsbest = ts;
+ }
+ }
+
+ if (tsbest == -1) tsbest = n*2;;
+
+ if (flags & DFT_FLAG_VERBOSE) {
+ //printf("forcing tsbest = 1024\n");
+ //tsbest = 1024;
+ printf("radix 2 threshold : %d\n\n", tsbest);
+
+ double t = tickmin / ntimes / 2;
+ double nf = 5 * n * log(n) / log(2) / (t * 1000000);
+
+ printf("nFlops = %d x %g\n", SIMDBase_VECTLEN, nf);
+ }
+
+ plan = DFTUndiff_MAKEPLANSUB(n, tsbest, useCobra, flags);
+
+ if (flags & DFT_FLAG_VERBOSE) {
+ printf("\nDone making plan\n--------------------------------\n");
+ }
+
+ return plan;
+}
diff --git a/plugins/supereq/nsfft-1.00/dft/DFTUndiff.h b/plugins/supereq/nsfft-1.00/dft/DFTUndiff.h
new file mode 100644
index 00000000..d26b0d9b
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/dft/DFTUndiff.h
@@ -0,0 +1,114 @@
+#ifndef __DFTIMPL_H__
+#define __DFTIMPL_H__
+
+#include "SIMDBaseUndiff.h"
+
+#define MAGIC_DFT 0x18839f6d82bb02b6ULL
+
+typedef struct {
+ uint64_t magic;
+
+ SIMDBase_VECT *s;
+ uint32_t offset1, offset2;
+ uint32_t butlen, log2butlen;
+ uint32_t stride;
+
+ SIMDBase_REAL **ptTable;
+ uint32_t length, log2len;
+
+ int32_t radix2thres, flagTrans, useCobra;
+
+ int32_t cobraQ;
+ SIMDBase_VECT *cobraT;
+ int32_t *cobraR;
+
+ SIMDBase_REAL **rtTable;
+
+ uint64_t flags;
+ int32_t mode;
+} DFTUndiff;
+
+#if defined(ENABLE_PUREC_FLOAT) ////////////////////////////////////////////
+
+#define DFTUndiff_GETMODEPARAMINT getModeParamInt_purec_float
+#define DFTUndiff_GETMODEPARAMSTRING getModeParamString_purec_float
+#define DFTUndiff_EXECUTE execute_purec_float
+#define DFTUndiff_MAKEPLAN makePlan_purec_float
+#define DFTUndiff_MAKEPLANSUB makePlanSub_purec_float
+#define DFTUndiff_DESTROYPLAN destroyPlan_purec_float
+
+#elif defined(ENABLE_PUREC_DOUBLE) ////////////////////////////////////////////
+
+#define DFTUndiff_GETMODEPARAMINT getModeParamInt_purec_double
+#define DFTUndiff_GETMODEPARAMSTRING getModeParamString_purec_double
+#define DFTUndiff_EXECUTE execute_purec_double
+#define DFTUndiff_MAKEPLAN makePlan_purec_double
+#define DFTUndiff_MAKEPLANSUB makePlanSub_purec_double
+#define DFTUndiff_DESTROYPLAN destroyPlan_purec_double
+
+#elif defined(ENABLE_PUREC_LONGDOUBLE) ////////////////////////////////////////////
+
+#define DFTUndiff_GETMODEPARAMINT getModeParamInt_purec_longdouble
+#define DFTUndiff_GETMODEPARAMSTRING getModeParamString_purec_longdouble
+#define DFTUndiff_EXECUTE execute_purec_longdouble
+#define DFTUndiff_MAKEPLAN makePlan_purec_longdouble
+#define DFTUndiff_MAKEPLANSUB makePlanSub_purec_longdouble
+#define DFTUndiff_DESTROYPLAN destroyPlan_purec_longdouble
+
+#elif defined(ENABLE_SSE_FLOAT) ////////////////////////////////////////////
+
+#define DFTUndiff_GETMODEPARAMINT getModeParamInt_sse_float
+#define DFTUndiff_GETMODEPARAMSTRING getModeParamString_sse_float
+#define DFTUndiff_EXECUTE execute_sse_float
+#define DFTUndiff_MAKEPLAN makePlan_sse_float
+#define DFTUndiff_MAKEPLANSUB makePlanSub_sse_float
+#define DFTUndiff_DESTROYPLAN destroyPlan_sse_float
+
+#elif defined(ENABLE_SSE2_DOUBLE) ////////////////////////////////////////////
+
+#define DFTUndiff_GETMODEPARAMINT getModeParamInt_sse2_double
+#define DFTUndiff_GETMODEPARAMSTRING getModeParamString_sse2_double
+#define DFTUndiff_EXECUTE execute_sse2_double
+#define DFTUndiff_MAKEPLAN makePlan_sse2_double
+#define DFTUndiff_MAKEPLANSUB makePlanSub_sse2_double
+#define DFTUndiff_DESTROYPLAN destroyPlan_sse2_double
+
+#elif defined(ENABLE_NEON_FLOAT) ////////////////////////////////////////////
+
+#define DFTUndiff_GETMODEPARAMINT getModeParamInt_neon_float
+#define DFTUndiff_GETMODEPARAMSTRING getModeParamString_neon_float
+#define DFTUndiff_EXECUTE execute_neon_float
+#define DFTUndiff_MAKEPLAN makePlan_neon_float
+#define DFTUndiff_MAKEPLANSUB makePlanSub_neon_float
+#define DFTUndiff_DESTROYPLAN destroyPlan_neon_float
+
+#elif defined(ENABLE_AVX_FLOAT) ////////////////////////////////////////////
+
+#define DFTUndiff_GETMODEPARAMINT getModeParamInt_avx_float
+#define DFTUndiff_GETMODEPARAMSTRING getModeParamString_avx_float
+#define DFTUndiff_EXECUTE execute_avx_float
+#define DFTUndiff_MAKEPLAN makePlan_avx_float
+#define DFTUndiff_MAKEPLANSUB makePlanSub_avx_float
+#define DFTUndiff_DESTROYPLAN destroyPlan_avx_float
+
+#elif defined(ENABLE_AVX_DOUBLE) ////////////////////////////////////////////
+
+#define DFTUndiff_GETMODEPARAMINT getModeParamInt_avx_double
+#define DFTUndiff_GETMODEPARAMSTRING getModeParamString_avx_double
+#define DFTUndiff_EXECUTE execute_avx_double
+#define DFTUndiff_MAKEPLAN makePlan_avx_double
+#define DFTUndiff_MAKEPLANSUB makePlanSub_avx_double
+#define DFTUndiff_DESTROYPLAN destroyPlan_avx_double
+
+#elif defined(ENABLE_ALTIVEC_FLOAT) ////////////////////////////////////////////
+
+#define DFTUndiff_GETMODEPARAMINT getModeParamInt_altivec_float
+#define DFTUndiff_GETMODEPARAMSTRING getModeParamString_altivec_float
+#define DFTUndiff_EXECUTE execute_altivec_float
+#define DFTUndiff_MAKEPLAN makePlan_altivec_float
+#define DFTUndiff_MAKEPLANSUB makePlanSub_altivec_float
+#define DFTUndiff_DESTROYPLAN destroyPlan_altivec_float
+
+#endif ////////////////////////////////////////////////////////////////////
+
+#endif
diff --git a/plugins/supereq/nsfft-1.00/dft/Makefile b/plugins/supereq/nsfft-1.00/dft/Makefile
new file mode 120000
index 00000000..fc484116
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/dft/Makefile
@@ -0,0 +1 @@
+Makefile.x86 \ No newline at end of file
diff --git a/plugins/supereq/nsfft-1.00/dft/Makefile.altivec b/plugins/supereq/nsfft-1.00/dft/Makefile.altivec
new file mode 100644
index 00000000..fe7fc993
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/dft/Makefile.altivec
@@ -0,0 +1,26 @@
+CC=gcc
+BASEOPT=-Wall -I ../simd -maltivec -mabi=altivec
+OPT=$(BASEOPT) -O3
+
+all : libDFT.a
+
+DFTpurecfloat.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h ../simd/SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_FLOAT DFTUndiff.c -c -o DFTpurecfloat.o
+
+DFTpurecdouble.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h ../simd/SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_DOUBLE DFTUndiff.c -c -o DFTpurecdouble.o
+
+DFTpureclongdouble.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h ../simd/SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_LONGDOUBLE DFTUndiff.c -c -o DFTpureclongdouble.o
+
+DFTaltivecfloat.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h ../simd/SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_ALTIVEC_FLOAT DFTUndiff.c -c -o DFTaltivecfloat.o
+
+DFT.o : DFT.c DFT.h
+ $(CC) $(OPT) -DENABLE_PUREC_FLOAT -DENABLE_PUREC_DOUBLE -DENABLE_PUREC_LONGDOUBLE -DENABLE_ALTIVEC_FLOAT DFT.c -c -o DFT.o
+
+libDFT.a : DFTpurecfloat.o DFTpurecdouble.o DFTpureclongdouble.o DFTaltivecfloat.o DFT.o
+ rm -f libDFT.a; ar -cvq libDFT.a DFTpurecfloat.o DFTpurecdouble.o DFTpureclongdouble.o DFTaltivecfloat.o DFT.o
+
+clean :
+ rm -f *~ *.o *.s *.a
diff --git a/plugins/supereq/nsfft-1.00/dft/Makefile.neon b/plugins/supereq/nsfft-1.00/dft/Makefile.neon
new file mode 100644
index 00000000..111a04ae
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/dft/Makefile.neon
@@ -0,0 +1,26 @@
+CC=gcc
+BASEOPT=-Wall -I ../simd -mfloat-abi=softfp
+OPT=$(BASEOPT) -O3
+
+all : libDFT.a
+
+DFTpurecfloat.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h
+ $(CC) $(OPT) -DENABLE_PUREC_FLOAT DFTUndiff.c -c -o DFTpurecfloat.o
+
+DFTpurecdouble.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h
+ $(CC) $(OPT) -DENABLE_PUREC_DOUBLE DFTUndiff.c -c -o DFTpurecdouble.o
+
+DFTpureclongdouble.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h
+ $(CC) $(OPT) -DENABLE_PUREC_LONGDOUBLE DFTUndiff.c -c -o DFTpureclongdouble.o
+
+DFTneonfloat.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h
+ $(CC) $(OPT) -mfpu=neon -DENABLE_NEON_FLOAT DFTUndiff.c -c -o DFTneonfloat.o
+
+DFT.o : DFT.c DFT.h
+ $(CC) $(OPT) -DENABLE_PUREC_FLOAT -DENABLE_PUREC_DOUBLE -DENABLE_PUREC_LONGDOUBLE -DENABLE_NEON_FLOAT DFT.c -c -o DFT.o
+
+libDFT.a : DFTpurecfloat.o DFTpurecdouble.o DFTpureclongdouble.o DFTneonfloat.o DFT.o
+ rm -f libDFT.a; ar -cvq libDFT.a DFTpurecfloat.o DFTpurecdouble.o DFTpureclongdouble.o DFTneonfloat.o DFT.o
+
+clean :
+ rm -f *~ *.o *.s *.a
diff --git a/plugins/supereq/nsfft-1.00/dft/Makefile.purec b/plugins/supereq/nsfft-1.00/dft/Makefile.purec
new file mode 100644
index 00000000..2c8b04f1
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/dft/Makefile.purec
@@ -0,0 +1,35 @@
+CC=gcc
+BASEOPT=-Wall
+OPT=$(BASEOPT) -O3
+
+all : libDFT.a
+
+DFTpurecfloat.o : DFTUndiff.c DFT.h SIMDBase.h
+ $(CC) $(OPT) -DENABLE_PUREC_FLOAT DFTUndiff.c -c -o DFTpurecfloat.o
+
+DFTpurecdouble.o : DFTUndiff.c DFT.h SIMDBase.h
+ $(CC) $(OPT) -DENABLE_PUREC_DOUBLE DFTUndiff.c -c -o DFTpurecdouble.o
+
+DFTpureclongdouble.o : DFTUndiff.c DFT.h SIMDBase.h
+ $(CC) $(OPT) -DENABLE_PUREC_LONGDOUBLE DFTUndiff.c -c -o DFTpureclongdouble.o
+
+SIMDBaseUndiff_purecfloat.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_FLOAT SIMDBaseUndiff.c -c -o SIMDBaseUndiff_purecfloat.o
+
+SIMDBaseUndiff_purecdouble.o : SIMDBaseUndiff.c DFT.h SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_DOUBLE SIMDBaseUndiff.c -c -o SIMDBaseUndiff_purecdouble.o
+
+SIMDBaseUndiff_pureclongdouble.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_LONGDOUBLE SIMDBaseUndiff.c -c -o SIMDBaseUndiff_pureclongdouble.o
+
+SIMDBase.o : SIMDBase.c SIMDBase.h
+ $(CC) $(BASEOPT) -O -DENABLE_PUREC_FLOAT -DENABLE_PUREC_DOUBLE -DENABLE_PUREC_LONGDOUBLE SIMDBase.c -c -o SIMDBase.o
+
+DFT.o : DFT.c DFT.h
+ $(CC) $(OPT) -DENABLE_PUREC_FLOAT -DENABLE_PUREC_DOUBLE -DENABLE_PUREC_LONGDOUBLE DFT.c -c -o DFT.o
+
+libDFT.a : DFTpurecfloat.o DFTpurecdouble.o DFTpureclongdouble.o DFT.o SIMDBase.o SIMDBaseUndiff_purecfloat.o SIMDBaseUndiff_purecdouble.o SIMDBaseUndiff_pureclongdouble.o
+ rm -f libDFT.a; ar -cvq libDFT.a DFTpurecfloat.o DFTpurecdouble.o DFTpureclongdouble.o DFT.o SIMDBase.o SIMDBaseUndiff_purecfloat.o SIMDBaseUndiff_purecdouble.o SIMDBaseUndiff_pureclongdouble.o
+
+clean :
+ rm -f *~ *.o *.s *.a
diff --git a/plugins/supereq/nsfft-1.00/dft/Makefile.x86 b/plugins/supereq/nsfft-1.00/dft/Makefile.x86
new file mode 100644
index 00000000..6ecbacec
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/dft/Makefile.x86
@@ -0,0 +1,29 @@
+CC=gcc
+BASEOPT=-Wall -I ../simd
+OPT=$(BASEOPT) -O3
+
+all : libDFT.a
+
+DFTpurecfloat.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h ../simd/SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_FLOAT DFTUndiff.c -c -o DFTpurecfloat.o
+
+DFTpurecdouble.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h ../simd/SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_DOUBLE DFTUndiff.c -c -o DFTpurecdouble.o
+
+DFTpureclongdouble.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h ../simd/SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_LONGDOUBLE DFTUndiff.c -c -o DFTpureclongdouble.o
+
+DFTssefloat.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h ../simd/SIMDBaseUndiff.h
+ $(CC) $(OPT) -msse -DENABLE_SSE_FLOAT DFTUndiff.c -c -o DFTssefloat.o
+
+DFTsse2double.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h ../simd/SIMDBaseUndiff.h
+ $(CC) $(OPT) -msse2 -DENABLE_SSE2_DOUBLE DFTUndiff.c -c -o DFTsse2double.o
+
+DFT.o : DFT.c DFT.h
+ $(CC) $(OPT) -DENABLE_PUREC_FLOAT -DENABLE_PUREC_DOUBLE -DENABLE_PUREC_LONGDOUBLE -DENABLE_SSE_FLOAT -DENABLE_SSE2_DOUBLE DFT.c -c -o DFT.o
+
+libDFT.a : DFTpurecfloat.o DFTpurecdouble.o DFTpureclongdouble.o DFTssefloat.o DFTsse2double.o DFT.o
+ rm -f libDFT.a; ar -cvq libDFT.a DFTpurecfloat.o DFTpurecdouble.o DFTpureclongdouble.o DFTssefloat.o DFTsse2double.o DFT.o
+
+clean :
+ rm -f *~ *.o *.s *.a a.out
diff --git a/plugins/supereq/nsfft-1.00/dft/Makefile.x86avx b/plugins/supereq/nsfft-1.00/dft/Makefile.x86avx
new file mode 100644
index 00000000..b38909cb
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/dft/Makefile.x86avx
@@ -0,0 +1,35 @@
+CC=gcc
+BASEOPT=-Wall -I ../simd
+OPT=$(BASEOPT) -O3
+
+all : libDFT.a
+
+DFTpurecfloat.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h ../simd/SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_FLOAT DFTUndiff.c -c -o DFTpurecfloat.o
+
+DFTpurecdouble.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h ../simd/SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_DOUBLE DFTUndiff.c -c -o DFTpurecdouble.o
+
+DFTpureclongdouble.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h ../simd/SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_LONGDOUBLE DFTUndiff.c -c -o DFTpureclongdouble.o
+
+DFTssefloat.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h ../simd/SIMDBaseUndiff.h
+ $(CC) $(OPT) -msse -DENABLE_SSE_FLOAT DFTUndiff.c -c -o DFTssefloat.o
+
+DFTsse2double.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h ../simd/SIMDBaseUndiff.h
+ $(CC) $(OPT) -msse2 -DENABLE_SSE2_DOUBLE DFTUndiff.c -c -o DFTsse2double.o
+
+DFTavxfloat.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h ../simd/SIMDBaseUndiff.h
+ $(CC) $(OPT) -mavx -DENABLE_AVX_FLOAT DFTUndiff.c -c -o DFTavxfloat.o
+
+DFTavxdouble.o : DFTUndiff.c DFT.h ../simd/SIMDBase.h ../simd/SIMDBaseUndiff.h
+ $(CC) $(OPT) -mavx -DENABLE_AVX_DOUBLE DFTUndiff.c -c -o DFTavxdouble.o
+
+DFT.o : DFT.c DFT.h
+ $(CC) $(OPT) -DENABLE_PUREC_FLOAT -DENABLE_PUREC_DOUBLE -DENABLE_PUREC_LONGDOUBLE -DENABLE_SSE_FLOAT -DENABLE_SSE2_DOUBLE -DENABLE_AVX_FLOAT -DENABLE_AVX_DOUBLE DFT.c -c -o DFT.o
+
+libDFT.a : DFTpurecfloat.o DFTpurecdouble.o DFTpureclongdouble.o DFTssefloat.o DFTsse2double.o DFTavxfloat.o DFTavxdouble.o DFT.o
+ rm -f libDFT.a; ar -cvq libDFT.a DFTpurecfloat.o DFTpurecdouble.o DFTpureclongdouble.o DFTssefloat.o DFTsse2double.o DFTavxfloat.o DFTavxdouble.o DFT.o
+
+clean :
+ rm -f *~ *.o *.s *.a a.out
diff --git a/plugins/supereq/nsfft-1.00/dfttest/DFTExample.c b/plugins/supereq/nsfft-1.00/dfttest/DFTExample.c
new file mode 100644
index 00000000..78ff14dc
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/dfttest/DFTExample.c
@@ -0,0 +1,88 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+#include <complex.h>
+
+#include "SIMDBase.h"
+#include "DFT.h"
+
+typedef float REAL;
+#define TYPE SIMDBase_TYPE_FLOAT
+
+#define THRES 1e-3
+
+double complex omega(double n, double kn) {
+ return cexp((-2 * M_PI * _Complex_I / n) * kn);
+}
+
+void forward(double complex *ts, double complex *fs, int len) {
+ int k, n;
+
+ for(k=0;k<len;k++) {
+ fs[k] = 0;
+
+ for(n=0;n<len;n++) {
+ fs[k] += ts[n] * omega(len, n*k);
+ }
+ }
+}
+
+int main(int argc, char **argv) {
+ const int n = 256;
+
+ int mode = SIMDBase_chooseBestMode(TYPE);
+ printf("mode : %d, %s\n", mode, SIMDBase_getModeParamString(SIMDBase_PARAMID_MODE_NAME, mode));
+
+ int veclen = SIMDBase_getModeParamInt(SIMDBase_PARAMID_VECTOR_LEN, mode);
+ int sizeOfVect = SIMDBase_getModeParamInt(SIMDBase_PARAMID_SIZE_OF_VECT, mode);
+
+ //
+
+ int i, j;
+
+ DFT *p = DFT_init(mode, n, 0);
+ REAL *sx = SIMDBase_alignedMalloc(sizeOfVect*n*2);
+
+ //
+
+ double complex ts[veclen][n], fs[veclen][n];
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n;i++) {
+ ts[j][i] = (random() / (double)RAND_MAX) + (random() / (double)RAND_MAX) * _Complex_I;
+ sx[(i*2+0)*veclen+j] = creal(ts[j][i]);
+ sx[(i*2+1)*veclen+j] = cimag(ts[j][i]);
+ }
+ }
+
+ //
+
+ DFT_execute(p, mode, sx, -1);
+
+ for(j=0;j<veclen;j++) {
+ forward(ts[j], fs[j], n);
+ }
+
+ //
+
+ int success = 1;
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n;i++) {
+ if ((fabs(sx[(i*2+0)*veclen+j] - creal(fs[j][i])) > THRES) ||
+ (fabs(sx[(i*2+1)*veclen+j] - cimag(fs[j][i])) > THRES)) {
+ success = 0;
+ }
+ }
+ }
+
+ printf("%s\n", success ? "OK" : "NG");
+
+ //
+
+ SIMDBase_alignedFree(sx);
+ DFT_dispose(p, mode);
+
+ exit(0);
+}
diff --git a/plugins/supereq/nsfft-1.00/dfttest/DFTTestFFTW.c b/plugins/supereq/nsfft-1.00/dfttest/DFTTestFFTW.c
new file mode 100644
index 00000000..42825ed9
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/dfttest/DFTTestFFTW.c
@@ -0,0 +1,317 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+#include <time.h>
+#include <complex.h>
+
+#include <fftw3.h>
+
+#include "SIMDBase.h"
+#include "DFT.h"
+
+#if 1
+typedef float REAL;
+#define TYPE SIMDBase_TYPE_FLOAT
+#else
+typedef double REAL;
+#define TYPE SIMDBase_TYPE_DOUBLE
+#endif
+
+#define THRES 1e-3
+
+// complex forward
+int check_cf(int n, int mode, int veclen, int sizeOfVect) {
+ int i, j;
+
+ DFT *p = DFT_init(mode, n, 0);
+ fftw_plan w[n];
+
+ fftw_complex *in[sizeOfVect], *out[sizeOfVect];
+
+ REAL *sx = SIMDBase_alignedMalloc(sizeOfVect*n*2);
+
+ //
+
+ for(j=0;j<veclen;j++) {
+ in[j] = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * n);
+ out[j] = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * n);
+ w[j] = fftw_plan_dft_1d(n, in[j], out[j], FFTW_FORWARD, FFTW_ESTIMATE);
+
+ for(i=0;i<n;i++) {
+ double re = random() / (double)RAND_MAX;
+ double im = random() / (double)RAND_MAX;
+ sx[(i*2+0)*veclen+j] = re;
+ sx[(i*2+1)*veclen+j] = im;
+ in[j][i] = re + im * _Complex_I;
+ }
+ }
+
+ //
+
+ DFT_execute(p, mode, sx, -1);
+
+ for(j=0;j<veclen;j++) {
+ fftw_execute(w[j]);
+ }
+
+ //
+
+ int success = 1;
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n;i++) {
+ if (fabs(sx[(i*2+0)*veclen+j] - creal(out[j][i])) > THRES) success = 0;
+ if (fabs(sx[(i*2+1)*veclen+j] - cimag(out[j][i])) > THRES) success = 0;
+ }
+ }
+
+ //
+
+ for(j=0;j<veclen;j++) {
+ fftw_destroy_plan(w[j]);
+ fftw_free(in[j]);
+ fftw_free(out[j]);
+ }
+
+ SIMDBase_alignedFree(sx);
+
+ DFT_dispose(p, mode);
+
+ //
+
+ return success;
+}
+
+// complex backward
+int check_cb(int n, int mode, int veclen, int sizeOfVect) {
+ int i, j;
+
+ DFT *p = DFT_init(mode, n, 0);
+ fftw_plan w[n];
+
+ fftw_complex *in[sizeOfVect], *out[sizeOfVect];
+
+ REAL *sx = SIMDBase_alignedMalloc(sizeOfVect*n*2);
+
+ //
+
+ for(j=0;j<veclen;j++) {
+ in[j] = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * n);
+ out[j] = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * n);
+ w[j] = fftw_plan_dft_1d(n, in[j], out[j], FFTW_BACKWARD, FFTW_ESTIMATE);
+
+ for(i=0;i<n;i++) {
+ double re = random() / (double)RAND_MAX;
+ double im = random() / (double)RAND_MAX;
+ sx[(i*2+0)*veclen+j] = re;
+ sx[(i*2+1)*veclen+j] = im;
+ in[j][i] = re + im * _Complex_I;
+ }
+ }
+
+ //
+
+ DFT_execute(p, mode, sx, 1);
+
+ for(j=0;j<veclen;j++) {
+ fftw_execute(w[j]);
+ }
+
+ //
+
+ int success = 1;
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n;i++) {
+ if (fabs(sx[(i*2+0)*veclen+j] - creal(out[j][i])) > THRES) success = 0;
+ if (fabs(sx[(i*2+1)*veclen+j] - cimag(out[j][i])) > THRES) success = 0;
+ }
+ }
+
+ //
+
+ for(j=0;j<veclen;j++) {
+ fftw_destroy_plan(w[j]);
+ fftw_free(in[j]);
+ fftw_free(out[j]);
+ }
+
+ SIMDBase_alignedFree(sx);
+
+ DFT_dispose(p, mode);
+
+ //
+
+ return success;
+}
+
+// real forward
+int check_rf(int n, int mode, int veclen, int sizeOfVect) {
+ int i, j;
+
+ DFT *p = DFT_init(mode, n, DFT_FLAG_REAL);
+ fftw_plan w[n];
+
+ double *in[sizeOfVect];
+ fftw_complex *out[sizeOfVect];
+
+ REAL *sx = SIMDBase_alignedMalloc(sizeOfVect*n*2);
+
+ //
+
+ for(j=0;j<veclen;j++) {
+ in[j] = (double *) fftw_malloc(sizeof(double) * n);
+ out[j] = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * (n/2+1));
+ w[j] = fftw_plan_dft_r2c_1d(n, in[j], out[j], FFTW_ESTIMATE);
+
+ for(i=0;i<n;i++) {
+ double re = random() / (double)RAND_MAX;
+ sx[i*veclen+j] = re;
+ in[j][i] = re;
+ }
+ }
+
+ //
+
+ DFT_execute(p, mode, sx, -1);
+
+ for(j=0;j<veclen;j++) {
+ fftw_execute(w[j]);
+ }
+
+ //
+
+ int success = 1;
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n/2;i++) {
+ if (i == 0) {
+ if (fabs(sx[(i*2+0)*veclen+j] - creal(out[j][0])) > THRES) success = 0;
+ if (fabs(sx[(i*2+1)*veclen+j] - creal(out[j][n/2])) > THRES) success = 0;
+ } else {
+ if (fabs(sx[(i*2+0)*veclen+j] - creal(out[j][i])) > THRES) success = 0;
+ if (fabs(sx[(i*2+1)*veclen+j] - cimag(out[j][i])) > THRES) success = 0;
+ }
+ }
+ }
+
+ //
+
+ for(j=0;j<veclen;j++) {
+ fftw_destroy_plan(w[j]);
+ fftw_free(in[j]);
+ fftw_free(out[j]);
+ }
+
+ SIMDBase_alignedFree(sx);
+
+ DFT_dispose(p, mode);
+
+ //
+
+ return success;
+}
+
+// real backward
+int check_rb(int n, int mode, int veclen, int sizeOfVect) {
+ int i, j;
+
+ DFT *p = DFT_init(mode, n, DFT_FLAG_REAL);
+ fftw_plan w[n];
+
+ fftw_complex *in[sizeOfVect];
+ double *out[sizeOfVect];
+
+ REAL *sx = SIMDBase_alignedMalloc(sizeOfVect*n*2);
+
+ //
+
+ for(j=0;j<veclen;j++) {
+ in[j] = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * (n/2+1));
+ out[j] = (double *) fftw_malloc(sizeof(double) * n);
+ w[j] = fftw_plan_dft_c2r_1d(n, in[j], out[j], FFTW_ESTIMATE);
+
+ for(i=0;i<n/2;i++) {
+ if (i == 0) {
+ in[j][0 ] = (random() / (double)RAND_MAX);
+ in[j][n/2] = (random() / (double)RAND_MAX);
+ } else {
+ in[j][i ] = (random() / (double)RAND_MAX) + (random() / (double)RAND_MAX) * _Complex_I;
+ }
+ }
+
+ for(i=0;i<n/2;i++) {
+ if (i == 0) {
+ sx[(2*0+0) * veclen + j] = creal(in[j][0 ]);
+ sx[(2*0+1) * veclen + j] = creal(in[j][n/2]);
+ } else {
+ sx[(2*i+0) * veclen + j] = creal(in[j][i]);
+ sx[(2*i+1) * veclen + j] = cimag(in[j][i]);
+ }
+ }
+ }
+
+ //
+
+ DFT_execute(p, mode, sx, 1);
+
+ for(j=0;j<veclen;j++) {
+ fftw_execute(w[j]);
+ }
+
+ //
+
+ int success = 1;
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n/2;i++) {
+ if ((fabs(sx[i * veclen + j]*2 - out[j][i]) > THRES)) {
+ success = 0;
+ }
+ }
+ }
+
+ //
+
+ for(j=0;j<veclen;j++) {
+ fftw_destroy_plan(w[j]);
+ fftw_free(in[j]);
+ fftw_free(out[j]);
+ }
+
+ SIMDBase_alignedFree(sx);
+
+ DFT_dispose(p, mode);
+
+ //
+
+ return success;
+}
+
+int main(int argc, char **argv) {
+ if (argc != 2) {
+ fprintf(stderr, "%s <log2n>\n", argv[0]);
+ exit(-1);
+ }
+
+ const int n = 1 << atoi(argv[1]);
+
+ srandom(time(NULL));
+
+ //
+
+ int mode = SIMDBase_chooseBestMode(TYPE);
+
+ printf("mode : %d, %s\n", mode, SIMDBase_getModeParamString(SIMDBase_PARAMID_MODE_NAME, mode));
+
+ int veclen = SIMDBase_getModeParamInt(SIMDBase_PARAMID_VECTOR_LEN, mode);
+ int sizeOfVect = SIMDBase_getModeParamInt(SIMDBase_PARAMID_SIZE_OF_VECT, mode);
+
+ printf("complex forward : %s\n", check_cf(n, mode, veclen, sizeOfVect) ? "OK" : "NG");
+ printf("complex backward : %s\n", check_cb(n, mode, veclen, sizeOfVect) ? "OK" : "NG");
+ printf("real forward : %s\n", check_rf(n, mode, veclen, sizeOfVect) ? "OK" : "NG");
+ printf("real backward : %s\n", check_rb(n, mode, veclen, sizeOfVect) ? "OK" : "NG");
+
+ exit(0);
+}
diff --git a/plugins/supereq/nsfft-1.00/dfttest/DFTTestNaive.c b/plugins/supereq/nsfft-1.00/dfttest/DFTTestNaive.c
new file mode 100644
index 00000000..9d4bdaae
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/dfttest/DFTTestNaive.c
@@ -0,0 +1,419 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+#include <time.h>
+#include <complex.h>
+
+#include "SIMDBase.h"
+#include "DFT.h"
+
+#if 1
+typedef float REAL;
+#define TYPE SIMDBase_TYPE_FLOAT
+#else
+typedef double REAL;
+#define TYPE SIMDBase_TYPE_DOUBLE
+#endif
+
+#define THRES 1e-3
+
+double complex omega(double n, double kn) {
+ return cexp((-2 * M_PI * _Complex_I / n) * kn);
+}
+
+void forward(double complex *ts, double complex *fs, int len) {
+ int k, n;
+
+ for(k=0;k<len;k++) {
+ fs[k] = 0;
+
+ for(n=0;n<len;n++) {
+ fs[k] += ts[n] * omega(len, n*k);
+ }
+ }
+}
+
+void backward(double complex *fs, double complex *ts, int len) {
+ int k, n;
+
+ for(k=0;k<len;k++) {
+ ts[k] = 0;
+
+ for(n=0;n<len;n++) {
+ ts[k] += fs[n] * omega(-len, n*k);
+ }
+ }
+}
+
+// complex forward
+int check_cf(int n, int mode, int veclen, int sizeOfVect) {
+ int i, j;
+
+ DFT *p = DFT_init(mode, n, 0);
+ REAL *sx = SIMDBase_alignedMalloc(sizeOfVect*n*2);
+
+ //
+
+ double complex ts[veclen][n], fs[veclen][n];
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n;i++) {
+ ts[j][i] = (random() / (double)RAND_MAX) + (random() / (double)RAND_MAX) * _Complex_I;
+ sx[(i*2+0)*veclen+j] = creal(ts[j][i]);
+ sx[(i*2+1)*veclen+j] = cimag(ts[j][i]);
+ }
+ }
+
+ //
+
+ DFT_execute(p, mode, sx, -1);
+
+ for(j=0;j<veclen;j++) {
+ forward(ts[j], fs[j], n);
+ }
+
+ //
+
+ int success = 1;
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n;i++) {
+ if ((fabs(sx[(i*2+0)*veclen+j] - creal(fs[j][i])) > THRES) ||
+ (fabs(sx[(i*2+1)*veclen+j] - cimag(fs[j][i])) > THRES)) {
+ success = 0;
+ }
+ }
+ }
+
+ //
+
+ SIMDBase_alignedFree(sx);
+ DFT_dispose(p, mode);
+
+ //
+
+ return success;
+}
+
+// complex backward
+int check_cb(int n, int mode, int veclen, int sizeOfVect) {
+ int i,j;
+
+ DFT *p = DFT_init(mode, n, 0);
+ REAL *sx = SIMDBase_alignedMalloc(sizeOfVect*n*2);
+
+ //
+
+ double complex fs[veclen][n], ts[veclen][n];
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n;i++) {
+ fs[j][i] = (random() / (double)RAND_MAX) + (random() / (double)RAND_MAX) * _Complex_I;
+
+ sx[(i*2+0)*veclen+j] = creal(fs[j][i]);
+ sx[(i*2+1)*veclen+j] = cimag(fs[j][i]);
+ }
+ }
+
+ //
+
+ DFT_execute(p, mode, sx, 1);
+
+ for(j=0;j<veclen;j++) {
+ backward(fs[j], ts[j], n);
+ }
+
+ //
+
+ int success = 1;
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n;i++) {
+ if ((fabs(sx[(i*2+0)*veclen+j] - creal(ts[j][i])) > THRES) ||
+ (fabs(sx[(i*2+1)*veclen+j] - cimag(ts[j][i])) > THRES)) {
+ success = 0;
+ }
+ }
+ }
+
+ //
+
+ SIMDBase_alignedFree(sx);
+ DFT_dispose(p, mode);
+
+ //
+
+ return success;
+}
+
+// real forward
+int check_rf(int n, int mode, int veclen, int sizeOfVect) {
+ int i,j;
+
+ DFT *p = DFT_init(mode, n, DFT_FLAG_REAL);
+ REAL *sx = SIMDBase_alignedMalloc(sizeOfVect*n);
+
+ //
+
+ double complex ts[veclen][n], fs[veclen][n];
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n;i++) {
+ ts[j][i] = (random() / (double)RAND_MAX);
+ sx[i*veclen+j] = creal(ts[j][i]);
+ }
+ }
+
+ //
+
+ DFT_execute(p, mode, sx, -1);
+
+ for(j=0;j<veclen;j++) {
+ forward(ts[j], fs[j], n);
+ }
+
+ //
+
+ int success = 1;
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n/2;i++) {
+ if (i == 0) {
+ if (fabs(sx[(2*0+0) * veclen + j] - creal(fs[j][0 ])) > THRES) success = 0;
+ if (fabs(sx[(2*0+1) * veclen + j] - creal(fs[j][n/2])) > THRES) success = 0;
+ } else {
+ if (fabs(sx[(2*i+0) * veclen + j] - creal(fs[j][i])) > THRES) success = 0;
+ if (fabs(sx[(2*i+1) * veclen + j] - cimag(fs[j][i])) > THRES) success = 0;
+ }
+ }
+ }
+
+ //
+
+ SIMDBase_alignedFree(sx);
+ DFT_dispose(p, mode);
+
+ //
+
+ return success;
+}
+
+// real backward
+int check_rb(int n, int mode, int veclen, int sizeOfVect) {
+ int i,j;
+
+ DFT *p = DFT_init(mode, n, DFT_FLAG_REAL);
+ REAL *sx = SIMDBase_alignedMalloc(sizeOfVect*n);
+
+ //
+
+ double complex fs[veclen][n], ts[veclen][n];
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n/2;i++) {
+ if (i == 0) {
+ fs[j][0 ] = (random() / (double)RAND_MAX);
+ fs[j][n/2] = (random() / (double)RAND_MAX);
+ } else {
+ fs[j][i ] = (random() / (double)RAND_MAX) + (random() / (double)RAND_MAX) * _Complex_I;
+ fs[j][n-i] = conj(fs[j][i]);
+ }
+ }
+ }
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n/2;i++) {
+ if (i == 0) {
+ sx[(2*0+0) * veclen + j] = creal(fs[j][0 ]);
+ sx[(2*0+1) * veclen + j] = creal(fs[j][n/2]);
+ } else {
+ sx[(2*i+0) * veclen + j] = creal(fs[j][i]);
+ sx[(2*i+1) * veclen + j] = cimag(fs[j][i]);
+ }
+ }
+ }
+
+ //
+
+ for(j=0;j<veclen;j++) {
+ backward(fs[j], ts[j], n);
+ }
+
+ DFT_execute(p, mode, sx, 1);
+
+ //
+
+ int success = 1;
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n;i++) {
+ if (fabs(cimag(ts[j][i])) > THRES) {
+ success = 0;
+ }
+
+ if ((fabs(sx[i * veclen + j]*2 - creal(ts[j][i])) > THRES)) {
+ success = 0;
+ }
+ }
+ }
+
+ //
+
+ SIMDBase_alignedFree(sx);
+ DFT_dispose(p, mode);
+
+ //
+
+ return success;
+}
+
+// alt real forward
+int check_arf(int n, int mode, int veclen, int sizeOfVect) {
+ int i,j;
+
+ DFT *p = DFT_init(mode, n, DFT_FLAG_ALT_REAL);
+ REAL *sx = SIMDBase_alignedMalloc(sizeOfVect*n);
+
+ //
+
+ double complex ts[veclen][n], fs[veclen][n];
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n;i++) {
+ ts[j][i] = (random() / (double)RAND_MAX);
+ sx[i*veclen+j] = creal(ts[j][i]);
+ }
+ }
+
+ //
+
+ DFT_execute(p, mode, sx, 1);
+
+ for(j=0;j<veclen;j++) {
+ backward(ts[j], fs[j], n);
+ }
+
+ //
+
+ int success = 1;
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n/2;i++) {
+ if (i == 0) {
+ if (fabs(sx[(2*0+0) * veclen + j] - creal(fs[j][0 ])) > THRES) success = 0;
+ if (fabs(sx[(2*0+1) * veclen + j] - creal(fs[j][n/2])) > THRES) success = 0;
+ } else {
+ if (fabs(sx[(2*i+0) * veclen + j] - creal(fs[j][i])) > THRES) success = 0;
+ if (fabs(sx[(2*i+1) * veclen + j] - cimag(fs[j][i])) > THRES) success = 0;
+ }
+ }
+ }
+
+ //
+
+ SIMDBase_alignedFree(sx);
+ DFT_dispose(p, mode);
+
+ //
+
+ return success;
+}
+
+// alt real backward
+int check_arb(int n, int mode, int veclen, int sizeOfVect) {
+ int i,j;
+
+ DFT *p = DFT_init(mode, n, DFT_FLAG_ALT_REAL);
+ REAL *sx = SIMDBase_alignedMalloc(sizeOfVect*n);
+
+ //
+
+ double complex fs[veclen][n], ts[veclen][n];
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n/2;i++) {
+ if (i == 0) {
+ fs[j][0 ] = (random() / (double)RAND_MAX);
+ fs[j][n/2] = (random() / (double)RAND_MAX);
+ } else {
+ fs[j][i ] = (random() / (double)RAND_MAX) + (random() / (double)RAND_MAX) * _Complex_I;
+ fs[j][n-i] = conj(fs[j][i]);
+ }
+ }
+ }
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n/2;i++) {
+ if (i == 0) {
+ sx[(2*0+0) * veclen + j] = creal(fs[j][0 ]);
+ sx[(2*0+1) * veclen + j] = creal(fs[j][n/2]);
+ } else {
+ sx[(2*i+0) * veclen + j] = creal(fs[j][i]);
+ sx[(2*i+1) * veclen + j] = cimag(fs[j][i]);
+ }
+ }
+ }
+
+ //
+
+ for(j=0;j<veclen;j++) {
+ forward(fs[j], ts[j], n);
+ }
+
+ DFT_execute(p, mode, sx, -1);
+
+ //
+
+ int success = 1;
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n;i++) {
+ if (fabs(cimag(ts[j][i])) > THRES) {
+ success = 0;
+ }
+
+ if ((fabs(sx[i * veclen + j]*2 - creal(ts[j][i])) > THRES)) {
+ success = 0;
+ }
+ }
+ }
+
+ //
+
+ SIMDBase_alignedFree(sx);
+ DFT_dispose(p, mode);
+
+ //
+
+ return success;
+}
+
+int main(int argc, char **argv) {
+ if (argc != 2) {
+ fprintf(stderr, "%s <log2n>\n", argv[0]);
+ exit(-1);
+ }
+
+ const int n = 1 << atoi(argv[1]);
+
+ srandom(time(NULL));
+
+ //
+
+ int mode = SIMDBase_chooseBestMode(TYPE);
+
+ printf("mode : %d, %s\n", mode, SIMDBase_getModeParamString(SIMDBase_PARAMID_MODE_NAME, mode));
+
+ int veclen = SIMDBase_getModeParamInt(SIMDBase_PARAMID_VECTOR_LEN, mode);
+ int sizeOfVect = SIMDBase_getModeParamInt(SIMDBase_PARAMID_SIZE_OF_VECT, mode);
+
+ printf("complex forward : %s\n", check_cf(n, mode, veclen, sizeOfVect) ? "OK" : "NG");
+ printf("complex backward : %s\n", check_cb(n, mode, veclen, sizeOfVect) ? "OK" : "NG");
+ printf("real forward : %s\n", check_rf(n, mode, veclen, sizeOfVect) ? "OK" : "NG");
+ printf("real backward : %s\n", check_rb(n, mode, veclen, sizeOfVect) ? "OK" : "NG");
+ printf("alt real forward : %s\n", check_arf(n, mode, veclen, sizeOfVect) ? "OK" : "NG");
+ printf("alt real backward : %s\n", check_arb(n, mode, veclen, sizeOfVect) ? "OK" : "NG");
+
+ exit(0);
+}
diff --git a/plugins/supereq/nsfft-1.00/dfttest/DFTTestOoura.c b/plugins/supereq/nsfft-1.00/dfttest/DFTTestOoura.c
new file mode 100644
index 00000000..08c8315f
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/dfttest/DFTTestOoura.c
@@ -0,0 +1,260 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+#include <time.h>
+
+#include "SIMDBase.h"
+#include "DFT.h"
+
+void cdft(int, int, double *, int *, double *);
+void rdft(int, int, double *, int *, double *);
+
+#if 1
+typedef float REAL;
+#define TYPE SIMDBase_TYPE_FLOAT
+#else
+typedef double REAL;
+#define TYPE SIMDBase_TYPE_DOUBLE
+#endif
+
+#define THRES 1e-3
+
+// complex forward
+int check_cf(int n, int mode, int veclen, int sizeOfVect) {
+ int i, j;
+
+ DFT *p = DFT_init(mode, n, 0);
+
+ int *ip = calloc(n, sizeof(int));
+ double *trigTable = SIMDBase_alignedMalloc(sizeof(double)*n/2);
+
+ REAL *sx = SIMDBase_alignedMalloc(sizeOfVect*n*2);
+ double *sy = SIMDBase_alignedMalloc(veclen * sizeof(double) *n*2);
+
+ //
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n*2;i++) {
+ sx[i*veclen + j] = random() / (double)RAND_MAX;
+ sy[j*n*2 + i] = sx[i*veclen + j];
+ }
+ }
+
+ //
+
+ DFT_execute(p, mode, sx, -1);
+
+ for(j=0;j<veclen;j++) {
+ cdft(n*2, -1, &sy[j*n*2], ip, trigTable);
+ }
+
+ //
+
+ int success = 1;
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n*2;i++) {
+ if (fabs(sx[i*veclen+j] - sy[j*n*2 + i]) > THRES) success = 0;
+ }
+ }
+
+ //
+
+ SIMDBase_alignedFree(sy);
+ SIMDBase_alignedFree(sx);
+ SIMDBase_alignedFree(trigTable);
+ free(ip);
+
+ DFT_dispose(p, mode);
+
+ //
+
+ return success;
+}
+
+// complex backward
+int check_cb(int n, int mode, int veclen, int sizeOfVect) {
+ int i, j;
+
+ DFT *p = DFT_init(mode, n, 0);
+
+ int *ip = calloc(n, sizeof(int));
+ double *trigTable = SIMDBase_alignedMalloc(sizeof(double)*n/2);
+
+ REAL *sx = SIMDBase_alignedMalloc(sizeOfVect*n*2);
+ double *sy = SIMDBase_alignedMalloc(veclen * sizeof(double) *n*2);
+
+ //
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n*2;i++) {
+ sx[i*veclen + j] = random() / (double)RAND_MAX;
+ sy[j*n*2 + i] = sx[i*veclen + j];
+ }
+ }
+
+ //
+
+ DFT_execute(p, mode, sx, 1);
+
+ for(j=0;j<veclen;j++) {
+ cdft(n*2, 1, &sy[j*n*2], ip, trigTable);
+ }
+
+ //
+
+ int success = 1;
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n*2;i++) {
+ if (fabs(sx[i*veclen+j] - sy[j*n*2 + i]) > THRES) success = 0;
+ }
+ }
+
+ //
+
+ SIMDBase_alignedFree(sy);
+ SIMDBase_alignedFree(sx);
+ SIMDBase_alignedFree(trigTable);
+ free(ip);
+
+ DFT_dispose(p, mode);
+
+ //
+
+ return success;
+}
+
+// real forward
+int check_rf(int n, int mode, int veclen, int sizeOfVect) {
+ int i, j;
+
+ DFT *p = DFT_init(mode, n, DFT_FLAG_ALT_REAL);
+
+ int *ip = calloc(n, sizeof(int));
+ double *trigTable = SIMDBase_alignedMalloc(sizeof(double)*n/2);
+
+ REAL *sx = SIMDBase_alignedMalloc(sizeOfVect*n);
+ double *sy = SIMDBase_alignedMalloc(veclen * sizeof(double) *n);
+
+ //
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n;i++) {
+ sx[i*veclen + j] = random() / (double)RAND_MAX;
+ sy[j*n + i] = sx[i*veclen + j];
+ }
+ }
+
+ //
+
+ DFT_execute(p, mode, sx, -1);
+
+ for(j=0;j<veclen;j++) {
+ rdft(n, -1, &sy[j*n], ip, trigTable);
+ }
+
+ //
+
+ int success = 1;
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n;i++) {
+ if (fabs(sx[i*veclen+j] - sy[j*n + i]) > THRES) success = 0;
+ }
+ }
+
+ //
+
+ SIMDBase_alignedFree(sy);
+ SIMDBase_alignedFree(sx);
+ SIMDBase_alignedFree(trigTable);
+ free(ip);
+
+ DFT_dispose(p, mode);
+
+ //
+
+ return success;
+}
+
+// real backward
+int check_rb(int n, int mode, int veclen, int sizeOfVect) {
+ int i, j;
+
+ DFT *p = DFT_init(mode, n, DFT_FLAG_ALT_REAL);
+
+ int *ip = calloc(n, sizeof(int));
+ double *trigTable = SIMDBase_alignedMalloc(sizeof(double)*n/2);
+
+ REAL *sx = SIMDBase_alignedMalloc(sizeOfVect*n);
+ double *sy = SIMDBase_alignedMalloc(veclen * sizeof(double) *n);
+
+ //
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n;i++) {
+ sx[i*veclen + j] = random() / (double)RAND_MAX;
+ sy[j*n + i] = sx[i*veclen + j];
+ }
+ }
+
+ //
+
+ DFT_execute(p, mode, sx, 1);
+
+ for(j=0;j<veclen;j++) {
+ rdft(n, 1, &sy[j*n], ip, trigTable);
+ }
+
+ //
+
+ int success = 1;
+
+ for(j=0;j<veclen;j++) {
+ for(i=0;i<n;i++) {
+ if (fabs(sx[i*veclen+j] - sy[j*n + i]) > THRES) success = 0;
+ }
+ }
+
+ //
+
+ SIMDBase_alignedFree(sy);
+ SIMDBase_alignedFree(sx);
+ SIMDBase_alignedFree(trigTable);
+ free(ip);
+
+ DFT_dispose(p, mode);
+
+ //
+
+ return success;
+}
+
+int main(int argc, char **argv) {
+ if (argc != 2) {
+ fprintf(stderr, "%s <log2n>\n", argv[0]);
+ exit(-1);
+ }
+
+ const int n = 1 << atoi(argv[1]);
+
+ srandom(time(NULL));
+
+ //
+
+ int mode = SIMDBase_chooseBestMode(TYPE);
+
+ printf("mode : %d, %s\n", mode, SIMDBase_getModeParamString(SIMDBase_PARAMID_MODE_NAME, mode));
+
+ int veclen = SIMDBase_getModeParamInt(SIMDBase_PARAMID_VECTOR_LEN, mode);
+ int sizeOfVect = SIMDBase_getModeParamInt(SIMDBase_PARAMID_SIZE_OF_VECT, mode);
+
+ printf("complex forward : %s\n", check_cf(n, mode, veclen, sizeOfVect) ? "OK" : "NG");
+ printf("complex backward : %s\n", check_cb(n, mode, veclen, sizeOfVect) ? "OK" : "NG");
+ printf("real forward : %s\n", check_rf(n, mode, veclen, sizeOfVect) ? "OK" : "NG");
+ printf("real backward : %s\n", check_rb(n, mode, veclen, sizeOfVect) ? "OK" : "NG");
+
+ exit(0);
+}
diff --git a/plugins/supereq/nsfft-1.00/dfttest/Makefile b/plugins/supereq/nsfft-1.00/dfttest/Makefile
new file mode 100644
index 00000000..924b8656
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/dfttest/Makefile
@@ -0,0 +1,35 @@
+CC=gcc
+BASEOPT=-Wall -g -I ../simd -I ../dft -L../simd -L../dft
+OPT=$(BASEOPT) -O
+
+all : DFTExample DFTTestNaive
+
+clean :
+ rm -f *~ *.o nsfftplan.*.txt *.log *.dat a.out DFTExample DFTTestNaive DFTTestOoura DFTTestFFTW pi_fft_mod pi_fft_mod.c
+
+../simd/libSIMD.a :
+ @cd ../simd; make
+
+../dft/libDFT.a :
+ @cd ../dft; make
+
+../ooura/fftsg.o :
+ @cd ../ooura; make
+
+DFTExample : DFTExample.c ../simd/libSIMD.a ../dft/libDFT.a
+ $(CC) $(OPT) DFTExample.c -lDFT -lSIMD -lm -o DFTExample
+
+DFTTestNaive : DFTTestNaive.c ../simd/libSIMD.a ../dft/libDFT.a
+ $(CC) $(OPT) DFTTestNaive.c -lDFT -lSIMD -lm -o DFTTestNaive
+
+DFTTestOoura : DFTTestOoura.c ../ooura/fftsg.o ../simd/libSIMD.a ../dft/libDFT.a
+ $(CC) $(OPT) DFTTestOoura.c ../ooura/fftsg.o -lDFT -lSIMD -lm -o DFTTestOoura
+
+DFTTestFFTW : DFTTestFFTW.c ../simd/libSIMD.a ../dft/libDFT.a
+ $(CC) $(OPT) DFTTestFFTW.c -lDFT -lSIMD -lfftw3 -lm -o DFTTestFFTW
+
+pi_fft_mod.c : ../ooura/pi_fft.c pi_fft.c.patch
+ patch -o pi_fft_mod.c ../ooura/pi_fft.c pi_fft.c.patch
+
+pi_fft_mod : ../simd/libSIMD.a ../dft/libDFT.a pi_fft_mod.c
+ $(CC) $(OPT) pi_fft_mod.c -I ../dft -I ../simd -L../dft -L../simd -lm -lDFT -lSIMD -o pi_fft_mod
diff --git a/plugins/supereq/nsfft-1.00/dfttest/pi_fft.c.patch b/plugins/supereq/nsfft-1.00/dfttest/pi_fft.c.patch
new file mode 100644
index 00000000..c50133cc
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/dfttest/pi_fft.c.patch
@@ -0,0 +1,131 @@
+--- pi_fft.c 2010-07-30 13:04:25.000000000 +0900
++++ pi_fft_mod.c 2010-07-31 20:50:11.000000000 +0900
+@@ -25,7 +25,75 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <time.h>
++#include <sys/time.h>
++#include <unistd.h>
+
++/****/
++
++#include <stdint.h>
++#include "SIMDBase.h"
++#include "DFT.h"
++
++DFT* dft[64];
++
++void initdft(int n) {
++ int i, logn = 31 - __builtin_clz(n), writeflag = 0;
++ char buf[20], fn[256];
++ gethostname(buf, 19);
++ sprintf(fn, "nsfftplan.%s.txt", buf);
++ FILE *fp = fopen(fn, "r");
++ if (fp != NULL) {
++ for(i=1;i<=logn;i++) {
++ int err;
++ dft[i] = DFT_fread(fp, &err);
++ if (err != DFT_ERROR_NOERROR) {
++ printf("error when reading plan %d : %d\n", i, err);
++ break;
++ }
++ if (DFT_getPlanParamInt(DFT_PARAMID_MODE, dft[i]) != SIMDBase_MODE_PUREC_DOUBLE ||
++ DFT_getPlanParamInt(DFT_PARAMID_FFT_LENGTH, dft[i]) != (1 << i) ||
++ DFT_getPlanParamInt(DFT_PARAMID_IS_ALT_REAL_TRANSFORM, dft[i]) != 1) {
++ fprintf(stderr, "plan not compatible : %d\n", i);
++ break;
++ }
++ }
++ }
++ if (fp != NULL) fclose(fp);
++
++ for(i=1;i<=logn;i++) {
++ if (dft[i] == NULL) {
++ dft[i] = DFT_init(SIMDBase_MODE_PUREC_DOUBLE, 1 << i, DFT_FLAG_ALT_REAL | DFT_FLAG_LIGHT_TEST_RUN | DFT_FLAG_VERBOSE);
++ if (dft[i] == NULL) {
++ printf("dft[%d] == NULL\n", i);
++ exit(-1);
++ }
++ writeflag = 1;
++ }
++ }
++
++ if (writeflag) {
++ fp = fopen(fn, "w");
++ if (fp != NULL) {
++ for(i=1;i<=logn;i++) {
++ DFT_fwrite(dft[i], fp);
++ }
++ fclose(fp);
++ }
++ }
++}
++
++void rdft(int n, int isgn, double *a, int *ip, double *w) {
++ int logn = 31 - __builtin_clz(n);
++ DFT_execute(dft[logn], SIMDBase_MODE_PUREC_DOUBLE, a, isgn);
++}
++
++double timeofday(void) {
++ struct timeval tp;
++ gettimeofday(&tp, NULL);
++ return (double)tp.tv_sec+(1e-6)*tp.tv_usec;
++}
++
++/****/
+
+ void mp_load_0(int n, int radix, int out[]);
+ void mp_load_1(int n, int radix, int out[]);
+@@ -67,7 +135,7 @@
+ double err, d_time, n_op;
+ int *a, *b, *c, *e, *i1, *i2, *ip;
+ double *d1, *d2, *d3, *w;
+- time_t t_1, t_2;
++ double t_1, t_2;
+ FILE *f_log, *f_out;
+
+ f_log = fopen("pi.log", "w");
+@@ -96,6 +164,8 @@
+ exit(1);
+ }
+ ip[0] = 0;
++
++ initdft(nfft);
+ /* ---- radix test ---- */
+ log10_radix = 1;
+ radix = 10;
+@@ -111,7 +181,7 @@
+ printf("calculating %d digits of PI...\n", log10_radix * (n - 2));
+ fprintf(f_log, "calculating %d digits of PI...\n", log10_radix * (n - 2));
+ /* ---- time check ---- */
+- time(&t_1);
++ t_1 = timeofday();
+ /*
+ * ---- a formula based on the AGM (Arithmetic-Geometric Mean) ----
+ * c = sqrt(0.125);
+@@ -216,10 +286,10 @@
+ mp_mul(n, radix, a, b, a, i1, nfft, d1, d2, d3, ip, w);
+ mp_idiv(n, radix, a, npow, a);
+ /* ---- time check ---- */
+- time(&t_2);
++ t_2 = timeofday();
+ /* ---- output ---- */
+ f_out = fopen("pi_mod.dat", "w");
+- printf("writing pi.dat...\n");
++ printf("writing pi_mod.dat...\n");
+ mp_fprintf(n - 1, log10_radix, a, f_out);
+ fclose(f_out);
+ free(d3);
+@@ -238,9 +308,9 @@
+ printf("floating point operation: %g op.\n", n_op);
+ fprintf(f_log, "floating point operation: %g op.\n", n_op);
+ /* ---- difftime ---- */
+- d_time = difftime(t_2, t_1);
+- printf("execution time: %g sec. (real time)\n", d_time);
+- fprintf(f_log, "execution time: %g sec. (real time)\n", d_time);
++ d_time = t_2 - t_1;
++ printf("execution time: %.5g sec. (real time)\n", d_time);
++ fprintf(f_log, "execution time: %.5g sec. (real time)\n", d_time);
+ fclose(f_log);
+ return 0;
+ }
diff --git a/plugins/supereq/nsfft-1.00/doc/default.css b/plugins/supereq/nsfft-1.00/doc/default.css
new file mode 100644
index 00000000..09721163
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/doc/default.css
@@ -0,0 +1,34 @@
+body {margin-left: 1.5cm; padding-left: 0.1cm; margin-right: 1.5cm; padding-right: 0.1cm; margin-top: 2.5cm; padding-top: 0.5cm; margin-bottom: 1cm; padding-bottom: 1.0cm; border-top-style:solid; border-bottom-style:solid; }
+h1 {font-family: arial, sansserif; font-weight: bold; font-style: italic; margin-top: 0.8cm; }
+h2 {font-family: arial, sansserif; font-weight: bold; font-style: italic; margin-top: 0.8cm; }
+h3 {font-family: arial, sansserif; font-weight: bold; margin-top: 1.2cm; margin-bottom: 0.8cm; }
+h4 {font-family: arial, sansserif; font-weight: bold; margin-top: 1.2cm; margin-bottom: 0.8cm; }
+p {font-family: Georgia, "Times New Roman", times, serif; margin-top: 0.3cm; margin-left: 0.5cm; margin-bottom: 0.3cm;}
+p.dir {font-family: arial, sansserif; margin-top: 0cm; margin-bottom: 0cm;}
+dl { margin-left: 0.5cm; }
+dt { font-weight: bold; }
+a:link {color: black;}
+a:visited {color: black;}
+ul.disc {list-style-type: disc; font-family: times, serif;}
+ul.circle {list-style-type: circle; font-family: times, serif;}
+ul.square {list-style-type: square; font-family: times, serif;}
+ul.none {list-style-type: none; font-family: times, serif;}
+pre.code { margin-top: 1.0cm; margin-bottom: 1.0cm; margin-left: 1.0cm; margin-right: 1.0cm; border:3px solid #c0c0c0; padding: 0.5cm; font-family: tahoma, sansserif; font-weight: normal; background-color:#f8f8f8; }
+pre.command { margin-top: 1.0cm; margin-bottom: 1.0cm; margin-left: 1.5cm; margin-right: 0.0cm; border:0px; padding:0.0cm; font-family: tahoma, sansserif; font-weight: bold; background-color:#f8fffc; }
+ol.level1 { font-family: arial, sansserif; font-weight: bold; font-style: italic; font-size:1.5em; }
+ol.level2 { font-family: "Times New Roman", serif; font-weight: normal; font-style: normal; font-size:0.85em; margin-top: 0.2cm; margin-bottom: 0.5cm; }
+table.figure { margin-left:auto; margin-right:auto; margin-top:1.0cm; margin-bottom:1.0cm; }
+
+td.caption { font-family: arial, sansserif; font-size: 75%; color: black; }
+td { font-family: times, serif; }
+
+table.lt { border-collapse: collapse; border-style: none; }
+td.lt- { margin: 0px; padding: 4px; padding-left:0.3cm; padding-right:0.3cm; border-width: 1px; border-style: none; padding-left=0.2cm; padding-right=0.2cm; }
+td.lt-r { margin: 0px; padding: 4px; padding-left:0.3cm; padding-right:0.3cm; border-style: none; border-right-style: solid; border-width: 1px; border-color: black; }
+td.lt-l { margin: 0px; padding: 4px; padding-left:0.3cm; padding-right:0.3cm; border-style: none; border-left-style: solid; border-width: 1px; border-color: black; }
+td.lt-lr { margin: 0px; padding: 4px; padding-left:0.3cm; padding-right:0.3cm; border-style: none; border-right-style: solid; border-left-style: solid; border-width: 1px; border-color: black; }
+td.lt-b { margin: 0px; padding: 4px; padding-left:0.3cm; padding-right:0.3cm; border-style: none; border-bottom-style: solid; border-width: 1px; border-color: black; }
+td.lt-hl { margin: 0px; border-style: none; border-bottom-style: solid; border-width: 1px; border-color: black; height: 2px; }
+td.lt-bl { margin: 0px; padding: 4px; padding-left:0.3cm; padding-right:0.3cm; border-style: none; border-bottom-style: solid; border-left-style: solid; border-width: 1px; border-color: black; }
+td.lt-br { margin: 0px; padding: 4px; padding-left:0.3cm; padding-right:0.3cm; border-style: none; border-bottom-style: solid; border-right-style: solid; border-width: 1px; border-color: black; }
+td.lt-blr { margin: 0px; padding: 4px; padding-left:0.3cm; padding-right:0.3cm; border-style: none; border-bottom-style: solid; border-left-style: solid; border-right-style: solid; border-width: 1px; border-color: black; }
diff --git a/plugins/supereq/nsfft-1.00/doc/index.xhtml b/plugins/supereq/nsfft-1.00/doc/index.xhtml
new file mode 100644
index 00000000..8b7e2c97
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/doc/index.xhtml
@@ -0,0 +1,2016 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/xhtml-math11-f.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="default.css"/>
+<title>NSFFT Reference Manual</title>
+</head>
+<body>
+<h1>NSFFT Reference Manual</h1>
+
+<h3>Introduction</h3>
+
+<p>
+This is a library for performing 1-dimensional discrete Fourier
+transforms. NSDFT is a simple, small and portable library, and it is
+efficient since it can utilize SIMD instruction sets in modern
+processors. It performs multiple transforms simultaneously, and thus
+it is especially suitable for digital signal processing. It does not
+need so much computation to make a good execution plan. This library
+is in public domain, so that you can incorporate this library into
+your product without any obligation.
+</p>
+
+<h3>API Reference</h3>
+
+<p>
+In this section, the API functions are explained.
+</p>
+
+<h4>Include files</h4>
+
+<p>
+You have to include two include files in dft directory.
+</p>
+
+<pre class="code">
+#include &lt;stdint.h&gt;
+#include "SIMDBase.h"
+#include "DFT.h"
+</pre>
+
+<h4>Data types</h4>
+
+<p>
+First, you have to choose a data type to represent an element in the
+input and output sequence of numbers. You can choose from the
+following three types.
+</p>
+
+<table class="figure">
+ <tr align="center">
+ <td>
+ <table class="lt">
+ <tr>
+ <td class="lt-hl"></td>
+ <td class="lt-hl"></td>
+ </tr>
+ <tr>
+ <td class="lt-br" align="center">Symbol</td>
+ <td class="lt-b" align="center">Data Type</td>
+ </tr>
+ <tr>
+ <td class="lt-hl"></td>
+ <td class="lt-hl"></td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">SIMDBase_TYPE_FLOAT</td>
+ <td class="lt-" align="left">float type in C language</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">SIMDBase_TYPE_DOUBLE</td>
+ <td class="lt-" align="left">double type in C language</td>
+ </tr>
+ <tr>
+ <td class="lt-br" align="left">SIMDBase_TYPE_LONGDOUBLE</td>
+ <td class="lt-b" align="left">long double type in C language</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr align="center">
+ <td class="caption">Table 1 Data types</td>
+ </tr>
+</table>
+
+
+<h4>Computation modes</h4>
+
+<p>
+Next, a compuation mode have to be chosen. You can choose from the
+following modes.
+</p>
+
+<table class="figure">
+ <tr align="center">
+ <td>
+ <table class="lt">
+ <tr>
+ <td class="lt-hl"></td>
+ <td class="lt-hl"></td>
+ <td class="lt-hl"></td>
+ <td class="lt-hl"></td>
+ </tr>
+ <tr>
+ <td class="lt-br" align="center">Symbol</td>
+ <td class="lt-br" align="center">Type</td>
+ <td class="lt-br" align="center">Vector Length</td>
+ <td class="lt-b" align="center">Computation Mode</td>
+ </tr>
+ <tr>
+ <td class="lt-hl"></td>
+ <td class="lt-hl"></td>
+ <td class="lt-hl"></td>
+ <td class="lt-hl"></td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">SIMDBase_MODE_PUREC_FLOAT</td>
+ <td class="lt-r" align="center">float</td>
+ <td class="lt-r" align="center">1</td>
+ <td class="lt-" align="center">Scalar float</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">SIMDBase_MODE_PUREC_DOUBLE</td>
+ <td class="lt-r" align="center">double</td>
+ <td class="lt-r" align="center">1</td>
+ <td class="lt-" align="center">Scalar double</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">SIMDBase_MODE_PUREC_LONGDOUBLE</td>
+ <td class="lt-r" align="center">long double</td>
+ <td class="lt-r" align="center">1</td>
+ <td class="lt-" align="center">Scalar long double</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">SIMDBase_MODE_SSE_FLOAT</td>
+ <td class="lt-r" align="center">float</td>
+ <td class="lt-r" align="center">4</td>
+ <td class="lt-" align="center">x86 SSE</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">SIMDBase_MODE_SSE2_DOUBLE</td>
+ <td class="lt-r" align="center">double</td>
+ <td class="lt-r" align="center">2</td>
+ <td class="lt-" align="center">x86 SSE2</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">SIMDBase_MODE_NEON_FLOAT</td>
+ <td class="lt-r" align="center">float</td>
+ <td class="lt-r" align="center">4</td>
+ <td class="lt-" align="center">ARM NEON</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">SIMDBase_MODE_AVX_FLOAT</td>
+ <td class="lt-r" align="center">float</td>
+ <td class="lt-r" align="center">8</td>
+ <td class="lt-" align="center">x86 AVX (float)</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">SIMDBase_MODE_AVX_DOUBLE</td>
+ <td class="lt-r" align="center">double</td>
+ <td class="lt-r" align="center">4</td>
+ <td class="lt-" align="center">x86 AVX (double)</td>
+ </tr>
+ <tr>
+ <td class="lt-br" align="left">SIMDBase_MODE_ALTIVEC_FLOAT</td>
+ <td class="lt-br" align="center">float</td>
+ <td class="lt-br" align="center">4</td>
+ <td class="lt-b" align="center">PowerPC Altivec</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr align="center">
+ <td class="caption">Table 2 Computation modes</td>
+ </tr>
+</table>
+
+<p>
+The following function automatically checks the availability of each
+instruction set on your computer, and chooses the best computation
+mode.
+</p>
+
+<pre class="code">
+int32_t SIMDBase_chooseBestMode(int32_t type);
+</pre>
+
+<p>
+The return value is the best mode chosen by this routine.
+<i>type</i> is the data type you chose.
+</p>
+
+
+<h4>Retrieving parameters</h4>
+
+<p>
+You can make queries for any mode using the following function.
+</p>
+
+<pre class="code">
+int32_t SIMDBase_getModeParamInt(int32_t paramId, int32_t mode);
+</pre>
+
+<p>
+<i>mode</i> is the computation mode you chose. <i>paramId</i> is one
+of the following.
+</p>
+
+<table class="figure">
+ <tr align="center">
+ <td>
+ <table class="lt">
+ <tr>
+ <td class="lt-hl"></td>
+ <td class="lt-hl"></td>
+ </tr>
+ <tr>
+ <td class="lt-br" align="center">Symbol</td>
+ <td class="lt-b" align="center">Meaning</td>
+ </tr>
+ <tr>
+ <td class="lt-hl"></td>
+ <td class="lt-hl"></td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">SIMDBase_PARAMID_SIZE_OF_REAL</td>
+ <td class="lt-" align="left">Size of an element in a vector in byte</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">SIMDBase_PARAMID_SIZE_OF_VECT</td>
+ <td class="lt-" align="left">Size of the vector in byte</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">SIMDBase_PARAMID_VECTOR_LEN</td>
+ <td class="lt-" align="left">Number of elements in a vector</td>
+ </tr>
+ <tr>
+ <td class="lt-br" align="left">SIMDBase_PARAMID_MODE_AVAILABILITY</td>
+ <td class="lt-b" align="left">Whether the given mode is available or not</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr align="center">
+ <td class="caption">Table 3 Querying parameter for computation mode</td>
+ </tr>
+</table>
+
+<p>
+Here, a vector is a set of multiple primitive data element (single or
+double precision FP number) which can be stored in one SIMD register,
+and can be processed by one SIMD instruction at the same time.
+</p>
+
+<p>
+You can get the mode name in string data type. In this
+case, <i>paramId</i> must be SIMDBase_PARAMID_MODE_NAME.
+</p>
+
+<pre class="code">
+char *SIMDBase_getModeParamString(int32_t paramId, int32_t mode);
+</pre>
+
+<p>
+You should not modify the data returned by the above function.
+</p>
+
+
+<h4>Making and destroying execution plan</h4>
+
+<p>
+An execution plan can be made by the following function.
+</p>
+
+<pre class="code">
+DFT *DFT_init(int32_t mode, int32_t n, int32_t flags);
+</pre>
+
+<p>
+The return value is a pointer to a newly made plan.
+<i>mode</i> is the mode you chose above. <i>n</i> is the length of a
+transform. You can specify a bitwise OR of the following symbols
+as <i>flags</i>. You should not specify more than one flags regarding
+to test run. You should not specify DFT_FLAG_FORCE_RECURSIVE and
+DFT_FLAG_FORCE_COBRA at the same time. If neither DFT_FLAG_REAL nor
+DFT_FLAG_ALT_REAL is specified, an execution plan for complex
+transforms are made.
+</p>
+
+<table class="figure">
+ <tr align="center">
+ <td>
+ <table class="lt">
+ <tr>
+ <td class="lt-hl"></td>
+ <td class="lt-hl"></td>
+ </tr>
+ <tr>
+ <td class="lt-br" align="center">Symbol</td>
+ <td class="lt-b" align="center">Meaning</td>
+ </tr>
+ <tr>
+ <td class="lt-hl"></td>
+ <td class="lt-hl"></td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_FLAG_NO_TEST_RUN</td>
+ <td class="lt-" align="left">Make execution plan without performing a test run</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_FLAG_LIGHT_TEST_RUN</td>
+ <td class="lt-" align="left">Perform small amount of test run to make an execution plan</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_FLAG_HEAVY_TEST_RUN</td>
+ <td class="lt-" align="left">Perform large amount of test run to make an execution plan</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_FLAG_EXHAUSTIVE_TEST_RUN</td>
+ <td class="lt-" align="left">Perform exhaustive search of parameters and find the optimal execution plan</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_FLAG_REAL</td>
+ <td class="lt-" align="left">Make an execution plan for a real transform</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_FLAG_ALT_REAL</td>
+ <td class="lt-" align="left">Make an execution plan for an alternative real transform</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_FLAG_VERBOSE</td>
+ <td class="lt-" align="left">Make some noise during making an execution plan</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_FLAG_NOBITREVERSAL</td>
+ <td class="lt-" align="left">Does not perforam bitreversal operation during a transform</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_FLAG_FORCE_RECURSIVE</td>
+ <td class="lt-" align="left">Force using the recursive bit-reveral routine. This routine is suited for small transforms.</td>
+ </tr>
+ <tr>
+ <td class="lt-br" align="left">DFT_FLAG_FORCE_COBRA</td>
+ <td class="lt-b" align="left">Force using the Cobra bit-reveral routine. This routine is suited for large transforms.</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr align="center">
+ <td class="caption">Table 4 Options for making execution plan</td>
+ </tr>
+</table>
+
+<p>
+You can destroy the plan you made by the following function.
+</p>
+
+<pre class="code">
+void DFT_dispose(DFT *p, int32_t mode);
+</pre>
+
+<p>
+<i>p</i> is a pointer to the execution plan. <i>mode</i> is the
+corresponding execution mode.
+</p>
+
+<p>
+You can retrieve parameters of a plan using the following function.
+</p>
+
+<pre class="code">
+int32_t DFT_getPlanParamInt(int32_t paramId, void *p);
+</pre>
+
+<p>
+<i>p</i> is a pointer to an execution plan. <i>paramId</i> is one
+of the following.
+</p>
+
+<table class="figure">
+ <tr align="center">
+ <td>
+ <table class="lt">
+ <tr>
+ <td class="lt-hl"></td>
+ <td class="lt-hl"></td>
+ </tr>
+ <tr>
+ <td class="lt-br" align="center">Symbol</td>
+ <td class="lt-b" align="center">Meaning</td>
+ </tr>
+ <tr>
+ <td class="lt-hl"></td>
+ <td class="lt-hl"></td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_PARAMID_TYPE</td>
+ <td class="lt-" align="left">Data type</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_PARAMID_MODE</td>
+ <td class="lt-" align="left">Computation mode</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_PARAMID_FFT_LENGTH</td>
+ <td class="lt-" align="left">Length of the transform</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_PARAMID_IS_REAL_TRANSFORM</td>
+ <td class="lt-" align="left">Whether the plan is for real transforms</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_PARAMID_NO_BIT_REVERSAL</td>
+ <td class="lt-" align="left">Whether the plan does not perform bit reversal operation</td>
+ </tr>
+ <tr>
+ <td class="lt-br" align="left">DFT_PARAMID_TEST_RUN</td>
+ <td class="lt-b" align="left">How much test run is performed when making this plan</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr align="center">
+ <td class="caption">Table 5 Querying parameter for execution plan</td>
+ </tr>
+</table>
+
+<h4>Writing and reading execution plan to/from file</h4>
+
+<p>
+You can write or read an execution plan to/from a file using the following functions.
+</p>
+
+<pre class="code">
+int32_t DFT_fwrite(DFT *p, FILE *fp);
+DFT *DFT_fread(FILE *fp, int32_t *errcode);
+</pre>
+
+<p>
+<i>p</i> is a pointer to a plan. <i>fp</i> is a file
+pointer. DFT_fwrite returns 1 if the plan is successfully written, and
+0 if an error occurs. DFT_fread returns the pointer to the read plan
+if the plan is successfully read, and NULL if an error occurs. If an
+error occurs, an error code is returned to a variable whose pointer is
+specified by <i>errcode</i>. The interpretation of error codes is
+given below.
+</p>
+
+<table class="figure">
+ <tr align="center">
+ <td>
+ <table class="lt">
+ <tr>
+ <td class="lt-hl"></td>
+ <td class="lt-hl"></td>
+ </tr>
+ <tr>
+ <td class="lt-br" align="center">Symbol</td>
+ <td class="lt-b" align="center">Meaning</td>
+ </tr>
+ <tr>
+ <td class="lt-hl"></td>
+ <td class="lt-hl"></td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_ERROR_NOERROR</td>
+ <td class="lt-" align="left">No error</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_ERROR_FILE_VERSION</td>
+ <td class="lt-" align="left">File format version mismatch</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_ERROR_FILE_IO</td>
+ <td class="lt-" align="left">I/O error</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_ERROR_UNEXPECTED_EOF</td>
+ <td class="lt-" align="left">Unexpected EOF</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_ERROR_MODE_NOT_COMPILED_IN</td>
+ <td class="lt-" align="left">Tried to read a plan with mode that is not compiled in</td>
+ </tr>
+ <tr>
+ <td class="lt-r" align="left">DFT_ERROR_MODE_NOT_AVAILABLE</td>
+ <td class="lt-" align="left">Tried to read a plan with mode that is not supported by hardware</td>
+ </tr>
+ <tr>
+ <td class="lt-br" align="left">DFT_ERROR_UNKNOWN_MODE</td>
+ <td class="lt-b" align="left">Tried to read a plan with mode that is unknown by library</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr align="center">
+ <td class="caption">Table 6 Errors that may happen during file I/O</td>
+ </tr>
+</table>
+
+
+<h4>Allocating and freeing buffers for transforms</h4>
+
+<p>
+In order to allocate word-aligned buffers for storing data which is
+fed to the FFT routine, you have to use the following function.
+</p>
+
+<pre class="code">
+void *DFT_alignedMalloc(uint64_t size);
+</pre>
+
+<p>
+This function allocates <i>size</i> bytes of word-aligned memory and
+returns the pointer. In order to free this memory, you have to use the
+following function.
+</p>
+
+<pre class="code">
+void DFT_alignedFree(void *ptr);
+</pre>
+
+<p>
+<i>ptr</i> is the pointer returned from DFT_alignedMalloc function.
+</p>
+
+<h4>Executing transform</h4>
+
+<p>
+By the following function, the planned transform can be executed.
+</p>
+
+<pre class="code">
+void DFT_execute(DFT *p, int32_t mode, void *s, int32_t dir);
+</pre>
+
+<p>
+<i>p</i> is a pointer to the plan. <i>mode</i> is the computation
+mode. <i>s</i> is the pointer to the buffer in which the sequence of
+input values is stored. This pointer must be a pointer returned from
+DFT_alignedMalloc function.
+<i>dir</i> specifies the direction of transform.
+</p>
+
+<p>
+The forward and backward discrete Fourier transforms are defined by
+the following formula (1) and (2), respectively.
+</p>
+
+<table border="0" style="margin-right:1.0cm; margin-left:1.0cm; margin-top:0.5cm; margin-bottom:0.5cm;">
+ <tr>
+ <td align="center" style="width:100%;">
+ <math mode="display" style="font-size:1.2em;" xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow>
+ <msub><mi>X</mi><mi>k</mi></msub>
+ <mo>=</mo>
+ <munderover>
+ <mo style="font-size:140%;">&Sum;</mo>
+ <mrow><mi>n</mi><mo>=</mo><mn>0</mn></mrow>
+ <mrow><mi>N</mi><mo>-</mo><mn>1</mn></mrow>
+ </munderover>
+ <msub><mi>x</mi><mi>n</mi></msub>
+ <msup>
+ <mi>e</mi>
+ <mrow>
+ <mo>-</mo>
+ <mfrac>
+ <mrow><mn>2</mn><mi>&pi;</mi><mi>i</mi></mrow>
+ <mi>N</mi>
+ </mfrac>
+ <mi>k</mi><mi>n</mi>
+ </mrow>
+ </msup>
+
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+
+ <mi>k</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>N</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </math>
+ </td>
+ <td>
+ <p>(1)</p>
+ </td>
+ </tr>
+ <tr>
+ <td align="center" style="width:100%;">
+ <math mode="display" style="font-size:1.2em;" xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow>
+ <msub><mi>x</mi><mi>n</mi></msub>
+ <mo>=</mo>
+ <mfrac>
+ <mn>1</mn>
+ <mi>N</mi>
+ </mfrac>
+ <munderover>
+ <mo style="font-size:140%;">&Sum;</mo>
+ <mrow><mi>k</mi><mo>=</mo><mn>0</mn></mrow>
+ <mrow><mi>N</mi><mo>-</mo><mn>1</mn></mrow>
+ </munderover>
+ <msub><mi>X</mi><mi>k</mi></msub>
+ <msup>
+ <mi>e</mi>
+ <mrow>
+ <mfrac>
+ <mrow><mn>2</mn><mi>&pi;</mi><mi>i</mi></mrow>
+ <mi>N</mi>
+ </mfrac>
+ <mi>k</mi><mi>n</mi>
+ </mrow>
+ </msup>
+
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+
+ <mi>n</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>N</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+
+ </mrow>
+ </math>
+ </td>
+ <td>
+ <p>(2)</p>
+ </td>
+ </tr>
+</table>
+
+<p>
+The complex forward and backward transforms perform the transforms
+defined by the following formula (3) and (4), respectively. <i>V</i>
+is the vector length mentioned above. Again, calling DFT_execute once
+performs <i>V</i> forward or backward transforms at a time. Please
+note that (4) gives values multiplied by <i>N</i> compared to
+(2). Specifying -1 as the direction of transform performs the
+transform defined by (3). In this case, the input should be given as
+in (5) , and the output is given as in (6). Specifying 1 as the
+direction of transform performs the transform defined by (4), and in
+this case, the input should be given as in (6) , and the output is
+given as in (5).
+</p>
+
+<table border="0" style="margin-right:1.0cm; margin-left:1.0cm; margin-top:0.5cm; margin-bottom:0.5cm;">
+ <tr>
+ <td align="center" style="width:100%;">
+ <math mode="display" style="font-size:1.2em;" xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow>
+ <msub><mi>X</mi><mrow><mi>k</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>=</mo>
+ <munderover>
+ <mo style="font-size:140%;">&Sum;</mo>
+ <mrow><mi>n</mi><mo>=</mo><mn>0</mn></mrow>
+ <mrow><mi>N</mi><mo>-</mo><mn>1</mn></mrow>
+ </munderover>
+ <msub><mi>x</mi><mrow><mi>n</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <msup>
+ <mi>e</mi>
+ <mrow>
+ <mo>-</mo>
+ <mfrac>
+ <mrow><mn>2</mn><mi>&pi;</mi><mi>i</mi></mrow>
+ <mi>N</mi>
+ </mfrac>
+ <mi>k</mi><mi>n</mi>
+ </mrow>
+ </msup>
+
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+
+ <mrow style="font-size:100%;">
+ <mi>k</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>N</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+
+ <mo>&nbsp;&nbsp;</mo>
+ <mo>,</mo>
+ <mo>&nbsp;&nbsp;</mo>
+
+ <mi>v</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>V</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </mrow>
+ </math>
+ </td>
+ <td>
+ <p>(3)</p>
+ </td>
+ </tr>
+ <tr>
+ <td align="center" style="width:100%;">
+ <math mode="display" style="font-size:1.2em;" xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow>
+ <msub><mi>x</mi><mrow><mi>n</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>=</mo>
+ <munderover>
+ <mo style="font-size:140%;">&Sum;</mo>
+ <mrow><mi>k</mi><mo>=</mo><mn>0</mn></mrow>
+ <mrow><mi>N</mi><mo>-</mo><mn>1</mn></mrow>
+ </munderover>
+ <msub><mi>X</mi><mrow><mi>k</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <msup>
+ <mi>e</mi>
+ <mrow>
+ <mfrac>
+ <mrow><mn>2</mn><mi>&pi;</mi><mi>i</mi></mrow>
+ <mi>N</mi>
+ </mfrac>
+ <mi>k</mi><mi>n</mi>
+ </mrow>
+ </msup>
+
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+
+ <mrow style="font-size:100%;">
+ <mi>n</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>N</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+
+ <mo>&nbsp;&nbsp;</mo>
+ <mo>,</mo>
+ <mo>&nbsp;&nbsp;</mo>
+
+ <mi>v</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>V</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </mrow>
+ </math>
+ </td>
+ <td>
+ <p>(4)</p>
+ </td>
+ </tr>
+</table>
+
+<table border="0" style="margin-right:1.0cm; margin-left:1.0cm; margin-top:0.5cm; margin-bottom:0.5cm;">
+ <tr>
+ <td align="center" style="width:100%;">
+ <math mode="display" style="font-size:1.2em;" xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow>
+ <mfenced open="{" close="">
+ <mtable>
+ <mtr>
+ <mtd>
+ <mrow>
+ <mi>s</mi>
+ <mo>[</mo>
+ <mo>(</mo>
+ <mn>2</mn>
+ <mi>n</mi>
+ <mo>+</mo>
+ <mn>0</mn>
+ <mo>)</mo>
+ <mi>V</mi>
+ <mo>+</mo>
+ <mi>v</mi>
+ <mo>]</mo>
+
+ <mo>=</mo>
+
+ <mi>Re</mi>
+ <mo>(</mo>
+ <msub><mi>x</mi><mrow><mi>n</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>)</mo>
+ </mrow>
+ </mtd>
+ </mtr>
+
+ <mtr>
+ <mtd>
+ <mrow>
+ <mi>s</mi>
+ <mo>[</mo>
+ <mo>(</mo>
+ <mn>2</mn>
+ <mi>n</mi>
+ <mo>+</mo>
+ <mn>1</mn>
+ <mo>)</mo>
+ <mi>V</mi>
+ <mo>+</mo>
+ <mi>v</mi>
+ <mo>]</mo>
+
+ <mo>=</mo>
+
+ <mi>Im</mi>
+ <mo>(</mo>
+ <msub><mi>x</mi><mrow><mi>n</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>)</mo>
+ </mrow>
+ </mtd>
+ </mtr>
+
+ </mtable>
+ </mfenced>
+
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+
+ <mrow style="font-size:100%;">
+ <mi>n</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>N</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+
+ <mo>&nbsp;&nbsp;</mo>
+ <mo>,</mo>
+ <mo>&nbsp;&nbsp;</mo>
+
+ <mi>v</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>V</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </mrow>
+ </math>
+ </td>
+ <td>
+ <p>(5)</p>
+ </td>
+ </tr>
+</table>
+
+<table border="0" style="margin-right:1.0cm; margin-left:1.0cm; margin-top:0.5cm; margin-bottom:0.5cm;">
+ <tr>
+ <td align="center" style="width:100%;">
+ <math mode="display" style="font-size:1.2em;" xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow>
+ <mfenced open="{" close="">
+ <mtable>
+ <mtr>
+ <mtd>
+ <mrow>
+ <mi>s</mi>
+ <mo>[</mo>
+ <mo>(</mo>
+ <mn>2</mn>
+ <mi>k</mi>
+ <mo>+</mo>
+ <mn>0</mn>
+ <mo>)</mo>
+ <mi>V</mi>
+ <mo>+</mo>
+ <mi>v</mi>
+ <mo>]</mo>
+
+ <mo>=</mo>
+
+ <mi>Re</mi>
+ <mo>(</mo>
+ <msub><mi>X</mi><mrow><mi>k</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>)</mo>
+ </mrow>
+ </mtd>
+ </mtr>
+
+ <mtr>
+ <mtd>
+ <mrow>
+ <mi>s</mi>
+ <mo>[</mo>
+ <mo>(</mo>
+ <mn>2</mn>
+ <mi>k</mi>
+ <mo>+</mo>
+ <mn>1</mn>
+ <mo>)</mo>
+ <mi>V</mi>
+ <mo>+</mo>
+ <mi>v</mi>
+ <mo>]</mo>
+
+ <mo>=</mo>
+
+ <mi>Im</mi>
+ <mo>(</mo>
+ <msub><mi>X</mi><mrow><mi>k</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>)</mo>
+ </mrow>
+ </mtd>
+ </mtr>
+
+ </mtable>
+ </mfenced>
+
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+
+ <mrow style="font-size:100%;">
+ <mi>k</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>N</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+
+ <mo>&nbsp;&nbsp;</mo>
+ <mo>,</mo>
+ <mo>&nbsp;&nbsp;</mo>
+
+ <mi>v</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>V</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </mrow>
+ </math>
+ </td>
+ <td>
+ <p>(6)</p>
+ </td>
+ </tr>
+</table>
+
+<p>
+The real forward transform performs the transform defined by (3) when
+the condition (7) is satisfied. In this case, the output satisfies
+(8). You should specify -1 as the direction of transform, and the
+input should be given as in (9), and the output is given as in (10).
+The real backward transform is the opposite of the real forward
+transform. The input should satisfy (8) and the output satisfies (7).
+You should specify 1 as the direction of transform, and the input
+should be given as in (10), and the output is given as in (11).
+</p>
+
+<table border="0" style="margin-right:1.0cm; margin-left:1.0cm; margin-top:0.5cm; margin-bottom:0.5cm;">
+ <tr>
+ <td align="center" style="width:100%;">
+ <math mode="display" style="font-size:1.2em;" xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow>
+ <mi>Im</mi>
+ <mo>(</mo>
+ <msub><mi>x</mi><mrow><mi>n</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>)</mo>
+ <mo>=</mo>
+ <mn>0</mn>
+
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+
+ <mrow style="font-size:100%;">
+ <mi>n</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>N</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+
+ <mo>&nbsp;&nbsp;</mo>
+ <mo>,</mo>
+ <mo>&nbsp;&nbsp;</mo>
+
+ <mi>v</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>V</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+
+ </mrow>
+ </math>
+ </td>
+ <td>
+ <p>(7)</p>
+ </td>
+ </tr>
+</table>
+
+<table border="0" style="margin-right:1.0cm; margin-left:1.0cm; margin-top:0.5cm; margin-bottom:0.5cm;">
+ <tr>
+ <td align="center" style="width:100%;">
+ <math mode="display" style="font-size:1.2em;" xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow>
+ <mfenced open="{" close="">
+ <mtable>
+ <mtr>
+ <mtd>
+ <mrow>
+ <msub><mi>X</mi><mrow><mi>k</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>=</mo>
+ <msubsup>
+ <mi>X</mi>
+ <mrow><mi>N</mi><mo>-</mo><mi>k</mi><mo>,</mo><mi>v</mi></mrow>
+ <mo>*</mo>
+ </msubsup>
+ </mrow>
+ </mtd>
+
+ <mtd>
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+ </mtd>
+
+ <mtd>
+ <mrow style="font-size:100%;">
+ <mi>k</mi>
+ <mo>=</mo>
+ <mn>1</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mfrac>
+ <mi>N</mi>
+ <mn>2</mn>
+ </mfrac>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </mtd>
+ </mtr>
+
+ <mtr>
+ <mtd>
+ <mrow>
+ <mi>Im</mi>
+ <mo>(</mo>
+ <msub><mi>X</mi><mrow><mi>k</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>)</mo>
+ <mo>=</mo>
+ <mn>0</mn>
+ </mrow>
+ </mtd>
+
+ <mtd>
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+ </mtd>
+
+ <mtd>
+ <mrow style="font-size:100%;">
+ <mi>k</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mfrac>
+ <mi>N</mi>
+ <mn>2</mn>
+ </mfrac>
+ </mrow>
+ </mtd>
+ </mtr>
+
+ </mtable>
+ </mfenced>
+
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+
+ <mrow style="font-size:100%;">
+ <mi>v</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>V</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </mrow>
+ </math>
+ </td>
+ <td>
+ <p>(8)</p>
+ </td>
+ </tr>
+</table>
+
+<table border="0" style="margin-right:1.0cm; margin-left:1.0cm; margin-top:0.5cm; margin-bottom:0.5cm;">
+ <tr>
+ <td align="center" style="width:100%;">
+ <math mode="display" style="font-size:1.2em;" xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow>
+ <mrow>
+ <mi>s</mi>
+ <mo>[</mo>
+ <mi>n</mi>
+ <mi>V</mi>
+ <mo>+</mo>
+ <mi>v</mi>
+ <mo>]</mo>
+
+ <mo>=</mo>
+
+ <mi>Re</mi>
+ <mo>(</mo>
+ <msub><mi>x</mi><mrow><mi>n</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>)</mo>
+ </mrow>
+
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+
+ <mrow style="font-size:100%;">
+ <mi>n</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>N</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+
+ <mo>&nbsp;&nbsp;</mo>
+ <mo>,</mo>
+ <mo>&nbsp;&nbsp;</mo>
+
+ <mi>v</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>V</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </mrow>
+ </math>
+ </td>
+ <td>
+ <p>(9)</p>
+ </td>
+ </tr>
+</table>
+
+<table border="0" style="margin-right:1.0cm; margin-left:1.0cm; margin-top:0.5cm; margin-bottom:0.5cm;">
+ <tr>
+ <td align="center" style="width:100%;">
+ <math mode="display" style="font-size:1.2em;" xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow>
+ <mfenced open="{" close="">
+ <mtable>
+ <mtr>
+ <mtd>
+ <mrow>
+ <mi>s</mi>
+ <mo>[</mo>
+ <mo>(</mo>
+ <mn>2</mn>
+ <mi>k</mi>
+ <mo>+</mo>
+ <mn>0</mn>
+ <mo>)</mo>
+ <mi>V</mi>
+ <mo>+</mo>
+ <mi>v</mi>
+ <mo>]</mo>
+ </mrow>
+ </mtd>
+
+ <mtd>
+ <mo>=</mo>
+ </mtd>
+
+ <mtd>
+ <mrow>
+ <mi>Re</mi>
+ <mo>(</mo>
+ <msub><mi>X</mi><mrow><mi>k</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>)</mo>
+ </mrow>
+ </mtd>
+
+ <mtd>
+ <mrow style="font-size:100%;">
+ <mi>k</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mfrac>
+ <mi>N</mi>
+ <mn>2</mn>
+ </mfrac>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </mtd>
+ </mtr>
+
+ <mtr>
+ <mtd>
+ <mrow>
+ <mi>s</mi>
+ <mo>[</mo>
+ <mi>V</mi>
+ <mo>+</mo>
+ <mi>v</mi>
+ <mo>]</mo>
+ </mrow>
+ </mtd>
+
+ <mtd>
+ <mo>=</mo>
+ </mtd>
+
+ <mtd>
+ <mrow>
+ <mi>Re</mi>
+ <mo>(</mo>
+ <msub><mi>X</mi><mrow><mi>N</mi><mo>/</mo><mn>2</mn><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>)</mo>
+ </mrow>
+ </mtd>
+
+ <mtd>
+ </mtd>
+ </mtr>
+
+ <mtr>
+ <mtd>
+ <mrow>
+ <mi>s</mi>
+ <mo>[</mo>
+ <mo>(</mo>
+ <mn>2</mn>
+ <mi>k</mi>
+ <mo>+</mo>
+ <mn>1</mn>
+ <mo>)</mo>
+ <mi>V</mi>
+ <mo>+</mo>
+ <mi>v</mi>
+ <mo>]</mo>
+ </mrow>
+ </mtd>
+
+ <mtd>
+ <mo>=</mo>
+ </mtd>
+
+ <mtd>
+ <mrow>
+ <mi>Im</mi>
+ <mo>(</mo>
+ <msub><mi>X</mi><mrow><mi>k</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>)</mo>
+ </mrow>
+ </mtd>
+
+ <mtd>
+ <mrow style="font-size:100%;">
+ <mi>k</mi>
+ <mo>=</mo>
+ <mn>1</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mfrac>
+ <mi>N</mi>
+ <mn>2</mn>
+ </mfrac>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </mtd>
+ </mtr>
+
+ </mtable>
+ </mfenced>
+
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+
+ <mrow style="font-size:100%;">
+ <mi>v</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>V</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </mrow>
+ </math>
+ </td>
+ <td>
+ <p>(10)</p>
+ </td>
+ </tr>
+</table>
+
+<table border="0" style="margin-right:1.0cm; margin-left:1.0cm; margin-top:0.5cm; margin-bottom:0.5cm;">
+ <tr>
+ <td align="center" style="width:100%;">
+ <math mode="display" style="font-size:1.2em;" xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow>
+ <mrow>
+ <mn>2</mn>
+ <mo> &nbsp; </mo>
+ <mi>s</mi>
+ <mo>[</mo>
+ <mi>n</mi>
+ <mi>V</mi>
+ <mo>+</mo>
+ <mi>v</mi>
+ <mo>]</mo>
+
+ <mo>=</mo>
+
+ <mi>Re</mi>
+ <mo>(</mo>
+ <msub><mi>x</mi><mrow><mi>n</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>)</mo>
+ </mrow>
+
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+
+ <mrow style="font-size:100%;">
+ <mi>n</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>N</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+
+ <mo>&nbsp;&nbsp;</mo>
+ <mo>,</mo>
+ <mo>&nbsp;&nbsp;</mo>
+
+ <mi>v</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>V</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </mrow>
+ </math>
+ </td>
+ <td>
+ <p>(11)</p>
+ </td>
+ </tr>
+</table>
+
+<p>
+The alternative real transforms are defined by (12) to (16), similarly
+to the real transforms. The alternative transforms are handy if you
+are migrating from the FFT library made by Prof. Takuya Ooura. You
+should specify 1 as the direction in order to perform a forward
+transform, and -1 when you perform a backward transform.
+</p>
+
+<table border="0" style="margin-right:1.0cm; margin-left:1.0cm; margin-top:0.5cm; margin-bottom:0.5cm;">
+ <tr>
+ <td align="center" style="width:100%;">
+ <math mode="display" style="font-size:1.2em;" xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow>
+ <mi>Im</mi>
+ <mo>(</mo>
+ <msub><mi>X</mi><mrow><mi>k</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>)</mo>
+ <mo>=</mo>
+ <mn>0</mn>
+
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+
+ <mrow style="font-size:100%;">
+ <mi>k</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>N</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+
+ <mo>&nbsp;&nbsp;</mo>
+ <mo>,</mo>
+ <mo>&nbsp;&nbsp;</mo>
+
+ <mi>v</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>V</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+
+ </mrow>
+ </math>
+ </td>
+ <td>
+ <p>(12)</p>
+ </td>
+ </tr>
+</table>
+
+<table border="0" style="margin-right:1.0cm; margin-left:1.0cm; margin-top:0.5cm; margin-bottom:0.5cm;">
+ <tr>
+ <td align="center" style="width:100%;">
+ <math mode="display" style="font-size:1.2em;" xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow>
+ <mfenced open="{" close="">
+ <mtable>
+ <mtr>
+ <mtd>
+ <mrow>
+ <msub><mi>x</mi><mrow><mi>n</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>=</mo>
+ <msubsup>
+ <mi>x</mi>
+ <mrow><mi>N</mi><mo>-</mo><mi>n</mi><mo>,</mo><mi>v</mi></mrow>
+ <mo>*</mo>
+ </msubsup>
+ </mrow>
+ </mtd>
+
+ <mtd>
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+ </mtd>
+
+ <mtd>
+ <mrow style="font-size:100%;">
+ <mi>n</mi>
+ <mo>=</mo>
+ <mn>1</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mfrac>
+ <mi>N</mi>
+ <mn>2</mn>
+ </mfrac>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </mtd>
+ </mtr>
+
+ <mtr>
+ <mtd>
+ <mrow>
+ <mi>Im</mi>
+ <mo>(</mo>
+ <msub><mi>x</mi><mrow><mi>n</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>)</mo>
+ <mo>=</mo>
+ <mn>0</mn>
+ </mrow>
+ </mtd>
+
+ <mtd>
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+ </mtd>
+
+ <mtd>
+ <mrow style="font-size:100%;">
+ <mi>n</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mfrac>
+ <mi>N</mi>
+ <mn>2</mn>
+ </mfrac>
+ </mrow>
+ </mtd>
+ </mtr>
+
+ </mtable>
+ </mfenced>
+
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+
+ <mrow style="font-size:100%;">
+ <mi>v</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>V</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </mrow>
+ </math>
+ </td>
+ <td>
+ <p>(13)</p>
+ </td>
+ </tr>
+</table>
+
+<table border="0" style="margin-right:1.0cm; margin-left:1.0cm; margin-top:0.5cm; margin-bottom:0.5cm;">
+ <tr>
+ <td align="center" style="width:100%;">
+ <math mode="display" style="font-size:1.2em;" xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow>
+ <mrow>
+ <mi>s</mi>
+ <mo>[</mo>
+ <mi>n</mi>
+ <mi>V</mi>
+ <mo>+</mo>
+ <mi>v</mi>
+ <mo>]</mo>
+
+ <mo>=</mo>
+
+ <mi>Re</mi>
+ <mo>(</mo>
+ <msub><mi>X</mi><mrow><mi>k</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>)</mo>
+ </mrow>
+
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+
+ <mrow style="font-size:100%;">
+ <mi>k</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>N</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+
+ <mo>&nbsp;&nbsp;</mo>
+ <mo>,</mo>
+ <mo>&nbsp;&nbsp;</mo>
+
+ <mi>v</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>V</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </mrow>
+ </math>
+ </td>
+ <td>
+ <p>(14)</p>
+ </td>
+ </tr>
+</table>
+
+<table border="0" style="margin-right:1.0cm; margin-left:1.0cm; margin-top:0.5cm; margin-bottom:0.5cm;">
+ <tr>
+ <td align="center" style="width:100%;">
+ <math mode="display" style="font-size:1.2em;" xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow>
+ <mfenced open="{" close="">
+ <mtable>
+ <mtr>
+ <mtd>
+ <mrow>
+ <mi>s</mi>
+ <mo>[</mo>
+ <mo>(</mo>
+ <mn>2</mn>
+ <mi>n</mi>
+ <mo>+</mo>
+ <mn>0</mn>
+ <mo>)</mo>
+ <mi>V</mi>
+ <mo>+</mo>
+ <mi>v</mi>
+ <mo>]</mo>
+ </mrow>
+ </mtd>
+
+ <mtd>
+ <mo>=</mo>
+ </mtd>
+
+ <mtd>
+ <mrow>
+ <mi>Re</mi>
+ <mo>(</mo>
+ <msub><mi>x</mi><mrow><mi>n</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>)</mo>
+ </mrow>
+ </mtd>
+
+ <mtd>
+ <mrow style="font-size:100%;">
+ <mi>n</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mfrac>
+ <mi>N</mi>
+ <mn>2</mn>
+ </mfrac>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </mtd>
+ </mtr>
+
+ <mtr>
+ <mtd>
+ <mrow>
+ <mi>s</mi>
+ <mo>[</mo>
+ <mi>V</mi>
+ <mo>+</mo>
+ <mi>v</mi>
+ <mo>]</mo>
+ </mrow>
+ </mtd>
+
+ <mtd>
+ <mo>=</mo>
+ </mtd>
+
+ <mtd>
+ <mrow>
+ <mi>Re</mi>
+ <mo>(</mo>
+ <msub><mi>x</mi><mrow><mi>N</mi><mo>/</mo><mn>2</mn><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>)</mo>
+ </mrow>
+ </mtd>
+
+ <mtd>
+ </mtd>
+ </mtr>
+
+ <mtr>
+ <mtd>
+ <mrow>
+ <mi>s</mi>
+ <mo>[</mo>
+ <mo>(</mo>
+ <mn>2</mn>
+ <mi>n</mi>
+ <mo>+</mo>
+ <mn>1</mn>
+ <mo>)</mo>
+ <mi>V</mi>
+ <mo>+</mo>
+ <mi>v</mi>
+ <mo>]</mo>
+ </mrow>
+ </mtd>
+
+ <mtd>
+ <mo>=</mo>
+ </mtd>
+
+ <mtd>
+ <mrow>
+ <mi>Im</mi>
+ <mo>(</mo>
+ <msub><mi>x</mi><mrow><mi>n</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>)</mo>
+ </mrow>
+ </mtd>
+
+ <mtd>
+ <mrow style="font-size:100%;">
+ <mi>n</mi>
+ <mo>=</mo>
+ <mn>1</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mfrac>
+ <mi>N</mi>
+ <mn>2</mn>
+ </mfrac>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </mtd>
+ </mtr>
+
+ </mtable>
+ </mfenced>
+
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+
+ <mrow style="font-size:100%;">
+ <mi>v</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>V</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </mrow>
+ </math>
+ </td>
+ <td>
+ <p>(15)</p>
+ </td>
+ </tr>
+</table>
+
+<table border="0" style="margin-right:1.0cm; margin-left:1.0cm; margin-top:0.5cm; margin-bottom:0.5cm;">
+ <tr>
+ <td align="center" style="width:100%;">
+ <math mode="display" style="font-size:1.2em;" xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow>
+ <mrow>
+ <mn>2</mn>
+ <mo> &nbsp; </mo>
+ <mi>s</mi>
+ <mo>[</mo>
+ <mi>n</mi>
+ <mi>V</mi>
+ <mo>+</mo>
+ <mi>v</mi>
+ <mo>]</mo>
+
+ <mo>=</mo>
+
+ <mi>Re</mi>
+ <mo>(</mo>
+ <msub><mi>X</mi><mrow><mi>k</mi><mo>,</mo><mi>v</mi></mrow></msub>
+ <mo>)</mo>
+ </mrow>
+
+ <mo>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mo>
+
+ <mrow style="font-size:100%;">
+ <mi>k</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>N</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+
+ <mo>&nbsp;&nbsp;</mo>
+ <mo>,</mo>
+ <mo>&nbsp;&nbsp;</mo>
+
+ <mi>v</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>,</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>&middot;</mo>
+ <mo>,</mo>
+ <mi>V</mi>
+ <mo>-</mo>
+ <mn>1</mn>
+ </mrow>
+ </mrow>
+ </math>
+ </td>
+ <td>
+ <p>(16)</p>
+ </td>
+ </tr>
+</table>
+
+
+<h3>Examples</h3>
+
+<p>
+Below is an example code using nsfft library.
+</p>
+
+<pre class="code">
+#include &lt;stdio.h&gt;
+#include &lt;stdlib.h&gt;
+#include &lt;math.h&gt;
+#include &lt;stdint.h&gt;
+#include &lt;complex.h&gt;
+
+#include "SIMDBase.h"
+#include "DFT.h"
+
+typedef float REAL;
+#define TYPE SIMDBase_TYPE_FLOAT
+
+#define THRES 1e-3
+
+double complex omega(double n, double kn) {
+ return cexp((-2 * M_PI * _Complex_I / n) * kn);
+}
+
+void forward(double complex *ts, double complex *fs, int len) {
+ int k, n;
+
+ for(k=0;k&lt;len;k++) {
+ fs[k] = 0;
+
+ for(n=0;n&lt;len;n++) {
+ fs[k] += ts[n] * omega(len, n*k);
+ }
+ }
+}
+
+int main(int argc, char **argv) {
+ const int n = 256;
+
+ int mode = SIMDBase_chooseBestMode(TYPE);
+ printf("mode : %d, %s\n", mode, SIMDBase_getModeParamString(SIMDBase_PARAMID_MODE_NAME, mode));
+
+ int veclen = SIMDBase_getModeParamInt(SIMDBase_PARAMID_VECTOR_LEN, mode);
+ int sizeOfVect = SIMDBase_getModeParamInt(SIMDBase_PARAMID_SIZE_OF_VECT, mode);
+
+ //
+
+ int i, j;
+
+ DFT *p = DFT_init(mode, n, 0);
+ REAL *sx = SIMDBase_alignedMalloc(sizeOfVect*n*2);
+
+ //
+
+ double complex ts[veclen][n], fs[veclen][n];
+
+ for(j=0;j&lt;veclen;j++) {
+ for(i=0;i&lt;n;i++) {
+ ts[j][i] = (random() / (double)RAND_MAX) + (random() / (double)RAND_MAX) * _Complex_I;
+ sx[(i*2+0)*veclen+j] = creal(ts[j][i]);
+ sx[(i*2+1)*veclen+j] = cimag(ts[j][i]);
+ }
+ }
+
+ //
+
+ DFT_execute(p, mode, sx, -1);
+
+ for(j=0;j&lt;veclen;j++) {
+ forward(ts[j], fs[j], n);
+ }
+
+ //
+
+ int success = 1;
+
+ for(j=0;j&lt;veclen;j++) {
+ for(i=0;i&lt;n;i++) {
+ if ((fabs(sx[(i*2+0)*veclen+j] - creal(fs[j][i])) &gt; THRES) ||
+ (fabs(sx[(i*2+1)*veclen+j] - cimag(fs[j][i])) &gt; THRES)) {
+ success = 0;
+ }
+ }
+ }
+
+ printf("%s\n", success ? "OK" : "NG");
+
+ //
+
+ SIMDBase_alignedFree(sx);
+ DFT_dispose(p, mode);
+
+ exit(0);
+}
+</pre>
+
+<p>
+You should put this code under a directory in the root directory of
+the library, and then you can compile this code with the following
+command.
+</p>
+
+<pre class="code">
+gcc -Wall -g -I ../simd -I ../dft -L../simd -L../dft -O DFTExample.c -lDFT -lSIMD -lm -o DFTExample
+</pre>
+
+<h3>Compilation</h3>
+
+<p>
+The nsfft source package include a few makefiles for various
+architectures. You should make symbolic links to makefiles suited for
+your computer under <i>dft</i> and <i>simd</i> directories.
+</p>
+
+</body>
+</html>
diff --git a/plugins/supereq/nsfft-1.00/doc/nsfft.pdf b/plugins/supereq/nsfft-1.00/doc/nsfft.pdf
new file mode 100644
index 00000000..ed4ad5db
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/doc/nsfft.pdf
Binary files differ
diff --git a/plugins/supereq/nsfft-1.00/ooura/Makefile b/plugins/supereq/nsfft-1.00/ooura/Makefile
new file mode 100644
index 00000000..bad1679e
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/ooura/Makefile
@@ -0,0 +1,11 @@
+CC=gcc
+BASEOPT=-Wall -g
+OPT=$(BASEOPT) -O3
+
+all : fftsg.o
+
+clean :
+ rm -f *~ *.o a.out
+
+fftsg.o : fftsg.c
+ $(CC) $(OPT) -c fftsg.c
diff --git a/plugins/supereq/nsfft-1.00/ooura/README b/plugins/supereq/nsfft-1.00/ooura/README
new file mode 100644
index 00000000..d7ddefc2
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/ooura/README
@@ -0,0 +1,2 @@
+Please put fftsg.c and pi_fft.c which is included in Prof. Takuya
+Ooura's FFT package.
diff --git a/plugins/supereq/nsfft-1.00/ooura/fftsg.c b/plugins/supereq/nsfft-1.00/ooura/fftsg.c
new file mode 100644
index 00000000..43d75344
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/ooura/fftsg.c
@@ -0,0 +1,3314 @@
+/*
+Fast Fourier/Cosine/Sine Transform
+ dimension :one
+ data length :power of 2
+ decimation :frequency
+ radix :split-radix
+ 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 *);
+macro definitions
+ USE_CDFT_PTHREADS : default=not defined
+ CDFT_THREADS_BEGIN_N : must be >= 512, default=8192
+ CDFT_4THREADS_BEGIN_N : must be >= 512, default=65536
+ USE_CDFT_WINTHREADS : default=not defined
+ CDFT_THREADS_BEGIN_N : must be >= 512, default=32768
+ CDFT_4THREADS_BEGIN_N : must be >= 512, default=524288
+
+
+-------- Complex DFT (Discrete Fourier Transform) --------
+ [definition]
+ <case1>
+ X[k] = sum_j=0^n-1 x[j]*exp(2*pi*i*j*k/n), 0<=k<n
+ <case2>
+ X[k] = sum_j=0^n-1 x[j]*exp(-2*pi*i*j*k/n), 0<=k<n
+ (notes: sum_j=0^n-1 is a summation from j=0 to n-1)
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ cdft(2*n, 1, a, ip, w);
+ <case2>
+ 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<n
+ output data
+ a[2*k] = Re(X[k]),
+ a[2*k+1] = Im(X[k]), 0<=k<n
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 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]
+ <case1> 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<k<n/2
+ <case2> 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<n
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ rdft(n, 1, a, ip, w);
+ <case2>
+ 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 *)
+ <case1>
+ output data
+ a[2*k] = R[k], 0<=k<n/2
+ a[2*k+1] = I[k], 0<k<n/2
+ a[1] = R[n/2]
+ <case2>
+ input data
+ a[2*j] = R[j], 0<=j<n/2
+ a[2*j+1] = I[j], 0<j<n/2
+ a[1] = R[n/2]
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 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]
+ <case1> IDCT (excluding scale)
+ C[k] = sum_j=0^n-1 a[j]*cos(pi*j*(k+1/2)/n), 0<=k<n
+ <case2> DCT
+ C[k] = sum_j=0^n-1 a[j]*cos(pi*(j+1/2)*k/n), 0<=k<n
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ ddct(n, 1, a, ip, w);
+ <case2>
+ 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<n
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 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]
+ <case1> IDST (excluding scale)
+ S[k] = sum_j=1^n A[j]*sin(pi*j*(k+1/2)/n), 0<=k<n
+ <case2> DST
+ S[k] = sum_j=0^n-1 a[j]*sin(pi*(j+1/2)*k/n), 0<k<=n
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ ddst(n, 1, a, ip, w);
+ <case2>
+ 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 *)
+ <case1>
+ input data
+ a[j] = A[j], 0<j<n
+ a[0] = A[n]
+ output data
+ a[k] = S[k], 0<=k<n
+ <case2>
+ output data
+ a[k] = S[k], 0<k<n
+ a[0] = S[n]
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 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<k<n
+ [usage]
+ ip[0] = 0; // first time only
+ dfst(n, a, t, ip, w);
+ [parameters]
+ n :data length + 1 (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (double *)
+ output data
+ a[k] = S[k], 0<k<n
+ (a[0] is used for work area)
+ t[0...n/2-1] :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
+ 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.
+*/
+
+
+void cdft(int n, int isgn, double *a, int *ip, double *w)
+{
+ void makewt(int nw, int *ip, double *w);
+ void cftfsub(int n, double *a, int *ip, int nw, double *w);
+ void cftbsub(int n, double *a, int *ip, int nw, double *w);
+ int nw;
+
+ nw = ip[0];
+ if (n > (nw << 2)) {
+ nw = n >> 2;
+ makewt(nw, ip, w);
+ }
+ if (isgn >= 0) {
+ cftfsub(n, a, ip, nw, w);
+ } else {
+ cftbsub(n, a, ip, nw, w);
+ }
+}
+
+
+void rdft(int n, int isgn, double *a, int *ip, double *w)
+{
+ void makewt(int nw, int *ip, double *w);
+ void makect(int nc, int *ip, double *c);
+ void cftfsub(int n, double *a, int *ip, int nw, double *w);
+ void cftbsub(int n, double *a, int *ip, int nw, double *w);
+ void rftfsub(int n, double *a, int nc, double *c);
+ void rftbsub(int n, double *a, int nc, double *c);
+ int nw, nc;
+ double xi;
+
+ 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) {
+ cftfsub(n, a, ip, nw, w);
+ rftfsub(n, a, nc, w + nw);
+ } else if (n == 4) {
+ cftfsub(n, a, ip, nw, 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);
+ cftbsub(n, a, ip, nw, w);
+ } else if (n == 4) {
+ cftbsub(n, a, ip, nw, w);
+ }
+ }
+}
+
+
+void ddct(int n, int isgn, double *a, int *ip, double *w)
+{
+ void makewt(int nw, int *ip, double *w);
+ void makect(int nc, int *ip, double *c);
+ void cftfsub(int n, double *a, int *ip, int nw, double *w);
+ void cftbsub(int n, double *a, int *ip, int nw, double *w);
+ void rftfsub(int n, double *a, int nc, double *c);
+ void rftbsub(int n, double *a, int nc, double *c);
+ void dctsub(int n, double *a, int nc, double *c);
+ int j, nw, nc;
+ double xr;
+
+ 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);
+ cftbsub(n, a, ip, nw, w);
+ } else if (n == 4) {
+ cftbsub(n, a, ip, nw, w);
+ }
+ }
+ dctsub(n, a, nc, w + nw);
+ if (isgn >= 0) {
+ if (n > 4) {
+ cftfsub(n, a, ip, nw, w);
+ rftfsub(n, a, nc, w + nw);
+ } else if (n == 4) {
+ cftfsub(n, a, ip, nw, 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)
+{
+ void makewt(int nw, int *ip, double *w);
+ void makect(int nc, int *ip, double *c);
+ void cftfsub(int n, double *a, int *ip, int nw, double *w);
+ void cftbsub(int n, double *a, int *ip, int nw, double *w);
+ void rftfsub(int n, double *a, int nc, double *c);
+ void rftbsub(int n, double *a, int nc, double *c);
+ void dstsub(int n, double *a, int nc, double *c);
+ int j, nw, nc;
+ double xr;
+
+ 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);
+ cftbsub(n, a, ip, nw, w);
+ } else if (n == 4) {
+ cftbsub(n, a, ip, nw, w);
+ }
+ }
+ dstsub(n, a, nc, w + nw);
+ if (isgn >= 0) {
+ if (n > 4) {
+ cftfsub(n, a, ip, nw, w);
+ rftfsub(n, a, nc, w + nw);
+ } else if (n == 4) {
+ cftfsub(n, a, ip, nw, 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)
+{
+ void makewt(int nw, int *ip, double *w);
+ void makect(int nc, int *ip, double *c);
+ void cftfsub(int n, double *a, int *ip, int nw, double *w);
+ void rftfsub(int n, double *a, int nc, double *c);
+ void dctsub(int n, double *a, int nc, double *c);
+ int j, k, l, m, mh, nw, nc;
+ double xr, xi, yr, yi;
+
+ 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) {
+ cftfsub(m, a, ip, nw, w);
+ rftfsub(m, a, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, a, ip, nw, 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) {
+ cftfsub(m, t, ip, nw, w);
+ rftfsub(m, t, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, t, ip, nw, 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)
+{
+ void makewt(int nw, int *ip, double *w);
+ void makect(int nc, int *ip, double *c);
+ void cftfsub(int n, double *a, int *ip, int nw, double *w);
+ void rftfsub(int n, double *a, int nc, double *c);
+ void dstsub(int n, double *a, int nc, double *c);
+ int j, k, l, m, mh, nw, nc;
+ double xr, xi, yr, yi;
+
+ 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) {
+ cftfsub(m, a, ip, nw, w);
+ rftfsub(m, a, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, a, ip, nw, 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) {
+ cftfsub(m, t, ip, nw, w);
+ rftfsub(m, t, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, t, ip, nw, 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 -------- */
+
+
+#include <math.h>
+
+void makewt(int nw, int *ip, double *w)
+{
+ void makeipt(int nw, int *ip);
+ int j, nwh, nw0, nw1;
+ double delta, wn4r, wk1r, wk1i, wk3r, wk3i;
+
+ ip[0] = nw;
+ ip[1] = 1;
+ if (nw > 2) {
+ nwh = nw >> 1;
+ delta = atan(1.0) / nwh;
+ wn4r = cos(delta * nwh);
+ w[0] = 1;
+ w[1] = wn4r;
+ if (nwh == 4) {
+ w[2] = cos(delta * 2);
+ w[3] = sin(delta * 2);
+ } else if (nwh > 4) {
+ makeipt(nw, ip);
+ w[2] = 0.5 / cos(delta * 2);
+ w[3] = 0.5 / cos(delta * 6);
+ for (j = 4; j < nwh; j += 4) {
+ w[j] = cos(delta * j);
+ w[j + 1] = sin(delta * j);
+ w[j + 2] = cos(3 * delta * j);
+ w[j + 3] = -sin(3 * delta * j);
+ }
+ }
+ nw0 = 0;
+ while (nwh > 2) {
+ nw1 = nw0 + nwh;
+ nwh >>= 1;
+ w[nw1] = 1;
+ w[nw1 + 1] = wn4r;
+ if (nwh == 4) {
+ wk1r = w[nw0 + 4];
+ wk1i = w[nw0 + 5];
+ w[nw1 + 2] = wk1r;
+ w[nw1 + 3] = wk1i;
+ } else if (nwh > 4) {
+ wk1r = w[nw0 + 4];
+ wk3r = w[nw0 + 6];
+ w[nw1 + 2] = 0.5 / wk1r;
+ w[nw1 + 3] = 0.5 / wk3r;
+ for (j = 4; j < nwh; j += 4) {
+ wk1r = w[nw0 + 2 * j];
+ wk1i = w[nw0 + 2 * j + 1];
+ wk3r = w[nw0 + 2 * j + 2];
+ wk3i = w[nw0 + 2 * j + 3];
+ w[nw1 + j] = wk1r;
+ w[nw1 + j + 1] = wk1i;
+ w[nw1 + j + 2] = wk3r;
+ w[nw1 + j + 3] = wk3i;
+ }
+ }
+ nw0 = nw1;
+ }
+ }
+}
+
+
+void makeipt(int nw, int *ip)
+{
+ int j, l, m, m2, p, q;
+
+ ip[2] = 0;
+ ip[3] = 16;
+ m = 2;
+ for (l = nw; l > 32; l >>= 2) {
+ m2 = m << 1;
+ q = m2 << 3;
+ for (j = m; j < m2; j++) {
+ p = ip[j] << 2;
+ ip[m + j] = p;
+ ip[m2 + j] = p + q;
+ }
+ m = m2;
+ }
+}
+
+
+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 -------- */
+
+
+#ifdef USE_CDFT_PTHREADS
+#define USE_CDFT_THREADS
+#ifndef CDFT_THREADS_BEGIN_N
+#define CDFT_THREADS_BEGIN_N 8192
+#endif
+#ifndef CDFT_4THREADS_BEGIN_N
+#define CDFT_4THREADS_BEGIN_N 65536
+#endif
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#define cdft_thread_t pthread_t
+#define cdft_thread_create(thp,func,argp) { \
+ if (pthread_create(thp, NULL, func, (void *) argp) != 0) { \
+ fprintf(stderr, "cdft thread error\n"); \
+ exit(1); \
+ } \
+}
+#define cdft_thread_wait(th) { \
+ if (pthread_join(th, NULL) != 0) { \
+ fprintf(stderr, "cdft thread error\n"); \
+ exit(1); \
+ } \
+}
+#endif /* USE_CDFT_PTHREADS */
+
+
+#ifdef USE_CDFT_WINTHREADS
+#define USE_CDFT_THREADS
+#ifndef CDFT_THREADS_BEGIN_N
+#define CDFT_THREADS_BEGIN_N 32768
+#endif
+#ifndef CDFT_4THREADS_BEGIN_N
+#define CDFT_4THREADS_BEGIN_N 524288
+#endif
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#define cdft_thread_t HANDLE
+#define cdft_thread_create(thp,func,argp) { \
+ DWORD thid; \
+ *(thp) = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) func, (LPVOID) argp, 0, &thid); \
+ if (*(thp) == 0) { \
+ fprintf(stderr, "cdft thread error\n"); \
+ exit(1); \
+ } \
+}
+#define cdft_thread_wait(th) { \
+ WaitForSingleObject(th, INFINITE); \
+ CloseHandle(th); \
+}
+#endif /* USE_CDFT_WINTHREADS */
+
+
+void cftfsub(int n, double *a, int *ip, int nw, double *w)
+{
+ void bitrv2(int n, int *ip, double *a);
+ void bitrv216(double *a);
+ void bitrv208(double *a);
+ void cftf1st(int n, double *a, double *w);
+ void cftrec4(int n, double *a, int nw, double *w);
+ void cftleaf(int n, int isplt, double *a, int nw, double *w);
+ void cftfx41(int n, double *a, int nw, double *w);
+ void cftf161(double *a, double *w);
+ void cftf081(double *a, double *w);
+ void cftf040(double *a);
+ void cftx020(double *a);
+#ifdef USE_CDFT_THREADS
+ void cftrec4_th(int n, double *a, int nw, double *w);
+#endif /* USE_CDFT_THREADS */
+
+ if (n > 8) {
+ if (n > 32) {
+ cftf1st(n, a, &w[nw - (n >> 2)]);
+#ifdef USE_CDFT_THREADS
+ if (n > CDFT_THREADS_BEGIN_N) {
+ cftrec4_th(n, a, nw, w);
+ } else
+#endif /* USE_CDFT_THREADS */
+ if (n > 512) {
+ cftrec4(n, a, nw, w);
+ } else if (n > 128) {
+ cftleaf(n, 1, a, nw, w);
+ } else {
+ cftfx41(n, a, nw, w);
+ }
+ bitrv2(n, ip, a);
+ } else if (n == 32) {
+ cftf161(a, &w[nw - 8]);
+ bitrv216(a);
+ } else {
+ cftf081(a, w);
+ bitrv208(a);
+ }
+ } else if (n == 8) {
+ cftf040(a);
+ } else if (n == 4) {
+ cftx020(a);
+ }
+}
+
+
+void cftbsub(int n, double *a, int *ip, int nw, double *w)
+{
+ void bitrv2conj(int n, int *ip, double *a);
+ void bitrv216neg(double *a);
+ void bitrv208neg(double *a);
+ void cftb1st(int n, double *a, double *w);
+ void cftrec4(int n, double *a, int nw, double *w);
+ void cftleaf(int n, int isplt, double *a, int nw, double *w);
+ void cftfx41(int n, double *a, int nw, double *w);
+ void cftf161(double *a, double *w);
+ void cftf081(double *a, double *w);
+ void cftb040(double *a);
+ void cftx020(double *a);
+#ifdef USE_CDFT_THREADS
+ void cftrec4_th(int n, double *a, int nw, double *w);
+#endif /* USE_CDFT_THREADS */
+
+ if (n > 8) {
+ if (n > 32) {
+ cftb1st(n, a, &w[nw - (n >> 2)]);
+#ifdef USE_CDFT_THREADS
+ if (n > CDFT_THREADS_BEGIN_N) {
+ cftrec4_th(n, a, nw, w);
+ } else
+#endif /* USE_CDFT_THREADS */
+ if (n > 512) {
+ cftrec4(n, a, nw, w);
+ } else if (n > 128) {
+ cftleaf(n, 1, a, nw, w);
+ } else {
+ cftfx41(n, a, nw, w);
+ }
+ bitrv2conj(n, ip, a);
+ } else if (n == 32) {
+ cftf161(a, &w[nw - 8]);
+ bitrv216neg(a);
+ } else {
+ cftf081(a, w);
+ bitrv208neg(a);
+ }
+ } else if (n == 8) {
+ cftb040(a);
+ } else if (n == 4) {
+ cftx020(a);
+ }
+}
+
+
+void bitrv2(int n, int *ip, double *a)
+{
+ int j, j1, k, k1, l, m, nh, nm;
+ double xr, xi, yr, yi;
+
+ m = 1;
+ for (l = n >> 2; l > 8; l >>= 2) {
+ m <<= 1;
+ }
+ nh = n >> 1;
+ nm = 4 * m;
+ if (l == 8) {
+ for (k = 0; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 4 * j + 2 * ip[m + k];
+ k1 = 4 * k + 2 * ip[m + 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 += nm;
+ k1 += 2 * nm;
+ 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 += nm;
+ k1 -= nm;
+ 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 += nm;
+ k1 += 2 * nm;
+ 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 += nh;
+ k1 += 2;
+ 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 -= nm;
+ k1 -= 2 * nm;
+ 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 -= nm;
+ k1 += nm;
+ 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 -= nm;
+ k1 -= 2 * nm;
+ 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;
+ k1 += nh;
+ 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 += nm;
+ k1 += 2 * nm;
+ 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 += nm;
+ k1 -= nm;
+ 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 += nm;
+ k1 += 2 * nm;
+ 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 -= nh;
+ k1 -= 2;
+ 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 -= nm;
+ k1 -= 2 * nm;
+ 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 -= nm;
+ k1 += nm;
+ 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 -= nm;
+ k1 -= 2 * nm;
+ 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 = 4 * k + 2 * ip[m + k];
+ j1 = k1 + 2;
+ k1 += nh;
+ 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 += nm;
+ k1 += 2 * nm;
+ 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 += nm;
+ k1 -= nm;
+ 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;
+ k1 -= nh;
+ 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 += nh + 2;
+ k1 += nh + 2;
+ 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 -= nh - nm;
+ k1 += 2 * nm - 2;
+ 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 = 0; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 4 * j + ip[m + k];
+ k1 = 4 * k + ip[m + 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 += nm;
+ k1 += nm;
+ 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 += nh;
+ k1 += 2;
+ 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 -= nm;
+ k1 -= nm;
+ 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;
+ k1 += nh;
+ 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 += nm;
+ k1 += nm;
+ 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 -= nh;
+ k1 -= 2;
+ 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 -= nm;
+ k1 -= nm;
+ 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 = 4 * k + ip[m + k];
+ j1 = k1 + 2;
+ k1 += nh;
+ 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 += nm;
+ k1 += nm;
+ 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;
+ }
+ }
+}
+
+
+void bitrv2conj(int n, int *ip, double *a)
+{
+ int j, j1, k, k1, l, m, nh, nm;
+ double xr, xi, yr, yi;
+
+ m = 1;
+ for (l = n >> 2; l > 8; l >>= 2) {
+ m <<= 1;
+ }
+ nh = n >> 1;
+ nm = 4 * m;
+ if (l == 8) {
+ for (k = 0; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 4 * j + 2 * ip[m + k];
+ k1 = 4 * k + 2 * ip[m + 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 += nm;
+ k1 += 2 * nm;
+ 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 += nm;
+ k1 -= nm;
+ 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 += nm;
+ k1 += 2 * nm;
+ 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 += nh;
+ k1 += 2;
+ 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 -= nm;
+ k1 -= 2 * nm;
+ 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 -= nm;
+ k1 += nm;
+ 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 -= nm;
+ k1 -= 2 * nm;
+ 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;
+ k1 += nh;
+ 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 += nm;
+ k1 += 2 * nm;
+ 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 += nm;
+ k1 -= nm;
+ 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 += nm;
+ k1 += 2 * nm;
+ 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 -= nh;
+ k1 -= 2;
+ 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 -= nm;
+ k1 -= 2 * nm;
+ 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 -= nm;
+ k1 += nm;
+ 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 -= nm;
+ k1 -= 2 * nm;
+ 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 = 4 * k + 2 * ip[m + k];
+ j1 = k1 + 2;
+ k1 += nh;
+ a[j1 - 1] = -a[j1 - 1];
+ 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;
+ a[k1 + 3] = -a[k1 + 3];
+ j1 += nm;
+ k1 += 2 * nm;
+ 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 += nm;
+ k1 -= nm;
+ 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;
+ k1 -= nh;
+ 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 += nh + 2;
+ k1 += nh + 2;
+ 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 -= nh - nm;
+ k1 += 2 * nm - 2;
+ a[j1 - 1] = -a[j1 - 1];
+ 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;
+ a[k1 + 3] = -a[k1 + 3];
+ }
+ } else {
+ for (k = 0; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 4 * j + ip[m + k];
+ k1 = 4 * k + ip[m + 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 += nm;
+ k1 += nm;
+ 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 += nh;
+ k1 += 2;
+ 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 -= nm;
+ k1 -= nm;
+ 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;
+ k1 += nh;
+ 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 += nm;
+ k1 += nm;
+ 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 -= nh;
+ k1 -= 2;
+ 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 -= nm;
+ k1 -= nm;
+ 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 = 4 * k + ip[m + k];
+ j1 = k1 + 2;
+ k1 += nh;
+ a[j1 - 1] = -a[j1 - 1];
+ 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;
+ a[k1 + 3] = -a[k1 + 3];
+ j1 += nm;
+ k1 += nm;
+ a[j1 - 1] = -a[j1 - 1];
+ 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;
+ a[k1 + 3] = -a[k1 + 3];
+ }
+ }
+}
+
+
+void bitrv216(double *a)
+{
+ double x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i,
+ x5r, x5i, x7r, x7i, x8r, x8i, x10r, x10i,
+ x11r, x11i, x12r, x12i, x13r, x13i, x14r, x14i;
+
+ x1r = a[2];
+ x1i = a[3];
+ x2r = a[4];
+ x2i = a[5];
+ x3r = a[6];
+ x3i = a[7];
+ x4r = a[8];
+ x4i = a[9];
+ x5r = a[10];
+ x5i = a[11];
+ x7r = a[14];
+ x7i = a[15];
+ x8r = a[16];
+ x8i = a[17];
+ x10r = a[20];
+ x10i = a[21];
+ x11r = a[22];
+ x11i = a[23];
+ x12r = a[24];
+ x12i = a[25];
+ x13r = a[26];
+ x13i = a[27];
+ x14r = a[28];
+ x14i = a[29];
+ a[2] = x8r;
+ a[3] = x8i;
+ a[4] = x4r;
+ a[5] = x4i;
+ a[6] = x12r;
+ a[7] = x12i;
+ a[8] = x2r;
+ a[9] = x2i;
+ a[10] = x10r;
+ a[11] = x10i;
+ a[14] = x14r;
+ a[15] = x14i;
+ a[16] = x1r;
+ a[17] = x1i;
+ a[20] = x5r;
+ a[21] = x5i;
+ a[22] = x13r;
+ a[23] = x13i;
+ a[24] = x3r;
+ a[25] = x3i;
+ a[26] = x11r;
+ a[27] = x11i;
+ a[28] = x7r;
+ a[29] = x7i;
+}
+
+
+void bitrv216neg(double *a)
+{
+ double x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i,
+ x5r, x5i, x6r, x6i, x7r, x7i, x8r, x8i,
+ x9r, x9i, x10r, x10i, x11r, x11i, x12r, x12i,
+ x13r, x13i, x14r, x14i, x15r, x15i;
+
+ x1r = a[2];
+ x1i = a[3];
+ x2r = a[4];
+ x2i = a[5];
+ x3r = a[6];
+ x3i = a[7];
+ x4r = a[8];
+ x4i = a[9];
+ x5r = a[10];
+ x5i = a[11];
+ x6r = a[12];
+ x6i = a[13];
+ x7r = a[14];
+ x7i = a[15];
+ x8r = a[16];
+ x8i = a[17];
+ x9r = a[18];
+ x9i = a[19];
+ x10r = a[20];
+ x10i = a[21];
+ x11r = a[22];
+ x11i = a[23];
+ x12r = a[24];
+ x12i = a[25];
+ x13r = a[26];
+ x13i = a[27];
+ x14r = a[28];
+ x14i = a[29];
+ x15r = a[30];
+ x15i = a[31];
+ a[2] = x15r;
+ a[3] = x15i;
+ a[4] = x7r;
+ a[5] = x7i;
+ a[6] = x11r;
+ a[7] = x11i;
+ a[8] = x3r;
+ a[9] = x3i;
+ a[10] = x13r;
+ a[11] = x13i;
+ a[12] = x5r;
+ a[13] = x5i;
+ a[14] = x9r;
+ a[15] = x9i;
+ a[16] = x1r;
+ a[17] = x1i;
+ a[18] = x14r;
+ a[19] = x14i;
+ a[20] = x6r;
+ a[21] = x6i;
+ a[22] = x10r;
+ a[23] = x10i;
+ a[24] = x2r;
+ a[25] = x2i;
+ a[26] = x12r;
+ a[27] = x12i;
+ a[28] = x4r;
+ a[29] = x4i;
+ a[30] = x8r;
+ a[31] = x8i;
+}
+
+
+void bitrv208(double *a)
+{
+ double x1r, x1i, x3r, x3i, x4r, x4i, x6r, x6i;
+
+ x1r = a[2];
+ x1i = a[3];
+ x3r = a[6];
+ x3i = a[7];
+ x4r = a[8];
+ x4i = a[9];
+ x6r = a[12];
+ x6i = a[13];
+ a[2] = x4r;
+ a[3] = x4i;
+ a[6] = x6r;
+ a[7] = x6i;
+ a[8] = x1r;
+ a[9] = x1i;
+ a[12] = x3r;
+ a[13] = x3i;
+}
+
+
+void bitrv208neg(double *a)
+{
+ double x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i,
+ x5r, x5i, x6r, x6i, x7r, x7i;
+
+ x1r = a[2];
+ x1i = a[3];
+ x2r = a[4];
+ x2i = a[5];
+ x3r = a[6];
+ x3i = a[7];
+ x4r = a[8];
+ x4i = a[9];
+ x5r = a[10];
+ x5i = a[11];
+ x6r = a[12];
+ x6i = a[13];
+ x7r = a[14];
+ x7i = a[15];
+ a[2] = x7r;
+ a[3] = x7i;
+ a[4] = x3r;
+ a[5] = x3i;
+ a[6] = x5r;
+ a[7] = x5i;
+ a[8] = x1r;
+ a[9] = x1i;
+ a[10] = x6r;
+ a[11] = x6i;
+ a[12] = x2r;
+ a[13] = x2i;
+ a[14] = x4r;
+ a[15] = x4i;
+}
+
+
+void cftf1st(int n, double *a, double *w)
+{
+ int j, j0, j1, j2, j3, k, m, mh;
+ double wn4r, csc1, csc3, wk1r, wk1i, wk3r, wk3i,
+ wd1r, wd1i, wd3r, wd3i;
+ double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i;
+
+ mh = n >> 3;
+ m = 2 * mh;
+ j1 = m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[0] + a[j2];
+ x0i = a[1] + a[j2 + 1];
+ x1r = a[0] - a[j2];
+ x1i = a[1] - a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[0] = x0r + x2r;
+ a[1] = x0i + x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ a[j2] = x1r - x3i;
+ a[j2 + 1] = x1i + x3r;
+ a[j3] = x1r + x3i;
+ a[j3 + 1] = x1i - x3r;
+ wn4r = w[1];
+ csc1 = w[2];
+ csc3 = w[3];
+ wd1r = 1;
+ wd1i = 0;
+ wd3r = 1;
+ wd3i = 0;
+ k = 0;
+ for (j = 2; j < mh - 2; j += 4) {
+ k += 4;
+ wk1r = csc1 * (wd1r + w[k]);
+ wk1i = csc1 * (wd1i + w[k + 1]);
+ wk3r = csc3 * (wd3r + w[k + 2]);
+ wk3i = csc3 * (wd3i + w[k + 3]);
+ wd1r = w[k];
+ wd1i = w[k + 1];
+ wd3r = w[k + 2];
+ wd3i = w[k + 3];
+ j1 = j + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j] + a[j2];
+ x0i = a[j + 1] + a[j2 + 1];
+ x1r = a[j] - a[j2];
+ x1i = a[j + 1] - a[j2 + 1];
+ y0r = a[j + 2] + a[j2 + 2];
+ y0i = a[j + 3] + a[j2 + 3];
+ y1r = a[j + 2] - a[j2 + 2];
+ y1i = a[j + 3] - a[j2 + 3];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ y2r = a[j1 + 2] + a[j3 + 2];
+ y2i = a[j1 + 3] + a[j3 + 3];
+ y3r = a[j1 + 2] - a[j3 + 2];
+ y3i = a[j1 + 3] - a[j3 + 3];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i + x2i;
+ a[j + 2] = y0r + y2r;
+ a[j + 3] = y0i + y2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ a[j1 + 2] = y0r - y2r;
+ a[j1 + 3] = y0i - y2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2] = wk1r * x0r - wk1i * x0i;
+ a[j2 + 1] = wk1r * x0i + wk1i * x0r;
+ x0r = y1r - y3i;
+ x0i = y1i + y3r;
+ a[j2 + 2] = wd1r * x0r - wd1i * x0i;
+ a[j2 + 3] = wd1r * x0i + wd1i * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3r * x0r + wk3i * x0i;
+ a[j3 + 1] = wk3r * x0i - wk3i * x0r;
+ x0r = y1r + y3i;
+ x0i = y1i - y3r;
+ a[j3 + 2] = wd3r * x0r + wd3i * x0i;
+ a[j3 + 3] = wd3r * x0i - wd3i * x0r;
+ j0 = m - j;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0] + a[j2];
+ x0i = a[j0 + 1] + a[j2 + 1];
+ x1r = a[j0] - a[j2];
+ x1i = a[j0 + 1] - a[j2 + 1];
+ y0r = a[j0 - 2] + a[j2 - 2];
+ y0i = a[j0 - 1] + a[j2 - 1];
+ y1r = a[j0 - 2] - a[j2 - 2];
+ y1i = a[j0 - 1] - a[j2 - 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ y2r = a[j1 - 2] + a[j3 - 2];
+ y2i = a[j1 - 1] + a[j3 - 1];
+ y3r = a[j1 - 2] - a[j3 - 2];
+ y3i = a[j1 - 1] - a[j3 - 1];
+ a[j0] = x0r + x2r;
+ a[j0 + 1] = x0i + x2i;
+ a[j0 - 2] = y0r + y2r;
+ a[j0 - 1] = y0i + y2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ a[j1 - 2] = y0r - y2r;
+ a[j1 - 1] = y0i - y2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2] = wk1i * x0r - wk1r * x0i;
+ a[j2 + 1] = wk1i * x0i + wk1r * x0r;
+ x0r = y1r - y3i;
+ x0i = y1i + y3r;
+ a[j2 - 2] = wd1i * x0r - wd1r * x0i;
+ a[j2 - 1] = wd1i * x0i + wd1r * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3i * x0r + wk3r * x0i;
+ a[j3 + 1] = wk3i * x0i - wk3r * x0r;
+ x0r = y1r + y3i;
+ x0i = y1i - y3r;
+ a[j3 - 2] = wd3i * x0r + wd3r * x0i;
+ a[j3 - 1] = wd3i * x0i - wd3r * x0r;
+ }
+ wk1r = csc1 * (wd1r + wn4r);
+ wk1i = csc1 * (wd1i + wn4r);
+ wk3r = csc3 * (wd3r - wn4r);
+ wk3i = csc3 * (wd3i - wn4r);
+ j0 = mh;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0 - 2] + a[j2 - 2];
+ x0i = a[j0 - 1] + a[j2 - 1];
+ x1r = a[j0 - 2] - a[j2 - 2];
+ x1i = a[j0 - 1] - a[j2 - 1];
+ x2r = a[j1 - 2] + a[j3 - 2];
+ x2i = a[j1 - 1] + a[j3 - 1];
+ x3r = a[j1 - 2] - a[j3 - 2];
+ x3i = a[j1 - 1] - a[j3 - 1];
+ a[j0 - 2] = x0r + x2r;
+ a[j0 - 1] = x0i + x2i;
+ a[j1 - 2] = x0r - x2r;
+ a[j1 - 1] = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2 - 2] = wk1r * x0r - wk1i * x0i;
+ a[j2 - 1] = wk1r * x0i + wk1i * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3 - 2] = wk3r * x0r + wk3i * x0i;
+ a[j3 - 1] = wk3r * x0i - wk3i * x0r;
+ x0r = a[j0] + a[j2];
+ x0i = a[j0 + 1] + a[j2 + 1];
+ x1r = a[j0] - a[j2];
+ x1i = a[j0 + 1] - a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[j0] = x0r + x2r;
+ a[j0 + 1] = x0i + x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2] = wn4r * (x0r - x0i);
+ a[j2 + 1] = wn4r * (x0i + x0r);
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = -wn4r * (x0r + x0i);
+ a[j3 + 1] = -wn4r * (x0i - x0r);
+ x0r = a[j0 + 2] + a[j2 + 2];
+ x0i = a[j0 + 3] + a[j2 + 3];
+ x1r = a[j0 + 2] - a[j2 + 2];
+ x1i = a[j0 + 3] - a[j2 + 3];
+ x2r = a[j1 + 2] + a[j3 + 2];
+ x2i = a[j1 + 3] + a[j3 + 3];
+ x3r = a[j1 + 2] - a[j3 + 2];
+ x3i = a[j1 + 3] - a[j3 + 3];
+ a[j0 + 2] = x0r + x2r;
+ a[j0 + 3] = x0i + x2i;
+ a[j1 + 2] = x0r - x2r;
+ a[j1 + 3] = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2 + 2] = wk1i * x0r - wk1r * x0i;
+ a[j2 + 3] = wk1i * x0i + wk1r * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3 + 2] = wk3i * x0r + wk3r * x0i;
+ a[j3 + 3] = wk3i * x0i - wk3r * x0r;
+}
+
+
+void cftb1st(int n, double *a, double *w)
+{
+ int j, j0, j1, j2, j3, k, m, mh;
+ double wn4r, csc1, csc3, wk1r, wk1i, wk3r, wk3i,
+ wd1r, wd1i, wd3r, wd3i;
+ double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i;
+
+ mh = n >> 3;
+ m = 2 * mh;
+ j1 = m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[0] + a[j2];
+ x0i = -a[1] - a[j2 + 1];
+ x1r = a[0] - a[j2];
+ x1i = -a[1] + a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[0] = x0r + x2r;
+ a[1] = x0i - x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i + x2i;
+ a[j2] = x1r + x3i;
+ a[j2 + 1] = x1i + x3r;
+ a[j3] = x1r - x3i;
+ a[j3 + 1] = x1i - x3r;
+ wn4r = w[1];
+ csc1 = w[2];
+ csc3 = w[3];
+ wd1r = 1;
+ wd1i = 0;
+ wd3r = 1;
+ wd3i = 0;
+ k = 0;
+ for (j = 2; j < mh - 2; j += 4) {
+ k += 4;
+ wk1r = csc1 * (wd1r + w[k]);
+ wk1i = csc1 * (wd1i + w[k + 1]);
+ wk3r = csc3 * (wd3r + w[k + 2]);
+ wk3i = csc3 * (wd3i + w[k + 3]);
+ wd1r = w[k];
+ wd1i = w[k + 1];
+ wd3r = w[k + 2];
+ wd3i = w[k + 3];
+ j1 = j + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j] + a[j2];
+ x0i = -a[j + 1] - a[j2 + 1];
+ x1r = a[j] - a[j2];
+ x1i = -a[j + 1] + a[j2 + 1];
+ y0r = a[j + 2] + a[j2 + 2];
+ y0i = -a[j + 3] - a[j2 + 3];
+ y1r = a[j + 2] - a[j2 + 2];
+ y1i = -a[j + 3] + a[j2 + 3];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ y2r = a[j1 + 2] + a[j3 + 2];
+ y2i = a[j1 + 3] + a[j3 + 3];
+ y3r = a[j1 + 2] - a[j3 + 2];
+ y3i = a[j1 + 3] - a[j3 + 3];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i - x2i;
+ a[j + 2] = y0r + y2r;
+ a[j + 3] = y0i - y2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i + x2i;
+ a[j1 + 2] = y0r - y2r;
+ a[j1 + 3] = y0i + y2i;
+ x0r = x1r + x3i;
+ x0i = x1i + x3r;
+ a[j2] = wk1r * x0r - wk1i * x0i;
+ a[j2 + 1] = wk1r * x0i + wk1i * x0r;
+ x0r = y1r + y3i;
+ x0i = y1i + y3r;
+ a[j2 + 2] = wd1r * x0r - wd1i * x0i;
+ a[j2 + 3] = wd1r * x0i + wd1i * x0r;
+ x0r = x1r - x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3r * x0r + wk3i * x0i;
+ a[j3 + 1] = wk3r * x0i - wk3i * x0r;
+ x0r = y1r - y3i;
+ x0i = y1i - y3r;
+ a[j3 + 2] = wd3r * x0r + wd3i * x0i;
+ a[j3 + 3] = wd3r * x0i - wd3i * x0r;
+ j0 = m - j;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0] + a[j2];
+ x0i = -a[j0 + 1] - a[j2 + 1];
+ x1r = a[j0] - a[j2];
+ x1i = -a[j0 + 1] + a[j2 + 1];
+ y0r = a[j0 - 2] + a[j2 - 2];
+ y0i = -a[j0 - 1] - a[j2 - 1];
+ y1r = a[j0 - 2] - a[j2 - 2];
+ y1i = -a[j0 - 1] + a[j2 - 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ y2r = a[j1 - 2] + a[j3 - 2];
+ y2i = a[j1 - 1] + a[j3 - 1];
+ y3r = a[j1 - 2] - a[j3 - 2];
+ y3i = a[j1 - 1] - a[j3 - 1];
+ a[j0] = x0r + x2r;
+ a[j0 + 1] = x0i - x2i;
+ a[j0 - 2] = y0r + y2r;
+ a[j0 - 1] = y0i - y2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i + x2i;
+ a[j1 - 2] = y0r - y2r;
+ a[j1 - 1] = y0i + y2i;
+ x0r = x1r + x3i;
+ x0i = x1i + x3r;
+ a[j2] = wk1i * x0r - wk1r * x0i;
+ a[j2 + 1] = wk1i * x0i + wk1r * x0r;
+ x0r = y1r + y3i;
+ x0i = y1i + y3r;
+ a[j2 - 2] = wd1i * x0r - wd1r * x0i;
+ a[j2 - 1] = wd1i * x0i + wd1r * x0r;
+ x0r = x1r - x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3i * x0r + wk3r * x0i;
+ a[j3 + 1] = wk3i * x0i - wk3r * x0r;
+ x0r = y1r - y3i;
+ x0i = y1i - y3r;
+ a[j3 - 2] = wd3i * x0r + wd3r * x0i;
+ a[j3 - 1] = wd3i * x0i - wd3r * x0r;
+ }
+ wk1r = csc1 * (wd1r + wn4r);
+ wk1i = csc1 * (wd1i + wn4r);
+ wk3r = csc3 * (wd3r - wn4r);
+ wk3i = csc3 * (wd3i - wn4r);
+ j0 = mh;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0 - 2] + a[j2 - 2];
+ x0i = -a[j0 - 1] - a[j2 - 1];
+ x1r = a[j0 - 2] - a[j2 - 2];
+ x1i = -a[j0 - 1] + a[j2 - 1];
+ x2r = a[j1 - 2] + a[j3 - 2];
+ x2i = a[j1 - 1] + a[j3 - 1];
+ x3r = a[j1 - 2] - a[j3 - 2];
+ x3i = a[j1 - 1] - a[j3 - 1];
+ a[j0 - 2] = x0r + x2r;
+ a[j0 - 1] = x0i - x2i;
+ a[j1 - 2] = x0r - x2r;
+ a[j1 - 1] = x0i + x2i;
+ x0r = x1r + x3i;
+ x0i = x1i + x3r;
+ a[j2 - 2] = wk1r * x0r - wk1i * x0i;
+ a[j2 - 1] = wk1r * x0i + wk1i * x0r;
+ x0r = x1r - x3i;
+ x0i = x1i - x3r;
+ a[j3 - 2] = wk3r * x0r + wk3i * x0i;
+ a[j3 - 1] = wk3r * x0i - wk3i * x0r;
+ x0r = a[j0] + a[j2];
+ x0i = -a[j0 + 1] - a[j2 + 1];
+ x1r = a[j0] - a[j2];
+ x1i = -a[j0 + 1] + a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[j0] = x0r + x2r;
+ a[j0 + 1] = x0i - x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i + x2i;
+ x0r = x1r + x3i;
+ x0i = x1i + x3r;
+ a[j2] = wn4r * (x0r - x0i);
+ a[j2 + 1] = wn4r * (x0i + x0r);
+ x0r = x1r - x3i;
+ x0i = x1i - x3r;
+ a[j3] = -wn4r * (x0r + x0i);
+ a[j3 + 1] = -wn4r * (x0i - x0r);
+ x0r = a[j0 + 2] + a[j2 + 2];
+ x0i = -a[j0 + 3] - a[j2 + 3];
+ x1r = a[j0 + 2] - a[j2 + 2];
+ x1i = -a[j0 + 3] + a[j2 + 3];
+ x2r = a[j1 + 2] + a[j3 + 2];
+ x2i = a[j1 + 3] + a[j3 + 3];
+ x3r = a[j1 + 2] - a[j3 + 2];
+ x3i = a[j1 + 3] - a[j3 + 3];
+ a[j0 + 2] = x0r + x2r;
+ a[j0 + 3] = x0i - x2i;
+ a[j1 + 2] = x0r - x2r;
+ a[j1 + 3] = x0i + x2i;
+ x0r = x1r + x3i;
+ x0i = x1i + x3r;
+ a[j2 + 2] = wk1i * x0r - wk1r * x0i;
+ a[j2 + 3] = wk1i * x0i + wk1r * x0r;
+ x0r = x1r - x3i;
+ x0i = x1i - x3r;
+ a[j3 + 2] = wk3i * x0r + wk3r * x0i;
+ a[j3 + 3] = wk3i * x0i - wk3r * x0r;
+}
+
+
+#ifdef USE_CDFT_THREADS
+struct cdft_arg_st {
+ int n0;
+ int n;
+ double *a;
+ int nw;
+ double *w;
+};
+typedef struct cdft_arg_st cdft_arg_t;
+
+
+void cftrec4_th(int n, double *a, int nw, double *w)
+{
+ void *cftrec1_th(void *p);
+ void *cftrec2_th(void *p);
+ int i, idiv4, m, nthread;
+ cdft_thread_t th[4];
+ cdft_arg_t ag[4];
+
+ nthread = 2;
+ idiv4 = 0;
+ m = n >> 1;
+ if (n > CDFT_4THREADS_BEGIN_N) {
+ nthread = 4;
+ idiv4 = 1;
+ m >>= 1;
+ }
+ for (i = 0; i < nthread; i++) {
+ ag[i].n0 = n;
+ ag[i].n = m;
+ ag[i].a = &a[i * m];
+ ag[i].nw = nw;
+ ag[i].w = w;
+ if (i != idiv4) {
+ cdft_thread_create(&th[i], cftrec1_th, &ag[i]);
+ } else {
+ cdft_thread_create(&th[i], cftrec2_th, &ag[i]);
+ }
+ }
+ for (i = 0; i < nthread; i++) {
+ cdft_thread_wait(th[i]);
+ }
+}
+
+
+void *cftrec1_th(void *p)
+{
+ int cfttree(int n, int j, int k, double *a, int nw, double *w);
+ void cftleaf(int n, int isplt, double *a, int nw, double *w);
+ void cftmdl1(int n, double *a, double *w);
+ int isplt, j, k, m, n, n0, nw;
+ double *a, *w;
+
+ n0 = ((cdft_arg_t *) p)->n0;
+ n = ((cdft_arg_t *) p)->n;
+ a = ((cdft_arg_t *) p)->a;
+ nw = ((cdft_arg_t *) p)->nw;
+ w = ((cdft_arg_t *) p)->w;
+ m = n0;
+ while (m > 512) {
+ m >>= 2;
+ cftmdl1(m, &a[n - m], &w[nw - (m >> 1)]);
+ }
+ cftleaf(m, 1, &a[n - m], nw, w);
+ k = 0;
+ for (j = n - m; j > 0; j -= m) {
+ k++;
+ isplt = cfttree(m, j, k, a, nw, w);
+ cftleaf(m, isplt, &a[j - m], nw, w);
+ }
+ return (void *) 0;
+}
+
+
+void *cftrec2_th(void *p)
+{
+ int cfttree(int n, int j, int k, double *a, int nw, double *w);
+ void cftleaf(int n, int isplt, double *a, int nw, double *w);
+ void cftmdl2(int n, double *a, double *w);
+ int isplt, j, k, m, n, n0, nw;
+ double *a, *w;
+
+ n0 = ((cdft_arg_t *) p)->n0;
+ n = ((cdft_arg_t *) p)->n;
+ a = ((cdft_arg_t *) p)->a;
+ nw = ((cdft_arg_t *) p)->nw;
+ w = ((cdft_arg_t *) p)->w;
+ k = 1;
+ m = n0;
+ while (m > 512) {
+ m >>= 2;
+ k <<= 2;
+ cftmdl2(m, &a[n - m], &w[nw - m]);
+ }
+ cftleaf(m, 0, &a[n - m], nw, w);
+ k >>= 1;
+ for (j = n - m; j > 0; j -= m) {
+ k++;
+ isplt = cfttree(m, j, k, a, nw, w);
+ cftleaf(m, isplt, &a[j - m], nw, w);
+ }
+ return (void *) 0;
+}
+#endif /* USE_CDFT_THREADS */
+
+
+void cftrec4(int n, double *a, int nw, double *w)
+{
+ int cfttree(int n, int j, int k, double *a, int nw, double *w);
+ void cftleaf(int n, int isplt, double *a, int nw, double *w);
+ void cftmdl1(int n, double *a, double *w);
+ int isplt, j, k, m;
+
+ m = n;
+ while (m > 512) {
+ m >>= 2;
+ cftmdl1(m, &a[n - m], &w[nw - (m >> 1)]);
+ }
+ cftleaf(m, 1, &a[n - m], nw, w);
+ k = 0;
+ for (j = n - m; j > 0; j -= m) {
+ k++;
+ isplt = cfttree(m, j, k, a, nw, w);
+ cftleaf(m, isplt, &a[j - m], nw, w);
+ }
+}
+
+
+int cfttree(int n, int j, int k, double *a, int nw, double *w)
+{
+ void cftmdl1(int n, double *a, double *w);
+ void cftmdl2(int n, double *a, double *w);
+ int i, isplt, m;
+
+ if ((k & 3) != 0) {
+ isplt = k & 1;
+ if (isplt != 0) {
+ cftmdl1(n, &a[j - n], &w[nw - (n >> 1)]);
+ } else {
+ cftmdl2(n, &a[j - n], &w[nw - n]);
+ }
+ } else {
+ m = n;
+ for (i = k; (i & 3) == 0; i >>= 2) {
+ m <<= 2;
+ }
+ isplt = i & 1;
+ if (isplt != 0) {
+ while (m > 128) {
+ cftmdl1(m, &a[j - m], &w[nw - (m >> 1)]);
+ m >>= 2;
+ }
+ } else {
+ while (m > 128) {
+ cftmdl2(m, &a[j - m], &w[nw - m]);
+ m >>= 2;
+ }
+ }
+ }
+ return isplt;
+}
+
+
+void cftleaf(int n, int isplt, double *a, int nw, double *w)
+{
+ void cftmdl1(int n, double *a, double *w);
+ void cftmdl2(int n, double *a, double *w);
+ void cftf161(double *a, double *w);
+ void cftf162(double *a, double *w);
+ void cftf081(double *a, double *w);
+ void cftf082(double *a, double *w);
+
+ if (n == 512) {
+ cftmdl1(128, a, &w[nw - 64]);
+ cftf161(a, &w[nw - 8]);
+ cftf162(&a[32], &w[nw - 32]);
+ cftf161(&a[64], &w[nw - 8]);
+ cftf161(&a[96], &w[nw - 8]);
+ cftmdl2(128, &a[128], &w[nw - 128]);
+ cftf161(&a[128], &w[nw - 8]);
+ cftf162(&a[160], &w[nw - 32]);
+ cftf161(&a[192], &w[nw - 8]);
+ cftf162(&a[224], &w[nw - 32]);
+ cftmdl1(128, &a[256], &w[nw - 64]);
+ cftf161(&a[256], &w[nw - 8]);
+ cftf162(&a[288], &w[nw - 32]);
+ cftf161(&a[320], &w[nw - 8]);
+ cftf161(&a[352], &w[nw - 8]);
+ if (isplt != 0) {
+ cftmdl1(128, &a[384], &w[nw - 64]);
+ cftf161(&a[480], &w[nw - 8]);
+ } else {
+ cftmdl2(128, &a[384], &w[nw - 128]);
+ cftf162(&a[480], &w[nw - 32]);
+ }
+ cftf161(&a[384], &w[nw - 8]);
+ cftf162(&a[416], &w[nw - 32]);
+ cftf161(&a[448], &w[nw - 8]);
+ } else {
+ cftmdl1(64, a, &w[nw - 32]);
+ cftf081(a, &w[nw - 8]);
+ cftf082(&a[16], &w[nw - 8]);
+ cftf081(&a[32], &w[nw - 8]);
+ cftf081(&a[48], &w[nw - 8]);
+ cftmdl2(64, &a[64], &w[nw - 64]);
+ cftf081(&a[64], &w[nw - 8]);
+ cftf082(&a[80], &w[nw - 8]);
+ cftf081(&a[96], &w[nw - 8]);
+ cftf082(&a[112], &w[nw - 8]);
+ cftmdl1(64, &a[128], &w[nw - 32]);
+ cftf081(&a[128], &w[nw - 8]);
+ cftf082(&a[144], &w[nw - 8]);
+ cftf081(&a[160], &w[nw - 8]);
+ cftf081(&a[176], &w[nw - 8]);
+ if (isplt != 0) {
+ cftmdl1(64, &a[192], &w[nw - 32]);
+ cftf081(&a[240], &w[nw - 8]);
+ } else {
+ cftmdl2(64, &a[192], &w[nw - 64]);
+ cftf082(&a[240], &w[nw - 8]);
+ }
+ cftf081(&a[192], &w[nw - 8]);
+ cftf082(&a[208], &w[nw - 8]);
+ cftf081(&a[224], &w[nw - 8]);
+ }
+}
+
+
+void cftmdl1(int n, double *a, double *w)
+{
+ int j, j0, j1, j2, j3, k, m, mh;
+ double wn4r, wk1r, wk1i, wk3r, wk3i;
+ double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+ mh = n >> 3;
+ m = 2 * mh;
+ j1 = m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[0] + a[j2];
+ x0i = a[1] + a[j2 + 1];
+ x1r = a[0] - a[j2];
+ x1i = a[1] - a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[0] = x0r + x2r;
+ a[1] = x0i + x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ a[j2] = x1r - x3i;
+ a[j2 + 1] = x1i + x3r;
+ a[j3] = x1r + x3i;
+ a[j3 + 1] = x1i - x3r;
+ wn4r = w[1];
+ k = 0;
+ for (j = 2; j < mh; j += 2) {
+ k += 4;
+ wk1r = w[k];
+ wk1i = w[k + 1];
+ wk3r = w[k + 2];
+ wk3i = w[k + 3];
+ j1 = j + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j] + a[j2];
+ x0i = a[j + 1] + a[j2 + 1];
+ x1r = a[j] - a[j2];
+ x1i = a[j + 1] - a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i + x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2] = wk1r * x0r - wk1i * x0i;
+ a[j2 + 1] = wk1r * x0i + wk1i * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3r * x0r + wk3i * x0i;
+ a[j3 + 1] = wk3r * x0i - wk3i * x0r;
+ j0 = m - j;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0] + a[j2];
+ x0i = a[j0 + 1] + a[j2 + 1];
+ x1r = a[j0] - a[j2];
+ x1i = a[j0 + 1] - a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[j0] = x0r + x2r;
+ a[j0 + 1] = x0i + x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2] = wk1i * x0r - wk1r * x0i;
+ a[j2 + 1] = wk1i * x0i + wk1r * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3i * x0r + wk3r * x0i;
+ a[j3 + 1] = wk3i * x0i - wk3r * x0r;
+ }
+ j0 = mh;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0] + a[j2];
+ x0i = a[j0 + 1] + a[j2 + 1];
+ x1r = a[j0] - a[j2];
+ x1i = a[j0 + 1] - a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[j0] = x0r + x2r;
+ a[j0 + 1] = x0i + x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2] = wn4r * (x0r - x0i);
+ a[j2 + 1] = wn4r * (x0i + x0r);
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = -wn4r * (x0r + x0i);
+ a[j3 + 1] = -wn4r * (x0i - x0r);
+}
+
+
+void cftmdl2(int n, double *a, double *w)
+{
+ int j, j0, j1, j2, j3, k, kr, m, mh;
+ double wn4r, wk1r, wk1i, wk3r, wk3i, wd1r, wd1i, wd3r, wd3i;
+ double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, y0r, y0i, y2r, y2i;
+
+ mh = n >> 3;
+ m = 2 * mh;
+ wn4r = w[1];
+ j1 = m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[0] - a[j2 + 1];
+ x0i = a[1] + a[j2];
+ x1r = a[0] + a[j2 + 1];
+ x1i = a[1] - a[j2];
+ x2r = a[j1] - a[j3 + 1];
+ x2i = a[j1 + 1] + a[j3];
+ x3r = a[j1] + a[j3 + 1];
+ x3i = a[j1 + 1] - a[j3];
+ y0r = wn4r * (x2r - x2i);
+ y0i = wn4r * (x2i + x2r);
+ a[0] = x0r + y0r;
+ a[1] = x0i + y0i;
+ a[j1] = x0r - y0r;
+ a[j1 + 1] = x0i - y0i;
+ y0r = wn4r * (x3r - x3i);
+ y0i = wn4r * (x3i + x3r);
+ a[j2] = x1r - y0i;
+ a[j2 + 1] = x1i + y0r;
+ a[j3] = x1r + y0i;
+ a[j3 + 1] = x1i - y0r;
+ k = 0;
+ kr = 2 * m;
+ for (j = 2; j < mh; j += 2) {
+ k += 4;
+ wk1r = w[k];
+ wk1i = w[k + 1];
+ wk3r = w[k + 2];
+ wk3i = w[k + 3];
+ kr -= 4;
+ wd1i = w[kr];
+ wd1r = w[kr + 1];
+ wd3i = w[kr + 2];
+ wd3r = w[kr + 3];
+ j1 = j + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j] - a[j2 + 1];
+ x0i = a[j + 1] + a[j2];
+ x1r = a[j] + a[j2 + 1];
+ x1i = a[j + 1] - a[j2];
+ x2r = a[j1] - a[j3 + 1];
+ x2i = a[j1 + 1] + a[j3];
+ x3r = a[j1] + a[j3 + 1];
+ x3i = a[j1 + 1] - a[j3];
+ y0r = wk1r * x0r - wk1i * x0i;
+ y0i = wk1r * x0i + wk1i * x0r;
+ y2r = wd1r * x2r - wd1i * x2i;
+ y2i = wd1r * x2i + wd1i * x2r;
+ a[j] = y0r + y2r;
+ a[j + 1] = y0i + y2i;
+ a[j1] = y0r - y2r;
+ a[j1 + 1] = y0i - y2i;
+ y0r = wk3r * x1r + wk3i * x1i;
+ y0i = wk3r * x1i - wk3i * x1r;
+ y2r = wd3r * x3r + wd3i * x3i;
+ y2i = wd3r * x3i - wd3i * x3r;
+ a[j2] = y0r + y2r;
+ a[j2 + 1] = y0i + y2i;
+ a[j3] = y0r - y2r;
+ a[j3 + 1] = y0i - y2i;
+ j0 = m - j;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0] - a[j2 + 1];
+ x0i = a[j0 + 1] + a[j2];
+ x1r = a[j0] + a[j2 + 1];
+ x1i = a[j0 + 1] - a[j2];
+ x2r = a[j1] - a[j3 + 1];
+ x2i = a[j1 + 1] + a[j3];
+ x3r = a[j1] + a[j3 + 1];
+ x3i = a[j1 + 1] - a[j3];
+ y0r = wd1i * x0r - wd1r * x0i;
+ y0i = wd1i * x0i + wd1r * x0r;
+ y2r = wk1i * x2r - wk1r * x2i;
+ y2i = wk1i * x2i + wk1r * x2r;
+ a[j0] = y0r + y2r;
+ a[j0 + 1] = y0i + y2i;
+ a[j1] = y0r - y2r;
+ a[j1 + 1] = y0i - y2i;
+ y0r = wd3i * x1r + wd3r * x1i;
+ y0i = wd3i * x1i - wd3r * x1r;
+ y2r = wk3i * x3r + wk3r * x3i;
+ y2i = wk3i * x3i - wk3r * x3r;
+ a[j2] = y0r + y2r;
+ a[j2 + 1] = y0i + y2i;
+ a[j3] = y0r - y2r;
+ a[j3 + 1] = y0i - y2i;
+ }
+ wk1r = w[m];
+ wk1i = w[m + 1];
+ j0 = mh;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0] - a[j2 + 1];
+ x0i = a[j0 + 1] + a[j2];
+ x1r = a[j0] + a[j2 + 1];
+ x1i = a[j0 + 1] - a[j2];
+ x2r = a[j1] - a[j3 + 1];
+ x2i = a[j1 + 1] + a[j3];
+ x3r = a[j1] + a[j3 + 1];
+ x3i = a[j1 + 1] - a[j3];
+ y0r = wk1r * x0r - wk1i * x0i;
+ y0i = wk1r * x0i + wk1i * x0r;
+ y2r = wk1i * x2r - wk1r * x2i;
+ y2i = wk1i * x2i + wk1r * x2r;
+ a[j0] = y0r + y2r;
+ a[j0 + 1] = y0i + y2i;
+ a[j1] = y0r - y2r;
+ a[j1 + 1] = y0i - y2i;
+ y0r = wk1i * x1r - wk1r * x1i;
+ y0i = wk1i * x1i + wk1r * x1r;
+ y2r = wk1r * x3r - wk1i * x3i;
+ y2i = wk1r * x3i + wk1i * x3r;
+ a[j2] = y0r - y2r;
+ a[j2 + 1] = y0i - y2i;
+ a[j3] = y0r + y2r;
+ a[j3 + 1] = y0i + y2i;
+}
+
+
+void cftfx41(int n, double *a, int nw, double *w)
+{
+ void cftf161(double *a, double *w);
+ void cftf162(double *a, double *w);
+ void cftf081(double *a, double *w);
+ void cftf082(double *a, double *w);
+
+ if (n == 128) {
+ cftf161(a, &w[nw - 8]);
+ cftf162(&a[32], &w[nw - 32]);
+ cftf161(&a[64], &w[nw - 8]);
+ cftf161(&a[96], &w[nw - 8]);
+ } else {
+ cftf081(a, &w[nw - 8]);
+ cftf082(&a[16], &w[nw - 8]);
+ cftf081(&a[32], &w[nw - 8]);
+ cftf081(&a[48], &w[nw - 8]);
+ }
+}
+
+
+void cftf161(double *a, double *w)
+{
+ double wn4r, wk1r, wk1i,
+ x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i,
+ y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i,
+ y8r, y8i, y9r, y9i, y10r, y10i, y11r, y11i,
+ y12r, y12i, y13r, y13i, y14r, y14i, y15r, y15i;
+
+ wn4r = w[1];
+ wk1r = w[2];
+ wk1i = w[3];
+ x0r = a[0] + a[16];
+ x0i = a[1] + a[17];
+ x1r = a[0] - a[16];
+ x1i = a[1] - a[17];
+ x2r = a[8] + a[24];
+ x2i = a[9] + a[25];
+ x3r = a[8] - a[24];
+ x3i = a[9] - a[25];
+ y0r = x0r + x2r;
+ y0i = x0i + x2i;
+ y4r = x0r - x2r;
+ y4i = x0i - x2i;
+ y8r = x1r - x3i;
+ y8i = x1i + x3r;
+ y12r = x1r + x3i;
+ y12i = x1i - x3r;
+ x0r = a[2] + a[18];
+ x0i = a[3] + a[19];
+ x1r = a[2] - a[18];
+ x1i = a[3] - a[19];
+ x2r = a[10] + a[26];
+ x2i = a[11] + a[27];
+ x3r = a[10] - a[26];
+ x3i = a[11] - a[27];
+ y1r = x0r + x2r;
+ y1i = x0i + x2i;
+ y5r = x0r - x2r;
+ y5i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ y9r = wk1r * x0r - wk1i * x0i;
+ y9i = wk1r * x0i + wk1i * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ y13r = wk1i * x0r - wk1r * x0i;
+ y13i = wk1i * x0i + wk1r * x0r;
+ x0r = a[4] + a[20];
+ x0i = a[5] + a[21];
+ x1r = a[4] - a[20];
+ x1i = a[5] - a[21];
+ x2r = a[12] + a[28];
+ x2i = a[13] + a[29];
+ x3r = a[12] - a[28];
+ x3i = a[13] - a[29];
+ y2r = x0r + x2r;
+ y2i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ y10r = wn4r * (x0r - x0i);
+ y10i = wn4r * (x0i + x0r);
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ y14r = wn4r * (x0r + x0i);
+ y14i = wn4r * (x0i - x0r);
+ x0r = a[6] + a[22];
+ x0i = a[7] + a[23];
+ x1r = a[6] - a[22];
+ x1i = a[7] - a[23];
+ x2r = a[14] + a[30];
+ x2i = a[15] + a[31];
+ x3r = a[14] - a[30];
+ x3i = a[15] - a[31];
+ y3r = x0r + x2r;
+ y3i = x0i + x2i;
+ y7r = x0r - x2r;
+ y7i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ y11r = wk1i * x0r - wk1r * x0i;
+ y11i = wk1i * x0i + wk1r * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ y15r = wk1r * x0r - wk1i * x0i;
+ y15i = wk1r * x0i + wk1i * x0r;
+ x0r = y12r - y14r;
+ x0i = y12i - y14i;
+ x1r = y12r + y14r;
+ x1i = y12i + y14i;
+ x2r = y13r - y15r;
+ x2i = y13i - y15i;
+ x3r = y13r + y15r;
+ x3i = y13i + y15i;
+ a[24] = x0r + x2r;
+ a[25] = x0i + x2i;
+ a[26] = x0r - x2r;
+ a[27] = x0i - x2i;
+ a[28] = x1r - x3i;
+ a[29] = x1i + x3r;
+ a[30] = x1r + x3i;
+ a[31] = x1i - x3r;
+ x0r = y8r + y10r;
+ x0i = y8i + y10i;
+ x1r = y8r - y10r;
+ x1i = y8i - y10i;
+ x2r = y9r + y11r;
+ x2i = y9i + y11i;
+ x3r = y9r - y11r;
+ x3i = y9i - y11i;
+ a[16] = x0r + x2r;
+ a[17] = x0i + x2i;
+ a[18] = x0r - x2r;
+ a[19] = x0i - x2i;
+ a[20] = x1r - x3i;
+ a[21] = x1i + x3r;
+ a[22] = x1r + x3i;
+ a[23] = x1i - x3r;
+ x0r = y5r - y7i;
+ x0i = y5i + y7r;
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ x0r = y5r + y7i;
+ x0i = y5i - y7r;
+ x3r = wn4r * (x0r - x0i);
+ x3i = wn4r * (x0i + x0r);
+ x0r = y4r - y6i;
+ x0i = y4i + y6r;
+ x1r = y4r + y6i;
+ x1i = y4i - y6r;
+ a[8] = x0r + x2r;
+ a[9] = x0i + x2i;
+ a[10] = x0r - x2r;
+ a[11] = x0i - x2i;
+ a[12] = x1r - x3i;
+ a[13] = x1i + x3r;
+ a[14] = x1r + x3i;
+ a[15] = x1i - x3r;
+ x0r = y0r + y2r;
+ x0i = y0i + y2i;
+ x1r = y0r - y2r;
+ x1i = y0i - y2i;
+ x2r = y1r + y3r;
+ x2i = y1i + y3i;
+ x3r = y1r - y3r;
+ x3i = y1i - y3i;
+ a[0] = x0r + x2r;
+ a[1] = x0i + x2i;
+ a[2] = x0r - x2r;
+ a[3] = x0i - x2i;
+ a[4] = x1r - x3i;
+ a[5] = x1i + x3r;
+ a[6] = x1r + x3i;
+ a[7] = x1i - x3r;
+}
+
+
+void cftf162(double *a, double *w)
+{
+ double wn4r, wk1r, wk1i, wk2r, wk2i, wk3r, wk3i,
+ x0r, x0i, x1r, x1i, x2r, x2i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i,
+ y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i,
+ y8r, y8i, y9r, y9i, y10r, y10i, y11r, y11i,
+ y12r, y12i, y13r, y13i, y14r, y14i, y15r, y15i;
+
+ wn4r = w[1];
+ wk1r = w[4];
+ wk1i = w[5];
+ wk3r = w[6];
+ wk3i = -w[7];
+ wk2r = w[8];
+ wk2i = w[9];
+ x1r = a[0] - a[17];
+ x1i = a[1] + a[16];
+ x0r = a[8] - a[25];
+ x0i = a[9] + a[24];
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ y0r = x1r + x2r;
+ y0i = x1i + x2i;
+ y4r = x1r - x2r;
+ y4i = x1i - x2i;
+ x1r = a[0] + a[17];
+ x1i = a[1] - a[16];
+ x0r = a[8] + a[25];
+ x0i = a[9] - a[24];
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ y8r = x1r - x2i;
+ y8i = x1i + x2r;
+ y12r = x1r + x2i;
+ y12i = x1i - x2r;
+ x0r = a[2] - a[19];
+ x0i = a[3] + a[18];
+ x1r = wk1r * x0r - wk1i * x0i;
+ x1i = wk1r * x0i + wk1i * x0r;
+ x0r = a[10] - a[27];
+ x0i = a[11] + a[26];
+ x2r = wk3i * x0r - wk3r * x0i;
+ x2i = wk3i * x0i + wk3r * x0r;
+ y1r = x1r + x2r;
+ y1i = x1i + x2i;
+ y5r = x1r - x2r;
+ y5i = x1i - x2i;
+ x0r = a[2] + a[19];
+ x0i = a[3] - a[18];
+ x1r = wk3r * x0r - wk3i * x0i;
+ x1i = wk3r * x0i + wk3i * x0r;
+ x0r = a[10] + a[27];
+ x0i = a[11] - a[26];
+ x2r = wk1r * x0r + wk1i * x0i;
+ x2i = wk1r * x0i - wk1i * x0r;
+ y9r = x1r - x2r;
+ y9i = x1i - x2i;
+ y13r = x1r + x2r;
+ y13i = x1i + x2i;
+ x0r = a[4] - a[21];
+ x0i = a[5] + a[20];
+ x1r = wk2r * x0r - wk2i * x0i;
+ x1i = wk2r * x0i + wk2i * x0r;
+ x0r = a[12] - a[29];
+ x0i = a[13] + a[28];
+ x2r = wk2i * x0r - wk2r * x0i;
+ x2i = wk2i * x0i + wk2r * x0r;
+ y2r = x1r + x2r;
+ y2i = x1i + x2i;
+ y6r = x1r - x2r;
+ y6i = x1i - x2i;
+ x0r = a[4] + a[21];
+ x0i = a[5] - a[20];
+ x1r = wk2i * x0r - wk2r * x0i;
+ x1i = wk2i * x0i + wk2r * x0r;
+ x0r = a[12] + a[29];
+ x0i = a[13] - a[28];
+ x2r = wk2r * x0r - wk2i * x0i;
+ x2i = wk2r * x0i + wk2i * x0r;
+ y10r = x1r - x2r;
+ y10i = x1i - x2i;
+ y14r = x1r + x2r;
+ y14i = x1i + x2i;
+ x0r = a[6] - a[23];
+ x0i = a[7] + a[22];
+ x1r = wk3r * x0r - wk3i * x0i;
+ x1i = wk3r * x0i + wk3i * x0r;
+ x0r = a[14] - a[31];
+ x0i = a[15] + a[30];
+ x2r = wk1i * x0r - wk1r * x0i;
+ x2i = wk1i * x0i + wk1r * x0r;
+ y3r = x1r + x2r;
+ y3i = x1i + x2i;
+ y7r = x1r - x2r;
+ y7i = x1i - x2i;
+ x0r = a[6] + a[23];
+ x0i = a[7] - a[22];
+ x1r = wk1i * x0r + wk1r * x0i;
+ x1i = wk1i * x0i - wk1r * x0r;
+ x0r = a[14] + a[31];
+ x0i = a[15] - a[30];
+ x2r = wk3i * x0r - wk3r * x0i;
+ x2i = wk3i * x0i + wk3r * x0r;
+ y11r = x1r + x2r;
+ y11i = x1i + x2i;
+ y15r = x1r - x2r;
+ y15i = x1i - x2i;
+ x1r = y0r + y2r;
+ x1i = y0i + y2i;
+ x2r = y1r + y3r;
+ x2i = y1i + y3i;
+ a[0] = x1r + x2r;
+ a[1] = x1i + x2i;
+ a[2] = x1r - x2r;
+ a[3] = x1i - x2i;
+ x1r = y0r - y2r;
+ x1i = y0i - y2i;
+ x2r = y1r - y3r;
+ x2i = y1i - y3i;
+ a[4] = x1r - x2i;
+ a[5] = x1i + x2r;
+ a[6] = x1r + x2i;
+ a[7] = x1i - x2r;
+ x1r = y4r - y6i;
+ x1i = y4i + y6r;
+ x0r = y5r - y7i;
+ x0i = y5i + y7r;
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ a[8] = x1r + x2r;
+ a[9] = x1i + x2i;
+ a[10] = x1r - x2r;
+ a[11] = x1i - x2i;
+ x1r = y4r + y6i;
+ x1i = y4i - y6r;
+ x0r = y5r + y7i;
+ x0i = y5i - y7r;
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ a[12] = x1r - x2i;
+ a[13] = x1i + x2r;
+ a[14] = x1r + x2i;
+ a[15] = x1i - x2r;
+ x1r = y8r + y10r;
+ x1i = y8i + y10i;
+ x2r = y9r - y11r;
+ x2i = y9i - y11i;
+ a[16] = x1r + x2r;
+ a[17] = x1i + x2i;
+ a[18] = x1r - x2r;
+ a[19] = x1i - x2i;
+ x1r = y8r - y10r;
+ x1i = y8i - y10i;
+ x2r = y9r + y11r;
+ x2i = y9i + y11i;
+ a[20] = x1r - x2i;
+ a[21] = x1i + x2r;
+ a[22] = x1r + x2i;
+ a[23] = x1i - x2r;
+ x1r = y12r - y14i;
+ x1i = y12i + y14r;
+ x0r = y13r + y15i;
+ x0i = y13i - y15r;
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ a[24] = x1r + x2r;
+ a[25] = x1i + x2i;
+ a[26] = x1r - x2r;
+ a[27] = x1i - x2i;
+ x1r = y12r + y14i;
+ x1i = y12i - y14r;
+ x0r = y13r - y15i;
+ x0i = y13i + y15r;
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ a[28] = x1r - x2i;
+ a[29] = x1i + x2r;
+ a[30] = x1r + x2i;
+ a[31] = x1i - x2r;
+}
+
+
+void cftf081(double *a, double *w)
+{
+ double wn4r, x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i,
+ y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i;
+
+ wn4r = w[1];
+ x0r = a[0] + a[8];
+ x0i = a[1] + a[9];
+ x1r = a[0] - a[8];
+ x1i = a[1] - a[9];
+ x2r = a[4] + a[12];
+ x2i = a[5] + a[13];
+ x3r = a[4] - a[12];
+ x3i = a[5] - a[13];
+ y0r = x0r + x2r;
+ y0i = x0i + x2i;
+ y2r = x0r - x2r;
+ y2i = x0i - x2i;
+ y1r = x1r - x3i;
+ y1i = x1i + x3r;
+ y3r = x1r + x3i;
+ y3i = x1i - x3r;
+ x0r = a[2] + a[10];
+ x0i = a[3] + a[11];
+ x1r = a[2] - a[10];
+ x1i = a[3] - a[11];
+ x2r = a[6] + a[14];
+ x2i = a[7] + a[15];
+ x3r = a[6] - a[14];
+ x3i = a[7] - a[15];
+ y4r = x0r + x2r;
+ y4i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ x2r = x1r + x3i;
+ x2i = x1i - x3r;
+ y5r = wn4r * (x0r - x0i);
+ y5i = wn4r * (x0r + x0i);
+ y7r = wn4r * (x2r - x2i);
+ y7i = wn4r * (x2r + x2i);
+ a[8] = y1r + y5r;
+ a[9] = y1i + y5i;
+ a[10] = y1r - y5r;
+ a[11] = y1i - y5i;
+ a[12] = y3r - y7i;
+ a[13] = y3i + y7r;
+ a[14] = y3r + y7i;
+ a[15] = y3i - y7r;
+ a[0] = y0r + y4r;
+ a[1] = y0i + y4i;
+ a[2] = y0r - y4r;
+ a[3] = y0i - y4i;
+ a[4] = y2r - y6i;
+ a[5] = y2i + y6r;
+ a[6] = y2r + y6i;
+ a[7] = y2i - y6r;
+}
+
+
+void cftf082(double *a, double *w)
+{
+ double wn4r, wk1r, wk1i, x0r, x0i, x1r, x1i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i,
+ y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i;
+
+ wn4r = w[1];
+ wk1r = w[2];
+ wk1i = w[3];
+ y0r = a[0] - a[9];
+ y0i = a[1] + a[8];
+ y1r = a[0] + a[9];
+ y1i = a[1] - a[8];
+ x0r = a[4] - a[13];
+ x0i = a[5] + a[12];
+ y2r = wn4r * (x0r - x0i);
+ y2i = wn4r * (x0i + x0r);
+ x0r = a[4] + a[13];
+ x0i = a[5] - a[12];
+ y3r = wn4r * (x0r - x0i);
+ y3i = wn4r * (x0i + x0r);
+ x0r = a[2] - a[11];
+ x0i = a[3] + a[10];
+ y4r = wk1r * x0r - wk1i * x0i;
+ y4i = wk1r * x0i + wk1i * x0r;
+ x0r = a[2] + a[11];
+ x0i = a[3] - a[10];
+ y5r = wk1i * x0r - wk1r * x0i;
+ y5i = wk1i * x0i + wk1r * x0r;
+ x0r = a[6] - a[15];
+ x0i = a[7] + a[14];
+ y6r = wk1i * x0r - wk1r * x0i;
+ y6i = wk1i * x0i + wk1r * x0r;
+ x0r = a[6] + a[15];
+ x0i = a[7] - a[14];
+ y7r = wk1r * x0r - wk1i * x0i;
+ y7i = wk1r * x0i + wk1i * x0r;
+ x0r = y0r + y2r;
+ x0i = y0i + y2i;
+ x1r = y4r + y6r;
+ x1i = y4i + y6i;
+ a[0] = x0r + x1r;
+ a[1] = x0i + x1i;
+ a[2] = x0r - x1r;
+ a[3] = x0i - x1i;
+ x0r = y0r - y2r;
+ x0i = y0i - y2i;
+ x1r = y4r - y6r;
+ x1i = y4i - y6i;
+ a[4] = x0r - x1i;
+ a[5] = x0i + x1r;
+ a[6] = x0r + x1i;
+ a[7] = x0i - x1r;
+ x0r = y1r - y3i;
+ x0i = y1i + y3r;
+ x1r = y5r - y7r;
+ x1i = y5i - y7i;
+ a[8] = x0r + x1r;
+ a[9] = x0i + x1i;
+ a[10] = x0r - x1r;
+ a[11] = x0i - x1i;
+ x0r = y1r + y3i;
+ x0i = y1i - y3r;
+ x1r = y5r + y7r;
+ x1i = y5i + y7i;
+ a[12] = x0r - x1i;
+ a[13] = x0i + x1r;
+ a[14] = x0r + x1i;
+ a[15] = x0i - x1r;
+}
+
+
+void cftf040(double *a)
+{
+ double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+ x0r = a[0] + a[4];
+ x0i = a[1] + a[5];
+ x1r = a[0] - a[4];
+ x1i = a[1] - a[5];
+ x2r = a[2] + a[6];
+ x2i = a[3] + a[7];
+ x3r = a[2] - a[6];
+ x3i = a[3] - a[7];
+ a[0] = x0r + x2r;
+ a[1] = x0i + x2i;
+ a[2] = x1r - x3i;
+ a[3] = x1i + x3r;
+ a[4] = x0r - x2r;
+ a[5] = x0i - x2i;
+ a[6] = x1r + x3i;
+ a[7] = x1i - x3r;
+}
+
+
+void cftb040(double *a)
+{
+ double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+ x0r = a[0] + a[4];
+ x0i = a[1] + a[5];
+ x1r = a[0] - a[4];
+ x1i = a[1] - a[5];
+ x2r = a[2] + a[6];
+ x2i = a[3] + a[7];
+ x3r = a[2] - a[6];
+ x3i = a[3] - a[7];
+ a[0] = x0r + x2r;
+ a[1] = x0i + x2i;
+ a[2] = x1r + x3i;
+ a[3] = x1i - x3r;
+ a[4] = x0r - x2r;
+ a[5] = x0i - x2i;
+ a[6] = x1r - x3i;
+ a[7] = x1i + x3r;
+}
+
+
+void cftx020(double *a)
+{
+ double x0r, x0i;
+
+ x0r = a[0] - a[2];
+ x0i = a[1] - a[3];
+ a[0] += a[2];
+ a[1] += a[3];
+ a[2] = x0r;
+ a[3] = x0i;
+}
+
+
+void rftfsub(int n, double *a, int nc, double *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;
+ }
+}
+
+
+void rftbsub(int n, double *a, int nc, double *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;
+ }
+}
+
+
+void dctsub(int n, double *a, int nc, double *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];
+}
+
+
+void dstsub(int n, double *a, int nc, double *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/plugins/supereq/nsfft-1.00/ooura/pi_fft.c b/plugins/supereq/nsfft-1.00/ooura/pi_fft.c
new file mode 100644
index 00000000..c9a76bf8
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/ooura/pi_fft.c
@@ -0,0 +1,1616 @@
+/*
+---- calculation of PI(= 3.14159...) using FFT ----
+ by T.Ooura, ver. LG1.1.2-MP1.5a Sep. 2001.
+
+This is a test program to estimate the performance of
+the FFT routines: fft*g.c.
+
+Example compilation:
+ GNU : gcc -O6 -ffast-math pi_fft.c fftsg.c -lm -o pi_fftsg
+ SUN : cc -fast -xO5 pi_fft.c fft8g.c -lm -o pi_fft8g
+ Microsoft: cl /O2 /G6 pi_fft.c fft4g.c /Fepi_fft4g.exe
+ ...
+ etc.
+*/
+
+/* Please check the following macros before compiling */
+#ifndef DBL_ERROR_MARGIN
+#define DBL_ERROR_MARGIN 0.3 /* must be < 0.5 */
+#endif
+
+
+#include <math.h>
+#include <limits.h>
+#include <float.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+
+void mp_load_0(int n, int radix, int out[]);
+void mp_load_1(int n, int radix, int out[]);
+void mp_copy(int n, int radix, int in[], int out[]);
+void mp_round(int n, int radix, int m, int inout[]);
+int mp_cmp(int n, int radix, int in1[], int in2[]);
+void mp_add(int n, int radix, int in1[], int in2[], int out[]);
+void mp_sub(int n, int radix, int in1[], int in2[], int out[]);
+void mp_imul(int n, int radix, int in1[], int in2, int out[]);
+int mp_idiv(int n, int radix, int in1[], int in2, int out[]);
+void mp_idiv_2(int n, int radix, int in[], int out[]);
+double mp_mul_radix_test(int n, int radix, int nfft,
+ double tmpfft[], int ip[], double w[]);
+void mp_mul(int n, int radix, int in1[], int in2[], int out[],
+ int tmp[], int nfft, double tmp1fft[], double tmp2fft[],
+ double tmp3fft[], int ip[], double w[]);
+void mp_squ(int n, int radix, int in[], int out[], int tmp[],
+ int nfft, double tmp1fft[], double tmp2fft[],
+ int ip[], double w[]);
+void mp_mulh(int n, int radix, int in1[], int in2[], int out[],
+ int nfft, double in1fft[], double outfft[],
+ int ip[], double w[]);
+void mp_squh(int n, int radix, int in[], int out[],
+ int nfft, double inoutfft[], int ip[], double w[]);
+int mp_inv(int n, int radix, int in[], int out[],
+ int tmp1[], int tmp2[], int nfft,
+ double tmp1fft[], double tmp2fft[], int ip[], double w[]);
+int mp_sqrt(int n, int radix, int in[], int out[],
+ int tmp1[], int tmp2[], int nfft,
+ double tmp1fft[], double tmp2fft[], int ip[], double w[]);
+void mp_sprintf(int n, int log10_radix, int in[], char out[]);
+void mp_sscanf(int n, int log10_radix, char in[], int out[]);
+void mp_fprintf(int n, int log10_radix, int in[], FILE *fout);
+
+
+int main()
+{
+ int nfft, log2_nfft, radix, log10_radix, n, npow, nprc;
+ double err, d_time, n_op;
+ int *a, *b, *c, *e, *i1, *i2, *ip;
+ double *d1, *d2, *d3, *w;
+ time_t t_1, t_2;
+ FILE *f_log, *f_out;
+
+ f_log = fopen("pi.log", "w");
+ printf("PI calculation to estimate the FFT benchmarks\n");
+ fprintf(f_log, "PI calculation to estimate the FFT benchmarks\n");
+ printf("length of FFT =?\n");
+ scanf("%d", &nfft);
+
+ printf("initializing...\n");
+ for (log2_nfft = 1; (1 << log2_nfft) < nfft; log2_nfft++);
+ nfft = 1 << log2_nfft;
+ n = nfft + 2;
+ ip = (int *) malloc((3 + (int) sqrt(0.5 * nfft)) * sizeof(int));
+ w = (double *) malloc(nfft / 2 * sizeof(double));
+ a = (int *) malloc((n + 2) * sizeof(int));
+ b = (int *) malloc((n + 2) * sizeof(int));
+ c = (int *) malloc((n + 2) * sizeof(int));
+ e = (int *) malloc((n + 2) * sizeof(int));
+ i1 = (int *) malloc((n + 2) * sizeof(int));
+ i2 = (int *) malloc((n + 2) * sizeof(int));
+ d1 = (double *) malloc((nfft + 2) * sizeof(double));
+ d2 = (double *) malloc((nfft + 2) * sizeof(double));
+ d3 = (double *) malloc((nfft + 2) * sizeof(double));
+ if (d3 == NULL) {
+ printf("Allocation Failure!\n");
+ exit(1);
+ }
+ ip[0] = 0;
+ /* ---- radix test ---- */
+ log10_radix = 1;
+ radix = 10;
+ err = mp_mul_radix_test(n, radix, nfft, d1, ip, w);
+ err += DBL_EPSILON * (n * radix * radix / 4);
+ while (100 * err < DBL_ERROR_MARGIN && radix <= INT_MAX / 20) {
+ err *= 100;
+ log10_radix++;
+ radix *= 10;
+ }
+ printf("nfft= %d\nradix= %d\nerror_margin= %g\n", nfft, radix, err);
+ fprintf(f_log, "nfft= %d\nradix= %d\nerror_margin= %g\n", nfft, radix, err);
+ printf("calculating %d digits of PI...\n", log10_radix * (n - 2));
+ fprintf(f_log, "calculating %d digits of PI...\n", log10_radix * (n - 2));
+ /* ---- time check ---- */
+ time(&t_1);
+ /*
+ * ---- a formula based on the AGM (Arithmetic-Geometric Mean) ----
+ * c = sqrt(0.125);
+ * a = 1 + 3 * c;
+ * b = sqrt(a);
+ * e = b - 0.625;
+ * b = 2 * b;
+ * c = e - c;
+ * a = a + e;
+ * npow = 4;
+ * do {
+ * npow = 2 * npow;
+ * e = (a + b) / 2;
+ * b = sqrt(a * b);
+ * e = e - b;
+ * b = 2 * b;
+ * c = c - e;
+ * a = e + b;
+ * } while (e > SQRT_SQRT_EPSILON);
+ * e = e * e / 4;
+ * a = a + b;
+ * pi = (a * a - e - e / 2) / (a * c - e) / npow;
+ * ---- modification ----
+ * This is a modified version of Gauss-Legendre formula
+ * (by T.Ooura). It is faster than original version.
+ * ---- reference ----
+ * 1. E.Salamin,
+ * Computation of PI Using Arithmetic-Geometric Mean,
+ * Mathematics of Computation, Vol.30 1976.
+ * 2. R.P.Brent,
+ * Fast Multiple-Precision Evaluation of Elementary Functions,
+ * J. ACM 23 1976.
+ * 3. D.Takahasi, Y.Kanada,
+ * Calculation of PI to 51.5 Billion Decimal Digits on
+ * Distributed Memoriy Parallel Processors,
+ * Transactions of Information Processing Society of Japan,
+ * Vol.39 No.7 1998.
+ * 4. T.Ooura,
+ * Improvement of the PI Calculation Algorithm and
+ * Implementation of Fast Multiple-Precision Computation,
+ * Information Processing Society of Japan SIG Notes,
+ * 98-HPC-74, 1998.
+ */
+ /* ---- c = sqrt(0.125) ---- */
+ mp_sscanf(n, log10_radix, "0.125", a);
+ mp_sqrt(n, radix, a, c, i1, i2, nfft, d1, d2, ip, w);
+ /* ---- a = 1 + 3 * c ---- */
+ mp_imul(n, radix, c, 3, e);
+ mp_sscanf(n, log10_radix, "1", a);
+ mp_add(n, radix, a, e, a);
+ /* ---- b = sqrt(a) ---- */
+ mp_sqrt(n, radix, a, b, i1, i2, nfft, d1, d2, ip, w);
+ /* ---- e = b - 0.625 ---- */
+ mp_sscanf(n, log10_radix, "0.625", e);
+ mp_sub(n, radix, b, e, e);
+ /* ---- b = 2 * b ---- */
+ mp_add(n, radix, b, b, b);
+ /* ---- c = e - c ---- */
+ mp_sub(n, radix, e, c, c);
+ /* ---- a = a + e ---- */
+ mp_add(n, radix, a, e, a);
+ printf("AGM iteration\n");
+ fprintf(f_log, "AGM iteration\n");
+ npow = 4;
+ do {
+ npow *= 2;
+ /* ---- e = (a + b) / 2 ---- */
+ mp_add(n, radix, a, b, e);
+ mp_idiv_2(n, radix, e, e);
+ /* ---- b = sqrt(a * b) ---- */
+ mp_mul(n, radix, a, b, a, i1, nfft, d1, d2, d3, ip, w);
+ mp_sqrt(n, radix, a, b, i1, i2, nfft, d1, d2, ip, w);
+ /* ---- e = e - b ---- */
+ mp_sub(n, radix, e, b, e);
+ /* ---- b = 2 * b ---- */
+ mp_add(n, radix, b, b, b);
+ /* ---- c = c - e ---- */
+ mp_sub(n, radix, c, e, c);
+ /* ---- a = e + b ---- */
+ mp_add(n, radix, e, b, a);
+ /* ---- convergence check ---- */
+ nprc = -e[1];
+ if (e[0] == 0) {
+ nprc = n;
+ }
+ printf("precision= %d\n", 4 * nprc * log10_radix);
+ fprintf(f_log, "precision= %d\n", 4 * nprc * log10_radix);
+ } while (4 * nprc <= n);
+ /* ---- e = e * e / 4 (half precision) ---- */
+ mp_idiv_2(n, radix, e, e);
+ mp_squh(n, radix, e, e, nfft, d1, ip, w);
+ /* ---- a = a + b ---- */
+ mp_add(n, radix, a, b, a);
+ /* ---- a = (a * a - e - e / 2) / (a * c - e) / npow ---- */
+ mp_mul(n, radix, a, c, c, i1, nfft, d1, d2, d3, ip, w);
+ mp_sub(n, radix, c, e, c);
+ mp_inv(n, radix, c, b, i1, i2, nfft, d1, d2, ip, w);
+ mp_squ(n, radix, a, a, i1, nfft, d1, d2, ip, w);
+ mp_sub(n, radix, a, e, a);
+ mp_idiv_2(n, radix, e, e);
+ mp_sub(n, radix, a, e, a);
+ mp_mul(n, radix, a, b, a, i1, nfft, d1, d2, d3, ip, w);
+ mp_idiv(n, radix, a, npow, a);
+ /* ---- time check ---- */
+ time(&t_2);
+ /* ---- output ---- */
+ f_out = fopen("pi.dat", "w");
+ printf("writing pi.dat...\n");
+ mp_fprintf(n - 1, log10_radix, a, f_out);
+ fclose(f_out);
+ free(d3);
+ free(d2);
+ free(d1);
+ free(i2);
+ free(i1);
+ free(e);
+ free(c);
+ free(b);
+ free(a);
+ free(w);
+ free(ip);
+ /* ---- benchmark ---- */
+ n_op = 50.0 * nfft * log2_nfft * log2_nfft;
+ printf("floating point operation: %g op.\n", n_op);
+ fprintf(f_log, "floating point operation: %g op.\n", n_op);
+ /* ---- difftime ---- */
+ d_time = difftime(t_2, t_1);
+ printf("execution time: %g sec. (real time)\n", d_time);
+ fprintf(f_log, "execution time: %g sec. (real time)\n", d_time);
+ fclose(f_log);
+ return 0;
+}
+
+
+/* -------- multiple precision routines -------- */
+
+
+#include <math.h>
+#include <float.h>
+#include <stdio.h>
+
+/* ---- floating point format ----
+ data := data[0] * pow(radix, data[1]) *
+ (data[2] + data[3]/radix + data[4]/radix/radix + ...),
+ data[0] : sign (1;data>0, -1;data<0, 0;data==0)
+ data[1] : exponent (0;data==0)
+ data[2...n+1] : digits
+ ---- function prototypes ----
+ void mp_load_0(int n, int radix, int out[]);
+ void mp_load_1(int n, int radix, int out[]);
+ void mp_copy(int n, int radix, int in[], int out[]);
+ void mp_round(int n, int radix, int m, int inout[]);
+ int mp_cmp(int n, int radix, int in1[], int in2[]);
+ void mp_add(int n, int radix, int in1[], int in2[], int out[]);
+ void mp_sub(int n, int radix, int in1[], int in2[], int out[]);
+ void mp_imul(int n, int radix, int in1[], int in2, int out[]);
+ int mp_idiv(int n, int radix, int in1[], int in2, int out[]);
+ void mp_idiv_2(int n, int radix, int in[], int out[]);
+ double mp_mul_radix_test(int n, int radix, int nfft,
+ double tmpfft[], int ip[], double w[]);
+ void mp_mul(int n, int radix, int in1[], int in2[], int out[],
+ int tmp[], int nfft, double tmp1fft[], double tmp2fft[],
+ double tmp3fft[], int ip[], double w[]);
+ void mp_squ(int n, int radix, int in[], int out[], int tmp[],
+ int nfft, double tmp1fft[], double tmp2fft[],
+ int ip[], double w[]);
+ void mp_mulh(int n, int radix, int in1[], int in2[], int out[],
+ int nfft, double in1fft[], double outfft[],
+ int ip[], double w[]);
+ void mp_squh(int n, int radix, int in[], int out[],
+ int nfft, double inoutfft[], int ip[], double w[]);
+ int mp_inv(int n, int radix, int in[], int out[],
+ int tmp1[], int tmp2[], int nfft,
+ double tmp1fft[], double tmp2fft[], int ip[], double w[]);
+ int mp_sqrt(int n, int radix, int in[], int out[],
+ int tmp1[], int tmp2[], int nfft,
+ double tmp1fft[], double tmp2fft[], int ip[], double w[]);
+ void mp_sprintf(int n, int log10_radix, int in[], char out[]);
+ void mp_sscanf(int n, int log10_radix, char in[], int out[]);
+ void mp_fprintf(int n, int log10_radix, int in[], FILE *fout);
+ ----
+*/
+
+
+/* -------- mp_load routines -------- */
+
+
+void mp_load_0(int n, int radix, int out[])
+{
+ int j;
+
+ for (j = 0; j <= n + 1; j++) {
+ out[j] = 0;
+ }
+}
+
+
+void mp_load_1(int n, int radix, int out[])
+{
+ int j;
+
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 1;
+ for (j = 3; j <= n + 1; j++) {
+ out[j] = 0;
+ }
+}
+
+
+void mp_copy(int n, int radix, int in[], int out[])
+{
+ int j;
+
+ for (j = 0; j <= n + 1; j++) {
+ out[j] = in[j];
+ }
+}
+
+
+void mp_round(int n, int radix, int m, int inout[])
+{
+ int j, x;
+
+ if (m < n) {
+ for (j = n + 1; j > m + 2; j--) {
+ inout[j] = 0;
+ }
+ x = 2 * inout[m + 2];
+ inout[m + 2] = 0;
+ if (x >= radix) {
+ for (j = m + 1; j >= 2; j--) {
+ x = inout[j] + 1;
+ if (x < radix) {
+ inout[j] = x;
+ break;
+ }
+ inout[j] = 0;
+ }
+ if (x >= radix) {
+ inout[2] = 1;
+ inout[1]++;
+ }
+ }
+ }
+}
+
+
+/* -------- mp_add routines -------- */
+
+
+int mp_cmp(int n, int radix, int in1[], int in2[])
+{
+ int mp_unsgn_cmp(int n, int in1[], int in2[]);
+
+ if (in1[0] > in2[0]) {
+ return 1;
+ } else if (in1[0] < in2[0]) {
+ return -1;
+ }
+ return in1[0] * mp_unsgn_cmp(n, &in1[1], &in2[1]);
+}
+
+
+void mp_add(int n, int radix, int in1[], int in2[], int out[])
+{
+ int mp_unsgn_cmp(int n, int in1[], int in2[]);
+ int mp_unexp_add(int n, int radix, int expdif,
+ int in1[], int in2[], int out[]);
+ int mp_unexp_sub(int n, int radix, int expdif,
+ int in1[], int in2[], int out[]);
+ int outsgn, outexp, expdif;
+
+ expdif = in1[1] - in2[1];
+ outexp = in1[1];
+ if (expdif < 0) {
+ outexp = in2[1];
+ }
+ outsgn = in1[0] * in2[0];
+ if (outsgn >= 0) {
+ if (outsgn > 0) {
+ outsgn = in1[0];
+ } else {
+ outsgn = in1[0] + in2[0];
+ outexp = in1[1] + in2[1];
+ expdif = 0;
+ }
+ if (expdif >= 0) {
+ outexp += mp_unexp_add(n, radix, expdif,
+ &in1[2], &in2[2], &out[2]);
+ } else {
+ outexp += mp_unexp_add(n, radix, -expdif,
+ &in2[2], &in1[2], &out[2]);
+ }
+ } else {
+ outsgn = mp_unsgn_cmp(n, &in1[1], &in2[1]);
+ if (outsgn >= 0) {
+ expdif = mp_unexp_sub(n, radix, expdif,
+ &in1[2], &in2[2], &out[2]);
+ } else {
+ expdif = mp_unexp_sub(n, radix, -expdif,
+ &in2[2], &in1[2], &out[2]);
+ }
+ outexp -= expdif;
+ outsgn *= in1[0];
+ if (expdif == n) {
+ outsgn = 0;
+ }
+ }
+ if (outsgn == 0) {
+ outexp = 0;
+ }
+ out[0] = outsgn;
+ out[1] = outexp;
+}
+
+
+void mp_sub(int n, int radix, int in1[], int in2[], int out[])
+{
+ int mp_unsgn_cmp(int n, int in1[], int in2[]);
+ int mp_unexp_add(int n, int radix, int expdif,
+ int in1[], int in2[], int out[]);
+ int mp_unexp_sub(int n, int radix, int expdif,
+ int in1[], int in2[], int out[]);
+ int outsgn, outexp, expdif;
+
+ expdif = in1[1] - in2[1];
+ outexp = in1[1];
+ if (expdif < 0) {
+ outexp = in2[1];
+ }
+ outsgn = in1[0] * in2[0];
+ if (outsgn <= 0) {
+ if (outsgn < 0) {
+ outsgn = in1[0];
+ } else {
+ outsgn = in1[0] - in2[0];
+ outexp = in1[1] + in2[1];
+ expdif = 0;
+ }
+ if (expdif >= 0) {
+ outexp += mp_unexp_add(n, radix, expdif,
+ &in1[2], &in2[2], &out[2]);
+ } else {
+ outexp += mp_unexp_add(n, radix, -expdif,
+ &in2[2], &in1[2], &out[2]);
+ }
+ } else {
+ outsgn = mp_unsgn_cmp(n, &in1[1], &in2[1]);
+ if (outsgn >= 0) {
+ expdif = mp_unexp_sub(n, radix, expdif,
+ &in1[2], &in2[2], &out[2]);
+ } else {
+ expdif = mp_unexp_sub(n, radix, -expdif,
+ &in2[2], &in1[2], &out[2]);
+ }
+ outexp -= expdif;
+ outsgn *= in1[0];
+ if (expdif == n) {
+ outsgn = 0;
+ }
+ }
+ if (outsgn == 0) {
+ outexp = 0;
+ }
+ out[0] = outsgn;
+ out[1] = outexp;
+}
+
+
+/* -------- mp_add child routines -------- */
+
+
+int mp_unsgn_cmp(int n, int in1[], int in2[])
+{
+ int j, cmp;
+
+ cmp = 0;
+ for (j = 0; j <= n && cmp == 0; j++) {
+ cmp = in1[j] - in2[j];
+ }
+ if (cmp > 0) {
+ cmp = 1;
+ } else if (cmp < 0) {
+ cmp = -1;
+ }
+ return cmp;
+}
+
+
+int mp_unexp_add(int n, int radix, int expdif,
+ int in1[], int in2[], int out[])
+{
+ int j, x, carry;
+
+ carry = 0;
+ if (expdif == 0 && in1[0] + in2[0] >= radix) {
+ x = in1[n - 1] + in2[n - 1];
+ carry = x >= radix ? -1 : 0;
+ for (j = n - 1; j > 0; j--) {
+ x = in1[j - 1] + in2[j - 1] - carry;
+ carry = x >= radix ? -1 : 0;
+ out[j] = x - (radix & carry);
+ }
+ out[0] = -carry;
+ } else {
+ if (expdif > n) {
+ expdif = n;
+ }
+ for (j = n - 1; j >= expdif; j--) {
+ x = in1[j] + in2[j - expdif] - carry;
+ carry = x >= radix ? -1 : 0;
+ out[j] = x - (radix & carry);
+ }
+ for (j = expdif - 1; j >= 0; j--) {
+ x = in1[j] - carry;
+ carry = x >= radix ? -1 : 0;
+ out[j] = x - (radix & carry);
+ }
+ if (carry != 0) {
+ for (j = n - 1; j > 0; j--) {
+ out[j] = out[j - 1];
+ }
+ out[0] = -carry;
+ }
+ }
+ return -carry;
+}
+
+
+int mp_unexp_sub(int n, int radix, int expdif,
+ int in1[], int in2[], int out[])
+{
+ int j, x, borrow, ncancel;
+
+ if (expdif > n) {
+ expdif = n;
+ }
+ borrow = 0;
+ for (j = n - 1; j >= expdif; j--) {
+ x = in1[j] - in2[j - expdif] + borrow;
+ borrow = x < 0 ? -1 : 0;
+ out[j] = x + (radix & borrow);
+ }
+ for (j = expdif - 1; j >= 0; j--) {
+ x = in1[j] + borrow;
+ borrow = x < 0 ? -1 : 0;
+ out[j] = x + (radix & borrow);
+ }
+ ncancel = 0;
+ for (j = 0; j < n && out[j] == 0; j++) {
+ ncancel = j + 1;
+ }
+ if (ncancel > 0 && ncancel < n) {
+ for (j = 0; j < n - ncancel; j++) {
+ out[j] = out[j + ncancel];
+ }
+ for (j = n - ncancel; j < n; j++) {
+ out[j] = 0;
+ }
+ }
+ return ncancel;
+}
+
+
+/* -------- mp_imul routines -------- */
+
+
+void mp_imul(int n, int radix, int in1[], int in2, int out[])
+{
+ void mp_unsgn_imul(int n, double dradix, int in1[], double din2,
+ int out[]);
+
+ if (in2 > 0) {
+ out[0] = in1[0];
+ } else if (in2 < 0) {
+ out[0] = -in1[0];
+ in2 = -in2;
+ } else {
+ out[0] = 0;
+ }
+ mp_unsgn_imul(n, radix, &in1[1], in2, &out[1]);
+ if (out[0] == 0) {
+ out[1] = 0;
+ }
+}
+
+
+int mp_idiv(int n, int radix, int in1[], int in2, int out[])
+{
+ void mp_load_0(int n, int radix, int out[]);
+ void mp_unsgn_idiv(int n, double dradix, int in1[], double din2,
+ int out[]);
+
+ if (in2 == 0) {
+ return -1;
+ }
+ if (in2 > 0) {
+ out[0] = in1[0];
+ } else {
+ out[0] = -in1[0];
+ in2 = -in2;
+ }
+ if (in1[0] == 0) {
+ mp_load_0(n, radix, out);
+ return 0;
+ }
+ mp_unsgn_idiv(n, radix, &in1[1], in2, &out[1]);
+ return 0;
+}
+
+
+void mp_idiv_2(int n, int radix, int in[], int out[])
+{
+ int j, ix, carry, shift;
+
+ out[0] = in[0];
+ shift = 0;
+ if (in[2] == 1) {
+ shift = 1;
+ }
+ out[1] = in[1] - shift;
+ carry = -shift;
+ for (j = 2; j <= n + 1 - shift; j++) {
+ ix = in[j + shift] + (radix & carry);
+ carry = -(ix & 1);
+ out[j] = ix >> 1;
+ }
+ if (shift > 0) {
+ out[n + 1] = (radix & carry) >> 1;
+ }
+}
+
+
+/* -------- mp_imul child routines -------- */
+
+
+void mp_unsgn_imul(int n, double dradix, int in1[], double din2,
+ int out[])
+{
+ int j, carry, shift;
+ double x, d1_radix;
+
+ d1_radix = 1.0 / dradix;
+ carry = 0;
+ for (j = n; j >= 1; j--) {
+ x = din2 * in1[j] + carry + 0.5;
+ carry = (int) (d1_radix * x);
+ out[j] = (int) (x - dradix * carry);
+ }
+ shift = 0;
+ x = carry + 0.5;
+ while (x > 1) {
+ x *= d1_radix;
+ shift++;
+ }
+ out[0] = in1[0] + shift;
+ if (shift > 0) {
+ while (shift > n) {
+ carry = (int) (d1_radix * carry + 0.5);
+ shift--;
+ }
+ for (j = n; j >= shift + 1; j--) {
+ out[j] = out[j - shift];
+ }
+ for (j = shift; j >= 1; j--) {
+ x = carry + 0.5;
+ carry = (int) (d1_radix * x);
+ out[j] = (int) (x - dradix * carry);
+ }
+ }
+}
+
+
+void mp_unsgn_idiv(int n, double dradix, int in1[], double din2,
+ int out[])
+{
+ int j, ix, carry, shift;
+ double x, d1_in2;
+
+ d1_in2 = 1.0 / din2;
+ shift = 0;
+ x = 0;
+ do {
+ shift++;
+ x *= dradix;
+ if (shift <= n) {
+ x += in1[shift];
+ }
+ } while (x < din2 - 0.5);
+ x += 0.5;
+ ix = (int) (d1_in2 * x);
+ carry = (int) (x - din2 * ix);
+ out[1] = ix;
+ shift--;
+ out[0] = in1[0] - shift;
+ if (shift >= n) {
+ shift = n - 1;
+ }
+ for (j = 2; j <= n - shift; j++) {
+ x = in1[j + shift] + dradix * carry + 0.5;
+ ix = (int) (d1_in2 * x);
+ carry = (int) (x - din2 * ix);
+ out[j] = ix;
+ }
+ for (j = n - shift + 1; j <= n; j++) {
+ x = dradix * carry + 0.5;
+ ix = (int) (d1_in2 * x);
+ carry = (int) (x - din2 * ix);
+ out[j] = ix;
+ }
+}
+
+
+/* -------- mp_mul routines -------- */
+
+
+double mp_mul_radix_test(int n, int radix, int nfft,
+ double tmpfft[], int ip[], double w[])
+{
+ void rdft(int n, int isgn, double *a, int *ip, double *w);
+ void mp_mul_csqu(int nfft, double dinout[]);
+ double mp_mul_d2i_test(int radix, int nfft, double din[]);
+ int j, ndata, radix_2;
+
+ ndata = (nfft >> 1) + 1;
+ if (ndata > n) {
+ ndata = n;
+ }
+ tmpfft[nfft + 1] = radix - 1;
+ for (j = nfft; j > ndata; j--) {
+ tmpfft[j] = 0;
+ }
+ radix_2 = (radix + 1) / 2;
+ for (j = ndata; j > 2; j--) {
+ tmpfft[j] = radix_2;
+ }
+ tmpfft[2] = radix;
+ tmpfft[1] = radix - 1;
+ tmpfft[0] = 0;
+ rdft(nfft, 1, &tmpfft[1], ip, w);
+ mp_mul_csqu(nfft, tmpfft);
+ rdft(nfft, -1, &tmpfft[1], ip, w);
+ return 2 * mp_mul_d2i_test(radix, nfft, tmpfft);
+}
+
+
+void mp_mul(int n, int radix, int in1[], int in2[], int out[],
+ int tmp[], int nfft, double tmp1fft[], double tmp2fft[],
+ double tmp3fft[], int ip[], double w[])
+{
+ void mp_copy(int n, int radix, int in[], int out[]);
+ void mp_add(int n, int radix, int in1[], int in2[], int out[]);
+ void rdft(int n, int isgn, double *a, int *ip, double *w);
+ void mp_mul_i2d(int n, int radix, int nfft, int shift,
+ int in[], double dout[]);
+ void mp_mul_cmul(int nfft, double din[], double dinout[]);
+ void mp_mul_cmuladd(int nfft, double din1[], double din2[],
+ double dinout[]);
+ void mp_mul_d2i(int n, int radix, int nfft, double din[], int out[]);
+ int n_h, shift;
+
+ shift = (nfft >> 1) + 1;
+ while (n > shift) {
+ if (in1[shift + 2] + in2[shift + 2] != 0) {
+ break;
+ }
+ shift++;
+ }
+ n_h = n / 2 + 1;
+ if (n_h < n - shift) {
+ n_h = n - shift;
+ }
+ /* ---- tmp3fft = (upper) in1 * (lower) in2 ---- */
+ mp_mul_i2d(n, radix, nfft, 0, in1, tmp1fft);
+ rdft(nfft, 1, &tmp1fft[1], ip, w);
+ mp_mul_i2d(n, radix, nfft, shift, in2, tmp3fft);
+ rdft(nfft, 1, &tmp3fft[1], ip, w);
+ mp_mul_cmul(nfft, tmp1fft, tmp3fft);
+ /* ---- tmp = (upper) in1 * (upper) in2 ---- */
+ mp_mul_i2d(n, radix, nfft, 0, in2, tmp2fft);
+ rdft(nfft, 1, &tmp2fft[1], ip, w);
+ mp_mul_cmul(nfft, tmp2fft, tmp1fft);
+ rdft(nfft, -1, &tmp1fft[1], ip, w);
+ mp_mul_d2i(n, radix, nfft, tmp1fft, tmp);
+ /* ---- tmp3fft += (upper) in2 * (lower) in1 ---- */
+ mp_mul_i2d(n, radix, nfft, shift, in1, tmp1fft);
+ rdft(nfft, 1, &tmp1fft[1], ip, w);
+ mp_mul_cmuladd(nfft, tmp1fft, tmp2fft, tmp3fft);
+ /* ---- out = tmp + tmp3fft ---- */
+ rdft(nfft, -1, &tmp3fft[1], ip, w);
+ mp_mul_d2i(n_h, radix, nfft, tmp3fft, out);
+ if (out[0] != 0) {
+ mp_add(n, radix, out, tmp, out);
+ } else {
+ mp_copy(n, radix, tmp, out);
+ }
+}
+
+
+void mp_squ(int n, int radix, int in[], int out[], int tmp[],
+ int nfft, double tmp1fft[], double tmp2fft[],
+ int ip[], double w[])
+{
+ void mp_add(int n, int radix, int in1[], int in2[], int out[]);
+ void rdft(int n, int isgn, double *a, int *ip, double *w);
+ void mp_mul_i2d(int n, int radix, int nfft, int shift,
+ int in[], double dout[]);
+ void mp_mul_cmul(int nfft, double din[], double dinout[]);
+ void mp_mul_csqu(int nfft, double dinout[]);
+ void mp_mul_d2i(int n, int radix, int nfft, double din[], int out[]);
+ int n_h, shift;
+
+ shift = (nfft >> 1) + 1;
+ while (n > shift) {
+ if (in[shift + 2] != 0) {
+ break;
+ }
+ shift++;
+ }
+ n_h = n / 2 + 1;
+ if (n_h < n - shift) {
+ n_h = n - shift;
+ }
+ /* ---- tmp = (upper) in * (lower) in ---- */
+ mp_mul_i2d(n, radix, nfft, 0, in, tmp1fft);
+ rdft(nfft, 1, &tmp1fft[1], ip, w);
+ mp_mul_i2d(n, radix, nfft, shift, in, tmp2fft);
+ rdft(nfft, 1, &tmp2fft[1], ip, w);
+ mp_mul_cmul(nfft, tmp1fft, tmp2fft);
+ rdft(nfft, -1, &tmp2fft[1], ip, w);
+ mp_mul_d2i(n_h, radix, nfft, tmp2fft, tmp);
+ /* ---- out = 2 * tmp + ((upper) in)^2 ---- */
+ mp_mul_csqu(nfft, tmp1fft);
+ rdft(nfft, -1, &tmp1fft[1], ip, w);
+ mp_mul_d2i(n, radix, nfft, tmp1fft, out);
+ if (tmp[0] != 0) {
+ mp_add(n_h, radix, tmp, tmp, tmp);
+ mp_add(n, radix, out, tmp, out);
+ }
+}
+
+
+void mp_mulh(int n, int radix, int in1[], int in2[], int out[],
+ int nfft, double in1fft[], double outfft[], int ip[], double w[])
+{
+ void rdft(int n, int isgn, double *a, int *ip, double *w);
+ void mp_mul_i2d(int n, int radix, int nfft, int shift,
+ int in[], double dout[]);
+ void mp_mul_cmul(int nfft, double din[], double dinout[]);
+ void mp_mul_d2i(int n, int radix, int nfft, double din[], int out[]);
+
+ mp_mul_i2d(n, radix, nfft, 0, in1, in1fft);
+ rdft(nfft, 1, &in1fft[1], ip, w);
+ mp_mul_i2d(n, radix, nfft, 0, in2, outfft);
+ rdft(nfft, 1, &outfft[1], ip, w);
+ mp_mul_cmul(nfft, in1fft, outfft);
+ rdft(nfft, -1, &outfft[1], ip, w);
+ mp_mul_d2i(n, radix, nfft, outfft, out);
+}
+
+
+void mp_mulh_use_in1fft(int n, int radix, double in1fft[],
+ int shift, int in2[], int out[], int nfft, double outfft[],
+ int ip[], double w[])
+{
+ void rdft(int n, int isgn, double *a, int *ip, double *w);
+ void mp_mul_i2d(int n, int radix, int nfft, int shift,
+ int in[], double dout[]);
+ void mp_mul_cmul(int nfft, double din[], double dinout[]);
+ void mp_mul_d2i(int n, int radix, int nfft, double din[], int out[]);
+ int n_h;
+
+ while (n > shift) {
+ if (in2[shift + 2] != 0) {
+ break;
+ }
+ shift++;
+ }
+ n_h = n / 2 + 1;
+ if (n_h < n - shift) {
+ n_h = n - shift;
+ }
+ mp_mul_i2d(n, radix, nfft, shift, in2, outfft);
+ rdft(nfft, 1, &outfft[1], ip, w);
+ mp_mul_cmul(nfft, in1fft, outfft);
+ rdft(nfft, -1, &outfft[1], ip, w);
+ mp_mul_d2i(n_h, radix, nfft, outfft, out);
+}
+
+
+void mp_squh(int n, int radix, int in[], int out[],
+ int nfft, double inoutfft[], int ip[], double w[])
+{
+ void rdft(int n, int isgn, double *a, int *ip, double *w);
+ void mp_mul_i2d(int n, int radix, int nfft, int shift,
+ int in[], double dout[]);
+ void mp_mul_csqu(int nfft, double dinout[]);
+ void mp_mul_d2i(int n, int radix, int nfft, double din[], int out[]);
+
+ mp_mul_i2d(n, radix, nfft, 0, in, inoutfft);
+ rdft(nfft, 1, &inoutfft[1], ip, w);
+ mp_mul_csqu(nfft, inoutfft);
+ rdft(nfft, -1, &inoutfft[1], ip, w);
+ mp_mul_d2i(n, radix, nfft, inoutfft, out);
+}
+
+
+void mp_squh_use_in1fft(int n, int radix, double inoutfft[], int out[],
+ int nfft, int ip[], double w[])
+{
+ void rdft(int n, int isgn, double *a, int *ip, double *w);
+ void mp_mul_csqu(int nfft, double dinout[]);
+ void mp_mul_d2i(int n, int radix, int nfft, double din[], int out[]);
+
+ mp_mul_csqu(nfft, inoutfft);
+ rdft(nfft, -1, &inoutfft[1], ip, w);
+ mp_mul_d2i(n, radix, nfft, inoutfft, out);
+}
+
+
+/* -------- mp_mul child routines -------- */
+
+
+void mp_mul_i2d(int n, int radix, int nfft, int shift,
+ int in[], double dout[])
+{
+ int j, x, carry, ndata, radix_2, topdgt;
+
+ ndata = 0;
+ topdgt = 0;
+ if (n > shift) {
+ topdgt = in[shift + 2];
+ ndata = (nfft >> 1) + 1;
+ if (ndata > n - shift) {
+ ndata = n - shift;
+ }
+ }
+ dout[nfft + 1] = in[0] * topdgt;
+ for (j = nfft; j > ndata; j--) {
+ dout[j] = 0;
+ }
+ /* ---- abs(dout[j]) <= radix/2 (to keep FFT precision) ---- */
+ if (ndata > 1) {
+ radix_2 = radix / 2;
+ carry = 0;
+ for (j = ndata + 1; j > 3; j--) {
+ x = in[j + shift] - carry;
+ carry = x >= radix_2 ? -1 : 0;
+ dout[j - 1] = x - (radix & carry);
+ }
+ dout[2] = in[shift + 3] - carry;
+ }
+ dout[1] = topdgt;
+ dout[0] = in[1] - shift;
+}
+
+
+void mp_mul_cmul(int nfft, double din[], double dinout[])
+{
+ int j;
+ double xr, xi, yr, yi;
+
+ dinout[0] += din[0];
+ dinout[1] *= din[1];
+ dinout[2] *= din[2];
+ for (j = 3; j < nfft; j += 2) {
+ xr = din[j];
+ xi = din[j + 1];
+ yr = dinout[j];
+ yi = dinout[j + 1];
+ dinout[j] = xr * yr - xi * yi;
+ dinout[j + 1] = xr * yi + xi * yr;
+ }
+ dinout[nfft + 1] *= din[nfft + 1];
+}
+
+
+void mp_mul_cmuladd(int nfft, double din1[], double din2[],
+ double dinout[])
+{
+ int j;
+ double xr, xi, yr, yi;
+
+ dinout[1] += din1[1] * din2[1];
+ dinout[2] += din1[2] * din2[2];
+ for (j = 3; j < nfft; j += 2) {
+ xr = din1[j];
+ xi = din1[j + 1];
+ yr = din2[j];
+ yi = din2[j + 1];
+ dinout[j] += xr * yr - xi * yi;
+ dinout[j + 1] += xr * yi + xi * yr;
+ }
+ dinout[nfft + 1] += din1[nfft + 1] * din2[nfft + 1];
+}
+
+
+void mp_mul_csqu(int nfft, double dinout[])
+{
+ int j;
+ double xr, xi;
+
+ dinout[0] *= 2;
+ dinout[1] *= dinout[1];
+ dinout[2] *= dinout[2];
+ for (j = 3; j < nfft; j += 2) {
+ xr = dinout[j];
+ xi = dinout[j + 1];
+ dinout[j] = xr * xr - xi * xi;
+ dinout[j + 1] = 2 * xr * xi;
+ }
+ dinout[nfft + 1] *= dinout[nfft + 1];
+}
+
+
+void mp_mul_d2i(int n, int radix, int nfft, double din[], int out[])
+{
+ int j, carry, carry1, carry2, shift, ndata;
+ double x, scale, d1_radix, d1_radix2, pow_radix, topdgt;
+
+ scale = 2.0 / nfft;
+ d1_radix = 1.0 / radix;
+ d1_radix2 = d1_radix * d1_radix;
+ topdgt = din[nfft + 1];
+ x = topdgt < 0 ? -topdgt : topdgt;
+ shift = x + 0.5 >= radix ? 1 : 0;
+ /* ---- correction of cyclic convolution of din[1] ---- */
+ x *= nfft * 0.5;
+ din[nfft + 1] = din[1] - x;
+ din[1] = x;
+ /* ---- output of digits ---- */
+ ndata = n;
+ if (n > nfft + 1 + shift) {
+ ndata = nfft + 1 + shift;
+ for (j = n + 1; j > ndata + 1; j--) {
+ out[j] = 0;
+ }
+ }
+ x = 0;
+ pow_radix = 1;
+ for (j = ndata + 1 - shift; j <= nfft + 1; j++) {
+ x += pow_radix * din[j];
+ pow_radix *= d1_radix;
+ if (pow_radix < DBL_EPSILON) {
+ break;
+ }
+ }
+ x = d1_radix2 * (scale * x + 0.5);
+ carry2 = ((int) x) - 1;
+ carry = (int) (radix * (x - carry2) + 0.5);
+ for (j = ndata; j > 1; j--) {
+ x = d1_radix2 * (scale * din[j - shift] + carry + 0.5);
+ carry = carry2;
+ carry2 = ((int) x) - 1;
+ x = radix * (x - carry2);
+ carry1 = (int) x;
+ out[j + 1] = (int) (radix * (x - carry1));
+ carry += carry1;
+ }
+ x = carry + ((double) radix) * carry2 + 0.5;
+ if (shift == 0) {
+ x += scale * din[1];
+ }
+ carry = (int) (d1_radix * x);
+ out[2] = (int) (x - ((double) radix) * carry);
+ if (carry > 0) {
+ for (j = n + 1; j > 2; j--) {
+ out[j] = out[j - 1];
+ }
+ out[2] = carry;
+ shift++;
+ }
+ /* ---- output of exp, sgn ---- */
+ x = din[0] + shift + 0.5;
+ shift = ((int) x) - 1;
+ out[1] = shift + ((int) (x - shift));
+ out[0] = topdgt > 0.5 ? 1 : -1;
+ if (out[2] == 0) {
+ out[0] = 0;
+ out[1] = 0;
+ }
+}
+
+
+double mp_mul_d2i_test(int radix, int nfft, double din[])
+{
+ int j, carry, carry1, carry2;
+ double x, scale, d1_radix, d1_radix2, err;
+
+ scale = 2.0 / nfft;
+ d1_radix = 1.0 / radix;
+ d1_radix2 = d1_radix * d1_radix;
+ /* ---- correction of cyclic convolution of din[1] ---- */
+ x = din[nfft + 1] * nfft * 0.5;
+ if (x < 0) {
+ x = -x;
+ }
+ din[nfft + 1] = din[1] - x;
+ /* ---- check of digits ---- */
+ err = 0;
+ carry = 0;
+ carry2 = 0;
+ for (j = nfft + 1; j > 1; j--) {
+ x = d1_radix2 * (scale * din[j] + carry + 0.5);
+ carry = carry2;
+ carry2 = ((int) x) - 1;
+ x = radix * (x - carry2);
+ carry1 = (int) x;
+ x = radix * (x - carry1);
+ carry += carry1;
+ x = x - 0.5 - ((int) x);
+ if (x > err) {
+ err = x;
+ } else if (-x > err) {
+ err = -x;
+ }
+ }
+ return err;
+}
+
+
+/* -------- mp_inv routines -------- */
+
+
+int mp_inv(int n, int radix, int in[], int out[],
+ int tmp1[], int tmp2[], int nfft,
+ double tmp1fft[], double tmp2fft[], int ip[], double w[])
+{
+ int mp_get_nfft_init(int radix, int nfft_max);
+ void mp_inv_init(int n, int radix, int in[], int out[]);
+ int mp_inv_newton(int n, int radix, int in[], int inout[],
+ int tmp1[], int tmp2[], int nfft, double tmp1fft[],
+ double tmp2fft[], int ip[], double w[]);
+ int n_nwt, nfft_nwt, thr, prc;
+
+ if (in[0] == 0) {
+ return -1;
+ }
+ nfft_nwt = mp_get_nfft_init(radix, nfft);
+ n_nwt = nfft_nwt + 2;
+ if (n_nwt > n) {
+ n_nwt = n;
+ }
+ mp_inv_init(n_nwt, radix, in, out);
+ thr = 8;
+ do {
+ n_nwt = nfft_nwt + 2;
+ if (n_nwt > n) {
+ n_nwt = n;
+ }
+ prc = mp_inv_newton(n_nwt, radix, in, out,
+ tmp1, tmp2, nfft_nwt, tmp1fft, tmp2fft, ip, w);
+ if (thr * nfft_nwt >= nfft) {
+ thr = 0;
+ if (2 * prc <= n_nwt - 2) {
+ nfft_nwt >>= 1;
+ }
+ } else {
+ if (3 * prc < n_nwt - 2) {
+ nfft_nwt >>= 1;
+ }
+ }
+ nfft_nwt <<= 1;
+ } while (nfft_nwt <= nfft);
+ return 0;
+}
+
+
+int mp_sqrt(int n, int radix, int in[], int out[],
+ int tmp1[], int tmp2[], int nfft,
+ double tmp1fft[], double tmp2fft[], int ip[], double w[])
+{
+ void mp_load_0(int n, int radix, int out[]);
+ int mp_get_nfft_init(int radix, int nfft_max);
+ void mp_sqrt_init(int n, int radix, int in[], int out[], int out_rev[]);
+ int mp_sqrt_newton(int n, int radix, int in[], int inout[],
+ int inout_rev[], int tmp[], int nfft, double tmp1fft[],
+ double tmp2fft[], int ip[], double w[], int *n_tmp1fft);
+ int n_nwt, nfft_nwt, thr, prc, n_tmp1fft;
+
+ if (in[0] < 0) {
+ return -1;
+ } else if (in[0] == 0) {
+ mp_load_0(n, radix, out);
+ return 0;
+ }
+ nfft_nwt = mp_get_nfft_init(radix, nfft);
+ n_nwt = nfft_nwt + 2;
+ if (n_nwt > n) {
+ n_nwt = n;
+ }
+ mp_sqrt_init(n_nwt, radix, in, out, tmp1);
+ n_tmp1fft = 0;
+ thr = 8;
+ do {
+ n_nwt = nfft_nwt + 2;
+ if (n_nwt > n) {
+ n_nwt = n;
+ }
+ prc = mp_sqrt_newton(n_nwt, radix, in, out,
+ tmp1, tmp2, nfft_nwt, tmp1fft, tmp2fft,
+ ip, w, &n_tmp1fft);
+ if (thr * nfft_nwt >= nfft) {
+ thr = 0;
+ if (2 * prc <= n_nwt - 2) {
+ nfft_nwt >>= 1;
+ }
+ } else {
+ if (3 * prc < n_nwt - 2) {
+ nfft_nwt >>= 1;
+ }
+ }
+ nfft_nwt <<= 1;
+ } while (nfft_nwt <= nfft);
+ return 0;
+}
+
+
+/* -------- mp_inv child routines -------- */
+
+
+int mp_get_nfft_init(int radix, int nfft_max)
+{
+ int nfft_init;
+ double r;
+
+ r = radix;
+ nfft_init = 1;
+ do {
+ r *= r;
+ nfft_init <<= 1;
+ } while (DBL_EPSILON * r < 1 && nfft_init < nfft_max);
+ return nfft_init;
+}
+
+
+void mp_inv_init(int n, int radix, int in[], int out[])
+{
+ void mp_unexp_d2mp(int n, int radix, double din, int out[]);
+ double mp_unexp_mp2d(int n, int radix, int in[]);
+ int outexp;
+ double din;
+
+ out[0] = in[0];
+ outexp = -in[1];
+ din = 1.0 / mp_unexp_mp2d(n, radix, &in[2]);
+ while (din < 1) {
+ din *= radix;
+ outexp--;
+ }
+ out[1] = outexp;
+ mp_unexp_d2mp(n, radix, din, &out[2]);
+}
+
+
+void mp_sqrt_init(int n, int radix, int in[], int out[], int out_rev[])
+{
+ void mp_unexp_d2mp(int n, int radix, double din, int out[]);
+ double mp_unexp_mp2d(int n, int radix, int in[]);
+ int outexp;
+ double din;
+
+ out[0] = 1;
+ out_rev[0] = 1;
+ outexp = in[1];
+ din = mp_unexp_mp2d(n, radix, &in[2]);
+ if (outexp % 2 != 0) {
+ din *= radix;
+ outexp--;
+ }
+ outexp /= 2;
+ din = sqrt(din);
+ if (din < 1) {
+ din *= radix;
+ outexp--;
+ }
+ out[1] = outexp;
+ mp_unexp_d2mp(n, radix, din, &out[2]);
+ outexp = -outexp;
+ din = 1.0 / din;
+ while (din < 1) {
+ din *= radix;
+ outexp--;
+ }
+ out_rev[1] = outexp;
+ mp_unexp_d2mp(n, radix, din, &out_rev[2]);
+}
+
+
+void mp_unexp_d2mp(int n, int radix, double din, int out[])
+{
+ int j, x;
+
+ for (j = 0; j < n; j++) {
+ x = (int) din;
+ if (x >= radix) {
+ x = radix - 1;
+ din = radix;
+ }
+ din = radix * (din - x);
+ out[j] = x;
+ }
+}
+
+
+double mp_unexp_mp2d(int n, int radix, int in[])
+{
+ int j;
+ double d1_radix, dout;
+
+ d1_radix = 1.0 / radix;
+ dout = 0;
+ for (j = n - 1; j >= 0; j--) {
+ dout = d1_radix * dout + in[j];
+ }
+ return dout;
+}
+
+
+int mp_inv_newton(int n, int radix, int in[], int inout[],
+ int tmp1[], int tmp2[], int nfft, double tmp1fft[],
+ double tmp2fft[], int ip[], double w[])
+{
+ void mp_load_1(int n, int radix, int out[]);
+ void mp_round(int n, int radix, int m, int inout[]);
+ void mp_add(int n, int radix, int in1[], int in2[], int out[]);
+ void mp_sub(int n, int radix, int in1[], int in2[], int out[]);
+ void mp_mulh(int n, int radix, int in1[], int in2[], int out[],
+ int nfft, double in1fft[], double outfft[],
+ int ip[], double w[]);
+ void mp_mulh_use_in1fft(int n, int radix, double in1fft[],
+ int shift, int in2[], int out[], int nfft, double outfft[],
+ int ip[], double w[]);
+ int n_h, shift, prc;
+
+ shift = (nfft >> 1) + 1;
+ n_h = n / 2 + 1;
+ if (n_h < n - shift) {
+ n_h = n - shift;
+ }
+ /* ---- tmp1 = inout * (upper) in (half to normal precision) ---- */
+ mp_round(n, radix, shift, inout);
+ mp_mulh(n, radix, inout, in, tmp1,
+ nfft, tmp1fft, tmp2fft, ip, w);
+ /* ---- tmp2 = 1 - tmp1 ---- */
+ mp_load_1(n, radix, tmp2);
+ mp_sub(n, radix, tmp2, tmp1, tmp2);
+ /* ---- tmp2 -= inout * (lower) in (half precision) ---- */
+ mp_mulh_use_in1fft(n, radix, tmp1fft, shift, in, tmp1,
+ nfft, tmp2fft, ip, w);
+ mp_sub(n_h, radix, tmp2, tmp1, tmp2);
+ /* ---- get precision ---- */
+ prc = -tmp2[1];
+ if (tmp2[0] == 0) {
+ prc = nfft + 1;
+ }
+ /* ---- tmp2 *= inout (half precision) ---- */
+ mp_mulh_use_in1fft(n_h, radix, tmp1fft, 0, tmp2, tmp2,
+ nfft, tmp2fft, ip, w);
+ /* ---- inout += tmp2 ---- */
+ if (tmp2[0] != 0) {
+ mp_add(n, radix, inout, tmp2, inout);
+ }
+ return prc;
+}
+
+
+int mp_sqrt_newton(int n, int radix, int in[], int inout[],
+ int inout_rev[], int tmp[], int nfft, double tmp1fft[],
+ double tmp2fft[], int ip[], double w[], int *n_tmp1fft)
+{
+ void mp_round(int n, int radix, int m, int inout[]);
+ void mp_add(int n, int radix, int in1[], int in2[], int out[]);
+ void mp_sub(int n, int radix, int in1[], int in2[], int out[]);
+ void mp_idiv_2(int n, int radix, int in[], int out[]);
+ void mp_mulh(int n, int radix, int in1[], int in2[], int out[],
+ int nfft, double in1fft[], double outfft[],
+ int ip[], double w[]);
+ void mp_squh(int n, int radix, int in[], int out[],
+ int nfft, double inoutfft[], int ip[], double w[]);
+ void mp_squh_use_in1fft(int n, int radix, double inoutfft[], int out[],
+ int nfft, int ip[], double w[]);
+ int n_h, nfft_h, shift, prc;
+
+ nfft_h = nfft >> 1;
+ shift = nfft_h + 1;
+ if (nfft_h < 2) {
+ nfft_h = 2;
+ }
+ n_h = n / 2 + 1;
+ if (n_h < n - shift) {
+ n_h = n - shift;
+ }
+ /* ---- tmp = inout_rev^2 (1/4 to half precision) ---- */
+ mp_round(n_h, radix, (nfft_h >> 1) + 1, inout_rev);
+ if (*n_tmp1fft != nfft_h) {
+ mp_squh(n_h, radix, inout_rev, tmp,
+ nfft_h, tmp1fft, ip, w);
+ } else {
+ mp_squh_use_in1fft(n_h, radix, tmp1fft, tmp,
+ nfft_h, ip, w);
+ }
+ /* ---- tmp = inout_rev - inout * tmp (half precision) ---- */
+ mp_round(n, radix, shift, inout);
+ mp_mulh(n_h, radix, inout, tmp, tmp,
+ nfft, tmp1fft, tmp2fft, ip, w);
+ mp_sub(n_h, radix, inout_rev, tmp, tmp);
+ /* ---- inout_rev += tmp ---- */
+ mp_add(n_h, radix, inout_rev, tmp, inout_rev);
+ /* ---- tmp = in - inout^2 (half to normal precision) ---- */
+ mp_squh_use_in1fft(n, radix, tmp1fft, tmp,
+ nfft, ip, w);
+ mp_sub(n, radix, in, tmp, tmp);
+ /* ---- get precision ---- */
+ prc = in[1] - tmp[1];
+ if (in[2] > tmp[2]) {
+ prc++;
+ }
+ if (tmp[0] == 0) {
+ prc = nfft + 1;
+ }
+ /* ---- tmp = tmp * inout_rev / 2 (half precision) ---- */
+ mp_round(n_h, radix, shift, inout_rev);
+ mp_mulh(n_h, radix, inout_rev, tmp, tmp,
+ nfft, tmp1fft, tmp2fft, ip, w);
+ *n_tmp1fft = nfft;
+ mp_idiv_2(n_h, radix, tmp, tmp);
+ /* ---- inout += tmp ---- */
+ if (tmp[0] != 0) {
+ mp_add(n, radix, inout, tmp, inout);
+ }
+ return prc;
+}
+
+
+/* -------- mp_io routines -------- */
+
+
+void mp_sprintf(int n, int log10_radix, int in[], char out[])
+{
+ int j, k, x, y, outexp, shift;
+
+ if (in[0] < 0) {
+ *out++ = '-';
+ }
+ x = in[2];
+ shift = log10_radix;
+ for (k = log10_radix; k > 0; k--) {
+ y = x % 10;
+ x /= 10;
+ out[k] = '0' + y;
+ if (y != 0) {
+ shift = k;
+ }
+ }
+ out[0] = out[shift];
+ out[1] = '.';
+ for (k = 1; k <= log10_radix - shift; k++) {
+ out[k + 1] = out[k + shift];
+ }
+ outexp = log10_radix - shift;
+ out += outexp + 2;
+ for (j = 3; j <= n + 1; j++) {
+ x = in[j];
+ for (k = log10_radix - 1; k >= 0; k--) {
+ y = x % 10;
+ x /= 10;
+ out[k] = '0' + y;
+ }
+ out += log10_radix;
+ }
+ *out++ = 'e';
+ outexp += log10_radix * in[1];
+ sprintf(out, "%d", outexp);
+}
+
+
+void mp_sscanf(int n, int log10_radix, char in[], int out[])
+{
+ char *s;
+ int j, x, outexp, outexp_mod;
+
+ while (*in == ' ') {
+ in++;
+ }
+ out[0] = 1;
+ if (*in == '-') {
+ out[0] = -1;
+ in++;
+ } else if (*in == '+') {
+ in++;
+ }
+ while (*in == ' ' || *in == '0') {
+ in++;
+ }
+ outexp = 0;
+ for (s = in; *s != '\0'; s++) {
+ if (*s == 'e' || *s == 'E' || *s == 'd' || *s == 'D') {
+ if (sscanf(++s, "%d", &outexp) != 1) {
+ outexp = 0;
+ }
+ break;
+ }
+ }
+ if (*in == '.') {
+ do {
+ outexp--;
+ while (*++in == ' ');
+ } while (*in == '0' && *in != '\0');
+ } else if (*in != '\0') {
+ s = in;
+ while (*++s == ' ');
+ while (*s >= '0' && *s <= '9' && *s != '\0') {
+ outexp++;
+ while (*++s == ' ');
+ }
+ }
+ x = outexp / log10_radix;
+ outexp_mod = outexp - log10_radix * x;
+ if (outexp_mod < 0) {
+ x--;
+ outexp_mod += log10_radix;
+ }
+ out[1] = x;
+ x = 0;
+ j = 2;
+ for (s = in; *s != '\0'; s++) {
+ if (*s == '.' || *s == ' ') {
+ continue;
+ }
+ if (*s < '0' || *s > '9') {
+ break;
+ }
+ x = 10 * x + (*s - '0');
+ if (--outexp_mod < 0) {
+ if (j > n + 1) {
+ break;
+ }
+ out[j++] = x;
+ x = 0;
+ outexp_mod = log10_radix - 1;
+ }
+ }
+ while (outexp_mod-- >= 0) {
+ x *= 10;
+ }
+ while (j <= n + 1) {
+ out[j++] = x;
+ x = 0;
+ }
+ if (out[2] == 0) {
+ out[0] = 0;
+ out[1] = 0;
+ }
+}
+
+
+void mp_fprintf(int n, int log10_radix, int in[], FILE *fout)
+{
+ int j, k, x, y, outexp, shift;
+ char out[256];
+
+ if (in[0] < 0) {
+ putc('-', fout);
+ }
+ x = in[2];
+ shift = log10_radix;
+ for (k = log10_radix; k > 0; k--) {
+ y = x % 10;
+ x /= 10;
+ out[k] = '0' + y;
+ if (y != 0) {
+ shift = k;
+ }
+ }
+ putc(out[shift], fout);
+ putc('.', fout);
+ for (k = 1; k <= log10_radix - shift; k++) {
+ putc(out[k + shift], fout);
+ }
+ outexp = log10_radix - shift;
+ for (j = 3; j <= n + 1; j++) {
+ x = in[j];
+ for (k = log10_radix - 1; k >= 0; k--) {
+ y = x % 10;
+ x /= 10;
+ out[k] = '0' + y;
+ }
+ for (k = 0; k < log10_radix; k++) {
+ putc(out[k], fout);
+ }
+ }
+ putc('e', fout);
+ outexp += log10_radix * in[1];
+ sprintf(out, "%d", outexp);
+ for (k = 0; out[k] != '\0'; k++) {
+ putc(out[k], fout);
+ }
+}
+
+
diff --git a/plugins/supereq/nsfft-1.00/simd/Makefile b/plugins/supereq/nsfft-1.00/simd/Makefile
new file mode 120000
index 00000000..fc484116
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/simd/Makefile
@@ -0,0 +1 @@
+Makefile.x86 \ No newline at end of file
diff --git a/plugins/supereq/nsfft-1.00/simd/Makefile.altivec b/plugins/supereq/nsfft-1.00/simd/Makefile.altivec
new file mode 100644
index 00000000..eeaed6a1
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/simd/Makefile.altivec
@@ -0,0 +1,26 @@
+CC=gcc
+BASEOPT=-Wall -maltivec -mabi=altivec
+OPT=$(BASEOPT) -O3
+
+all : libSIMD.a
+
+SIMDBaseUndiff_purecfloat.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_FLOAT SIMDBaseUndiff.c -c -o SIMDBaseUndiff_purecfloat.o
+
+SIMDBaseUndiff_purecdouble.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_DOUBLE SIMDBaseUndiff.c -c -o SIMDBaseUndiff_purecdouble.o
+
+SIMDBaseUndiff_pureclongdouble.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_LONGDOUBLE SIMDBaseUndiff.c -c -o SIMDBaseUndiff_pureclongdouble.o
+
+SIMDBaseUndiff_altivecfloat.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_ALTIVEC_FLOAT SIMDBaseUndiff.c -c -o SIMDBaseUndiff_altivecfloat.o
+
+SIMDBase.o : SIMDBase.c SIMDBase.h
+ $(CC) $(BASEOPT) -O -DENABLE_PUREC_FLOAT -DENABLE_PUREC_DOUBLE -DENABLE_PUREC_LONGDOUBLE -DENABLE_ALTIVEC_FLOAT SIMDBase.c -c -o SIMDBase.o
+
+libSIMD.a : SIMDBase.o SIMDBaseUndiff_purecfloat.o SIMDBaseUndiff_purecdouble.o SIMDBaseUndiff_pureclongdouble.o SIMDBaseUndiff_altivecfloat.o
+ rm -f libSIMD.a; ar -cvq libSIMD.a SIMDBase.o SIMDBaseUndiff_purecfloat.o SIMDBaseUndiff_purecdouble.o SIMDBaseUndiff_pureclongdouble.o SIMDBaseUndiff_altivecfloat.o
+
+clean :
+ rm -f *~ *.o *.s *.a
diff --git a/plugins/supereq/nsfft-1.00/simd/Makefile.neon b/plugins/supereq/nsfft-1.00/simd/Makefile.neon
new file mode 100644
index 00000000..ace704f1
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/simd/Makefile.neon
@@ -0,0 +1,26 @@
+CC=gcc
+BASEOPT=-Wall -mfloat-abi=softfp
+OPT=$(BASEOPT) -O3
+
+all : libSIMD.a
+
+SIMDBaseUndiff_purecfloat.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_FLOAT SIMDBaseUndiff.c -c -o SIMDBaseUndiff_purecfloat.o
+
+SIMDBaseUndiff_purecdouble.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_DOUBLE SIMDBaseUndiff.c -c -o SIMDBaseUndiff_purecdouble.o
+
+SIMDBaseUndiff_pureclongdouble.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_LONGDOUBLE SIMDBaseUndiff.c -c -o SIMDBaseUndiff_pureclongdouble.o
+
+SIMDBaseUndiff_neonfloat.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -mfpu=neon -DENABLE_NEON_FLOAT SIMDBaseUndiff.c -c -o SIMDBaseUndiff_neonfloat.o
+
+SIMDBase.o : SIMDBase.c SIMDBase.h
+ $(CC) $(BASEOPT) -O -DENABLE_PUREC_FLOAT -DENABLE_PUREC_DOUBLE -DENABLE_PUREC_LONGDOUBLE -DENABLE_NEON_FLOAT SIMDBase.c -c -o SIMDBase.o
+
+libSIMD.a : SIMDBase.o SIMDBaseUndiff_purecfloat.o SIMDBaseUndiff_purecdouble.o SIMDBaseUndiff_pureclongdouble.o SIMDBaseUndiff_neonfloat.o
+ rm -f libSIMD.a; ar -cvq libSIMD.a SIMDBase.o SIMDBaseUndiff_purecfloat.o SIMDBaseUndiff_purecdouble.o SIMDBaseUndiff_pureclongdouble.o SIMDBaseUndiff_neonfloat.o
+
+clean :
+ rm -f *~ *.o *.s *.a
diff --git a/plugins/supereq/nsfft-1.00/simd/Makefile.purec b/plugins/supereq/nsfft-1.00/simd/Makefile.purec
new file mode 100644
index 00000000..2c8b04f1
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/simd/Makefile.purec
@@ -0,0 +1,35 @@
+CC=gcc
+BASEOPT=-Wall
+OPT=$(BASEOPT) -O3
+
+all : libDFT.a
+
+DFTpurecfloat.o : DFTUndiff.c DFT.h SIMDBase.h
+ $(CC) $(OPT) -DENABLE_PUREC_FLOAT DFTUndiff.c -c -o DFTpurecfloat.o
+
+DFTpurecdouble.o : DFTUndiff.c DFT.h SIMDBase.h
+ $(CC) $(OPT) -DENABLE_PUREC_DOUBLE DFTUndiff.c -c -o DFTpurecdouble.o
+
+DFTpureclongdouble.o : DFTUndiff.c DFT.h SIMDBase.h
+ $(CC) $(OPT) -DENABLE_PUREC_LONGDOUBLE DFTUndiff.c -c -o DFTpureclongdouble.o
+
+SIMDBaseUndiff_purecfloat.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_FLOAT SIMDBaseUndiff.c -c -o SIMDBaseUndiff_purecfloat.o
+
+SIMDBaseUndiff_purecdouble.o : SIMDBaseUndiff.c DFT.h SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_DOUBLE SIMDBaseUndiff.c -c -o SIMDBaseUndiff_purecdouble.o
+
+SIMDBaseUndiff_pureclongdouble.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_LONGDOUBLE SIMDBaseUndiff.c -c -o SIMDBaseUndiff_pureclongdouble.o
+
+SIMDBase.o : SIMDBase.c SIMDBase.h
+ $(CC) $(BASEOPT) -O -DENABLE_PUREC_FLOAT -DENABLE_PUREC_DOUBLE -DENABLE_PUREC_LONGDOUBLE SIMDBase.c -c -o SIMDBase.o
+
+DFT.o : DFT.c DFT.h
+ $(CC) $(OPT) -DENABLE_PUREC_FLOAT -DENABLE_PUREC_DOUBLE -DENABLE_PUREC_LONGDOUBLE DFT.c -c -o DFT.o
+
+libDFT.a : DFTpurecfloat.o DFTpurecdouble.o DFTpureclongdouble.o DFT.o SIMDBase.o SIMDBaseUndiff_purecfloat.o SIMDBaseUndiff_purecdouble.o SIMDBaseUndiff_pureclongdouble.o
+ rm -f libDFT.a; ar -cvq libDFT.a DFTpurecfloat.o DFTpurecdouble.o DFTpureclongdouble.o DFT.o SIMDBase.o SIMDBaseUndiff_purecfloat.o SIMDBaseUndiff_purecdouble.o SIMDBaseUndiff_pureclongdouble.o
+
+clean :
+ rm -f *~ *.o *.s *.a
diff --git a/plugins/supereq/nsfft-1.00/simd/Makefile.x86 b/plugins/supereq/nsfft-1.00/simd/Makefile.x86
new file mode 100644
index 00000000..02f49610
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/simd/Makefile.x86
@@ -0,0 +1,35 @@
+CC=gcc
+BASEOPT=-Wall
+OPT=$(BASEOPT) -O3
+
+all : libSIMD.a
+
+SIMDBaseUndiff_purecfloat.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_FLOAT SIMDBaseUndiff.c -c -o SIMDBaseUndiff_purecfloat.o
+
+SIMDBase_purecdouble.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_DOUBLE SIMDBaseUndiff.c -c -o SIMDBase_purecdouble.o
+
+SIMDBase_pureclongdouble.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_LONGDOUBLE SIMDBaseUndiff.c -c -o SIMDBase_pureclongdouble.o
+
+SIMDBase_ssefloat.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -msse -DENABLE_SSE_FLOAT SIMDBaseUndiff.c -c -o SIMDBase_ssefloat.o
+
+SIMDBase_sse2double.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -msse2 -DENABLE_SSE2_DOUBLE SIMDBaseUndiff.c -c -o SIMDBase_sse2double.o
+
+SIMDBase_avxfloat.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -mavx -DENABLE_AVX_FLOAT SIMDBaseUndiff.c -c -o SIMDBase_avxfloat.o
+
+SIMDBase_avxdouble.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -mavx -DENABLE_AVX_DOUBLE SIMDBaseUndiff.c -c -o SIMDBase_avxdouble.o
+
+SIMDBase.o : SIMDBase.c SIMDBase.h
+ $(CC) $(BASEOPT) -O -DENABLE_PUREC_FLOAT -DENABLE_PUREC_DOUBLE -DENABLE_PUREC_LONGDOUBLE -DENABLE_SSE_FLOAT -DENABLE_SSE2_DOUBLE SIMDBase.c -c -o SIMDBase.o
+
+libSIMD.a : SIMDBase.o SIMDBaseUndiff_purecfloat.o SIMDBase_purecdouble.o SIMDBase_pureclongdouble.o SIMDBase_ssefloat.o SIMDBase_sse2double.o
+ rm -f libSIMD.a; ar -cvq libSIMD.a SIMDBase.o SIMDBaseUndiff_purecfloat.o SIMDBase_purecdouble.o SIMDBase_pureclongdouble.o SIMDBase_ssefloat.o SIMDBase_sse2double.o
+
+clean :
+ rm -f *~ *.o *.s *.a a.out
diff --git a/plugins/supereq/nsfft-1.00/simd/Makefile.x86avx b/plugins/supereq/nsfft-1.00/simd/Makefile.x86avx
new file mode 100644
index 00000000..d9d27a2e
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/simd/Makefile.x86avx
@@ -0,0 +1,35 @@
+CC=gcc
+BASEOPT=-Wall
+OPT=$(BASEOPT) -O3
+
+all : libSIMD.a
+
+SIMDBaseUndiff_purecfloat.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_FLOAT SIMDBaseUndiff.c -c -o SIMDBaseUndiff_purecfloat.o
+
+SIMDBaseUndiff_purecdouble.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_DOUBLE SIMDBaseUndiff.c -c -o SIMDBaseUndiff_purecdouble.o
+
+SIMDBaseUndiff_pureclongdouble.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -DENABLE_PUREC_LONGDOUBLE SIMDBaseUndiff.c -c -o SIMDBaseUndiff_pureclongdouble.o
+
+SIMDBaseUndiff_ssefloat.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -msse -DENABLE_SSE_FLOAT SIMDBaseUndiff.c -c -o SIMDBaseUndiff_ssefloat.o
+
+SIMDBaseUndiff_sse2double.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -msse2 -DENABLE_SSE2_DOUBLE SIMDBaseUndiff.c -c -o SIMDBaseUndiff_sse2double.o
+
+SIMDBaseUndiff_avxfloat.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -mavx -DENABLE_AVX_FLOAT SIMDBaseUndiff.c -c -o SIMDBaseUndiff_avxfloat.o
+
+SIMDBaseUndiff_avxdouble.o : SIMDBaseUndiff.c SIMDBase.h SIMDBaseUndiff.h
+ $(CC) $(OPT) -mavx -DENABLE_AVX_DOUBLE SIMDBaseUndiff.c -c -o SIMDBaseUndiff_avxdouble.o
+
+SIMDBase.o : SIMDBase.c SIMDBase.h
+ $(CC) $(BASEOPT) -O -DENABLE_PUREC_FLOAT -DENABLE_PUREC_DOUBLE -DENABLE_PUREC_LONGDOUBLE -DENABLE_SSE_FLOAT -DENABLE_SSE2_DOUBLE -DENABLE_AVX_FLOAT -DENABLE_AVX_DOUBLE SIMDBase.c -c -o SIMDBase.o
+
+libSIMD.a : SIMDBase.o SIMDBaseUndiff_purecfloat.o SIMDBaseUndiff_purecdouble.o SIMDBaseUndiff_pureclongdouble.o SIMDBaseUndiff_ssefloat.o SIMDBaseUndiff_sse2double.o SIMDBaseUndiff_avxfloat.o SIMDBaseUndiff_avxdouble.o
+ rm -f libSIMD.a; ar -cvq libSIMD.a SIMDBase.o SIMDBaseUndiff_purecfloat.o SIMDBaseUndiff_purecdouble.o SIMDBaseUndiff_pureclongdouble.o SIMDBaseUndiff_ssefloat.o SIMDBaseUndiff_sse2double.o SIMDBaseUndiff_avxfloat.o SIMDBaseUndiff_avxdouble.o
+
+clean :
+ rm -f *~ *.o *.s *.a a.out
diff --git a/plugins/supereq/nsfft-1.00/simd/SIMDBase.c b/plugins/supereq/nsfft-1.00/simd/SIMDBase.c
new file mode 100644
index 00000000..eb51ee10
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/simd/SIMDBase.c
@@ -0,0 +1,454 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <string.h>
+
+#include "SIMDBase.h"
+
+void detect_purec_float(void);
+void detect_purec_double(void);
+void detect_purec_longdouble(void);
+void detect_sse_float(void);
+void detect_sse2_double(void);
+void detect_neon_float(void);
+void detect_avx_float(void);
+void detect_avx_double(void);
+void detect_altivec_float(void);
+
+int32_t getModeParamInt_purec_float(int32_t paramId);
+int32_t getModeParamInt_purec_double(int32_t paramId);
+int32_t getModeParamInt_purec_longdouble(int32_t paramId);
+int32_t getModeParamInt_sse_float(int32_t paramId);
+int32_t getModeParamInt_sse2_double(int32_t paramId);
+int32_t getModeParamInt_neon_float(int32_t paramId);
+int32_t getModeParamInt_avx_float(int32_t paramId);
+int32_t getModeParamInt_avx_double(int32_t paramId);
+int32_t getModeParamInt_altivec_float(int32_t paramId);
+
+char * getModeParamString_purec_float(int32_t paramId);
+char * getModeParamString_purec_double(int32_t paramId);
+char * getModeParamString_purec_longdouble(int32_t paramId);
+char * getModeParamString_sse_float(int32_t paramId);
+char * getModeParamString_sse2_double(int32_t paramId);
+char * getModeParamString_neon_float(int32_t paramId);
+char * getModeParamString_avx_float(int32_t paramId);
+char * getModeParamString_avx_double(int32_t paramId);
+char * getModeParamString_altivec_float(int32_t paramId);
+
+uint8_t detectBuffer[256];
+char SIMDBase_processorNameString[256];
+
+static char *startsWith(char *str1, char *str2) {
+ if (strncmp(str1, str2, strlen(str2)) == 0) {
+ return str1 + strlen(str2);
+ }
+
+ return NULL;
+}
+
+#if defined(__linux__)
+static char *tryReadingProcCpuinfo(char *entry) {
+ int i;
+
+ FILE *fp = fopen("/proc/cpuinfo", "r");
+ if (fp == NULL) return NULL;
+
+ for(i=0;i<100;i++) {
+ char *q;
+ bzero(SIMDBase_processorNameString, 256);
+ if (fgets(SIMDBase_processorNameString, 255, fp) == NULL) break;
+
+ if ((q = startsWith(SIMDBase_processorNameString, entry)) != NULL) {
+ int j;
+ fclose(fp);
+
+ for(j=0;j<256;j++) {
+ if (SIMDBase_processorNameString[j] == '\n') SIMDBase_processorNameString[j] = ' ';
+ }
+ while(*q != '\0' && *q != ':' && q - SIMDBase_processorNameString < 200) q++;
+ if (q - SIMDBase_processorNameString >= 200) return NULL;
+ if (*q == ':' && *(q+1) == ' ') return q + 2;
+ return NULL;
+ }
+ }
+
+ fclose(fp);
+ return NULL;
+}
+#else
+static char *tryReadingProcCpuinfo(char *entry) { return NULL; }
+#endif
+
+#if defined(__i386__)
+static void SIMDBase_x86cpuid(uint32_t out[4], uint32_t eax, uint32_t ecx) {
+ uint32_t a, b, c, d;
+ __asm__ __volatile__("pushl %%eax; \n\t"
+ "pushl %%ebx; \n\t"
+ "pushl %%ecx; \n\t"
+ "pushl %%edx; \n\t"
+ "cpuid; \n\t"
+ "movl %%eax, %0; \n\t"
+ "movl %%ebx, %1; \n\t"
+ "movl %%ecx, %2; \n\t"
+ "movl %%edx, %3; \n\t"
+ "popl %%edx; \n\t"
+ "popl %%ecx; \n\t"
+ "popl %%ebx; \n\t"
+ "popl %%eax; \n\t"
+ : "=m"(a), "=m"(b), "=m"(c), "=m"(d)
+ : "a"(eax), "c"(ecx)
+ : "cc");
+ out[0] = a; out[1] = b; out[2] = c; out[3] = d;
+}
+#endif
+
+#if defined(__x86_64__)
+static void SIMDBase_x86cpuid(uint32_t out[4], uint32_t eax, uint32_t ecx) {
+ uint32_t a, b, c, d;
+ __asm__ __volatile__ ("cpuid" : "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (eax), "c"(ecx));
+ out[0] = a; out[1] = b; out[2] = c; out[3] = d;
+}
+#endif
+
+#if defined(__i386__) || defined(__x86_64__)
+static void getCacheParam(CacheParam *p) {
+ static int l2assoc[] = {0,1,2,0,4,0,8,0,16,0,32,48,64,96,128,-1};
+ int32_t i;
+ uint32_t out[4];
+
+ for(i=0;i<8;i++) {
+ p->size[i] = p->assoc[i] = 0;
+ }
+
+ SIMDBase_x86cpuid(out, 4, 0);
+
+ if ((out[0] & 0xf) != 0) {
+ p->linesize = ((out[1] >> 0) & 2047)+1;
+ for(i=0;i<8;i++) {
+ SIMDBase_x86cpuid(out, 4, i);
+ if ((out[0] & 0xf) == 0) break;
+ int level = (out[0] >> 5) & 0x7;
+ int type = (out[0] >> 0) & 0xf;
+ int assoc = ((out[1] >> 22) & 1023)+1;
+ int part = ((out[1] >> 12) & 1023)+1;
+ int lsize = ((out[1] >> 0) & 2047)+1;
+ int nsets = ((out[2] >> 0))+1;
+ int nthre = ((out[0] >> 14) & 1023)+1;
+
+ if (type != 1 && type != 3) continue;
+ p->assoc[level-1] = assoc;
+ p->size[level-1] = (uint64_t)assoc * part * lsize * nsets / nthre;
+ }
+ } else {
+ SIMDBase_x86cpuid(out, 0x80000008U, 0);
+ int ncores = (out[2] & 0xff) + 1;
+
+ SIMDBase_x86cpuid(out, 0x80000005U, 0);
+ p->linesize = out[2] & 255;
+ p->size[0] = (out[2] >> 24) * 1024 / ncores;
+ p->assoc[0] = (out[2] >> 16) & 0xff;
+
+ SIMDBase_x86cpuid(out, 0x80000006U, 0);
+ p->size[1] = (out[2] >> 16) * 1024 / ncores;
+ p->assoc[1] = l2assoc[(out[2] >> 12) & 0xf];
+ p->size[2] = (out[3] >> 18) * 512 * 1024 / ncores;
+ p->assoc[2] = l2assoc[(out[3] >> 12) & 0xf];
+ }
+
+ if (p->size[0] == 0) {
+ p->size[0] = 16 * 1024;
+ p->assoc[0] = 4;
+ }
+
+ if (p->size[1] == 0) {
+ p->size[1] = 256 * 1024;
+ p->assoc[1] = 4;
+ }
+}
+
+char *SIMDBase_getProcessorNameString() {
+ union {
+ uint32_t info[4];
+ uint8_t str[16];
+ } u;
+ int i,j;
+ char *p;
+
+ p = SIMDBase_processorNameString;
+
+ SIMDBase_x86cpuid(u.info, 0, 0);
+
+ for(i=0;i<4;i++) *p++ = u.str[i+4];
+ for(i=0;i<4;i++) *p++ = u.str[i+12];
+ for(i=0;i<4;i++) *p++ = u.str[i+8];
+
+ *p++ = ' ';
+
+ for(i=0;i<3;i++) {
+ SIMDBase_x86cpuid(u.info, i + 0x80000002, 0);
+
+ for(j=0;j<16;j++) {
+ *p++ = u.str[j];
+ }
+ }
+
+ *p++ = '\n';
+
+ return SIMDBase_processorNameString;
+}
+#else
+char *SIMDBase_getProcessorNameString() {
+ char *p = "Unknown";
+#if defined(__powerpc__)
+ if ((p = tryReadingProcCpuinfo("cpu")) == NULL) p = "PowerPC";
+#elif defined(__arm__)
+ if ((p = tryReadingProcCpuinfo("Processor")) == NULL) p = "ARM";
+#endif
+
+ return p;
+}
+#endif
+
+int32_t SIMDBase_sizeOfCachelineInByte() {
+#if defined(__i386__) || defined(__x86_64__)
+ CacheParam p;
+ getCacheParam(&p);
+ return p.linesize;
+#else
+ return 64;
+#endif
+}
+
+int32_t SIMDBase_sizeOfDataCacheInByte() {
+#if defined(__i386__) || defined(__x86_64__)
+ CacheParam p;
+ getCacheParam(&p);
+ return p.size[1] + p.size[2]; // L2 + L3
+#else
+ return 256 * 1024;
+#endif
+}
+
+static jmp_buf sigjmp;
+
+static void sighandler(int signum) {
+ longjmp(sigjmp, 1);
+}
+
+int32_t SIMDBase_detect(int32_t paramId) {
+#if defined(__i386__) || defined(__x86_64__)
+ uint32_t reg[4];
+#endif
+
+ switch(paramId) {
+ case SIMDBase_MODE_PUREC_FLOAT:
+#if defined(ENABLE_PUREC_FLOAT)
+ return 1;
+#else
+ return -1;
+#endif
+ case SIMDBase_MODE_PUREC_DOUBLE:
+#if defined(ENABLE_PUREC_DOUBLE)
+ return 1;
+#else
+ return -1;
+#endif
+ case SIMDBase_MODE_PUREC_LONGDOUBLE:
+#if defined(ENABLE_PUREC_LONGDOUBLE)
+ return 1;
+#else
+ return -1;
+#endif
+ case SIMDBase_MODE_SSE_FLOAT:
+#if defined(ENABLE_SSE_FLOAT)
+ SIMDBase_x86cpuid(reg, 1, 0);
+ return (reg[3] & (1 << 25)) != 0;
+#else
+ return -1;
+#endif
+ case SIMDBase_MODE_SSE2_DOUBLE:
+#if defined(ENABLE_SSE2_DOUBLE)
+ SIMDBase_x86cpuid(reg, 1, 0);
+ return (reg[3] & (1 << 26)) != 0;
+#else
+ return -1;
+#endif
+ case SIMDBase_MODE_AVX_FLOAT:
+#if defined(ENABLE_AVX_FLOAT)
+ SIMDBase_x86cpuid(reg, 1, 0);
+ return (reg[2] & (1 << 28)) != 0;
+#else
+ return -1;
+#endif
+ case SIMDBase_MODE_AVX_DOUBLE:
+#if defined(ENABLE_AVX_DOUBLE)
+ SIMDBase_x86cpuid(reg, 1, 0);
+ return (reg[2] & (1 << 28)) != 0;
+#else
+ return -1;
+#endif
+ default:
+ break;
+ }
+
+ signal(SIGILL, sighandler);
+
+ if (setjmp(sigjmp) == 0) {
+ switch(paramId) {
+#if defined(ENABLE_NEON_FLOAT)
+ case SIMDBase_MODE_NEON_FLOAT:
+ detect_neon_float();
+ break;
+#endif
+#if defined(ENABLE_ALTIVEC_FLOAT)
+ case SIMDBase_MODE_ALTIVEC_FLOAT:
+ detect_altivec_float();
+ break;
+#endif
+ default:
+ signal(SIGILL, SIG_DFL);
+ return -1;
+ }
+ signal(SIGILL, SIG_DFL);
+ return 1;
+ } else {
+ signal(SIGILL, SIG_DFL);
+ return 0;
+ }
+}
+
+int32_t SIMDBase_chooseBestMode(int32_t typeId) {
+ switch(typeId) {
+ case SIMDBase_TYPE_HALF:
+ break;
+ case SIMDBase_TYPE_FLOAT:
+ if (SIMDBase_detect(SIMDBase_MODE_AVX_FLOAT) == 1) return SIMDBase_MODE_AVX_FLOAT;
+ if (SIMDBase_detect(SIMDBase_MODE_SSE_FLOAT) == 1) return SIMDBase_MODE_SSE_FLOAT;
+ if (SIMDBase_detect(SIMDBase_MODE_NEON_FLOAT) == 1) return SIMDBase_MODE_NEON_FLOAT;
+ if (SIMDBase_detect(SIMDBase_MODE_ALTIVEC_FLOAT) == 1) return SIMDBase_MODE_ALTIVEC_FLOAT;
+ if (SIMDBase_detect(SIMDBase_MODE_PUREC_FLOAT) == 1) return SIMDBase_MODE_PUREC_FLOAT;
+ break;
+
+ case SIMDBase_TYPE_DOUBLE:
+ if (SIMDBase_detect(SIMDBase_MODE_AVX_DOUBLE) == 1) return SIMDBase_MODE_AVX_DOUBLE;
+ if (SIMDBase_detect(SIMDBase_MODE_SSE2_DOUBLE) == 1) return SIMDBase_MODE_SSE2_DOUBLE;
+ if (SIMDBase_detect(SIMDBase_MODE_PUREC_DOUBLE) == 1) return SIMDBase_MODE_PUREC_DOUBLE;
+ break;
+
+ case SIMDBase_TYPE_LONGDOUBLE:
+ if (SIMDBase_detect(SIMDBase_MODE_PUREC_LONGDOUBLE) == 1) return SIMDBase_MODE_PUREC_LONGDOUBLE;
+ break;
+
+ case SIMDBase_TYPE_EXTENDED:
+ break;
+
+ case SIMDBase_TYPE_QUAD:
+ break;
+ }
+
+ return SIMDBase_MODE_NONE;
+}
+
+int32_t SIMDBase_getModeParamInt(int32_t paramId, int32_t mode) {
+ switch(mode) {
+#if defined(ENABLE_PUREC_FLOAT)
+ case 1: return getModeParamInt_purec_float(paramId); break;
+#endif
+#if defined(ENABLE_PUREC_DOUBLE)
+ case 2: return getModeParamInt_purec_double(paramId); break;
+#endif
+#if defined(ENABLE_PUREC_LONGDOUBLE)
+ case 3: return getModeParamInt_purec_longdouble(paramId); break;
+#endif
+#if defined(ENABLE_SSE_FLOAT)
+ case 4: return getModeParamInt_sse_float(paramId); break;
+#endif
+#if defined(ENABLE_SSE2_DOUBLE)
+ case 5: return getModeParamInt_sse2_double(paramId); break;
+#endif
+#if defined(ENABLE_NEON_FLOAT)
+ case 6: return getModeParamInt_neon_float(paramId); break;
+#endif
+#if defined(ENABLE_AVX_FLOAT)
+ case 7: return getModeParamInt_avx_float(paramId); break;
+#endif
+#if defined(ENABLE_AVX_DOUBLE)
+ case 8: return getModeParamInt_avx_double(paramId); break;
+#endif
+#if defined(ENABLE_ALTIVEC_FLOAT)
+ case 9: return getModeParamInt_altivec_float(paramId); break;
+#endif
+ }
+
+ return -1;
+}
+
+char *SIMDBase_getModeParamString(int32_t paramId, int32_t mode) {
+ switch(mode) {
+#if defined(ENABLE_PUREC_FLOAT)
+ case 1: return getModeParamString_purec_float(paramId); break;
+#endif
+#if defined(ENABLE_PUREC_DOUBLE)
+ case 2: return getModeParamString_purec_double(paramId); break;
+#endif
+#if defined(ENABLE_PUREC_LONGDOUBLE)
+ case 3: return getModeParamString_purec_longdouble(paramId); break;
+#endif
+#if defined(ENABLE_SSE_FLOAT)
+ case 4: return getModeParamString_sse_float(paramId); break;
+#endif
+#if defined(ENABLE_SSE2_DOUBLE)
+ case 5: return getModeParamString_sse2_double(paramId); break;
+#endif
+#if defined(ENABLE_NEON_FLOAT)
+ case 6: return getModeParamString_neon_float(paramId); break;
+#endif
+#if defined(ENABLE_AVX_FLOAT)
+ case 7: return getModeParamString_avx_float(paramId); break;
+#endif
+#if defined(ENABLE_AVX_DOUBLE)
+ case 8: return getModeParamString_avx_double(paramId); break;
+#endif
+#if defined(ENABLE_ALTIVEC_FLOAT)
+ case 9: return getModeParamString_altivec_float(paramId); break;
+#endif
+ }
+
+ return NULL;
+}
+
+#ifdef ANDROID
+int posix_memalign (void **memptr, size_t alignment, size_t size) {
+ *memptr = malloc (size);
+ return *memptr ? 0 : -1;
+}
+#endif
+
+void *SIMDBase_alignedMalloc(uint64_t size) {
+ void *p;
+ if (posix_memalign(&p, SIMDBase_sizeOfCachelineInByte(), size) != 0) abort();
+ return p;
+}
+
+void SIMDBase_alignedFree(void *ptr) {
+ free(ptr);
+}
+
+int32_t SIMDBase_getParamInt(int32_t paramId) {
+ switch(paramId) {
+ case SIMDBase_PARAMID_MODE_MAX:
+ return SIMDBase_LAST_MODE + 1;
+ }
+
+ return -1;
+}
+
+int32_t SIMDBase_getTypeParamInt(int32_t paramId, int32_t typeId) {
+ switch(typeId) {
+ }
+
+ return -1;
+}
diff --git a/plugins/supereq/nsfft-1.00/simd/SIMDBase.h b/plugins/supereq/nsfft-1.00/simd/SIMDBase.h
new file mode 100644
index 00000000..10cdeb81
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/simd/SIMDBase.h
@@ -0,0 +1,53 @@
+#ifndef _SIMDBase_H_
+#define _SIMDBase_H_
+
+#include <stdint.h>
+
+#define SIMDBase_TYPE_FLOAT ( 1 | ( 1 << 24 ))
+#define SIMDBase_TYPE_DOUBLE ( 2 | ( 1 << 24 ))
+#define SIMDBase_TYPE_LONGDOUBLE ( 3 | ( 1 << 24 ))
+#define SIMDBase_TYPE_EXTENDED ( 4 | ( 1 << 24 ))
+#define SIMDBase_TYPE_QUAD ( 5 | ( 1 << 24 ))
+#define SIMDBase_TYPE_HALF ( 6 | ( 1 << 24 ))
+
+#define SIMDBase_MODE_NONE 0
+#define SIMDBase_MODE_PUREC_FLOAT 1
+#define SIMDBase_MODE_PUREC_DOUBLE 2
+#define SIMDBase_MODE_PUREC_LONGDOUBLE 3
+#define SIMDBase_MODE_SSE_FLOAT 4
+#define SIMDBase_MODE_SSE2_DOUBLE 5
+#define SIMDBase_MODE_NEON_FLOAT 6
+#define SIMDBase_MODE_AVX_FLOAT 7
+#define SIMDBase_MODE_AVX_DOUBLE 8
+#define SIMDBase_MODE_ALTIVEC_FLOAT 9
+
+#define SIMDBase_LAST_MODE SIMDBase_MODE_ALTIVEC_FLOAT
+
+#define SIMDBase_PARAMID_MODE_MAX ( 1 | ( 2 << 24 ))
+#define SIMDBase_PARAMID_TYPE_AVAILABILITY ( 2 | ( 2 << 24 ))
+#define SIMDBase_PARAMID_SIZE_OF_REAL ( 3 | ( 2 << 24 ))
+#define SIMDBase_PARAMID_SIZE_OF_VECT ( 4 | ( 2 << 24 ))
+#define SIMDBase_PARAMID_VECTOR_LEN ( 5 | ( 2 << 24 ))
+#define SIMDBase_PARAMID_MODE_AVAILABILITY ( 6 | ( 2 << 24 ))
+#define SIMDBase_PARAMID_MODE_NAME ( 7 | ( 2 << 24 ))
+
+//
+
+typedef struct {
+ uint32_t linesize;
+ uint32_t size[8], assoc[8];
+} CacheParam;
+
+void *SIMDBase_alignedMalloc(uint64_t size);
+void SIMDBase_alignedFree(void *ptr);
+int32_t SIMDBase_sizeOfCachelineInByte();
+int32_t SIMDBase_sizeOfDataCacheInByte();
+int32_t SIMDBase_chooseBestMode(int32_t typeId);
+char *SIMDBase_getProcessorNameString();
+int32_t SIMDBase_detect(int32_t paramId);
+int32_t SIMDBase_getParamInt(int32_t paramId);
+int32_t SIMDBase_getTypeParamInt(int32_t paramId, int32_t typeId);
+int32_t SIMDBase_getModeParamInt(int32_t paramId, int32_t mode);
+char *SIMDBase_getModeParamString(int32_t paramId, int32_t mode);
+
+#endif
diff --git a/plugins/supereq/nsfft-1.00/simd/SIMDBaseUndiff.c b/plugins/supereq/nsfft-1.00/simd/SIMDBaseUndiff.c
new file mode 100644
index 00000000..257a5ff0
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/simd/SIMDBaseUndiff.c
@@ -0,0 +1,38 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "SIMDBase.h"
+#include "SIMDBaseUndiff.h"
+
+void SIMDBaseUndiff_DETECT() {
+ extern uint8_t detectBuffer[256];
+ SIMDBase_VECT a = SIMDBase_LOAD((SIMDBase_VECT *)&detectBuffer[0]);
+ SIMDBase_VECT b = SIMDBase_LOAD((SIMDBase_VECT *)&detectBuffer[64]);
+ SIMDBase_VECT c = SIMDBase_ADDi(a, b);
+ SIMDBase_STOR((SIMDBase_VECT *)&detectBuffer[128], c);
+}
+
+int32_t SIMDBaseUndiff_GETMODEPARAMINT(int32_t paramId) {
+ switch(paramId) {
+ case SIMDBase_PARAMID_SIZE_OF_REAL:
+ return sizeof(SIMDBase_REAL);
+ case SIMDBase_PARAMID_SIZE_OF_VECT:
+ return sizeof(SIMDBase_VECT);
+ case SIMDBase_PARAMID_VECTOR_LEN:
+ return SIMDBase_VECTLEN;
+ case SIMDBase_PARAMID_MODE_AVAILABILITY:
+ return SIMDBase_detect(paramId);
+ }
+
+ return -1;
+}
+
+char * SIMDBaseUndiff_GETMODEPARAMSTRING(int32_t paramId) {
+ switch(paramId) {
+ case SIMDBase_PARAMID_MODE_NAME:
+ return SIMDBase_NAME;
+ }
+
+ return NULL;
+}
diff --git a/plugins/supereq/nsfft-1.00/simd/SIMDBaseUndiff.h b/plugins/supereq/nsfft-1.00/simd/SIMDBaseUndiff.h
new file mode 100644
index 00000000..1af849a8
--- /dev/null
+++ b/plugins/supereq/nsfft-1.00/simd/SIMDBaseUndiff.h
@@ -0,0 +1,231 @@
+#ifndef _SIMDBaseUndiff_H_
+#define _SIMDBaseUndiff_H_
+
+#if defined(ENABLE_PUREC_FLOAT) ////////////////////////////////////////////
+
+typedef float SIMDBase_REAL;
+typedef float SIMDBase_VECT;
+
+#define SIMDBase_MODE 1
+#define SIMDBase_TYPE SIMDBase_TYPE_FLOAT
+#define SIMDBase_VECTLEN 1
+#define SIMDBase_NAME "Pure C float"
+#define SIMDBaseUndiff_DETECT detect_purec_float
+#define SIMDBaseUndiff_GETMODEPARAMINT getModeParamInt_purec_float
+#define SIMDBaseUndiff_GETMODEPARAMSTRING getModeParamString_purec_float
+
+static inline SIMDBase_VECT SIMDBase_LOAD(SIMDBase_VECT *p) { return *p; }
+static inline void SIMDBase_STOR(SIMDBase_VECT *p, SIMDBase_VECT u) { *p = u; }
+static inline SIMDBase_VECT SIMDBase_SET1(SIMDBase_REAL f) { return f; }
+static inline SIMDBase_VECT SIMDBase_LOAD1(SIMDBase_REAL *p) { return *p; }
+static inline SIMDBase_VECT SIMDBase_ADDi(SIMDBase_VECT u, SIMDBase_VECT v) { return u + v; }
+static inline SIMDBase_VECT SIMDBase_SUBi(SIMDBase_VECT u, SIMDBase_VECT v) { return u - v; }
+static inline SIMDBase_VECT SIMDBase_MULi(SIMDBase_VECT u, SIMDBase_VECT v) { return u * v; }
+static inline SIMDBase_VECT SIMDBase_NEGi(SIMDBase_VECT u) { return -u; }
+
+#elif defined(ENABLE_PUREC_DOUBLE) ////////////////////////////////////////////
+
+typedef double SIMDBase_REAL;
+typedef double SIMDBase_VECT;
+
+#define SIMDBase_MODE 2
+#define SIMDBase_TYPE SIMDBase_TYPE_DOUBLE
+#define SIMDBase_VECTLEN 1
+#define SIMDBase_NAME "Pure C double"
+#define SIMDBaseUndiff_DETECT detect_purec_double
+#define SIMDBaseUndiff_GETMODEPARAMINT getModeParamInt_purec_double
+#define SIMDBaseUndiff_GETMODEPARAMSTRING getModeParamString_purec_double
+
+static inline SIMDBase_VECT SIMDBase_LOAD(SIMDBase_VECT *p) { return *p; }
+static inline void SIMDBase_STOR(SIMDBase_VECT *p, SIMDBase_VECT u) { *p = u; }
+static inline SIMDBase_VECT SIMDBase_SET1(SIMDBase_REAL f) { return f; }
+static inline SIMDBase_VECT SIMDBase_LOAD1(SIMDBase_REAL *p) { return *p; }
+static inline SIMDBase_VECT SIMDBase_ADDi(SIMDBase_VECT u, SIMDBase_VECT v) { return u + v; }
+static inline SIMDBase_VECT SIMDBase_SUBi(SIMDBase_VECT u, SIMDBase_VECT v) { return u - v; }
+static inline SIMDBase_VECT SIMDBase_MULi(SIMDBase_VECT u, SIMDBase_VECT v) { return u * v; }
+static inline SIMDBase_VECT SIMDBase_NEGi(SIMDBase_VECT u) { return -u; }
+
+#elif defined(ENABLE_PUREC_LONGDOUBLE) ////////////////////////////////////////////
+
+typedef long double SIMDBase_REAL;
+typedef long double SIMDBase_VECT;
+
+#define SIMDBase_MODE 3
+#define SIMDBase_TYPE SIMDBase_TYPE_LONGDOUBLE
+#define SIMDBase_VECTLEN 1
+#define SIMDBase_NAME "Pure C long double"
+#define SIMDBaseUndiff_DETECT detect_purec_longdouble
+#define SIMDBaseUndiff_GETMODEPARAMINT getModeParamInt_purec_longdouble
+#define SIMDBaseUndiff_GETMODEPARAMSTRING getModeParamString_purec_longdouble
+
+static inline SIMDBase_VECT SIMDBase_LOAD(SIMDBase_VECT *p) { return *p; }
+static inline void SIMDBase_STOR(SIMDBase_VECT *p, SIMDBase_VECT u) { *p = u; }
+static inline SIMDBase_VECT SIMDBase_SET1(SIMDBase_REAL f) { return f; }
+static inline SIMDBase_VECT SIMDBase_LOAD1(SIMDBase_REAL *p) { return *p; }
+static inline SIMDBase_VECT SIMDBase_ADDi(SIMDBase_VECT u, SIMDBase_VECT v) { return u + v; }
+static inline SIMDBase_VECT SIMDBase_SUBi(SIMDBase_VECT u, SIMDBase_VECT v) { return u - v; }
+static inline SIMDBase_VECT SIMDBase_MULi(SIMDBase_VECT u, SIMDBase_VECT v) { return u * v; }
+static inline SIMDBase_VECT SIMDBase_NEGi(SIMDBase_VECT u) { return -u; }
+
+#elif defined(ENABLE_SSE_FLOAT) ////////////////////////////////////////////
+
+#include <xmmintrin.h>
+
+typedef float SIMDBase_REAL;
+typedef __m128 SIMDBase_VECT;
+
+#define SIMDBase_MODE 4
+#define SIMDBase_TYPE SIMDBase_TYPE_FLOAT
+#define SIMDBase_VECTLEN 4
+#define SIMDBase_NAME "x86 SSE float"
+#define SIMDBaseUndiff_DETECT detect_sse_float
+#define SIMDBaseUndiff_GETMODEPARAMINT getModeParamInt_sse_float
+#define SIMDBaseUndiff_GETMODEPARAMSTRING getModeParamString_sse_float
+
+static inline SIMDBase_VECT SIMDBase_LOAD(SIMDBase_VECT *p) { return _mm_load_ps((float *)p); }
+static inline void SIMDBase_STOR(SIMDBase_VECT *p, SIMDBase_VECT u) { _mm_store_ps((float *)p, u); }
+static inline SIMDBase_VECT SIMDBase_SET1(SIMDBase_REAL f) { return _mm_set1_ps(f); }
+static inline SIMDBase_VECT SIMDBase_LOAD1(SIMDBase_REAL *p) { return _mm_load1_ps(p); }
+static inline SIMDBase_VECT SIMDBase_ADDi(SIMDBase_VECT u, SIMDBase_VECT v) { return _mm_add_ps(u, v); }
+static inline SIMDBase_VECT SIMDBase_SUBi(SIMDBase_VECT u, SIMDBase_VECT v) { return _mm_sub_ps(u, v); }
+static inline SIMDBase_VECT SIMDBase_MULi(SIMDBase_VECT u, SIMDBase_VECT v) { return _mm_mul_ps(u, v); }
+static inline SIMDBase_VECT SIMDBase_NEGi(SIMDBase_VECT u) { return _mm_xor_ps(u, _mm_set_ps(-0.0f, -0.0f, -0.0f, -0.0f)); }
+
+#elif defined(ENABLE_SSE2_DOUBLE) ////////////////////////////////////////////
+
+#include <emmintrin.h>
+
+typedef double SIMDBase_REAL;
+typedef __m128d SIMDBase_VECT;
+
+#define SIMDBase_MODE 5
+#define SIMDBase_TYPE SIMDBase_TYPE_DOUBLE
+#define SIMDBase_VECTLEN 2
+#define SIMDBase_NAME "x86 SSE2 double"
+#define SIMDBaseUndiff_DETECT detect_sse2_double
+#define SIMDBaseUndiff_GETMODEPARAMINT getModeParamInt_sse2_double
+#define SIMDBaseUndiff_GETMODEPARAMSTRING getModeParamString_sse2_double
+
+static inline SIMDBase_VECT SIMDBase_LOAD(SIMDBase_VECT *p) { return _mm_load_pd((double *)p); }
+static inline void SIMDBase_STOR(SIMDBase_VECT *p, SIMDBase_VECT u) { _mm_store_pd((double *)p, u); }
+static inline SIMDBase_VECT SIMDBase_SET1(SIMDBase_REAL f) { return _mm_set1_pd(f); }
+static inline SIMDBase_VECT SIMDBase_LOAD1(SIMDBase_REAL *p) { return _mm_load1_pd(p); }
+static inline SIMDBase_VECT SIMDBase_ADDi(SIMDBase_VECT u, SIMDBase_VECT v) { return _mm_add_pd(u, v); }
+static inline SIMDBase_VECT SIMDBase_SUBi(SIMDBase_VECT u, SIMDBase_VECT v) { return _mm_sub_pd(u, v); }
+static inline SIMDBase_VECT SIMDBase_MULi(SIMDBase_VECT u, SIMDBase_VECT v) { return _mm_mul_pd(u, v); }
+static inline SIMDBase_VECT SIMDBase_NEGi(SIMDBase_VECT u) { return _mm_xor_pd(u, _mm_set_pd(-0.0, -0.0)); }
+
+#elif defined(ENABLE_NEON_FLOAT) ////////////////////////////////////////////
+
+#include <arm_neon.h>
+
+typedef float32_t SIMDBase_REAL;
+typedef float32x4_t SIMDBase_VECT;
+
+#define SIMDBase_MODE 6
+#define SIMDBase_TYPE SIMDBase_TYPE_FLOAT
+#define SIMDBase_VECTLEN 4
+#define SIMDBase_NAME "ARM NEON float"
+#define SIMDBaseUndiff_DETECT detect_neon_float
+#define SIMDBaseUndiff_GETMODEPARAMINT getModeParamInt_neon_float
+#define SIMDBaseUndiff_GETMODEPARAMSTRING getModeParamString_neon_float
+
+static inline SIMDBase_VECT SIMDBase_LOAD(SIMDBase_VECT *p) { return vld1q_f32((float32_t *)p); }
+static inline void SIMDBase_STOR(SIMDBase_VECT *p, SIMDBase_VECT u) { vst1q_f32((float32_t *)p, u); }
+static inline SIMDBase_VECT SIMDBase_SET1(SIMDBase_REAL f) { return vdupq_n_f32(f); }
+static inline SIMDBase_VECT SIMDBase_LOAD1(SIMDBase_REAL *p) { return vdupq_n_f32(*p); }
+static inline SIMDBase_VECT SIMDBase_ADDi(SIMDBase_VECT u, SIMDBase_VECT v) { return vaddq_f32(u, v); }
+static inline SIMDBase_VECT SIMDBase_SUBi(SIMDBase_VECT u, SIMDBase_VECT v) { return vsubq_f32(u, v); }
+static inline SIMDBase_VECT SIMDBase_MULi(SIMDBase_VECT u, SIMDBase_VECT v) { return vmulq_f32(u, v); }
+static inline SIMDBase_VECT SIMDBase_NEGi(SIMDBase_VECT u) {
+ return vreinterpretq_f32_u32( veorq_u32(vreinterpretq_u32_f32(u), vdupq_n_u32(0x80000000U)));
+}
+
+#define SIMDBase_FMADD_AVAILABLE
+
+static inline SIMDBase_VECT SIMDBase_FMADDi(SIMDBase_VECT u, SIMDBase_VECT v, SIMDBase_VECT w) { return vmlaq_f32(w, u, v); } // w + u * v
+static inline SIMDBase_VECT SIMDBase_FMSUBi(SIMDBase_VECT u, SIMDBase_VECT v, SIMDBase_VECT w) { return vmlsq_f32(w, u, v); } // w - u * v
+
+#elif defined(ENABLE_AVX_FLOAT) ////////////////////////////////////////////
+
+#include <immintrin.h>
+
+typedef float SIMDBase_REAL;
+typedef __m256 SIMDBase_VECT;
+
+#define SIMDBase_MODE 7
+#define SIMDBase_TYPE SIMDBase_TYPE_FLOAT
+#define SIMDBase_VECTLEN 8
+#define SIMDBase_NAME "x86 AVX float"
+#define SIMDBaseUndiff_DETECT detect_avx_float
+#define SIMDBaseUndiff_GETMODEPARAMINT getModeParamInt_avx_float
+#define SIMDBaseUndiff_GETMODEPARAMSTRING getModeParamString_avx_float
+
+static inline SIMDBase_VECT SIMDBase_LOAD(SIMDBase_VECT *p) { return _mm256_load_ps((float *)p); }
+static inline void SIMDBase_STOR(SIMDBase_VECT *p, SIMDBase_VECT u) { _mm256_store_ps((float *)p, u); }
+static inline SIMDBase_VECT SIMDBase_SET1(SIMDBase_REAL f) { return _mm256_set1_ps(f); }
+static inline SIMDBase_VECT SIMDBase_LOAD1(SIMDBase_REAL *p) { return _mm256_set1_ps(*p); }
+static inline SIMDBase_VECT SIMDBase_ADDi(SIMDBase_VECT u, SIMDBase_VECT v) { return _mm256_add_ps(u, v); }
+static inline SIMDBase_VECT SIMDBase_SUBi(SIMDBase_VECT u, SIMDBase_VECT v) { return _mm256_sub_ps(u, v); }
+static inline SIMDBase_VECT SIMDBase_MULi(SIMDBase_VECT u, SIMDBase_VECT v) { return _mm256_mul_ps(u, v); }
+static inline SIMDBase_VECT SIMDBase_NEGi(SIMDBase_VECT u) { return _mm256_xor_ps(u, _mm256_set1_ps(-0.0f)); }
+
+#elif defined(ENABLE_AVX_DOUBLE) ////////////////////////////////////////////
+
+#include <immintrin.h>
+
+typedef double SIMDBase_REAL;
+typedef __m256d SIMDBase_VECT;
+
+#define SIMDBase_MODE 8
+#define SIMDBase_TYPE SIMDBase_TYPE_DOUBLE
+#define SIMDBase_VECTLEN 4
+#define SIMDBase_NAME "x86 AVX double"
+#define SIMDBaseUndiff_DETECT detect_avx_double
+#define SIMDBaseUndiff_GETMODEPARAMINT getModeParamInt_avx_double
+#define SIMDBaseUndiff_GETMODEPARAMSTRING getModeParamString_avx_double
+
+static inline SIMDBase_VECT SIMDBase_LOAD(SIMDBase_VECT *p) { return _mm256_load_pd((double *)p); }
+static inline void SIMDBase_STOR(SIMDBase_VECT *p, SIMDBase_VECT u) { _mm256_store_pd((double *)p, u); }
+static inline SIMDBase_VECT SIMDBase_SET1(SIMDBase_REAL f) { return _mm256_set1_pd(f); }
+static inline SIMDBase_VECT SIMDBase_LOAD1(SIMDBase_REAL *p) { return _mm256_set1_pd(*p); }
+static inline SIMDBase_VECT SIMDBase_ADDi(SIMDBase_VECT u, SIMDBase_VECT v) { return _mm256_add_pd(u, v); }
+static inline SIMDBase_VECT SIMDBase_SUBi(SIMDBase_VECT u, SIMDBase_VECT v) { return _mm256_sub_pd(u, v); }
+static inline SIMDBase_VECT SIMDBase_MULi(SIMDBase_VECT u, SIMDBase_VECT v) { return _mm256_mul_pd(u, v); }
+static inline SIMDBase_VECT SIMDBase_NEGi(SIMDBase_VECT u) { return _mm256_xor_pd(u, _mm256_set1_pd(-0.0)); }
+
+#elif defined(ENABLE_ALTIVEC_FLOAT) ////////////////////////////////////////////
+
+#include <altivec.h>
+
+typedef float SIMDBase_REAL;
+typedef vector float SIMDBase_VECT;
+
+#define SIMDBase_MODE 9
+#define SIMDBase_TYPE SIMDBase_TYPE_FLOAT
+#define SIMDBase_VECTLEN 4
+#define SIMDBase_NAME "PowerPC AltiVec float"
+#define SIMDBaseUndiff_DETECT detect_altivec_float
+#define SIMDBaseUndiff_GETMODEPARAMINT getModeParamInt_altivec_float
+#define SIMDBaseUndiff_GETMODEPARAMSTRING getModeParamString_altivec_float
+
+static inline SIMDBase_VECT SIMDBase_LOAD(SIMDBase_VECT *p) { return vec_ld(0, p); }
+static inline void SIMDBase_STOR(SIMDBase_VECT *p, SIMDBase_VECT u) { vec_st(u, 0, p); }
+static inline SIMDBase_VECT SIMDBase_SET1(SIMDBase_REAL f) { return (vector float){f, f, f, f}; }
+static inline SIMDBase_VECT SIMDBase_LOAD1(SIMDBase_REAL *p) { return (vector float){*p, *p, *p, *p}; }
+static inline SIMDBase_VECT SIMDBase_ADDi(SIMDBase_VECT u, SIMDBase_VECT v) { return vec_add(u, v); }
+static inline SIMDBase_VECT SIMDBase_SUBi(SIMDBase_VECT u, SIMDBase_VECT v) { return vec_sub(u, v); }
+static inline SIMDBase_VECT SIMDBase_MULi(SIMDBase_VECT u, SIMDBase_VECT v) { return vec_madd(u, v, (vector float){0, 0, 0, 0}); }
+static inline SIMDBase_VECT SIMDBase_NEGi(SIMDBase_VECT u) { return vec_xor(u, (vector float){-0.0f, -0.0f, -0.0f, -0.0f}); }
+
+#define SIMDBase_FMADD_AVAILABLE
+
+static inline SIMDBase_VECT SIMDBase_FMADDi(SIMDBase_VECT u, SIMDBase_VECT v, SIMDBase_VECT w) { return vec_madd(u, v, w); } // w + u * v
+static inline SIMDBase_VECT SIMDBase_FMSUBi(SIMDBase_VECT u, SIMDBase_VECT v, SIMDBase_VECT w) { return vec_nmsub(u, v, w); } // w - u * v
+
+#endif ////////////////////////////////////////////////////////////////////
+
+static inline SIMDBase_VECT SIMDBase_ADDm(SIMDBase_VECT *p, SIMDBase_VECT *q) { return SIMDBase_ADDi(SIMDBase_LOAD(p), SIMDBase_LOAD(q)); }
+static inline SIMDBase_VECT SIMDBase_SUBm(SIMDBase_VECT *p, SIMDBase_VECT *q) { return SIMDBase_SUBi(SIMDBase_LOAD(p), SIMDBase_LOAD(q)); }
+
+#endif
diff --git a/plugins/supereq/paramlist.hpp b/plugins/supereq/paramlist.hpp
index 0c513b78..9c5b09c4 100644
--- a/plugins/supereq/paramlist.hpp
+++ b/plugins/supereq/paramlist.hpp
@@ -1,4 +1,22 @@
-//#include <iostream.h>
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>
+ Original SuperEQ code (C) Naoki Shibata <shibatch@users.sf.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 <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -7,12 +25,10 @@ class paramlistelm {
public:
class paramlistelm *next;
- char left,right;
float lower,upper,gain,gain2;
int sortindex;
paramlistelm(void) {
- left = right = 1;
lower = upper = gain = 0;
next = NULL;
};
@@ -21,13 +37,6 @@ public:
delete next;
next = NULL;
};
-
- char *getString(void) {
- static char str[64];
- sprintf(str,"%gHz to %gHz, %gdB %c%c",
- (double)lower,(double)upper,(double)gain,left?'L':' ',right?'R':' ');
- return str;
- }
};
class paramlist {
@@ -52,8 +61,6 @@ public:
for(p=&elm,q=src.elm;q != NULL;q = q->next,p = &(*p)->next)
{
*p = new paramlistelm;
- (*p)->left = q->left;
- (*p)->right = q->right;
(*p)->lower = q->lower;
(*p)->upper = q->upper;
(*p)->gain = q->gain;
diff --git a/plugins/supereq/shibatch_rdft.c b/plugins/supereq/shibatch_rdft.c
new file mode 100644
index 00000000..db453eb8
--- /dev/null
+++ b/plugins/supereq/shibatch_rdft.c
@@ -0,0 +1,71 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+
+#include "SIMDBase.h"
+#include "DFT.h"
+
+#define TYPE SIMDBase_TYPE_FLOAT
+
+void rfft(int n,int isign,float *x) {
+ static DFT *p = NULL;
+ static float *buf = NULL;
+ static int ipsize = 0;
+ static int mode = 0;
+ static int veclen = 0;
+ int newipsize;
+ if (n == 0) {
+ if (buf) {
+ SIMDBase_alignedFree (buf);
+ buf = NULL;
+ }
+ if (p) {
+ DFT_dispose(p, mode);
+ p = NULL;
+ }
+ return;
+ }
+ int nn = n;
+ n = 1<<n;
+ newipsize = n;
+ if (newipsize != ipsize) {
+ ipsize = newipsize;
+
+ if (buf) {
+ SIMDBase_alignedFree (buf);
+ buf = NULL;
+ }
+
+ if (p) {
+ DFT_dispose(p, mode);
+ p = NULL;
+ }
+
+ buf = SIMDBase_alignedMalloc (n * sizeof (float));
+
+ mode = SIMDBase_chooseBestMode(TYPE);
+ veclen = SIMDBase_getModeParamInt(SIMDBase_PARAMID_VECTOR_LEN, mode);
+ int sizeOfVect = SIMDBase_getModeParamInt(SIMDBase_PARAMID_SIZE_OF_VECT, mode);
+ printf ("n: %d, veclen: %d, sizeOfVect: %d\n", n, veclen, sizeOfVect);
+ p = DFT_init(mode, n/veclen, DFT_FLAG_REAL);
+ }
+
+ // store in simd order
+ int asize = n / veclen;
+ int i, j;
+ for(j=0;j<veclen;j++) {
+ for (i = 0; i < asize; i++) {
+ buf[i * veclen + j] = x[j * asize + i];
+ }
+ }
+
+ DFT_execute(p, mode, buf, isign);
+
+#define THRES 1e-3
+ for(j=0;j<veclen;j++) {
+ for (i = 0; i < asize; i++) {
+ x[j * asize + i] = buf[i * veclen + j];
+ }
+ }
+}
diff --git a/plugins/supereq/supereq.c b/plugins/supereq/supereq.c
index af4000fd..a773b4ef 100644
--- a/plugins/supereq/supereq.c
+++ b/plugins/supereq/supereq.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -18,217 +18,301 @@
*/
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
+#include <math.h>
#include "../../deadbeef.h"
-#include "supereq.h"
+#include "Equ.h"
static DB_functions_t *deadbeef;
-static DB_supereq_dsp_t plugin;
-
-void *paramlist_alloc (void);
-void paramlist_free (void *);
-void equ_makeTable(float *lbc,float *rbc,void *param,float fs);
-int equ_modifySamples(char *buf,int nsamples,int nch,int bps);
-void equ_clearbuf(int bps,int srate);
-void equ_init(int wb);
-void equ_quit(void);
-
-void supereq_reset (void);
-
-static float last_srate = 0;
-static int last_nch = 0, last_bps = 0;
-static float lbands[18] = {1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0};
-static float rbands[18] = {1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0};
-static float preamp = 1;
-static void *paramsroot;
-
-static int params_changed = 0;
-static intptr_t tid = 0;
-static uintptr_t mutex = 0;
-static int enabled = 0;
-
-static int
-supereq_on_configchanged (DB_event_t *ev, uintptr_t data) {
- int e = deadbeef->conf_get_int ("supereq.enable", 0);
- if (e != enabled) {
- if (e) {
- supereq_reset ();
- }
- enabled = e;
- }
-
- return 0;
-}
+static DB_dsp_t plugin;
+
+typedef struct {
+ ddb_dsp_context_t ctx;
+ float last_srate;
+ int last_nch;
+ float bands[18];
+ float preamp;
+ void *paramsroot;
+ int params_changed;
+ uintptr_t mutex;
+ SuperEqState state;
+ int enabled;
+} ddb_supereq_ctx_t;
+
+void supereq_reset (ddb_dsp_context_t *ctx);
void
-recalc_table (void) {
+recalc_table (ddb_supereq_ctx_t *eq) {
void *params = paramlist_alloc ();
- deadbeef->mutex_lock (mutex);
- float lbands_copy[18];
- float rbands_copy[18];
- float srate = last_srate;
- memcpy (lbands_copy, lbands, sizeof (lbands));
- memcpy (rbands_copy, rbands, sizeof (rbands));
+ deadbeef->mutex_lock (eq->mutex);
+ float bands_copy[18];
+ float srate = eq->last_srate;
+ memcpy (bands_copy, eq->bands, sizeof (eq->bands));
for (int i = 0; i < 18; i++) {
- lbands_copy[i] *= preamp;
- rbands_copy[i] *= preamp;
+ bands_copy[i] *= eq->preamp;
}
- deadbeef->mutex_unlock (mutex);
+ deadbeef->mutex_unlock (eq->mutex);
- equ_makeTable (lbands_copy, rbands_copy, params, srate);
+ equ_makeTable (&eq->state, bands_copy, params, srate);
- deadbeef->mutex_lock (mutex);
- paramlist_free (paramsroot);
- paramsroot = params;
- deadbeef->mutex_unlock (mutex);
+ deadbeef->mutex_lock (eq->mutex);
+ paramlist_free (eq->paramsroot);
+ eq->paramsroot = params;
+ deadbeef->mutex_unlock (eq->mutex);
}
int
supereq_plugin_start (void) {
- enabled = deadbeef->conf_get_int ("supereq.enable", 0);
- // load bands from config
- preamp = deadbeef->conf_get_float ("eq.preamp", 1);
- for (int i = 0; i < 18; i++) {
- char key[100];
- snprintf (key, sizeof (key), "eq.band%d", i);
- lbands[i] = rbands[i] = deadbeef->conf_get_float (key, 1);
- }
-
- equ_init (14);
- paramsroot = paramlist_alloc ();
- last_srate = 44100;
- last_nch = 2;
- last_bps = 16;
- mutex = deadbeef->mutex_create ();
- recalc_table ();
- equ_clearbuf (last_bps,last_srate);
- deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_CONFIGCHANGED, DB_CALLBACK (supereq_on_configchanged), 0);
return 0;
}
int
supereq_plugin_stop (void) {
- deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_CONFIGCHANGED, DB_CALLBACK (supereq_on_configchanged), 0);
- if (tid) {
- deadbeef->thread_join (tid);
- tid = 0;
- }
- if (mutex) {
- deadbeef->mutex_free (mutex);
- mutex = 0;
- }
- equ_quit ();
- paramlist_free (paramsroot);
return 0;
}
-void
-supereq_regen_table_thread (void *param) {
- recalc_table ();
- tid = 0;
-}
-
int
-supereq_process_int16 (int16_t *samples, int nsamples, int nch, int bps, int srate) {
- if ((nch != 1 && nch != 2) || (bps != 8 && bps != 16 && bps != 24)) return nsamples;
- if (params_changed && !tid) {
- tid = deadbeef->thread_start (supereq_regen_table_thread, NULL);
- params_changed = 0;
+supereq_process (ddb_dsp_context_t *ctx, float *samples, int frames, int maxframes, ddb_waveformat_t *fmt, float *r) {
+ ddb_supereq_ctx_t *supereq = (ddb_supereq_ctx_t *)ctx;
+ if (supereq->enabled != ctx->enabled) {
+ if (ctx->enabled && !supereq->enabled) {
+ supereq_reset (ctx);
+ }
+ supereq->enabled = ctx->enabled;
+
+// this causes a glitch on 1st track
+// DB_playItem_t *it = deadbeef->streamer_get_playing_track ();
+// if (it) {
+// float playpos = deadbeef->streamer_get_playpos ();
+// deadbeef->streamer_seek (playpos);
+// deadbeef->pl_item_unref (it);
+// }
}
- if (last_srate != srate) {
- deadbeef->mutex_lock (mutex);
- //equ_makeTable (lbands, rbands, paramsroot, srate);
- last_srate = srate;
- last_nch = nch;
- last_bps = bps;
- recalc_table ();
- deadbeef->mutex_unlock (mutex);
- equ_clearbuf(bps,srate);
+ if (supereq->params_changed) {
+ recalc_table (supereq);
+ supereq->params_changed = 0;
}
- else if (last_nch != nch || last_bps != bps) {
- deadbeef->mutex_lock (mutex);
- last_nch = nch;
- last_bps = bps;
- deadbeef->mutex_unlock (mutex);
- equ_clearbuf(bps,srate);
+ if (supereq->last_srate != fmt->samplerate || supereq->last_nch != fmt->channels) {
+ deadbeef->mutex_lock (supereq->mutex);
+ supereq->last_srate = fmt->samplerate;
+ supereq->last_nch = fmt->channels;
+ equ_init (&supereq->state, 10, fmt->channels);
+ recalc_table (supereq);
+ equ_clearbuf(&supereq->state);
+ deadbeef->mutex_unlock (supereq->mutex);
}
- equ_modifySamples((char *)samples,nsamples,nch,bps);
- return nsamples;
+ equ_modifySamples_float(&supereq->state, (char *)samples,frames,fmt->channels);
+ return frames;
}
float
-supereq_get_band (int band) {
- return lbands[band];
+supereq_get_band (ddb_dsp_context_t *ctx, int band) {
+ ddb_supereq_ctx_t *supereq = (ddb_supereq_ctx_t *)ctx;
+ return supereq->bands[band];
}
void
-supereq_set_band (int band, float value) {
- deadbeef->mutex_lock (mutex);
- lbands[band] = rbands[band] = value;
- deadbeef->mutex_unlock (mutex);
- params_changed = 1;
- char key[100];
- snprintf (key, sizeof (key), "eq.band%d", band);
- deadbeef->conf_set_float (key, value);
+supereq_set_band (ddb_dsp_context_t *ctx, int band, float value) {
+ ddb_supereq_ctx_t *supereq = (ddb_supereq_ctx_t *)ctx;
+ deadbeef->mutex_lock (supereq->mutex);
+ supereq->bands[band] = value;
+ deadbeef->mutex_unlock (supereq->mutex);
+ supereq->params_changed = 1;
}
float
-supereq_get_preamp (void) {
- return preamp;
+supereq_get_preamp (ddb_dsp_context_t *ctx) {
+ ddb_supereq_ctx_t *supereq = (ddb_supereq_ctx_t *)ctx;
+ return supereq->preamp;
}
void
-supereq_set_preamp (float value) {
- deadbeef->mutex_lock (mutex);
- preamp = value;
- deadbeef->mutex_unlock (mutex);
- params_changed = 1;
- deadbeef->conf_set_float ("eq.preamp", value);
+supereq_set_preamp (ddb_dsp_context_t *ctx, float value) {
+ ddb_supereq_ctx_t *supereq = (ddb_supereq_ctx_t *)ctx;
+ deadbeef->mutex_lock (supereq->mutex);
+ supereq->preamp = value;
+ deadbeef->mutex_unlock (supereq->mutex);
+ supereq->params_changed = 1;
}
void
-supereq_reset (void) {
- deadbeef->mutex_lock (mutex);
- equ_clearbuf(last_bps,last_srate);
- deadbeef->mutex_unlock (mutex);
+supereq_reset (ddb_dsp_context_t *ctx) {
+ ddb_supereq_ctx_t *supereq = (ddb_supereq_ctx_t *)ctx;
+ deadbeef->mutex_lock (supereq->mutex);
+ equ_clearbuf(&supereq->state);
+ deadbeef->mutex_unlock (supereq->mutex);
+}
+
+int
+supereq_num_params (void) {
+ return 19;
+}
+
+static const char *bandnames[] = {
+ "Preamp",
+ "55 Hz",
+ "77 Hz",
+ "110 Hz",
+ "156 Hz",
+ "220 Hz",
+ "311 Hz",
+ "440 Hz",
+ "622 Hz",
+ "880 Hz",
+ "1.2 kHz",
+ "1.8 kHz",
+ "2.5 kHz",
+ "3.5 kHz",
+ "5 kHz",
+ "7 kHz",
+ "10 kHz",
+ "14 kHz",
+ "20 kHz"
+};
+
+const char *
+supereq_get_param_name (int p) {
+ return bandnames[p];
+}
+
+
+static inline float
+db_to_amp (float dB) {
+ const float ln10=2.3025850929940002f;
+ return exp(ln10*dB/20.f);
+}
+
+static inline float
+amp_to_db (float amp) {
+ return 20*log10 (amp);
}
void
-supereq_enable (int e) {
- if (e != enabled) {
- deadbeef->conf_set_int ("supereq.enable", e);
- if (e && !enabled) {
- supereq_reset ();
- }
- enabled = e;
+supereq_set_param (ddb_dsp_context_t *ctx, int p, const char *val) {
+ switch (p) {
+ case 0:
+ supereq_set_preamp (ctx, db_to_amp (atof (val)));
+ break;
+ case 1 ... 18:
+ supereq_set_band (ctx, p-1, db_to_amp (atof (val)));
+ break;
+ default:
+ fprintf (stderr, "supereq_set_param: invalid param index (%d)\n", p);
}
}
-int
-supereq_enabled (void) {
- return enabled;
-}
-
-static DB_supereq_dsp_t plugin = {
- .dsp.plugin.api_vmajor = DB_API_VERSION_MAJOR,
- .dsp.plugin.api_vminor = DB_API_VERSION_MINOR,
- .dsp.plugin.type = DB_PLUGIN_DSP,
- .dsp.plugin.id = "supereq",
- .dsp.plugin.name = "SuperEQ",
- .dsp.plugin.descr = "equalizer plugin using SuperEQ library by Naoki Shibata",
- .dsp.plugin.author = "Alexey Yakovenko",
- .dsp.plugin.email = "waker@users.sourceforge.net",
- .dsp.plugin.website = "http://deadbeef.sf.net",
- .dsp.plugin.start = supereq_plugin_start,
- .dsp.plugin.stop = supereq_plugin_stop,
- .dsp.process_int16 = supereq_process_int16,
- .dsp.reset = supereq_reset,
- .dsp.enable = supereq_enable,
- .dsp.enabled = supereq_enabled,
- .get_band = supereq_get_band,
- .set_band = supereq_set_band,
- .get_preamp = supereq_get_preamp,
- .set_preamp = supereq_set_preamp,
+void
+supereq_get_param (ddb_dsp_context_t *ctx, int p, char *v, int sz) {
+ switch (p) {
+ case 0:
+ snprintf (v, sz, "%f", amp_to_db (supereq_get_preamp (ctx)));
+ break;
+ case 1 ... 18:
+ snprintf (v, sz, "%f", amp_to_db (supereq_get_band (ctx, p-1)));
+ break;
+ default:
+ fprintf (stderr, "supereq_get_param: invalid param index (%d)\n", p);
+ }
+}
+
+
+ddb_dsp_context_t*
+supereq_open (void) {
+ ddb_supereq_ctx_t *supereq = malloc (sizeof (ddb_supereq_ctx_t));
+ DDB_INIT_DSP_CONTEXT (supereq,ddb_supereq_ctx_t,&plugin);
+
+ equ_init (&supereq->state, 10, 2);
+ supereq->paramsroot = paramlist_alloc ();
+ supereq->last_srate = 44100;
+ supereq->last_nch = 2;
+ supereq->mutex = deadbeef->mutex_create ();
+ supereq->preamp = 1;
+ for (int i = 0; i < 18; i++) {
+ supereq->bands[i] = 1;
+ }
+ recalc_table (supereq);
+ equ_clearbuf (&supereq->state);
+
+ return (ddb_dsp_context_t*)supereq;
+}
+
+void
+supereq_close (ddb_dsp_context_t *ctx) {
+ ddb_supereq_ctx_t *supereq = (ddb_supereq_ctx_t *)ctx;
+ if (supereq->mutex) {
+ deadbeef->mutex_free (supereq->mutex);
+ supereq->mutex = 0;
+ }
+ equ_quit (&supereq->state);
+ paramlist_free (supereq->paramsroot);
+ free (ctx);
+}
+
+static const char settings_dlg[] =
+ "property \"\" hbox[19] hmg fill expand border=0 spacing=8 height=200;\n"
+ "property \"Preamp\" vscale[20,-20,1] vert 0 0;\n"
+ "property \"55 Hz\" vscale[20,-20,1] vert 1 0;\n"
+ "property \"77 Hz\" vscale[20,-20,1] vert 2 0;\n"
+ "property \"110 Hz\" vscale[20,-20,1] vert 3 0;\n"
+ "property \"156 Hz\" vscale[20,-20,1] vert 4 0;\n"
+ "property \"220 Hz\" vscale[20,-20,1] vert 5 0;\n"
+ "property \"311 Hz\" vscale[20,-20,1] vert 6 0;\n"
+ "property \"440 Hz\" vscale[20,-20,1] vert 7 0;\n"
+ "property \"622 Hz\" vscale[20,-20,1] vert 8 0;\n"
+ "property \"880 Hz\" vscale[20,-20,1] vert 9 0;\n"
+ "property \"1.2 kHz\" vscale[20,-20,1] vert 10 0;\n"
+ "property \"1.8 kHz\" vscale[20,-20,1] vert 11 0;\n"
+ "property \"2.5 kHz\" vscale[20,-20,1] vert 12 0;\n"
+ "property \"3.5 kHz\" vscale[20,-20,1] vert 13 0;\n"
+ "property \"5 kHz\" vscale[20,-20,1] vert 14 0;\n"
+ "property \"7 kHz\" vscale[20,-20,1] vert 15 0;\n"
+ "property \"10 kHz\" vscale[20,-20,1] vert 16 0;\n"
+ "property \"14 kHz\" vscale[20,-20,1] vert 17 0;\n"
+ "property \"20 kHz\" vscale[20,-20,1] vert 18 0;\n"
+;
+
+static DB_dsp_t plugin = {
+ .plugin.api_vmajor = DB_API_VERSION_MAJOR,
+ .plugin.api_vminor = DB_API_VERSION_MINOR,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
+ .plugin.type = DB_PLUGIN_DSP,
+ .plugin.id = "supereq",
+ .plugin.name = "SuperEQ",
+ .plugin.descr = "equalizer plugin using SuperEQ library",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "Uses supereq library by Naoki Shibata, http://shibatch.sourceforge.net\n"
+ "Uses FFT library by Takuya Ooura, http://www.kurims.kyoto-u.ac.jp/~ooura/\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
+ .plugin.website = "http://deadbeef.sf.net",
+ .plugin.start = supereq_plugin_start,
+ .plugin.stop = supereq_plugin_stop,
+ .open = supereq_open,
+ .close = supereq_close,
+ .process = supereq_process,
+ .reset = supereq_reset,
+ .num_params = supereq_num_params,
+ .get_param_name = supereq_get_param_name,
+ .set_param = supereq_set_param,
+ .get_param = supereq_get_param,
+ .configdialog = settings_dlg,
};
DB_plugin_t *
diff --git a/plugins/tta/filter.h b/plugins/tta/filter.h
index 6e8b13da..1f86cbb1 100644
--- a/plugins/tta/filter.h
+++ b/plugins/tta/filter.h
@@ -42,7 +42,7 @@
///////// Filter Settings //////////
static int flt_set[3] = {10, 9, 10};
-__inline void
+static __inline void
memshl (register int *pA, register int *pB) {
*pA++ = *pB++;
*pA++ = *pB++;
@@ -54,7 +54,7 @@ memshl (register int *pA, register int *pB) {
*pA = *pB;
}
-__inline void
+static __inline void
hybrid_filter (fltst *fs, int *in) {
register int *pA = fs->dl;
register int *pB = fs->qm;
diff --git a/plugins/tta/ttadec.c b/plugins/tta/ttadec.c
index d5466359..7a33d072 100644
--- a/plugins/tta/ttadec.c
+++ b/plugins/tta/ttadec.c
@@ -267,9 +267,7 @@ int open_tta_file (const char *filename, tta_info *info, unsigned int data_offse
info->HANDLE = infile;
// get file size
- deadbeef->fseek (infile, 0, SEEK_END);
- info->FILESIZE = deadbeef->ftell (infile);
- deadbeef->fseek (infile, 0, SEEK_SET);
+ info->FILESIZE = deadbeef->fgetlength (infile);
// read id3 tags
if (!data_offset) {
diff --git a/plugins/tta/ttaplug.c b/plugins/tta/ttaplug.c
index 196df859..20a0c8a5 100644
--- a/plugins/tta/ttaplug.c
+++ b/plugins/tta/ttaplug.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -20,6 +20,7 @@
#include <assert.h>
#include <limits.h>
#include <unistd.h>
+#include <math.h>
#include "ttadec.h"
#ifdef HAVE_CONFIG_H
# include <config.h>
@@ -49,7 +50,7 @@ typedef struct {
} tta_info_t;
static DB_fileinfo_t *
-tta_open (void) {
+tta_open (uint32_t hints) {
DB_fileinfo_t *_info = malloc (sizeof (tta_info_t));
tta_info_t *info = (tta_info_t *)_info;
memset (info, 0, sizeof (tta_info_t));
@@ -60,20 +61,23 @@ static int
tta_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
tta_info_t *info = (tta_info_t *)_info;
- trace ("open_tta_file %s\n", it->fname);
- if (open_tta_file (it->fname, &info->tta, 0) != 0) {
- fprintf (stderr, "tta: failed to open %s\n", it->fname);
+ trace ("open_tta_file %s\n", deadbeef->pl_find_meta (it, ":URI"));
+ if (open_tta_file (deadbeef->pl_find_meta (it, ":URI"), &info->tta, 0) != 0) {
+ fprintf (stderr, "tta: failed to open %s\n", deadbeef->pl_find_meta (it, ":URI"));
return -1;
}
if (player_init (&info->tta) != 0) {
- fprintf (stderr, "tta: failed to init player for %s\n", it->fname);
+ fprintf (stderr, "tta: failed to init player for %s\n", deadbeef->pl_find_meta (it, ":URI"));
return -1;
}
- _info->bps = info->tta.BPS;
- _info->channels = info->tta.NCH;
- _info->samplerate = info->tta.SAMPLERATE;
+ _info->fmt.bps = info->tta.BPS;
+ _info->fmt.channels = info->tta.NCH;
+ _info->fmt.samplerate = info->tta.SAMPLERATE;
+ for (int i = 0; i < _info->fmt.channels; i++) {
+ _info->fmt.channelmask |= 1 << i;
+ }
_info->readpos = 0;
_info->plugin = &plugin;
@@ -86,7 +90,7 @@ tta_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
info->startsample = 0;
info->endsample = (info->tta.DATALENGTH)-1;
}
- trace ("open_tta_file %s success!\n", it->fname);
+ trace ("open_tta_file %s success!\n", deadbeef->pl_find_meta (it, ":URI"));
return 0;
}
@@ -101,65 +105,40 @@ tta_free (DB_fileinfo_t *_info) {
}
static int
-tta_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
+tta_read (DB_fileinfo_t *_info, char *bytes, int size) {
tta_info_t *info = (tta_info_t *)_info;
- int out_ch = min (_info->channels, 2);
- if (info->currentsample + size / (2 * out_ch) > info->endsample) {
- size = (info->endsample - info->currentsample + 1) * 2 * out_ch;
+ int samplesize = _info->fmt.channels * _info->fmt.bps / 8;
+ if (info->currentsample + size / samplesize > info->endsample) {
+ size = (info->endsample - info->currentsample + 1) * samplesize;
if (size <= 0) {
return 0;
}
}
int initsize = size;
- int sample_size = 2 * out_ch;
while (size > 0) {
if (info->samples_to_skip > 0 && info->remaining > 0) {
int skip = min (info->remaining, info->samples_to_skip);
if (skip < info->remaining) {
- memmove (info->buffer, info->buffer + skip * info->tta.BSIZE * info->tta.NCH, (info->remaining - skip) * info->tta.BSIZE * info->tta.NCH);
+ memmove (info->buffer, info->buffer + skip * samplesize, (info->remaining - skip) * samplesize);
}
info->remaining -= skip;
info->samples_to_skip -= skip;
}
if (info->remaining > 0) {
- int n = size / sample_size;
+ int n = size / samplesize;
n = min (n, info->remaining);
int nn = n;
char *p = info->buffer;
- if (_info->bps > 8) {
- // hack: shift buffer, so that we always get 2 most significant bytes (24 bit support)
- // same hack kinda works for 8bit, but it's not lossless
- p += (_info->bps >> 3) - 2;
- while (n > 0) {
- *((int16_t*)bytes) = (int16_t)(((uint8_t)p[1]<<8) | (uint8_t)p[0]);
- bytes += 2;
- if (out_ch == 2) {
- *((int16_t*)bytes) = (int16_t)(((uint8_t)(p+info->tta.BSIZE)[1]<<8) | (uint8_t)(p+info->tta.BSIZE)[0]);
- bytes += 2;
- }
- n--;
- size -= sample_size;
- p += info->tta.NCH * info->tta.BSIZE;
- }
- p -= (_info->bps >> 3) - 2;
- }
- else {
- while (n > 0) {
- *((int16_t*)bytes) = ((int16_t)(p[0])) << 8;
- bytes += 2;
- if (out_ch == 2) {
- *((int16_t*)bytes) = ((int16_t)(p[1])) << 8;
- bytes += 2;
- }
- n--;
- size -= sample_size;
- p += info->tta.NCH * info->tta.BSIZE;
- }
- }
+
+ memcpy (bytes, p, n * samplesize);
+ bytes += n * samplesize;
+ size -= n * samplesize;
+ p += n * samplesize;
+
if (info->remaining > nn) {
- memmove (info->buffer, p, (info->remaining - nn) * info->tta.BSIZE * info->tta.NCH);
+ memmove (info->buffer, p, (info->remaining - nn) * samplesize);
}
info->remaining -= nn;
}
@@ -171,7 +150,8 @@ tta_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
}
}
}
- info->currentsample += (initsize-size) / sample_size;
+ info->currentsample += (initsize-size) / samplesize;
+ deadbeef->streamer_set_bitrate (info->tta.BITRATE);
return initsize-size;
}
@@ -187,14 +167,14 @@ tta_seek_sample (DB_fileinfo_t *_info, int sample) {
info->currentsample = sample + info->startsample;
info->remaining = 0;
- _info->readpos = sample / _info->samplerate;
+ _info->readpos = sample / _info->fmt.samplerate;
return 0;
}
static int
tta_seek (DB_fileinfo_t *_info, float time) {
tta_info_t *info = (tta_info_t *)_info;
- return tta_seek_sample (_info, time * _info->samplerate);
+ return tta_seek_sample (_info, time * _info->fmt.samplerate);
}
static DB_playItem_t *
@@ -213,15 +193,16 @@ tta_insert (DB_playItem_t *after, const char *fname) {
int totalsamples = tta.DATALENGTH;
double dur = tta.LENGTH;
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (fname);
- it->filetype = "TTA";
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
+ deadbeef->pl_add_meta (it, ":FILETYPE", "TTA");
deadbeef->pl_set_item_duration (it, dur);
close_tta_file (&tta);
DB_FILE *fp = deadbeef->fopen (fname);
+
+ int64_t fsize = -1;
if (fp) {
+ fsize = deadbeef->fgetlength (fp);
/*int v2err = */deadbeef->junk_id3v2_read (it, fp);
/*int v1err = */deadbeef->junk_id3v1_read (it, fp);
deadbeef->fclose (fp);
@@ -242,6 +223,18 @@ tta_insert (DB_playItem_t *after, const char *fname) {
}
deadbeef->pl_unlock ();
+ char s[100];
+ snprintf (s, sizeof (s), "%lld", fsize);
+ deadbeef->pl_add_meta (it, ":FILE_SIZE", s);
+ snprintf (s, sizeof (s), "%d", tta.BPS);
+ deadbeef->pl_add_meta (it, ":BPS", s);
+ snprintf (s, sizeof (s), "%d", tta.NCH);
+ deadbeef->pl_add_meta (it, ":CHANNELS", s);
+ snprintf (s, sizeof (s), "%d", tta.SAMPLERATE);
+ deadbeef->pl_add_meta (it, ":SAMPLERATE", s);
+ snprintf (s, sizeof (s), "%d", tta.BITRATE);
+ deadbeef->pl_add_meta (it, ":BITRATE", s);
+
cue = deadbeef->pl_insert_cue (after, it, totalsamples, tta.SAMPLERATE);
if (cue) {
deadbeef->pl_item_unref (it);
@@ -257,7 +250,7 @@ tta_insert (DB_playItem_t *after, const char *fname) {
}
static int tta_read_metadata (DB_playItem_t *it) {
- DB_FILE *fp = deadbeef->fopen (it->fname);
+ DB_FILE *fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!fp) {
return -1;
}
@@ -292,7 +285,8 @@ static int tta_write_metadata (DB_playItem_t *it) {
}
int id3v2_version = 4;
- const char *id3v1_encoding = deadbeef->conf_get_str ("mp3.id3v1_encoding", "iso8859-1");
+ char id3v1_encoding[50];
+ deadbeef->conf_get_str ("mp3.id3v1_encoding", "iso8859-1", id3v1_encoding, sizeof (id3v1_encoding));
return deadbeef->junk_rewrite_tags (it, junk_flags, id3v2_version, id3v1_encoding);
}
@@ -313,22 +307,39 @@ static const char *filetypes[] = { "TTA", NULL };
// define plugin interface
static DB_decoder_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.id = "tta",
.plugin.name = "tta decoder",
.plugin.descr = "tta decoder based on TTA Hardware Players Library Version 1.2",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "Uses modified TTA Hardware Players Library Version 1.2,\n"
+ "(c) 2004 Alexander Djourik. All rights reserved.\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = tta_start,
.plugin.stop = tta_stop,
.open = tta_open,
.init = tta_init,
.free = tta_free,
- .read_int16 = tta_read_int16,
-// .read_float32 = tta_read_float32,
+ .read = tta_read,
.seek = tta_seek,
.seek_sample = tta_seek_sample,
.insert = tta_insert,
diff --git a/plugins/uade2/plugin.c b/plugins/uade2/plugin.c
new file mode 100644
index 00000000..a07f82fe
--- /dev/null
+++ b/plugins/uade2/plugin.c
@@ -0,0 +1,692 @@
+/*
+ ddb_input_uade2 - UADE input plugin for DeaDBeeF player
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>
+ based on UADE2 plugin for Audacious, Copyright (C) 2005-2006 Heikki Orsila, UADE TEAM
+
+ 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 <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <signal.h>
+#include "../../deadbeef.h"
+#include "uadeipc.h"
+#include "eagleplayer.h"
+#include "uadeconfig.h"
+#include "uadecontrol.h"
+#include "uadeconstants.h"
+#include "ossupport.h"
+#include "uadeconf.h"
+#include "effects.h"
+#include "sysincludes.h"
+#include "songdb.h"
+#include "songinfo.h"
+
+#define min(x,y) ((x)<(y)?(x):(y))
+#define max(x,y) ((x)>(y)?(x):(y))
+
+#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+//#define trace(fmt,...)
+
+static char configname[PATH_MAX];
+static struct uade_config config_backup;
+static time_t config_load_time;
+static time_t md5_load_time;
+static char md5name[PATH_MAX];
+static char songconfname[PATH_MAX];
+static char gui_filename[PATH_MAX];
+
+static const char *
+get_uade_base_conf_dir (void) {
+ return UADE_CONFIG_BASE_DIR;
+}
+
+static void load_content_db(void)
+{
+ struct stat st;
+ time_t curtime = time(NULL);
+ char name[PATH_MAX];
+
+ if (curtime)
+ md5_load_time = curtime;
+
+ if (md5name[0] == 0) {
+ char *home = uade_open_create_home();
+ if (home)
+ snprintf(md5name, sizeof md5name, "%s/.uade2/contentdb", home);
+ }
+
+ /* User database has priority over global database, so we read it first */
+ if (md5name[0]) {
+ if (stat(md5name, &st) == 0) {
+ if (uade_read_content_db(md5name))
+ return;
+ } else {
+ FILE *f = fopen(md5name, "w");
+ if (f)
+ fclose(f);
+ uade_read_content_db(md5name);
+ }
+ }
+
+ snprintf(name, sizeof name, "%s/contentdb.conf", get_uade_base_conf_dir ());
+ if (stat(name, &st) == 0)
+ uade_read_content_db(name);
+}
+
+/* xmms initializes uade by calling this function */
+static void uade_init(void)
+{
+ static int initialized = 0;
+ if (!initialized) {
+ char *home;
+ int config_loaded;
+
+ config_load_time = time(NULL);
+
+ config_loaded = uade_load_initial_config(configname, sizeof configname,
+ &config_backup, NULL);
+
+ load_content_db();
+
+ uade_load_initial_song_conf(songconfname, sizeof songconfname,
+ &config_backup, NULL);
+
+ home = uade_open_create_home();
+
+ if (home != NULL) {
+ /* If config exists in home, ignore global uade.conf. */
+ snprintf(configname, sizeof configname, "%s/.uade2/uade.conf", home);
+ }
+
+ if (config_loaded == 0) {
+ fprintf(stderr, "No config file found for UADE XMMS plugin. Will try to load config from\n");
+ fprintf(stderr, "$HOME/.uade2/uade.conf in the future.\n");
+ }
+ initialized = 1;
+ }
+}
+
+static void uade_get_song_info(const char *filename, char **title, int *length)
+{
+ char tempname[PATH_MAX];
+ const char *t;
+
+ if (strncmp(filename, "uade://", 7) == 0)
+ filename += 7;
+
+ strlcpy(tempname, filename, sizeof tempname);
+ t = basename(tempname);
+ if (t == NULL)
+ t = filename;
+ if ((*title = strdup(t)) == NULL)
+ trace("Not enough memory for song info.\n");
+ *length = -1;
+}
+
+int uade_get_max_subsong(struct uade_state *state, int def)
+{
+ int subsong;
+ subsong = -1;
+ if (state->song != NULL)
+ subsong = state->song->max_subsong;
+ if (subsong == -1)
+ subsong = def;
+ return subsong;
+}
+
+
+int uade_get_min_subsong(struct uade_state *state, int def)
+{
+ int subsong;
+ subsong = -1;
+ if (state->song != NULL)
+ subsong = state->song->min_subsong;
+ if (subsong == -1)
+ subsong = def;
+ return subsong;
+}
+
+DB_functions_t *deadbeef;
+static DB_decoder_t plugin;
+
+static const char *exts[] = { NULL };
+static const char *prefixes[] = { "mod", NULL };
+static const char *filetypes[] = { "UADE", NULL };
+
+#define UADE_BUFFER_SIZE 100000
+
+typedef struct {
+ DB_fileinfo_t info;
+ struct uade_state state;
+ int controlstate;
+ int record_playtime;
+ int remaining;
+ char buffer[UADE_BUFFER_SIZE];
+ int subsong_end;
+ int song_end_trigger;
+ int64_t skip_bytes;
+ int abort_playing;
+ int uade_seek_forward;
+} uade_info_t;
+
+DB_fileinfo_t *
+uadeplug_open (uint32_t hints) {
+ DB_fileinfo_t *_info = malloc (sizeof (uade_info_t));
+ uade_info_t *info = (uade_info_t *)_info;
+ memset (info, 0, sizeof (uade_info_t));
+ return _info;
+}
+
+static int
+uadeplug_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
+ uade_info_t *info = (uade_info_t *)_info;
+
+ uade_init ();
+ char modulename[PATH_MAX];
+ char playername[PATH_MAX];
+ char scorename[PATH_MAX];
+ char gui_module_filename[PATH_MAX];
+ char gui_player_filename[PATH_MAX];
+
+ info->state.config = config_backup;
+ info->state.validconfig = 1;
+
+ printf ("probing the file\n");
+ int ret = uade_is_our_file(it->fname, 0, &info->state);
+
+ if (!ret) {
+ trace ("not uade file\n");
+ return -1;
+ }
+ strlcpy(modulename, it->fname, sizeof modulename);
+ trace ("modulename: %s\n", modulename);
+ strlcpy(gui_module_filename, it->fname, sizeof gui_module_filename);
+ trace ("gui_module_fname: %s\n", gui_module_filename);
+
+ snprintf(scorename, sizeof scorename, "%s/score", get_uade_base_conf_dir ());
+ trace ("scorename: %s\n", scorename);
+
+ if (strcmp(info->state.ep->playername, "custom") == 0) {
+ strlcpy(playername, modulename, sizeof playername);
+ modulename[0] = 0;
+ gui_module_filename[0] = 0;
+ } else {
+ snprintf(playername, sizeof playername, "%s/players/%s", get_uade_base_conf_dir (), info->state.ep->playername);
+ }
+ trace ("playername: %s\n", playername);
+
+ if (!uade_alloc_song(&info->state, it->fname)) {
+ trace ("uade_alloc_song fail\n");
+ return -1;
+ }
+
+ uade_set_ep_attributes(&info->state);
+
+ uade_set_song_attributes(&info->state, playername, sizeof playername);
+
+ uade_set_effects(&info->state);
+
+ strlcpy(gui_player_filename, playername, sizeof gui_player_filename);
+
+ if (!info->state.pid) {
+ char configname[PATH_MAX];
+ snprintf(configname, sizeof configname, "%s/uaerc", UADE_CONFIG_BASE_DIR);
+ uade_spawn(&info->state, UADE_CONFIG_UADE_CORE, configname);
+ }
+
+ printf ("uade_song_initialization\n");
+ ret = uade_song_initialization(scorename, playername, modulename, &info->state);
+ if (ret) {
+ if (ret != UADECORE_CANT_PLAY && ret != UADECORE_INIT_ERROR) {
+ fprintf(stderr, "Can not initialize song. Unknown error.\n");
+ return -1;
+ }
+ uade_unalloc_song(&info->state);
+ return -1;
+ }
+ printf ("init done\n");
+ int minsong = uade_get_min_subsong (&info->state, 0);
+ int maxsong = uade_get_max_subsong (&info->state, 0);
+ info->state.song->cur_subsong = it->tracknum;
+ uade_change_subsong(&info->state);
+
+ _info->fmt.bps = 16;
+ _info->fmt.channels = UADE_CHANNELS;
+ _info->fmt.samplerate = info->state.config.frequency;
+ for (int i = 0; i < _info->fmt.channels; i++) {
+ _info->fmt.channelmask |= 1 << i;
+ }
+ _info->readpos = 0;
+ _info->plugin = &plugin;
+ info->record_playtime = 1;
+ info->controlstate = UADE_S_STATE;
+
+ return 0;
+}
+
+// free everything allocated in _init
+static void
+uadeplug_free (DB_fileinfo_t *_info) {
+ uade_info_t *info = (uade_info_t *)_info;
+ if (info) {
+ uade_unalloc_song(&info->state);
+ if (info->state.pid) {
+ kill(info->state.pid, SIGTERM);
+ }
+ free (info);
+ }
+}
+
+int
+uadeplug_frame (uade_info_t *info) {
+ uint8_t space[UADE_MAX_MESSAGE_SIZE];
+ struct uade_msg *um = (struct uade_msg *) space;
+ uint16_t *sm;
+ int i;
+ unsigned int play_bytes, tailbytes = 0;
+ uint64_t subsong_bytes = 0;
+ int framesize = UADE_CHANNELS * UADE_BYTES_PER_SAMPLE;
+ int left = 0;
+ char gui_formatname[256];
+ char gui_modulename[256];
+ char gui_playername[256];
+ char *reason;
+ uint32_t *u32ptr;
+ int frame_received = 0;
+
+ while (!frame_received) {
+ if (info->controlstate == UADE_S_STATE) {
+
+ assert(left == 0);
+
+ if (info->abort_playing) {
+ info->record_playtime = 0;
+ break;
+ }
+
+ if (info->uade_seek_forward) {
+ info->skip_bytes += info->uade_seek_forward * (UADE_BYTES_PER_FRAME * info->state.config.frequency);
+ info->uade_seek_forward = 0;
+ }
+
+ left = uade_read_request(&info->state.ipc);
+
+ if (uade_send_short_message(UADE_COMMAND_TOKEN, &info->state.ipc)) {
+ fprintf(stderr, "Can not send token.\n");
+ return -1;
+ }
+ info->controlstate = UADE_R_STATE;
+
+ } else {
+
+ if (uade_receive_message(um, sizeof(space), &info->state.ipc) <= 0) {
+ fprintf(stderr, "Can not receive events from uade\n");
+ exit(-1);
+ }
+
+
+ switch (um->msgtype) {
+
+ case UADE_COMMAND_TOKEN:
+ info->controlstate = UADE_S_STATE;
+ break;
+
+ case UADE_REPLY_DATA:
+ sm = (uint16_t *) um->data;
+ for (i = 0; i < um->size; i += 2) {
+ *sm = ntohs(*sm);
+ sm++;
+ }
+
+ if (info->subsong_end) {
+ play_bytes = tailbytes;
+ tailbytes = 0;
+ } else {
+ play_bytes = um->size;
+ }
+
+ if (info->subsong_end == 0 && info->song_end_trigger == 0 &&
+ uade_test_silence(um->data, play_bytes, &info->state)) {
+ info->subsong_end = 1;
+ }
+
+ subsong_bytes += play_bytes;
+ info->state.song->out_bytes += play_bytes;
+
+ if (info->skip_bytes > 0) {
+ if (play_bytes <= info->skip_bytes) {
+ info->skip_bytes -= play_bytes;
+ play_bytes = 0;
+ } else {
+ play_bytes -= info->skip_bytes;
+ info->skip_bytes = 0;
+ }
+ }
+
+ uade_effect_run(&info->state.effects, (int16_t *) um->data, play_bytes / framesize);
+
+ // ... copy data ...
+ memcpy (info->buffer + info->remaining, um->data, play_bytes);
+ frame_received = 1;
+ info->remaining += play_bytes;
+
+ if (info->state.config.timeout != -1 && info->state.config.use_timeouts) {
+ if (info->song_end_trigger == 0) {
+ if (info->state.song->out_bytes / (UADE_BYTES_PER_FRAME * info->state.config.frequency) >= info->state.config.timeout) {
+ info->song_end_trigger = 1;
+ info->record_playtime = 0;
+ }
+ }
+ }
+
+ if (info->state.config.subsong_timeout != -1 && info->state.config.use_timeouts) {
+ if (info->subsong_end == 0 && info->song_end_trigger == 0) {
+ if (subsong_bytes / (UADE_BYTES_PER_FRAME * info->state.config.frequency) >= info->state.config.subsong_timeout) {
+ info->subsong_end = 1;
+ info->record_playtime = 0;
+ }
+ }
+ }
+
+ assert (left >= um->size);
+ left -= um->size;
+ break;
+
+ case UADE_REPLY_FORMATNAME:
+ uade_check_fix_string(um, 128);
+ strlcpy(gui_formatname, (char *) um->data, sizeof gui_formatname);
+ strlcpy(info->state.song->formatname, (char *) um->data, sizeof info->state.song->formatname);
+ break;
+
+ case UADE_REPLY_MODULENAME:
+ uade_check_fix_string(um, 128);
+ strlcpy(gui_modulename, (char *) um->data, sizeof gui_modulename);
+ strlcpy(info->state.song->modulename, (char *) um->data, sizeof info->state.song->modulename);
+ break;
+
+ case UADE_REPLY_MSG:
+ uade_check_fix_string(um, 128);
+ trace ("Message: %s\n", (char *) um->data);
+ break;
+
+ case UADE_REPLY_PLAYERNAME:
+ uade_check_fix_string(um, 128);
+ strlcpy(gui_playername, (char *) um->data, sizeof gui_playername);
+ strlcpy(info->state.song->playername, (char *) um->data, sizeof info->state.song->playername);
+ break;
+
+ case UADE_REPLY_SONG_END:
+ if (um->size < 9) {
+ fprintf(stderr, "Invalid song end reply\n");
+ exit(-1);
+ }
+ tailbytes = ntohl(((uint32_t *) um->data)[0]);
+ /* next ntohl() is only there for a principle. it is not useful */
+ if (ntohl(((uint32_t *) um->data)[1]) == 0) {
+ /* normal happy song end. go to next subsong if any */
+ info->subsong_end = 1;
+ } else {
+ /* unhappy song end (error in the 68k side). skip to next song
+ ignoring possible subsongs */
+ info->song_end_trigger = 1;
+ }
+ i = 0;
+ reason = (char *) &um->data[8];
+ while (reason[i] && i < (um->size - 8))
+ i++;
+ if (reason[i] != 0 || (i != (um->size - 9))) {
+ fprintf(stderr, "Broken reason string with song end notice\n");
+ exit(-1);
+ }
+ /* fprintf(stderr, "Song end (%s)\n", reason); */
+ break;
+
+ case UADE_REPLY_SUBSONG_INFO:
+ if (um->size != 12) {
+ fprintf(stderr, "subsong info: too short a message\n");
+ exit(-1);
+ }
+ u32ptr = (uint32_t *) um->data;
+ info->state.song->min_subsong = ntohl(u32ptr[0]);
+ info->state.song->max_subsong = ntohl(u32ptr[1]);
+ info->state.song->cur_subsong = ntohl(u32ptr[2]);
+
+ if (!(-1 <= info->state.song->min_subsong && info->state.song->min_subsong <= info->state.song->cur_subsong && info->state.song->cur_subsong <= info->state.song->max_subsong)) {
+ int tempmin = info->state.song->min_subsong, tempmax = info->state.song->max_subsong;
+ fprintf(stderr, "uade: The player is broken. Subsong info does not match with %s.\n", gui_filename);
+ info->state.song->min_subsong = tempmin <= tempmax ? tempmin : tempmax;
+ info->state.song->max_subsong = tempmax >= tempmin ? tempmax : tempmin;
+ if (info->state.song->cur_subsong > info->state.song->max_subsong)
+ info->state.song->max_subsong = info->state.song->cur_subsong;
+ else if (info->state.song->cur_subsong < info->state.song->min_subsong)
+ info->state.song->min_subsong = info->state.song->cur_subsong;
+ }
+ break;
+
+ default:
+ fprintf(stderr, "Expected sound data. got %d.\n", um->msgtype);
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+// try decode `size' bytes
+// return number of decoded bytes
+// or 0 on EOF/error
+static int
+uadeplug_read (DB_fileinfo_t *_info, char *bytes, int size) {
+ uade_info_t *info = (uade_info_t *)_info;
+ int samplesize = _info->fmt.channels * _info->fmt.bps / 8;
+ int initsize = size;
+
+ while (size > 0) {
+ if (info->remaining) {
+ int n = min (info->remaining, size);
+ memcpy (bytes, info->buffer, n);
+ bytes += n;
+ size -= n;
+ if (n < info->remaining) {
+ memmove (info->buffer, info->buffer + n, info->remaining-n);
+ info->remaining -= n;
+ break;
+ }
+ info->remaining = 0;
+ }
+
+ if (uadeplug_frame (info) < 0) {
+ return initsize-size;
+ }
+ }
+
+ _info->readpos += ((initsize-size) / samplesize) / (float)(_info->fmt.samplerate);
+ return initsize-size;
+}
+
+// seek to specified sample (frame)
+// return 0 on success
+// return -1 on failure
+static int
+uadeplug_seek_sample (DB_fileinfo_t *_info, int sample) {
+ uade_info_t *info = (uade_info_t *)_info;
+
+ _info->readpos = (float)sample / _info->fmt.samplerate;
+ return 0;
+}
+
+// seek to specified time in seconds
+// return 0 on success
+// return -1 on failure
+static int
+uadeplug_seek (DB_fileinfo_t *_info, float time) {
+ return uadeplug_seek_sample (_info, time * _info->fmt.samplerate);
+}
+
+static DB_playItem_t *
+uadeplug_insert (DB_playItem_t *after, const char *fname) {
+ uade_init ();
+
+ char modulename[PATH_MAX];
+ char playername[PATH_MAX];
+ char scorename[PATH_MAX];
+ char gui_module_filename[PATH_MAX];
+ char gui_player_filename[PATH_MAX];
+
+ struct uade_state state;
+ memset (&state, 0, sizeof (state));
+ state.config = config_backup;
+ state.validconfig = 1;
+
+ printf ("probing the file\n");
+ int ret = uade_is_our_file(fname, 0, &state);
+
+ if (!ret) {
+ trace ("not uade file\n");
+ return NULL;
+ }
+
+ strlcpy(modulename, fname, sizeof modulename);
+ trace ("modulename: %s\n", modulename);
+ strlcpy(gui_module_filename, fname, sizeof gui_module_filename);
+ trace ("gui_module_fname: %s\n", gui_module_filename);
+
+ snprintf(scorename, sizeof scorename, "%s/score", get_uade_base_conf_dir ());
+ trace ("scorename: %s\n", scorename);
+
+ if (strcmp(state.ep->playername, "custom") == 0) {
+ strlcpy(playername, modulename, sizeof playername);
+ modulename[0] = 0;
+ gui_module_filename[0] = 0;
+ } else {
+ snprintf(playername, sizeof playername, "%s/players/%s", get_uade_base_conf_dir (), state.ep->playername);
+ }
+ trace ("playername: %s\n", playername);
+
+ if (!uade_alloc_song(&state, fname)) {
+ trace ("uade_alloc_song fail\n");
+ return NULL;
+ }
+
+ uade_set_ep_attributes(&state);
+
+ uade_set_song_attributes(&state, playername, sizeof playername);
+
+ uade_set_effects(&state);
+
+ strlcpy(gui_player_filename, playername, sizeof gui_player_filename);
+
+ if (!state.pid) {
+ char configname[PATH_MAX];
+ snprintf(configname, sizeof configname, "%s/uaerc", UADE_CONFIG_BASE_DIR);
+ uade_spawn(&state, UADE_CONFIG_UADE_CORE, configname);
+ }
+
+ printf ("uade_song_initialization\n");
+ ret = uade_song_initialization(scorename, playername, modulename, &state);
+ if (ret) {
+ if (ret != UADECORE_CANT_PLAY && ret != UADECORE_INIT_ERROR) {
+ fprintf(stderr, "Can not initialize song. Unknown error.\n");
+ return NULL;
+ }
+ uade_unalloc_song(&state);
+ return NULL;
+ }
+ printf ("init done\n");
+ int minsong = uade_get_min_subsong (&state, 0);
+ int maxsong = uade_get_max_subsong (&state, 0);
+
+ char info[256];
+ int playtime = state.song->playtime;
+
+ /* Hack. Set info text and song length late because we didn't know
+ subsong amounts before this. Pass zero as a length so that the
+ graphical play time counter will run but seek is still enabled.
+ Passing -1 as playtime would disable seeking. */
+ if (playtime <= 0)
+ playtime = 0;
+
+ if (uade_generate_song_title(info, sizeof info, &state))
+ strlcpy(info, gui_filename, sizeof info);
+
+// playhandle->set_params(playhandle, info, playtime,
+// UADE_BYTES_PER_FRAME * state.config.frequency,
+// state.config.frequency, UADE_CHANNELS);
+
+
+ // no cuesheet, prepare track for addition
+ DB_playItem_t *it = deadbeef->pl_item_alloc ();
+ it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
+ it->fname = strdup (fname);
+ it->filetype = filetypes[0];
+ float duration = -1;
+ if (playtime != -1) {
+ duration = playtime / 1000.f;
+ }
+ deadbeef->pl_set_item_duration (it, duration);
+
+ // title is empty, this call will set track title to filename without extension
+ const char *fn = strrchr (fname, '/');
+ if (fn) {
+ fn++;
+ }
+ else {
+ fn = fname;
+ }
+ deadbeef->pl_add_meta (it, "title", info);
+
+ // now the track is ready, insert into playlist
+ after = deadbeef->pl_insert_item (after, it);
+ deadbeef->pl_item_unref (it);
+ uade_unalloc_song(&state);
+ if (state.pid) {
+ kill(state.pid, SIGTERM);
+ }
+ return after;
+}
+
+// define plugin interface
+static DB_decoder_t plugin = {
+ DB_PLUGIN_SET_API_VERSION
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
+ .plugin.type = DB_PLUGIN_DECODER,
+ .plugin.id = "uade",
+ .plugin.name = "UADE player",
+ .plugin.descr = "amiga module player based on UADE (http://zakalwe.fi/uade/)",
+ .plugin.author = "Alexey Yakovenko",
+ .plugin.email = "waker@users.sourceforge.net",
+ .plugin.website = "http://deadbeef.sf.net",
+ .open = uadeplug_open,
+ .init = uadeplug_init,
+ .free = uadeplug_free,
+ .read = uadeplug_read,
+ .seek = uadeplug_seek,
+ .seek_sample = uadeplug_seek_sample,
+ .insert = uadeplug_insert,
+ .exts = exts,
+ .prefixes = prefixes,
+ .filetypes = filetypes
+};
+
+DB_plugin_t *
+ddb_uade2_load (DB_functions_t *api) {
+ deadbeef = api;
+ return DB_PLUGIN (&plugin);
+}
diff --git a/plugins/uade2/uade-2.13/AUTHORS b/plugins/uade2/uade-2.13/AUTHORS
new file mode 100644
index 00000000..b1d24130
--- /dev/null
+++ b/plugins/uade2/uade-2.13/AUTHORS
@@ -0,0 +1,59 @@
+Authors of UADE
+---------------
+
+Main authors
+------------
+
+ - Heikki Orsila <heikki.orsila@iki.fi>
+ - Michael Doering <mldoering@gmx.net>
+
+Subsystems
+----------
+
+ - Antti S. Lankila <alankila@bel.fi> for filter emulation and sound effects
+ - Claudio Matsuoka and Hipolito Carraro Jr for module decruncing code in
+ uade 1.xy.
+ jah@fh-zwickau.de for unsqsh
+ Sipos Attila for unsqsh checksum
+ Olivier Lapicque for mmcp
+ Marc Espie (old depack.c)
+ - Harry "Piru" Sintonen <sintonen@iki.fi> for AmigaOS and MorphOS port
+ - Martin Blapp for configure fixes and enhancements from FreeBSD project
+ - Michael S. Baltaks for Mac OS X port
+ - Nicolas A. Mendoza (part of the AmigaOS port)
+ - Stuart 'kyzer' Caie for Mac OS X port and powerpacker decruncher
+ http://www.kyz.uklinux.net
+
+Everyone from UAE project. See doc/UAE-CREDITS.
+
+Eagleplayers
+------------
+
+ - Don Adan / Wanted Team
+ - Eagleeye and Buggs from Defect (Eagleplayer project authors)
+ - Nicolas Frank <gryzor@club-internet.fr> for PTK-Prowiz
+ - Andy Silva <silva@psi5.com> for his replayers
+ - Bartman and Dexter from Abyss for AHX v2 replay routine:
+ http://www.the-leader-of-the-eighties.de
+ - Brian Postma <b.postma@hetnet.nl> for Brian's Soundmonitor player
+ http://www.homepages.hetnet.nl/~brianpostma
+ - Nicolas Pomared <npomarede@kaptech.com> for MYST/YMST replayer
+ - Sean Connolly for EMS V6 replay: http://www.cosine-systems.com/
+ - Stephen Mifsud (Malta) <teknologik@technologist.com> for Darius Zendeh
+ replayer. http://www.marz-kreations.com
+ - Sunbeam/Shelter for his replayers
+ - Paul v.d. Valk for Medley replay routine
+ - Tap & Walt for digibooster source
+ http://www.highantdev2.de/dbpro/index.php
+ - The Welder / Divine for protracker replay routine
+
+ - Everyone else whose Eagleplayer plugins we use. Respective authors of
+ eagleplayer plugins can be found from inside the plugin.
+
+Media
+-----
+
+Manfred Linzner aka Pink/Abyss <linzner@shinen.com> for a great test tune
+(AHX.Cruisin).
+
+
diff --git a/plugins/uade2/uade-2.13/COPYING b/plugins/uade2/uade-2.13/COPYING
new file mode 100644
index 00000000..d8917caa
--- /dev/null
+++ b/plugins/uade2/uade-2.13/COPYING
@@ -0,0 +1,12 @@
+This source distribution contains works with various licenses. Please read
+copyright notices of those works before reuse.
+
+All the code from the UAE (Unix Amiga Emulator) project is licensed
+under the GNU GPL. Read COPYING.GPL for details of the GNU GPL license.
+UAE people work is credited in doc/UAE-* files.
+
+Files under players/ directory are licensed with various different licenses
+and quite a many different copyright holders. See inside the player binaries
+for more details.
+
+Sound core in directory amigasrc/score/ is licensed under the GNU LGPL.
diff --git a/plugins/uade2/uade-2.13/COPYING.GPL b/plugins/uade2/uade-2.13/COPYING.GPL
new file mode 100644
index 00000000..60549be5
--- /dev/null
+++ b/plugins/uade2/uade-2.13/COPYING.GPL
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/plugins/uade2/uade-2.13/COPYING.LGPL b/plugins/uade2/uade-2.13/COPYING.LGPL
new file mode 100644
index 00000000..8add30ad
--- /dev/null
+++ b/plugins/uade2/uade-2.13/COPYING.LGPL
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/plugins/uade2/uade-2.13/ChangeLog b/plugins/uade2/uade-2.13/ChangeLog
new file mode 100644
index 00000000..54a2d409
--- /dev/null
+++ b/plugins/uade2/uade-2.13/ChangeLog
@@ -0,0 +1,1907 @@
+
+* ALL THE CHANGE LOG ENTRIES SINCE 2007-05-28 ARE IN THE GIT REPOSITORY. USE
+ "git log" COMMAND
+
+2007-05-28 Heikki Orsila <heikki.orsila@iki.fi>
+ - The development has been moved to a Git repository. Please issue
+ "git-clone git://zakalwe.fi/uade uade.git" to checkout the latest
+ version from the repository.
+
+2007-05-27 Heikki Orsila <heikki.orsila@iki.fi>
+ - Commit messages into version repository should from now on include
+ a short tag explaining the nature of the commit.
+ The tags are:
+ * [ADAPTIVE] - adaptive maintenance: the commit makes software to
+ work better with the surrounding environment (compilers, libraries,
+ path names ...)
+ * [CORRECTVE] - corrective maintenance: fix a defect in the program
+ * [PERFECTIVE] - perfective maintenance: used when adding a feature
+ or improving an existing feature
+ * [PREVENTIVE] - preventive maintenance: used when refactoring,
+ cleaning or asserting the code, or adding self-tests
+
+ See http://www.site.uottawa.ca:4321/oose/index.html#maintenance
+
+ - Fixed Audacious plugin to work for Audacious 1.4/2.x
+ Christian Birchinger <joker@netswarm.net> [ADAPTIVE] [CORRECTIVE]
+
+2007-05-03 Michael Doering <mld@users.sourceforge.net>
+ - Added a new version of Synthdream replayer from Don Adan
+
+2007-04-30 Heikki Orsila <heikki.orsila@iki.fi>
+ * UADE 2.07 (Walpurgis night)
+ - Added Special FX ST replayer from Don Adan
+ - Added a new version of Special FX replayer from Don Adan
+ - Work-arounded libao/alsa so that it drains the audio device for
+ the last few milliseconds of sample data for the last played song.
+ Thanks to Cthulhu for pointing out the problem.
+ - Many fixes in song length database code
+ # Fixed a bug that only the last played subsong time was recorded
+ into the song db
+ # Fixed a file-locking race condition in song db
+ # Fixed a song db corruption bug
+ # Cleaned song db code
+ - Support for full Drag and Drop/Local URL Support in Audacious 1.3
+ plugin
+ - Fixed misdetection and modlen calculation bug of Soundtracker IV
+ mods
+
+2007-04-29 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added Special FX ST replayer from Don Adan
+ - Added a new version of Special FX replayer from Don Adan
+
+2007-04-27 Heikki Orsila <heikki.orsila@iki.fi>
+ - Work-arounded libao/alsa so that it drains the audio device for
+ the last few milliseconds of song data for the last played song.
+ Thanks to Cthulhu for pointing out the problem.
+
+2007-04-15 Michael Doering <mld@users.sourceforge.net>
+ - Bug in songlength database handling fixed (shd)
+
+2007-04-14 Michael Doering <mld@users.sourceforge.net>
+ - Support for full Drag and Drop/Local URL Support in Audacious 1.3
+ plugin. (shd, mld)
+ - Fixed misdetection and modlen calculation bug of Soundtracker IV
+ mods. (shd/mld)
+
+2007-04-09 Heikki Orsila <heikki.orsila@iki.fi>
+ * UADE 2.06 (7 YEARS BIRTHDAY PARTY AT PAULAS!)
+ - UADE project is now exactly 7 years old \o/ PARTY!
+ - Started working for Audacious 1.3 support, at least songs that
+ are added directly through playlist should work if they are
+ regular files. Audacious VFS is not supported in general. Nothing
+ else is guaranteed. Audacious < 1.3 works as in the past.
+ - Infogrames replayer improved, gobliins 2 et al. play with correct
+ tempo
+ - Added new Quartet ST player from Don Adan / Wanted Team
+ (qts.* files)
+ - KRIS aka Chip Tracker replayer (KRIS.* files) from Don Adan /
+ Wanted team. This replaces PTK-Prowiz for Chip Tracker songs, so
+ not a new format.
+ - Quartet PSG replayer (SQT.* files) from Don Adan / Wanted Team
+ - Many small changes, cleanups etc
+
+ - Fixed user installation of Audacious 1.3 plugin...
+
+2007-03-19 Michael Doering <mld@users.sourceforge.net>
+ - Merged Christian Birchingers Audacious 1.3.x API Patches in.
+
+2007-03-03 Heikki Orsila <heikki.orsila@iki.fi>
+ - KRIS aka Chip Tracker replayer (KRIS.* files) from Don Adan /
+ Wanted team. This replaces PTK-Prowiz for Chip Tracker songs, so
+ not a new format.
+ - Quartet PSG replayer (SQT.* files) from Don Adan / Wanted Team
+
+2007-02-13 Heikki Orsila <heikki.orsila@iki.fi>
+ - Updated Inforgrames player to use tempo 0x24ff for Ween songs.
+ Thanks to DrMcCoy of SCUMM VM project.
+ - Reverted Michael's 2007-02-13 patch regarding LC_Numeric and
+ strtod(). Fixed the problem manually by converting x,y values into
+ x.y format and vice versa.
+
+2007-02-13 Michael Doering <mld@users.sourceforge.net>
+ - Fix for German LC_Numeric="," parameters in uadeconfig.c.
+ Thanks for Steffen Wulf for reporting.
+ - Bumped Version to 2.05. :-)
+
+2007-02-08 Michael Doering <mld@users.sourceforge.net>
+ - Added new Quartet ST player from Don Adan / Wanted Team
+ (qts.* files). Great work as ever Don!
+ - Disabled Hippel COSO check in amifilemagic.c to avoid a conflict
+ between Amiga and Atari ST Coso Files.
+ TODO: The file heuristics for Coso in amifilemagic.c has to be fixed,
+ the checkroutine of the Amiga Hippel-Coso replayer isn't HIP-ST Coso
+ aware either.
+
+2007-02-06 Michael Doering <mld@users.sourceforge.net>
+ - Small correction of shd's patch in PTK-Prowiz commited.
+
+2007-02-05 Michael Doering <mld@users.sourceforge.net>
+ - Applied shd's uade_new_get_info patch to PTK-Prowiz.
+
+2007-02-04 Michael Doering <mld@users.sourceforge.net>
+ - Added sanity check to query eagleopts in PTK-Prowiz (needed for
+ score fix)
+ - Added a new uade.library method: UadeNewGetInfo(). It is now used
+ with Infogrames replayer (see
+ amigasrc/players/infogrames/Infogrames.asm). It will be used with
+ PTK-Prowiz soon. Documentation for UadeNewGetInfo() can be read
+ from amigasrc/score/score.s, see function "uade_new_get_info".
+
+2007-02-03 Heikki Orsila <heikki.orsila@iki.fi>
+ - Disassembled Andy Silvas Infogrames replayer, added a work-around
+ list for Gobliins 2 songs to fix tempo. Thanks to Sven Hesse of
+ ScummVM project for letting us know of the tempo problem.
+ The next thing to do is go through all Infogrames games with UAE
+ and record the tempo value for each song? Any volunteers?-)
+
+2007-01-30 Michael Doering <mld@users.sourceforge.net>
+ - Changed Scrollbar policy for audacious modinfo to avoid
+ ugly line breaking in hexmode
+
+2007-01-25 Heikki Orsila <heikki.orsila@iki.fi>
+ * UADE 2.05 (It came from the Paula)
+ - This release workarounds scheduler features of some 2.6.x Linux
+ kernels. IPC method was changed to use sockets instead of pipes,
+ which significantly reduces buffer underruns. This is really the
+ only change affecting scheduling! Weird.
+
+2007-01-24 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed compilation for platforms that lack memmem(), such as Mac.
+ The compilation bug was introduced at 2007-01-21 when unixipc
+ and unixsupport were merged.
+
+2007-01-22 Michael Doering <mld@users.sourceforge.net>
+ - Fixed songinfo for mods detected as Protracker compatible
+
+2007-01-21 Heikki Orsila <heikki.orsila@iki.fi>
+ - Merge unixipc.c and unixsupport.c. Modularise uadecore spawn into
+ unixsupport.c.
+ - Move from pipe based IPC communication to UNIX socket based
+ communication. This solves a scheduling problem for some 2.6.x Linux
+ kernels.
+
+2007-01-21 Heikki Orsila <heikki.orsila@iki.fi>
+ * UADE 2.04 (Defective by Design .org)
+ - Added Jochen Hippel ST player (hst.* files)
+ - Added Quartet player from Don Adan / Wanted Team (qpa.* files)
+ - Updated Mark Cookset replayer with a new version from Don Adan of
+ Wanted Team
+ - It's now possible to command an eagleplayer listed in
+ eagleplayer.conf to ignore file type check. This is useful
+ with the CustomMade replayer as it rejects some valid song files.
+ See the change log entry from 2007-01-02 and the man page
+ about song.conf and eagleplayer.conf.
+ - Cygwin work-around (locking on song contents db is broken). Does
+ NOT affect unixes.
+ - Amiga memory size can now be configured properly from ~/.uade2/uaerc.
+ This is useful with big sound files (rare).
+ - Fixed the sinc filter, it had a bug that made it less accurate
+ - Man page updates about filters
+ - GCC 4.x clean ups
+ - Small bug fixes. The default uade.conf had a deprecated option
+ in comments. It was removed.
+ - Updated installation instructions
+
+2007-01-18 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed a bug in default uade.conf. "headphone" option for the
+ uade.conf was obsoleted at 2006-05-13, the new option name
+ became "headphones". The backward compatibility is retained
+ again and thus "headphone" option will work to some future.
+ - Fixed several missing cvs sticky bits (-kb) in players/ dir
+
+2007-01-15 Michael Doering <mld@users.sourceforge.net>
+ - Made "detect_format_by_content" parameter for modfiles default.
+ This way only true Amiga 4ch mod files now get played.
+ - Added Quartet player from Don Adan / Wanted Team. It recognizes
+ QPA.* files.
+
+2007-01-12 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added "ignore_player_check" option for eagleplayer.conf and
+ song.conf. It is useful with bad eagleplayers and rips. This
+ feature was requested for use with CustomMade player and therefore
+ this option will also be made default for that player. See the
+ new eagleplayer.conf.
+
+2007-01-11 Antti S. Lankila <alankila@bel.fi>
+ - Correct some ancient mistakes in uade123.1, regarding filter
+ operation. For instance the LED filter center frequency was
+ reported halved due to an earlier mistake in graph drawing
+
+2006-12-22 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added Jochen Hippel ST player from Don Adan / Wanted Team. It
+ recognizes HST.* files
+ - Replaced old Mark Cooksey replayer with a new version from
+ Don Adan / Wanted Team
+
+2006-12-07 Antti S. Lankila <alankila@bel.fi>
+ - Remove uadecore with make clean
+
+2006-12-03 Antti S. Laknila <alankila@bel.fi>
+ - Fixed a strict aliasing warning that occured with GCC 4.1 in
+ newcpu.h
+
+2006-12-01 Heikki Orsila <heikki.orsila@iki.fi>
+ - Memory size of Amiga can now be increased over 2 MiB by editing
+ the uaerc file (e.g. ~/.uade2/uaerc). The variable named chipmem_size
+ should be edited. Allocated memory for the amiga is determined by
+ chipmem_size * 512 KiB
+ By default, chipmem_size = 4 -> 2 MiB of memory. This variable can
+ be set up to 16 (8 MiB of memory).
+
+2006-11-26 Heikki Orsila <heikki.orsila@iki.fi>
+ - Updated instructions about -x option in uade123 and its man page.
+
+2006-10-28 Antti S. Lankila <alankila@bel.fi>
+ - Due to me misunderstanding the Kaiser window beta parameter,
+ the BLEP tables for sinc synthesis were set to attenuate aliasing
+ only for 40 dB instead of the target 80 dB.
+
+2006-10-24 Heikki Orsila <heikki.orsila@iki.fi>
+ - No locking with Cygwin -> uade is dangerous with songdb.
+
+2006-10-02 Heikki Orsila <heikki.orsila@iki.fi>
+ - Updated INSTALL.readme to include more dependencies (pkg-config
+ and sed) and tips for Mac OS X compiling (workarounds)
+
+2006-08-27 Heikki Orsila <heikki.orsila@iki.fi>
+ * UADE 2.03 (Microsoft punishment)
+ - Added song.conf support to set song specific attributes for
+ playback, such as ntsc, blank, filtering etc. See the man
+ page. An example, one may add following line to ~/.uade2/song.conf
+ to make fred.hybris_light always timeout on 200 seconds:
+ md5=60f3bb11cc1bacaf77d7c16d13361844 broken_song_end timeout=200 comment FRED.Hybris_Light
+ This need not be added manually, one can just issue:
+ uade123 --set=broken_song_end --set=timeout=200 FRED.Hybris_Light
+ and afterwards uade will always play the song correctly.
+ Similarly, one can fix volume gain for some songs:
+ uade123 --set=gain=2 foo
+ To reset all options for a given song, do:
+ uade123 --set= foo
+ - Fixed PAL audio synthesis frequency (inaudible)
+ - --interpolator=x is now --resampler=x because the function of
+ interpolators was actually resampling.
+ - Only A500 and A1200 filters are now supported and A500 is the
+ default.
+ - Added Play time database support for uade123
+ - Compatibility fixes
+ - Lots of bug fixes
+ - Improvements in uade123 UI (press i or I for info on song)
+ - Improved file magic support for some formats (P61A, Fuzzac, ...)
+ - Hacky NTSC mode support available now. Use --ntsc or ntsc
+ directive in uade123. Also works per-song with song.conf.
+ One can now make specific songs be played in NTSC mode by
+ programming song.conf with proper values. One can issue:
+ uade123 --set=ntsc dw.FooBar
+ or put a line to ~/.uade2/song.conf:
+ md5=225bbb405433c7c05fe10b99b8e088ff ntsc comment dw.AlfredChicken
+ - One can force protracker replayer to use VBlank timing with many
+ ways, see the man page on section EAGLEPLAYER OPTIONS. For example,
+ do:
+ uade123 -x vblank mod.FooBar
+ - Enhancements in PTK-Prowiz. Protracker version is now selectable
+ between 3.0b, 2.3a and 1.0c. See the man page section EAGLEPLAYERS
+ OPTIONS. This option is not yet guaranteed to be 100% but may
+ fix some immediate problems with some songs.. These settings
+ may also be recorded to song.conf so that one only has to give
+ these parameters once. Example:
+ uade123 -x type:pt10c mod.TheClassicProtrackerVersionedSong
+ btw. uade is probably the first mod player for non-amigas that
+ has a direct version support for protrackers.
+ - Improved some players
+ - Titles in audacious and xmms plugins on the playlist are now
+ programmable with uade.conf. The default is
+ song_title %F %X [%P]
+ This displays filename, subsong (if more than one) and player.
+ See SONG TITLE SPECIFICATION section in the man page. There's a
+ small help in the uade.conf too.
+ - Significant code refactorizations
+ - Fixed a memory leak issue (see Change log on 2006-04-15)
+ - Added Dirk Bialluch format support by Don Adan/Wanted Team
+
+2006-07-27 Heikki Orsila <heikki.orsila@iki.fi>
+ - Removed -fno-strength-reduce from src/Makefile.in. Some old
+ GCC 2.x versions had bugged strength reduce, but it shouldn't
+ matter anymore. Maybe the compiler will produce better code
+ without this. AHX.cruisin showed approx 3% speedup :) Thanks
+ to alankila for pointing out use of this flag.
+
+2006-07-17 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed a segfault bug in songdb caused by recent changes to add
+ subsong volume normalisation info to contentdb. Segfaults were
+ catched in several places due to uninitialized vplist in
+ struct uade_content.
+
+2006-07-02 Heikki Orsila <heikki.orsila@iki.fi>
+ - Merged an initial version of volume normalization effect from
+ alankila.
+ - Split song.conf and contentdb related functionality away from
+ eagleplayer.c to songdb.c.
+
+2006-06-30 Heikki Orsila <heikki.orsila@iki.fi>
+ - Work-arounded signedness warnings with GCC4 in src/frontends/common/
+
+2006-06-23 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fix sinc resampler to support --filter=none (alankila)
+ - Optimize sinc_handler() inner-loop by avoiding unnecessary
+ indexing (alankila)
+
+2006-06-22 Heikki Orsila <heikki.orsila@iki.fi>
+ - Separated accumulator and sinc resamplers into separate functions
+ in src/audio.c.
+ - Removed "anti" name from resampler list. "anti" has been the
+ "default" for a long time already.
+ - Change FIR convolution of sinc into bandlimited step synthesis.
+ Filters are applied directly by the BLEPs. Warning, sinc and
+ filtering are now integrated together so they can not be
+ changed separately (breaking modular development idea). The
+ default resampler does not suffer from this modularity problem
+ and it is still the recommended resampler. (alankila)
+
+2006-06-18 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added play time database saving support into uade123.
+
+2006-05-22 Heikki Orsila <heikki.orsila@iki.fi>
+ - Changed --magic to --detect-format-by-content and changed
+ corresponding "content_detection" directive in eagleplayer.conf and
+ uade.conf to "detect_format_by_content". Changed --no-song-end to
+ "--no-ep-end-detect".
+
+2006-05-20 Heikki Orsila <heikki.orsila@iki.fi>
+ - Changed default input file to be /dev/tty instead of stdin for
+ uade123. Also, failing terminal setup (input file is not a tty)
+ is not a fatal error.
+ - Added a warning to eagleplayer.conf parsing for the situation
+ that user has removed all prefixes from an eagleplayer. It makes
+ all kind of detection (including content detection) unusable.
+ If you don't want to detect a particular file type by name
+ extensions, add "content_detection" option for the line in
+ eagleplayer.conf. But note that there isn't content detection
+ for all formats. For example, adding "content_detection" for
+ Thomas Hermann player will make all Thomas Hermann songs
+ unplayable because there is no content detection for it.
+
+2006-05-19 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added Gryzors (Nicholas Franck <gryzor@club-internet.fr>)
+ Protracker converter source code into CVS. See
+ amigasrc/players/tracker/converter/README.txt for copyright and
+ licensing information. Thanks to Stuart Caie for leading us
+ to the distribution terms (we did have the source before :-)
+
+2006-05-18 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added p5x and p6x file extensions for The Player 5.x/6.x to
+ eagleplayer.conf (Stuart Caie requested it)
+ - Added "P50A" four letter magic detection to amifilemagic.c
+
+2006-05-17 Michael Doering <mld@users.sourceforge.net>
+ - Removed deprecated <audacious/configfile.h> from audacious
+ plugin. Thanks to Joker for the report.
+
+2006-05-16 Michael Doering <mld@users.sourceforge.net>
+ - Raised length of extension[] in uade_analyze_file from 11 to 16,
+ which caused the xmms and audacious plugin to segfault on
+ very long prefixes (such as mod15_st-iv) in eagleplayer.conf.
+
+2006-06-15 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added "-x y" to set eagleplayer options more conveniently. It's
+ now possible to do: uade123 -x type:pt11b mod.foo. -x can be
+ used multiple times on the same command line.
+
+2006-05-15 Michael Doering <mld@users.sourceforge.net>
+ - PTK-Prowiz now uses the epopt config system. You can set options
+ such as "vblank" and/or "type:" on a song base with the uade123
+ "--set=xyz" command line parameter or edit uade.conf or song.conf
+ manually. For valid protracker types: check the uade123 man page.
+ Please test. I hope I didn't break anything.
+ - Changed Protracker and compatible tag in amifilemagic. It seems
+ it was too long for xmms/audacious and crashed. Odd.
+
+2006-05-13 Heikki Orsila <heikki.orsila@iki.fi>
+ - Merged man page update from alankila, explaining filter and
+ resampling features
+ - Merged headphones 2 effect patch from alankila, making it sample
+ rate independent
+ - Added --version to uade123
+ - Cleaned up frontends with respect to configuration management.
+ Initial configuration loading is made in uade_load_initial_config()
+ in all frontends.
+ - Fixed song.conf locking
+ - Fixed recursive mode song.conf option setting. Try:
+ uade123 -r --set=gain=2 songdir
+
+2006-05-12 Michael Doering <mld@users.sourceforge.net>
+ - Audacious modinfo GTK-2.8's assertion error fixed by "porting"
+ the legacy gdk_font_load/gtk_text to gtk2's tag, viewport,
+ buffer system.
+ - Worked around gtk2's assumption any text has to be clean UTF-8
+ which obviously will break when displaying binaryhexdumps or
+ Amiga locale strings.
+
+2006-05-11 Heikki Orsila <heikki.orsila@iki.fi>
+ - Updated documentation to reflect implementation.
+ - Added support for eagleplayer/song specific eagleplayer options.
+ Use epopt=x in eagleplayer.conf and song.conf. Look at the
+ man page section "EAGLEPLAYER OPTIONS" for valid options.
+
+2006-05-09 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added information about sample rate into effects API.
+ - Fixed a race condition for Audacious and XMMS plugins.
+ A shared static buffer was not locked for file magic detection
+ in eagleplayer.c:analyze_file_format().
+ - Fixed a bug in eagleplayer.c:analyze_file_format() that might
+ have caused a partial read for file to be detected.
+ - Fixed a buffer overrun bug in uade.c:uade_get_amiga_message().
+ With AMIGAMSG_GET_INFO request, the eagleplayer could
+ cause a slight overrun of the amiga memory to uade data memory.
+ The attacker could not however choose the string to be written
+ over the bounds.
+
+2006-05-07 Heikki Orsila <heikki.orsila@iki.fi>
+ - Improved filters to work on arbitrary frequency (alankila)
+ - Removed A500S and A1200S filters. For compatibility, they're now
+ aliased to A500 and A1200.
+ - Moved computation of audio emulation parameters away from
+ init_sound() to audio_set_rate(). init_sound() calls
+ audio_set_rate().
+ - It's now possible to use frequency directive in uade.conf to
+ set playback frequency. But watch out, it can cause bugs
+ and sound quality degradation.
+ - Now only two models (FILTER_MODEL_(A500|A1200)) exist in
+ amigafilter.h.
+ - Code cleanups
+ - Renamed interpolator to be resampler in command line options
+ and configuration files. Use --resampler=x instead of
+ --interpolator=x.
+ - Fixed IIR filter not to waste CPU time with denormal numbers.
+ This idea was presented to us by Antti Huovilainen, thanks.
+ Try playing BD.Mickey_mouse with an older version and see how
+ much cpu it takes with A500 filter. The new version is one
+ quarter CPU time on an AMD64 machine (alankila)
+ - Optimized event handling in include/events.h by removing
+ redundant vsynctime check that relied upon processor/OS
+ specific timers (that we've removed long ago).
+
+2006-05-06 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added two util functions into uadeipc.c. They are uade_send_u32()
+ and uade_send_two_u32s().
+ - Started changes towards changeable output frequency. You can
+ experiment with --freq=x but filter emulation only works for
+ 44,1 kHz at the moment. Note that filter emulation always has an
+ effect on sound.
+
+2006-05-05 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed --filter=x and --force-led=y to work again.
+
+2006-05-02 Michael Doering <mld@users.sourceforge.net>
+ - Fixed crash due to uninitialized pointer to subsong scale in seek
+ window for xmms and auda plugin.
+ Seems the UI got into a race condition when trying to update the
+ scale belonging to the seek window and the pointer for the seek
+ window was there, while the scale wasn't ready. This happend for
+ very short subsongs only...
+ - Added NTK/STK detection to modinfo
+ - Check for Dirk Bialluch songs in amifilemagic.
+
+2006-05-02 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed a small bug that allows resetting song.conf options from
+ the command line. Use 'uade123 --set= foo' to reset options.
+
+2006-05-01 Heikki Orsila <heikki.orsila@iki.fi>
+ - Changing to a previous song is now possible in uade123. Try
+ pressing '<'. -z option now means randomizing the playlist
+ order before playing, but random play mode (press 's') does
+ randomizing on the fly. Both alternatives support seeking to
+ previous song in the same way, but seeking to next song will
+ always be random in random play mode (not with -z).
+ - Added --repeat option into uade123 to play playlist over and
+ over again.
+
+2006-04-30 Heikki Orsila <heikki.orsila@iki.fi>
+ - It's now possible to set options into song.conf by using uade123
+ directly. This is not the final feature, only a step towards
+ a more usable feature. Try:
+ # uade123 --set="gain=2" foo
+ It should add the associated entry into ~/.uade2/song.conf.
+ Eventually uade123 should be used like:
+ # uade123 --set --gain=2 foo
+
+2006-04-29 Heikki Orsila <heikki.orsila@iki.fi>
+ - Changed hexdump of module/player to show 2 KiBs of text.
+ - Fixed some memory leaks in eagleplayer.c and songinfo.c.
+ - Removed doc/eagleplayer.conf and doc/song.conf. doc/uade123.1 is
+ the authorative documentation for all configuration files.
+ - Many uade song attribute and configuration management changes.
+ - Added broken song end directive for eagleplayers and songs.
+ To work-around a defective timeout logics in song.conf you could
+ add a following line to your song.conf:
+ md5=60f3bb11cc1bacaf77d7c16d13361844 broken_song_end timeout=200 comment FRED.Hybris_Light
+ - Marked song end detection of FRED format as defective in
+ eagleplayer.conf:
+ Fred prefixes=fred broken_song_end
+ - Unified eagleplayer.conf and song.conf settings. See uade123
+ man page for those options.
+
+2006-04-28 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed another config bug introduced by last config refactorization.
+ Filter type could not be set from config file in uade123. The bug
+ did not happen on Audacious/XMMS plugins.
+ - uade123 -v now prints the uade.conf and song.conf files that were
+ loaded.
+
+2006-04-28 Michael Doering <mld@users.sourceforge.net>
+ - Fixed bug in Soundtracker 31 instruments check introduced
+ by fixing the misdetection of a digibooster as protracker mod which
+ was introduced by easing accepting mods with bad length...
+ See a pattern there, folks?!?
+ - Along the way, added a distinction between Soundtracker 2.5/
+ Noisetracker1.0 and Soundtracker 2.4. ST2.5/NT1.0 obviously shared
+ the same replay by Kaktus & Mahoney, while ST2.4 was still based on
+ the old 2.3 replay by Unknown and Mnemotron (using repeat offset in
+ bytes).
+
+2006-04-27 Michael Doering <mld@users.sourceforge.net>
+ - Fixed misdetection of a digibooster mod as protracker in
+ amifilemagic.
+ - Fortified modplayer checks against amifilemagic's new policy
+ to accept modfiles with trailing garbage...
+
+2006-04-26 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed panning, gain and recursive mode to work again. The problem
+ was the new configuration management system. Command line options
+ were not merged into used options. Also, even if they were merged,
+ they would happen before effects were set ;) Sorry. Fixed now.
+ - Improved gain effect. It can now clip samples if an overflow
+ happens.
+ - Improved song.conf settings. It now supports all but two
+ options. See doc/song.conf.
+
+2006-04-21 Michael Doering <mld@users.sourceforge.net>
+ - Fixed detection bug triptodestroy.mod in PTK-Prowiz. Thanks to
+ Joker for the report.
+ The mod uses very large instruments with loops which rolled over
+ to negative checking instrument sizes in words and when large
+ enough. Stupid bug. Stupid me. :-)
+ - Replaced \t with white spaces. This might fix Joker's bug report
+ about garbled output in modinfo for audacious.
+ - Fixed audacious crash, when trying to access fileinfo while not
+ playing a song... Bug was simple we did't have uadesong struct.
+ get_cur_subsong, get_max_subsong and get_min_ subsong was trying
+ read from that struct even when idle and uade went up in a blaze...
+ Now checking towards uadsong struct exists and all is nice
+ - Fixed the Audacious crash fix. It contained a race condition with
+ respect to the NULL pointer. Also fixed the XMMS plugin. (shd)
+
+2006-04-19 Michael Doering <mld@users.sourceforge.net>
+ - Added new replayer for the Dirk Bialluch format by
+ Don Adan/Wanted Team.
+ - Amended Startrekker/Audiosculpture detection in amifilemagic again.
+
+2006-04-18 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed a bug in memmem() replacement. If needle length was zero,
+ it returned NULL, but glibc would return pointer to haystack.
+
+2006-04-15 Michael Doering <mld@users.sourceforge.net>
+ - Fixed bug in sanity check in pt_karplusstrong effect (e8x) in
+ mod player. (thanks Heikki)
+ - Disabled Effect E8x for Protracker 2.3a, 1.1b and 1.0c compatibility
+ mode in PTK-Prowiz.
+ E.g. Playing mod.cyberlogik as PTK3.0 will result in timing bugs,
+ playing it as PTK2.3a will play ok.
+ - Fixed a very serious memory leak issue. Each played song that was
+ read into memory was leaked. My chip collection is 230 MiB and
+ after running
+ valgrind -zr -t1 --enable-timeouts -f /dev/null /chips
+ I noticed a huge chunk of mem leaked :( Now it's fixed. (shd)
+
+2006-04-14 Heikki Orsila <heikki.orsila@iki.fi>
+ - Refactored and changed amifilemagic.c. Changed tracker type magic
+ values into enums. A warning about differing file size and
+ calculated file size for protracker modules is given if one of
+ two conditions happen:
+ - uade123 is run in verbose mode (-v)
+ - xmms or audacious plugin starts to play file
+ - Refactored configuration code
+ - Fixed a subsong/total timeout bug in xmms and audacious plugins.
+ Always ends directive was not obeyed.
+
+2006-04-13 Heikki Orsila <heikki.orsila@iki.fi>
+ - Committed a programmable option for displaying song titles on
+ playlist. Try setting
+ song_title %F %X [%P]
+ to uade.conf.
+ - Reverted xmms buffer underrun fix that was ported to audacious
+ plugin. With produce_audio() one does not need to wait for
+ buffer_free(). (shd)
+ [Comment: it still locks up here :-\] (mld)
+ - Added songtitle feature to audacious plugin and uade.conf (mld)
+ - Added #include <songinfo.h> to audacious plugin and removed some
+ unused variables.
+ - Added a work-around against ALSA output plugin into XMMS plugin
+ which avoids to old subsong change blocking bug. Now sleeping is
+ hardlimited to 5 secs. If work-around is activated, you will see:
+ UADE: blocking work-around activated.
+ on stderr. It seems like snd_pcm_state(pcm) in ALSA output plugin
+ never comes out of SND_PCM_STATE_RUNNING.
+ - Set song_title default to %F %X [%P]
+ - Fixed all xmms and audacious plugin symbols to be non-exportable
+ symbols. The get_iplugin_info() remains the only exportable
+ symbol. 'objcopy -G get_iplugin_info foo.so' should do it, right?
+
+2006-04-12 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed configure script to handle uade.pc file correctly in the
+ situation of '--user'.
+ - Added a user warning to amifilemagic.c about truncated protracker
+ modules.
+ - Reverted Michaels change partially. Audacious and XMMS plugins will
+ not show song name that is obtained from the module because it
+ is unreliable. This will be made configurable in the future.
+ - Fixed a potential bug in XMMS plugin. If maximum free audio buffers
+ was less than 4088 bytes, uade plugin would refuse to write
+ anything. This was noticed because XMMS wouldn't recover from
+ a buffer underrun in ALSA mmap mode. The output plugin would
+ not increase the amount of free buffers even if time passes.
+ XMMS 1.2.10 ALSA output plugin (or alsa library) is still buggy.
+ - Ported shd's xmms buffer underrun fix to audacious (mld)
+ - Changed user warning about truncated protracker modules in
+ amifilemagic to produce less false positives. (mld)
+
+2006-04-11 Michael Doering <mld@users.sourceforge.net>
+ - Fixed my crap indentation in audacious plugin
+ - Sync'd xmms and audacious playlist display
+ - Fixed possible changing current subsong > maximal subsong
+ in audacious plugin.
+
+2006-04-10 Heikki Orsila <heikki.orsila@iki.fi>
+ - --no-song-end is now aliased to -n in uade123
+ - Fixed bug in ArtOfNoise8 replayer end routine. (mld)
+ - Added Songtitle to ArtOfNoise 4V/8V players (mld)
+ - Display "Guru Meditation" error in audacious playlist for a song
+ that crashed uadecore. :-) (mld).
+ - Fixed bug updating the playtime in audacious playlist (mld)
+
+2006-04-09 Heikki Orsila <heikki.orsila@iki.fi>
+ - Code refactorization to unify configuration, effect and song
+ attribute handling among all frontends.
+ - Added memmem() replacement for operating systems not having it.
+ - Added uade.pc for pkg-config.
+ - Upgraded MED/OctaMED replay to v7.0, using Fastmem replay if
+ available and needed by the song (long samples :-) (mld)
+ - DigiBooster player now reports songname. (mld)
+ - Fixed ommited pointer in MED/Octamed fastmem replay detection.
+ (mld)
+
+2006-04-06 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added a small README file
+ - Moved some effect related configuration issues to
+ src/frontends/common/ so that they're not reimplemented in all
+ frontends. See src/frontends/common/uadeconf.c function
+ uade_enable_conf_effects().
+ - Use of uade_enable_conf_effects() in audacious plugin (mld)
+ - Disabled debug messages in Audacious and XMMS plugins
+ - Removed debug message about song.conf not found. It's perfectly
+ valid that song.conf does not exist anywhere.
+ - Cleaned songinfo.c. Added a common implementation of read_be_u16/u32
+ to src/include/uadeutils.h, which is now used from songinfo.c and
+ amifilemagic.c. Changed length types to size_t. Made find_tag()
+ more generic and made it use memmem() function.
+ - Added Heikki's dpiutil to songinfo for CUST.* songs. (mld)
+
+2006-04-05 Michael Doering <mld@users.sourceforge.net>
+ - PTK-Prowiz: changed opcodes beq, sf to seq on Heikkis advice.
+ - Tiny Protracker player compatibility change when calling
+ playvoice.
+ - Nicer playlist entries for Audcious plugin:
+ title (cur/max) - [Format]
+
+2006-04-03 Heikki Orsila <heikki.orsila@iki.fi>
+ - Implemented NTSC mode support. It can be buggy and it will not
+ affect some players at all (those which set CIA tempo by
+ themselves). NTSC mode can detected in eagleplayers by reading
+ $212(execbase) aka VBlankFrequency(execbase). It's a byte
+ with value 50 (PAL) or 60 (NTSC):
+ move.l 4.w,a6
+ cmp.b #60,$212(a6)
+ beq is_an_ntsc_system
+ * pal system
+ - Changed Timing configuration in players/env/PTK-Prowiz.cfg
+ from CIA <-> VBI/NTSC to CIA <-> VBI. (mld)
+ - Mod player now honours pal/ntsc setting automatically. (mld)
+ - Fixed stupid *oops* in mod player reading cia timing from config
+ file.
+ - Added ntsc option uade.conf. (mld)
+
+2006-04-02 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed P61A detection (introduced by mlds change sometime ago).
+ src/frontends/common/amifilemagic.c had "P60A" as the pattern
+ for Player 6.1, but obviously it should be "P61A".
+ - Improved the man page.
+
+2006-03-31 Michael Doering <mld@users.sourceforge.net>
+ - Changed DMAWait to dtg_DMAWait and add dtg_Timer support
+ to DIGI-Booster
+ - DIGI-booster songinfo now matches modfiles songinfo.
+
+2006-03-30 Michael Doering <mld@users.sourceforge.net>
+ - Small check for Fuzzac Packer in amifilemagic.
+
+2006-03-27 Michael Doering <mld@users.sourceforge.net>
+ - Renamed XANN-Packer to XANN-Player, following Sylvain 'Asle'
+ Chipeaux' suggestion.
+ - Merged Funkok saftey check from EP2.04 to protracker player...
+
+2006-03-25 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added a new action key into uade123. 'i' will print module info
+ and 'I' will print a hex dump of a head of the module.
+
+2006-03-23 Michael Doering <mld@users.sourceforge.net>
+ - Sync'd songinfo for modfiles with the more verbose appearance of
+ Asle's ModInfo v2.31 appearance... It displays now sample sizes,
+ volume, finetune, loop start and loop size, too.
+ - Added yet some more tiny differences between Protracker 2.3 and 3.0
+ compatibility mode for completeness... (set sample_num in pt_plvskip,
+ and n_period in pt_doretrig).
+ These changes might have no effect on the replay quality like e.g.
+ earlier mentioned Updatefunk calling difference or volume setting,
+ though.
+
+2006-03-21 Michael Doering <mld@users.sourceforge.net>
+ - Small protacker replayer config file parsing fix...
+
+2006-03-20 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed slight bugs in build system. Architecture specific CFLAGS
+ were missing from xmms and audacious frontends. Also, those flags
+ will be the last flags always so that they can be used for
+ overriding other options.
+ - Made debug flags really optional. They can be turned off with
+ --no-debug (for configure).
+
+2006-03-20 Michael Doering <mld@users.sourceforge.net>
+ - Figured out the period multiplier issue. It was a bug in my
+ brain. *g*
+ - Forgot to add notecut volume setting for protracker 2.3 and below.
+ This is now fixed.
+ - Set the default playback style to Protracker 3.0b.
+ - Added an experimental hybrid protracker setup: 9.
+ Effects are done ptk2.3a style, volume setting like 3.0.
+ This fixes some pops and clicks which even the original
+ protacker 2.3a replay and below had.
+
+2006-03-17 Michael Doering <mld@users.sourceforge.net>
+ - Enhanced compatibilty concerning protracker 2.3a/1.1b(fixed),
+ 2.1a/1.1b, 1.0c and Prottracker 3.0b concerning access of
+ the periodtable while using the effects.
+ It's astonishing in how many ways the protracker replays
+ differ... :-)
+ E.g. Protracker 3.0b (like Noisetracker) uses a multiplication of
+ 37*2 for all effects to get the right period. Protracker 2.3a and
+ the socalled bugfixed 1.1b replay use a value of 36*2 (like the
+ old Soundtracker)
+ Last but least ptk 1.0c, the original ptk1.1b and ptk2.1a use
+ one or the other value for some effects...
+ All in all, it's a mess and we have 4 different setups in our
+ protracker config file :-)
+ - Temporarily disabled the period multiplier hack mentioned above
+ because it borked on some tunes.
+ - Added "update volume when skip/hold note" for protracker 2.3 and
+ below. Protracker 3.0 doesn't do it.
+
+2006-03-16 Heikki Orsila <heikki.orsila@iki.fi>
+ - Changed PAL audio synthesis frequency to be exactly 3546895 Hz. It
+ was 3541200 Hz before. The old value was totally synchronous with
+ video hw. Changing this does not affect anything else than audio.
+ The new value is from the hardware reference manual.
+
+2006-03-16 Michael Doering <mld@users.sourceforge.net>
+ - Compatibility for PTK-Prowiz can now be set to play files like
+ Protracker 3.0b, 2.3a or 1.0c.
+ INFO: Files being played as PT1.0c will have a different vibrato
+ depth, and use funk_repeat effect instead of the invert loop effect
+ which might break all mods composed with later protrackers.
+ - Added support for the different ways Protrackers 1.0, 2.3 and 3.0
+ updated periods.
+
+2006-03-14 Heikki Orsila <heikki.orsila@iki.fi>
+ * UADE 2.02 (Muhammad pictures)
+ - Fixed a bug in xmms plugin that cut off sound data from the end of
+ a song.
+ - New Sierra AGI player by Don Adan / Wanted Team
+ - Better support for old sonic arranger files.
+ - Improved file type detection on many formats.
+ - Debugger improvements (see 'c' and 'i' commands)
+ - Added --buffer-time=x option for uade123 to set audio buffer
+ length in milliseconds.
+ - A configuration file was added for PTK-Prowiz (that plays protracker
+ and clones) to set compatibility to either protracker v3.0b or
+ v2.3a. Please edit file: players/ENV/EaglePlayer/EP-PTK-Prowiz.cfg.
+ - More KDE integration: support for kfmexec wrapper.
+ - Fixed many bugs.
+ - Many other changes :-)
+
+2006-03-12 Heikki Orsila <heikki.orsila@iki.fi>
+ - Changed various uade123 parameters. -k and -K have been changed
+ to one option:
+ -k x or --keys=x, where x is 0 or 1 (disabling and enabling action
+ keys).
+ --no-filter has been removed. Use --filter=none instead.
+
+2006-03-10 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed some compiler warnings. Using %u to print unsigned ints :)
+
+2006-03-01 Heikki Orsila <heikki.orsila@iki.fi>
+ - Reverted mlds work-around to avoid subsong change lockups.
+ - Did a potential fix for the XMMS plugin lockup bug. However, I
+ do not have a test case for this. The problem was, I think, that
+ play_loop() called uade_lock(), then called
+ uade_gui_subsong_changed(), then gtk called some function,
+ which would eventually call get_next_subsong() which would
+ try to re-take the mutex by uade_lock() -> deadlock.
+ * THIS THEORY WAS WRONG.
+ - Merged a patch from Martin Jeppensen to rename some eagleplayers
+ to better names.
+
+2006-02-28 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed -m option for uade123. "uade123 -m file" would only print help
+ but not play the file.
+
+2006-02-17 Michael Doering <mld@users.sourceforge.net>
+ - Added some missing file extensions for the KDE mimelnk.
+ - Use of kfmexec wrapper in KDE mimelnk for easy ftp:// http://,
+ smb://, zip:// etc. support under KDE/Konqueror.
+ - Added install script for KDE users in /src/frontents/uade123/KDE.
+ Now playing Amiga music is just one click away from you ;-)
+
+2006-02-15 Michael Doering <mld@users.sourceforge.net>
+ - NTSC Flag in config file ENV:eagleplayer/ for PTK-Prowiz affecting
+ Sound, Noisetracker, Startrekker and Protracker (vblank) added.
+ Normal Pro- and Fastracker are not affected.
+ Info: it's not a real ntsc mode in emulation but just calculating
+ the CIAA timer to use a value ~ 7.15Mhz, 60khz, 125bpm on PAL
+ machines...
+ It's a cludge I know :)
+
+2006-02-14 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed /dev/urandom detection. Using test -c rather than test -e.
+ Test -c is more compatible and more exact too.
+ - Worked around random lock ups when switching very short subsongs
+ with the xmms subsong changer (mld)
+ - Config file for PTK-Prowiz' Protracker engine added to set the
+ way _Protracker_ mods are played. There's currently two values: 0
+ for Protracker 3.0b like, 1 for Protracker 2.3A like (for anyone
+ interested: funkrepeat is updated before parsing the extended fx :)
+ Differences are probl. not audible but Latter is currently the
+ default. If it breaks a mod file, you can savely turn back to
+ "0" (mld)
+
+2006-02-13 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed uade123 to accept -k and -K switches. Their meaning is now
+ changed. '-k' disables action keys and '-K' enables.
+
+2006-02-10 Michael Doering <mld@users.sourceforge.net>
+ - A new email alias. ;)
+ - Cosmetical change in name from 32 to 31 instr. for Soundtracker II
+ in PTK-Prowiz.
+
+2006-02-08 Michael Doering <mldoering@gmx.net>
+ - Updated mod2ogg.sh to set encoding quality (Giulio Canevari).
+
+2006-02-07 Michael Doering <mldoering@gmx.net>
+ - Put new Sierra AGI player by Don Adan/Wanted Team into players dir.
+
+2006-02-02 Heikki Orsila <heikki.orsila@iki.fi>
+ - Cleaned up gensound.h. It contained unuseful external variables
+ such as sample16s_handler and sample_handler.
+ - Improved mod detection in amifilemagic and Protracker replayer for
+ Protracker compatible mods using effects 5,6,7 and 9. (mld)
+ - Quick "work around" of a lock up with the subsong seek popup and very
+ short subsongs in audacious plugin. Needs further investigation
+ though. Some kind of race condition, I think. (mld)
+ - Reintroduced produce_audio(); to audacious plugin for the freshly
+ released Audacious 0.2 at http://audacious-media-player.org (mld)
+
+2006-02-01 Michael Doering <mldoering@gmx.net>
+ - Changed association of jp file extension to Jason Page New.
+ - Added simple detection for Jason Page old in amifilemagic.
+ - Added alternative Jason Page Player for one file Jason Page New
+ files (Thanks dom from the legacy.de for the report).
+ - Changed HIP, HIPC and HIP7 to SOG, SOC and S7G prefix in
+ amifilemagic.
+
+2006-01-31 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed song length database bug in the XMMS plugin. The XMMS plugin
+ didn't use the correct md5sum in struct uade_song, instead it used
+ the old and useless array called curmd5[] which was an empty
+ string.
+ - Continued to move common variables in frontends to struct uade_song.
+ - Fixed instrument name len in songinfo for mods. (mld)
+
+2006-01-25 Michael Doering <mldoering@gmx.net>
+ - Added Turbo/Infect's SonicArranger Player for "old" sa.* files
+ - Added experimental filedetection for two different
+ Sonicarranger_pc types...
+
+2006-01-24 Michael Doering <mldoering@gmx.net>
+ - Synced audacious plugin with xmms plugin and changed back
+ to support the current stable audacious 0.1.2.
+ The audacious supporting "produce_audio()" will be supported as
+ soon as there's a stable release... (mld)
+ - Ported songinfo for Wanted Team song formats [e.g BSS, DL, FP...]
+ - Fixed mod title display in songinfo
+
+2006-01-22 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added a new option to uade.conf: buffer_time x. buffer_time x in
+ uade.conf sets audio buffer length to x milliseconds. This can
+ be used to avoid buffer underruns on some systems. Beware that
+ Alsa support in libao is buggy in versions 0.8.6 and earlier so
+ that the actual buffer time must be given in microseconds. At
+ this time it is not fixed in any official libao releases.
+ - uade123 option --buffer-time=x can be used to set audio buffer
+ length to x milliseconds.
+
+2006-01-21 Heikki Orsila <heikki.orsila@iki.fi>
+ - Imported the LGPL'ed Max Trax source to amigasrc/players/max_trax.
+ Then applied a patch from alankila. It is not yet an eagleplayer
+ but a work-in-progress. (alankila)
+ - Added a command 'i' to the debugger that traces till next hw
+ interrupt.
+ - 'c' command in debugger will now also print cycle count.
+
+2006-01-20 Heikki Orsila <heikki.orsila@iki.fi>
+ - Continued frontend modularization and code sharing effort. Created
+ struct uade_song in eagleplayer.h to store relevant properties
+ of songs that are played. Modified uade123 and XMMS plugin to use
+ it. The transition is not completed yet. Many fields are still
+ unused and those fields unnecessarily duplicated in frontends.
+ Notice that audacious plugin is broken because of this, but it's
+ also in a transition phase.
+ - Fixed merging conflicts between latest frontend modularization
+ effort and mlds mod/fileinfo changes.
+ - Fixed bugs in songinfo.c. Some file checking could have read over
+ over memory boundary causing a segfault (but nothing else).
+ - Backported fileinfo for DIGI-Booster mods. (mld)
+ - Fixed a bug in XMMS plugin that it stopped a subsong too early
+ if there was another subsong to play. The sound data that was
+ buffered in audio output plugin was discarded. Thanks to Cthulhu
+ (the old one) for the bug report.
+
+
+2006-01-19 Michael Doering <mldoering@gmx.net>
+ - Improved vblank detection in Protracker replay for mod.slow_motion
+ by Jogeir Liljedahl. (mld)
+ - Started work on backporting modinfo from uade 1. Ideally all
+ frontends should be able to use it. (mld)
+ - Experimental "update fileinfo window on songchange" feature...
+
+2006-01-18 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added a simple and broken XMMS file info window. Module info
+ displays a hexdump of the first 1024 bytes of the module.
+ - Fixed #include issues with FreeBSD in unixatomic.c.
+ - Optimized sinc interpolator (alankila)
+ - Changed fileinfo.c to allow many different types of infos for
+ modules. Hexdump is the current default since nothing else has
+ been implemented.
+
+2006-01-17 Michael Doering <mldoering@gmx.net>
+ - (hopefully) Fixed broken subsong detection for Digital Illusion
+ mods.
+ - Fixed unallocating timer resources when changing subsong in
+ MED/Octamed replayer. As a consequence, changing subsongs works
+ again.
+ - Removed sinc table from audio.c and put it into a separate file
+ named sinctable.c. (alankila)
+ - audacious plugin: changed legacy uade_ip audio output from xmms
+ to audacious 0.2 produce_audio(); Seems to work here, but I'm not
+ sure if it's 100% ok... So give it a test and report back.
+ - Fixed strlrep.h to #include <strings.h> to have size_t type (shd)
+
+2006-01-15 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added more debug messages into the interface between emulator and
+ sound core. Now Amiga file loading events will give informative
+ message to the frontend. Use uade123 with -v to see all the spam.
+
+2006-01-14 Heikki Orsila <heikki.orsila@iki.fi>
+ - Merged sinc interpolator patch (alankila)
+ - Changed RK to CM prefix in amifilemagic. This affects custom made
+ format. Old RK and RKB prefixes are still supported but they may
+ be removed in the future.
+ - Added contrib/sinc-integral.py which computes the sinc antialiasing
+ window for audio.c synthesis. (alankila)
+ - Made huge changes into sound cores subsong restart and interrupt
+ logic. Some formats were fixed with respect to subsong changing.
+ Try Monkey Island now. The tempo should be correct after subsong
+ change. 4ch MED/OctaMED is still broken. Try changing to subsong
+ 9 in DaveNinja.med (some channels do not get re-initialized and
+ a disturbing sound plays on the background). The changes are:
+ 1. Earlier we didn't call StopInt and EndSound in subsong change,
+ but now we do. The old procedure just called InitSound and
+ StartInt because our allocators in sound core were robust
+ against double allocation.
+ 2. Implemented unallocation for CIA resources. See
+ rem_cia[ab]_interrupt functions.
+ 3. StopInt unallocates the CIA resource used for the player
+ interrupt. Set_player_interrupt allocates the player interrupt
+ and calls StartInt.
+ 4. EndSound has a default code now which turns off audio DMA and
+ sets volumes to zero.
+ 5. exec.library/SetIntVector() does not enable interrupts anymore.
+ If interrupts are disabled they stay disabled.
+
+2006-01-12 Heikki Orsila <heikki.orsila@iki.fi>
+ - Made anti (accumulator) interpolator to be the default.
+
+2006-01-08 Michael Doering <mldoering@gmx.net>
+ - Commited audacious input plugin based on the XMMS plugin
+ (http://audacious.nenoload.net).
+
+2006-01-08 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed XMMS plugin installation which didn't obey package prefix
+ (Michal Januszewski <spock@gentoo.org>).
+ - Added some more b-flags for fopen(). This time in code in
+ src/frontends/common.
+ - Cleaned up sound data buffering code in uadeipc.c, uade.c and
+ audio.c. Removed uademsg.h as being useless.
+ - Changed uadecontrol.c to uadeipc.c in src/Makefile.in because
+ uadecontrol.c is long gone.
+ - Optimized uade123 to issue next song data request for the uadecore
+ before passing sample data to libao. This way the uadecore may
+ do useful work while libao is blocked on sound device. This didn't
+ solve the underrun problem completely but effect of improving
+ behavior is clearly observable with 'top'. Before this change, top
+ showed only 0.4% CPU usage for uadecore, but after the change it
+ shows 3.3% CPU usage, and the latter reflects reality much better.
+
+2006-01-07 Heikki Orsila <heikki.orsila@iki.fi>
+ - Changed fopen() to use "b" flag for porting to Windows environment.
+ - Thanks to sasq <jonas@nightmode.org> for help with cross-compiling.
+
+2006-01-06 Heikki Orsila <heikki.orsila@iki.fi>
+ - Made uadeipc() re-entrant so that uadecore and a frontend could in
+ theory be run in the same process but different threads.
+ - Replaced poll() with select() in unixatomic.c to be compatible with
+ weak systems.
+
+2006-01-05 Heikki Orsila <heikki.orsila@iki.fi>
+ - Continued cleaning up run-time configuration issues. uade123 and
+ XMMS plugin do not duplicate settings anymore. Most configuration
+ and command line options are stored inside 'struct uade_config'
+ which is defined in src/frontends/common/uadeconf.h.
+
+2006-01-04 Heikki Orsila <heikki.orsila@iki.fi>
+ - Changed -I./include/ to be -I./include in src/Makefile.in to make
+ it compatible with mingw.
+ - PTK-Prowiz now accepts mods with max 1KiB trailing garbage...
+ Nevertheless use 100% good rips, people! (mld)
+ - Fixed spelling mistake in PTK-Prowiz *g* (mld)
+ - Updated uade123 man page with apologies about bad file detection
+ heuristic :(
+
+2006-01-04 Heikki Orsila <heikki.orsila@iki.fi>
+ * UADE 2.01
+ - Compatibility fixes for OpenLSD and Mac OS X to make UADE compile
+ - Added 'cm.' prefix for CustomMade format (Ron Klaren)
+ - PTK-Prowiz subsong scanning was improved (mld)
+
+2006-01-03 Heikki Orsila <heikki.orsila@iki.fi>
+ - Cleaned up post-processing of sound data. Removed postprocessing.[ch]
+ because it was redundant functionality and added necessary
+ functionality into effects.[ch]. Also, moved effect state out of
+ effects.c by creating 'struct uade_effect'. This allows easy
+ loading and storing of state.
+ The goal is to have a unified mechanism for handling information
+ from command line options, uade.conf, eagleplayer.conf and
+ song.conf that is easy. All the setting must be storable and
+ restorable through that mechanism. Currently that is broken,
+ incomplete and messy. The functionality is even duplicated between
+ frontends :( It will probably take many cleanup steps to achieve
+ the goal.
+ - Fixed Mac OS X compatibility issue. poll() was replaced with
+ select(). Thanks to Juuso Raitala.
+ - Improved (hopefully) subsong detection for mods and similar. Now
+ there should be less false positives in PTK-Prowiz than there
+ used to be. (mld)
+ - Removed 255 BPM SetTempo fix in PTK-Prowiz for mod.loader from
+ Coolspot to fix mod.alkupala by jorma... *sigh* (mld)
+ - Fixed broken Prorunner support introduced by reorganization
+ PTK-Prowiz (mld)
+
+2006-01-02 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed a configure bug that occured when --with-xmms was specified.
+ (Michal Januszewski <spock@gentoo.org>)
+ - Made contrib/uadexmmsadd script to be installed if XMMS plugin is
+ installed
+ - Added a work-around for OpenBSD 3.8 which lacks portable types from
+ stdint.h. inttypes.h is used instead. Possibly this avoids type
+ problems on some other OSes too. Note that we require some C99
+ features from standard C libraries. Thanks to ave@silokki.org.
+ - Made OpenBSD use 'gmake'. Thanks to ave@silokki.org.
+ - Fixed execlp() call in src/frontends/common/uadecontrol.c by
+ casting NULL as (char *). Thanks to ave@silokki.org.
+
+2006-01-01 Heikki Orsila <heikki.orsila@iki.fi>
+ * UADE 2.00 (Mental hangover)
+ - Finally the first stable release of UADE 2 series. The work began
+ 6 months ago. There are still rough edges and deficiencies but
+ it is superior to UADE 1 in many respects.
+ - UADE 2 series has following improvements over UADE 1 series:
+ * Superior audio quality due to excellent Amiga 500 and 1200
+ filter models. The default sound model is now the Amiga 500
+ model. This affects all songs whether or not they use filtering.
+ (Antti S. Lankila)
+ * A component architecture which makes creating new frontends
+ easier
+ * Unified configuration files to set defaults for all frontends
+ * Improved command line tool, uade123, supports run-time control
+ of song playback for switching subsong, skipping to next song,
+ skipping fast forward, pausing and altering post-processing
+ effects
+ * Post-processing effect for headphone users (Antti S. Lankila)
+ * Skip fast forward feature in uade123 and XMMS plugin
+ * Many core subsystems have been rewritten or heavily altered
+ * New supported formats
+ * UADE 1 produces snaps in audio output because of a bug in
+ audio DMA engine, but is fixed in UADE 2
+
+2006-01-01 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added contrib/uadexmmsadd script to add uade:// prefixed songs into
+ XMMS playlist. This is useful to avoid conflicts with protracker
+ songs with modplug and other XMMS plugins. Any other plugin will not
+ accept uade:// prefixed entries from the playlist.
+ - Changed forward seeking button in XMMS plugin from ">>" to "10s fwd".
+ - Allow gain values greater than 1.0.
+ - Improved uade123 man page.
+ - Fixed a NULL pointer derefecence in eagleplayer.conf loading. If
+ eagleplayer.conf couldn't be loaded it would crash.
+ - Fixed a directory creation problem with 'make feinstall'.
+
+2005-12-30 Heikki Orsila <heikki.orsila@iki.fi>
+ - Merged an altered sample accumulation patch from alankila. The
+ patch has an effect only if anti interpolator is used.
+ - Removed crux, linear and rh interpolators because they're broken
+ by design. Only default and anti are now supported.
+
+2005-12-22 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed shared library compilation for Mac OS X. Thanks to
+ Michael Baltaks <mbaltaks@mac.com> for information.
+
+2005-12-21 Michael Doering <mldoering@gmx.net>
+ - PTK-Prowiz: Commited various changes to cvs.
+ o Almost finished reorganizing and redoing the mod checks.
+ o Fixed bug in Soundtracker with repeat in bytes handling.
+ o Fixed some bugs in handling empty instruments.
+ o Added hack for vblank mod detection.
+ o Hopefully working, support for Karplusstrong fx.
+ - Amifilemagic: backported a small bugfix in mod detection.
+
+2005-12-20 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added a short note for Max OS X users to address a compilation
+ problem.
+ - Renamed INSTALL to be INSTALL.readme to avoid makefile problems with
+ Mac OS X.
+
+2005-12-19 Heikki Orsila <heikki.orsila@iki.fi>
+ - Merged accurate audio output patch from Antti S. Lankila. The patch
+ solves the problem that Paula's 3.5 MHz output was sampled at
+ regular integer valued intervals that caused inaccuracy. The old
+ interval was round_down(3541200 / 44100) = 80 paula cycles, but
+ the real interval is ~80.299 paula cycles. This means 0.4% relative
+ error in outputted sampling rate that is not audible, but it is
+ harming filter accuracy analysis.
+
+2005-12-17 Heikki Orsila <heikki.orsila@iki.fi>
+ * UADE 1.50-pre10
+ - Cleaned up src/include/events.h. Removed unnecessary event
+ scheduler.
+ - Reworked audio subsystem to be more debuggable and added comments.
+ - Fixed a bug in audio state engine that caused DMA engine to play
+ one word too much of sample data. How could this bug have gone
+ unnoticed for so long? The same bug exists in UAE too.
+ - Reverted back to not using interpolation with A500E and A1200E
+ filters. The anti interpolator caused problems with many songs.
+ It will be fixed at some point and changed back, but at the
+ moment there's doubt how to fix the problem.
+
+2005-12-16 Heikki Orsila <heikki.orsila@iki.fi>
+ - Applied filter improvement and optimization to audio.c. The
+ filter should be slightly better than the old. Affects only
+ A500E and A1200E filters. (alankila)
+ - Cleaned up audio.c
+ - Reworked configuration loading system to avoid conflicts with
+ uade123 command line parameters. Command line parameters have
+ priority over uade.conf.
+
+2005-12-15 Michael Doering <mldoering@gmx.net>
+ - Some progress on porting the mod detection to m68k asm.
+
+2005-12-15 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed a bug that forced filter to be A500E type when --force-led
+ was uade with uade123. (alankila)
+
+2005-12-14 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added displaying total playtime based on content database into
+ uade123
+
+2005-12-12 Michael Doering <mldoering@gmx.net>
+ - replaced Grouleff replayer with Wanted Team's EarAche.
+ - added new EMS replayer by Wanted Team.
+
+2005-12-12 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added INSTALL file to document build process.
+
+2005-12-11 Heikki Orsila <heikki.orsila@iki.fi>
+ * UADE 1.50-pre9
+ - An XMMS plugin has been added. New features compared to UADE1 XMMS
+ plugin are seek fast forward and correct subsong seeking bar. The
+ plugin still lacks GUI for configuration, but uade.conf can be
+ edited directly.
+ - Filtering settings are audibly different compared to last release.
+ A500E filter model is now the default. It was A1200 in the last
+ release. This affects all songs, even those which do not use the
+ filter.
+ - New players for 15 instrument soundtracker variants have been added.
+ - uade123 man page has been updated.
+ - Most subsystems have gone through changes. Some important changes
+ have been left out. See log entries for further details.
+
+2005-12-11 Heikki Orsila <heikki.orsila@iki.fi>
+ - Significant changes in filter default values. Current default filter
+ is A500E, which is audibly different on every song compared to the
+ old default (A1200). To restore the old behavior, set "filter a1200"
+ in uade.conf. If you want to advocate another default value, please
+ post to the forum or send email. The forum is preferred.
+
+2005-12-10 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added notices to documentation that setting filter model has an
+ audible effect even if a song doesn't use filtering at all.
+ - Cleaned up configure script (that is originated from uade1)
+
+2005-12-07 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added unrecognizable type "packed" into amifilemagic. It is
+ used to inform user about files that are packed with an amiga
+ packer.
+ - some work on m68k mod checking and replay routine (mld)
+
+2005-12-06 Michael Doering <mldoering@gmx.net>
+ - XMMS plugin now automagically advances the subsong seek slider, if
+ the replay rolls over to the next subsong.
+ - Soundtracker15 name check that was added yesterday was removed. (shd)
+ - Fixed a bug in uade_filemagic() that char *pre was not initialized
+ to be an empty string by default. This caused
+ uade_analyze_file_format() to receive garbage data when file format
+ was not recognized. (shd)
+ - Valgrinded a memory allocation bug in two places of eagleplayer.c
+ (the same error actually due to replicating same lines of code),
+ where space for (n + 1) pointers should have been allocated, but
+ only ((n * sizeof ptr) + 1) bytes was allocated. (shd)
+ - Added gain effect into uade.conf. You can use variable named
+ 'gain' to set scaling value for each outputted sample. For
+ example, add a following line to uade.conf:
+ gain 0.25 (shd)
+ - Made length test of mods with 32 instruments less strict. Due to
+ popular demand *g* now "oversize mods" get accepted.
+ - Added check for sane finetune and volume values in modchecks.
+
+2005-12-05 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added initial version of song length database into XMMS plugin. It
+ is compatible with uade1 db-content, but named differently:
+ ~/.uade2/contentdb. You can just copy the old db:
+ cp ~/.uade/db-content ~/.uade2/contentdb
+ - Content db is loaded during play_file if it has changed
+ on the disk. If it has not changed on the disk, then it is
+ saved if an hour has passed and the db has been changed.
+ - Added a requirement for Soundtracker15 song content detection that
+ the name must have prefix or postix being: "mod", "mod15", or
+ "mod15_". This change could be reverted at some point but now it's
+ the safest choice.
+
+2005-12-04 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added missing #include for uadecontrol.h (sys/types.h for pid_t).
+
+2005-12-03 Heikki Orsila <heikki.orsila@iki.fi>
+ - Made XMMS plugin display play time correctly in the play list
+ after a song ends. If song ended volutarily, tell XMMS the
+ play time. If song ended involuntarily by user intervention,
+ error, or timeout, tell XMMS that the song doesn't have a length
+ leaving the play list time empty.
+
+2005-12-02 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed a latency and time bug in the XMMS plugin that affected
+ fast forward seeking. When forward seeking happened the XMMS time
+ display was not updated and the seeking happened with a delay.
+ - Made XMMS plugin report the play time for XMMS after a song
+ ends.
+ - Added comments about variable locking in XMMS plugin.
+
+2005-12-01 Michael Doering <mldoering@gmx.net>
+ - eagleplayer.conf: Amended the different MarkCooksey prefixes.
+ - amifilemagic: fixed TFMX 1.5 detection bug introduced by the recent
+ clean-up.
+ - amifilemagic: fixed another TFMX detection bug. Should be alright
+ again now.
+
+2005-11-30 Heikki Orsila <heikki.orsila@iki.fi>
+ - Make XMMS plugin auto detectable in configure script. The plugin is
+ still very experimental and incomplete in features, but it can
+ already play songs, or at least it should.
+ - GCC4 gave warnings of problems I had not noticed: Fixed a bug in
+ md5.h. uint32_t was accidently redefined (that is #included
+ originally from stdint.h). XMMS plugin's uade_ip structure was
+ declared static but later as external. Fixed signedness warnings
+ from various modules.
+ - Added seek-forward button into XMMS plugin. (mld)
+ - New replayer for Soundtracker v2-v5 mods with 15 instruments and
+ a lot of different effects added. (mld)
+ - fixed WaitAudioDMA for all old mod15 replayers. (thanks heikki!)
+ - changed mod15 (again) for stricter st-iv detection (mld)
+ - changed to a stricter tracker module length policy...
+ If uade doesn't play your modfiles anymore, it's a bad rip.
+ Get a good one! :)
+ - Since Master-Soundtracker files seem to use a subset of the normal
+ Soundtracker fx, they now get played with the mod15 replay
+ This makes Master-ST replayer kind of obsolete atm. (mld)
+
+2005-11-29 Heikki Orsila <heikki.orsila@iki.fi>
+ - Partial and buggy implementation of song.conf. It is used for uade
+ specific work-arounds for broken or bad songs. Look at doc/song.conf
+ and src/frontends/common/eagleplayer.c. Please do not use this yet.
+ - Fixed some compiler warnings that surprisingly came with gcc 4.0.2.
+ - Fixed Makefile.in to not report error on 'make install' when XMMS
+ plugin is not installed.
+
+2005-11-28 Heikki Orsila <heikki.orsila@iki.fi>
+ - Modularized loading and parsing on uade.conf options. See
+ src/frontends/common/uadeconf.[ch].
+ - It is possible that config parsing for uade123 breaks now.
+ - Added partial config loading support for XMMS plugin. Doesn't
+ support setting filter type or interpolation mode yet. You must
+ edit uade.conf by hand if you want configuration changes. No GUI
+ for setting options yet.
+ - Added cleaning rule for XMMS plugin
+ - New make rule: 'make feclean' will clean all frontend objects
+ - The XMMS plugin determines configuration file path for uade.conf
+ once during XMMS plugin initialization, and it will not change
+ afterwards. If no global or user configuration is found, then
+ the plugin chooses the file under HOME ($HOME/.uade2/uade.conf).
+ It will try to load the configuration each time a new song is
+ selected from the XMMS.
+ - Optimization: XMMS will re-read configuration when a new song is
+ selected if the file timestamp of uade.conf has changed.
+ - Fixed synchronization problem in XMMS plugin's play loop. The audio
+ device is drained of written sound data before actually stopping
+ the device. The earlier version cut of audible data from the end
+ of the song :( However, draining can be interrupted if the user
+ requests something urgent, such as wanting an immediate song change.
+ Draining takes time as long as audio
+ device has buffered data. Buffering settings can be found from
+ output plugin settings, as usual.
+
+2005-11-28 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added hardcoded timeouts for the XMMS plugin. They are the same
+ as uade123 defaults. 20 seconds for silence and 512 seconds for
+ subsong. Reading uade.conf variables is not supported yet.
+
+2005-11-27 Heikki Orsila <heikki.orsila@iki.fi>
+ - Continuing modularization of uade frontends. Various commands,
+ such as set subsong, change subsong, set filter type, and set
+ interpolation mode, were moved to src/frontends/common/uadecontrol.c.
+ The idea is that all the non-trivial commands have a wrapper in
+ uadecontrol.c, but trivial commands that don't require parameters
+ can be used through uadeipc.c (uade_send_short_message()).
+ - Added src/include/uadeconstants.h that should contain constants that
+ are common with uadecore and frontends.
+ - Subsong seeking works in XMMS plugin :-)
+ - Made XMMS plugin globally installable as it should be
+
+2005-11-26 Heikki Orsila <heikki.orsila@iki.fi>
+ - Continuing modularization of uade frontends. Renamed
+ src/uadecontrol.c to be src/uadeipc.c, and added
+ src/frontends/common/uadecontrol.c which contains a set of
+ helper functions to control and spawn uadecore.
+ - Added --with-xmms to configure script for developing the XMMS
+ plugin. It does not work yet!
+
+2005-11-25 Heikki Orsila <heikki.orsila@iki.fi>
+ - Cleaned up and fixed tronictest check in amifilemagic. Added
+ read_be_u16() and read_be_u32() to help parsing amiga formats.
+ - Cleaned up tfmxtest in amifilemagic.
+ - Cleaned up modparsing in amifilemagic.
+
+2005-11-24 Michael Doering <mldoering@gmx.net>
+ - amifilemagic: improved mod32 and mod15 checks a bit
+ - ha! found pitchbend incompatibility bewteen
+ Master-ST and DOC Soundtracker II in amifilemagic. Now
+ Mods using the pitchbends bigger than 0xf are played as
+ DOC Soundtracker II:)
+
+2005-11-23 Michael Doering <mldoering@gmx.net>
+ - Master-ST and Ultimate-ST replayers now check for a valid file
+ length, thus badly ripped mod15 songs won't get played anymore with
+ UADE. No exceptions.
+ FYI this will also be future for all other Sound and Protracker
+ derivates, so for anyone having bad rips - get some valid files! :)
+
+2005-11-22 Michael Doering <mldoering@gmx.net>
+ - Improved amifilemagic: mod32 check now tries to distinguish
+ 10 different mod types. (BTW. 4ch Fastracker mods and similar
+ now default to mod_pc and get played by the Multichannel PS3M player)
+ - Some more work on the mod15 check in amifilemagic again.
+ - Started to update the amiga mod15 replayers (Ultimate-ST and
+ Master-ST with better checks, resulting in breaking support for other
+ players like EP or DT atm.
+
+2005-11-18 Michael Doering <mldoering@gmx.net>
+ - Lowered the file buffer size to 8192 bytes to reduce overhead with
+ xmms plugin scans. Unfortunately mods with a header and pattern data
+ beyond that buffer size can't be detected properly and get played
+ as plain mod15.
+ - Improved mod15 check. It should produce now less false positives.
+ - Added a smarter(?) way of the mod check for larger files that
+ don't fit into the check buffer completely.
+ - Renamed filemagic() to uade_filemagic() (shd)
+ - Filemagic buffer size (8192) is now passed as an argument to
+ uade_filemagic(). Previously both the caller and callee knew the
+ size.
+ - Made amifilemagic tables static (only visible inside the module)
+ (shd)
+ - Name prefix conflict between Future Player and PTK-Prowiz was
+ resolved in favor of Future Player. The name prefix/extension is
+ 'fp'. (shd)
+
+2005-11-16 Heikki Orsila <heikki.orsila@iki.fi>
+ - Made install to a standard path by default. That is /usr/local.
+ Use ./configure --prefix to override. configure --user will install
+ to users home directory as in the past.
+ - Committed initial version of man page for uade123.
+ - added a first uade-only mod15_Mastertracker player (mld)
+ - improved (?) mod15 type checks in amifilemagic (mld)
+ - started to work on more complete mod type check in amifilemagic
+ (mld)
+
+2005-11-13 Heikki Orsila <heikki.orsila@iki.fi>
+ - Cleaned up src/frontends/common/eagleplayer.c. Removed skip_ws(),
+ skip_nws(), and loops that used them, and replaced those with
+ shorted loops that use strsep(). Changed index variables to use
+ size_t instead of int to be more robust against bad input.
+ - Fixed a bug that if eagleplayers.conf specifies always_ends for
+ an eagleplayer then forcing timeout from command line with -t
+ didn't work.
+ - Fixed a dirty bug in score that made score crash if an eagleplayer
+ gave a NULL pointer as module name. This happened with Frontier
+ custom. Closer inspection revealed that Frontier custom is also
+ buggy because it sets module name in InitSound() but the
+ specification says module name is evaluated after InitPlayer()
+ which is before InitSound(). This looks like a design bug in
+ the interface, or a typo in the documentation, because setting
+ module separately for each subsong is useful, and that is what
+ Frontier actually does.
+
+2005-11-12 Heikki Orsila <heikki.orsila@iki.fi>
+ - Add new antialiasing interpolation mode, which corrects for noisy
+ treble especially audible in the A1200 filter model. It does its
+ work by computing the average value of Paula's output pins between
+ samples.
+
+2005-11-09 Michael Doering <mldoering@gmx.net>
+ - Fixed missing hipc and soc prefixes in eagleplayer.conf.
+ - Associated #chn, ##ch mods to PS3M again. (note: s3m, xm or mtm
+ are still omitted by uade)
+
+2005-11-08 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added slight noise reduction into CSpline code to reduce
+ noise due to interpolation errors, and snapping sounds from
+ sudden volume changes. (alankila)
+ - Updated headphone filtering parameters to place virtual
+ sound sources closer to head and reduced the associated treble
+ filtering to make the sound at the same time brighter and more
+ forward placed. The sources still appear slightly behind and
+ perhaps elevated, so the illusion will be further improved.
+ (alankila)
+ - fixed AON8 timing now for real *grin* (mld)
+ - added Musicline Editor to be detected by amifilemagic (mld)
+
+2005-11-07 Michael Doering <mldoering@gmx.net>
+ - Removed dupes from new eagleplayer.conf (mld)
+ - Added new player: Musicline Editor (mld)
+ - Broke ArtOfNoise8 timing, and added song end detection. (mld)
+
+2005-11-06 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added an experimental support for eagleplayer.conf, which is
+ specified at doc/eagleplayer.conf. The new system allows eagleplayer
+ specific settings. uadeformats is no longer used, so it has been
+ removed. Here's a list of currently possible eagleplayer options:
+ a500 (A500 type filter emulation is used.)
+ a1200 (A1200 type filter emulation is used.)
+ always_ends (A song always ends, so timeouts are not used.)
+ content_detection (File name prefix or postfix heuristics are not
+ used for determining format.)
+ speed_hack (Speed hack is enabled.)
+ Tips:
+ Speed hack can be turned on for a specific format by editing
+ eagleplayer.conf. A format can be marked as ending always, which
+ means that timeout values are not used (except silence timeout).
+ There are other options too, and all of them are specified in
+ doc/eagleplayer.conf.
+
+
+2005-11-05 Heikki Orsila <heikki.orsila@iki.fi>
+ - Player interrupt is now a CIA A interrupt by default. As a
+ consequence CUST.Loom works (it requires that player interrupt
+ runs at a lower priority level than audio interrupts).
+ THM.BlueAngel69 might play better now - a good comparison is needed.
+ There are still a few things to do in the sound core's interrupt
+ system, see amigasrc/score/todo.txt.
+ - Headphones effect clipping fix (alankila)
+ - Added improved (but currently experimental) LED filtering code.
+ The old code was based on assumption that A500 and A1200 have same
+ output filtering circuitry, but this was not correct. After
+ analysing hi-fi measurements by pyksy, I designed new filters
+ by tweaking a couple of equalizers on top of a RC filter that
+ provided basic treble attenuation. Use --filter=a500e or a1200e to
+ test the new filters. (alankila)
+
+2005-11-04 Heikki Orsila <heikki.orsila@iki.fi>
+ - Separated CIA B timer A and timer B interrupts finally. Some
+ Forgotten World songs started to work, but not all. Thomas
+ Herman BlueAngel69 swent back to its earlier buggy state. Our
+ recent interrupt handler change broke Thomas Hermann completely.
+ This change fixes our original design fault that only one CIA
+ timer interrupt may be used, but not both. This patch takes us
+ much closer to full CIA interrupt handler support.
+ - Heikki's CIAB-A and CIAB-B separation in soundcore gave us full
+ support of the MusiclineEditor player from Eagleplayer 2.02.
+ You still have to use --speedhack to give it enough
+ cpu cycles, though. (mld)
+ - forgot to add detection bug fix of the two different MCMD formats
+ in amifilemagic to changelog *grin* (mld)
+
+2005-11-03 Heikki Orsila <heikki.orsila@iki.fi>
+ * UADE 1.50-pre8
+ - Many bug fixes and cleanups.
+ - Headphones postprocessing effect.
+ - Improved A1200 filter emulation.
+ - Added A500 filter emulation. Use --filter=a500.
+ - Cleaned up sound cores timer code.
+ - Fixed CIA timer initialization.
+ - Improved uade123 user interface. Press 'h' in uade123 or list
+ action keys with uade123 --help.
+ - New sample interpolation code (--interpolator=cspline).
+ - --stderr can be used to pipe sound data to stdout.
+
+2005-11-02 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed a very stupid bug I introduced yesterday to src/uade.c.
+ if (curs > maxs)
+ foo();
+ bar();
+ Duh. Why did I forgot {}??
+ - Network byte orderized, or big endianized, subsong info transmission
+ between uadecore and frontend. This wasn't a bug. Just a change for
+ consistency.
+
+2005-11-01 Heikki Orsila <heikki.orsila@iki.fi>
+ - Removed src/effects.c. It was accidently left there from uade 1
+ (alankila)
+ - Removed unnecessary functionality from src/players.c. Black listing
+ Protracker modules to be VBI timed should be in frontend logic
+ rather than emulator logic.
+ - Cleaned up text messages all over the place.
+
+2005-10-31 Heikki Orsila <heikki.orsila@iki.fi>
+ - Did highly experimental changes to sound core's timing interrupt
+ system. I tested the change with all known players, and only the
+ Thomas Hermann broke out, but it was broken already, so no big
+ loss there. Of course I only tested each format with a few songs,
+ so it's very possible that if the new system doesn't work,
+ then I couldn't catch the problems. Nevertheless, I spent over an
+ hour listening to different samples. Testing this change would be
+ appreciated. One should especially pay attention to tempo, because
+ that may have gone wrong. The changes I technically made were:
+ - Made default interrupt timer to be CIA B timer A. Took away all
+ the hacks to use VBI when ever possible to be the default timer.
+ - While turning on any CIA B timer (A or B), it does not turn off
+ the other CIA B timer.
+ - Fixed CIA B timer initialization. Setting a timer (A or B) gets
+ the timer value from dtg_Timer(eaglebase).
+ - Cleaned up audio interrupt server.
+ - Fixed tiny bug in uade123 file extension detection (mld)
+ - Moved amifilemagic, uadeformats, and unixwalkdir modules to
+ frontends/common/ where they belong.
+
+2005-10-30 Heikki Orsila <heikki.orsila@iki.fi>
+ - Modified headphones effect. (alankila)
+ - Added 'H' action key to toggle headphones effect, and 'P' to toggle
+ panning effect. Default panning value is 0.7, unless specified
+ otherwise with command line option or in uade.conf.
+ - Added forgotten -O2 optimization flag to uade123 Makefile
+ - Cleaned audio.c. Removed some debug #defines.
+ - Imported amiga player sources from uade1 project to amigasrc/players/
+
+2005-10-29 Heikki Orsila <heikki.orsila@iki.fi>
+ - Antti S. Lankila <alankila@bel.fi> will be referred to as 'alankila'
+ in ChangeLog from now.
+ - Beautified and cleaned up audio.c and sd-sound-generic.h.
+ - Fixed a bug that caused 1 bit precision loss in audio output.
+ Sample data was multiplied after filtering, but it should have been
+ multiplied before. (alankila)
+ - cust.Bubble_Bobble gives wrong subsong information. Added a logic
+ into uade123 that determines subsong ranges if default subsong
+ is outside the reported range.
+ - Changed score's CIA setup so that both CIA-A and CIA-B time of day
+ counters run continously. Some players, such as Oktalyzer and
+ sean connolly depend on this. As a consequence it was possible to
+ remove a work around from score that patched the sean connolly
+ player not to use CIA TOD. However, any player using CIA TOD is at
+ risk of not functioning properly, but I have only seen two cases
+ so far (those which I mentioned).
+ - Removed score from uade source root, now it's only located at
+ amigasrc/score/ directory.
+ - Fixed a bug in uade123/playloop.c. If one subsong ended because of
+ silence, all the rest subsongs would end because of silence too.
+ I forgot to reset the silence counter to zero..
+ - Added a headphone postprocessing effect, and an effect framework for
+ different uade frontends. Try --headphone. (alankila)
+ - Try pressing 'p' on uade123 to toggle postprocessing effects on
+ and off.
+ - New filter code (alankila)
+
+2005-10-28 Heikki Orsila <heikki.orsila@iki.fi>
+ - Radical cleaned up in audio.c.
+ - Fixed rh and crux interpolators. Thanks to Antti S. Lankila.
+ <alankila@bel.fi>
+ - Removed lots of unnecessary macros, variables and functions.
+ - rh interpolator is now names as linear.
+ - Removed src/config.h. It is unnecessary.
+ - uade123 help will now print usable action keys too. Also, one may
+ press 'h' at run-time to see usable keys. It will print currently
+ as follows:
+ Action keys for interactive mode:
+ '.' Skip 10 seconds forward.
+ SPACE, 'b' Go to next subsong.
+ 'c' Pause.
+ 'f' Toggle filter (takes filter control away from eagleplayer).
+ 'h' Print this list.
+ RETURN, 'n' Next song.
+ 'q' Quit.
+ 's' Toggle between shuffle mode and normal play.
+ 'x' Restart current subsong.
+ 'z' Previous subsong.
+ - To verify whether a song uses filter or not, enable verbose mode
+ for uade123 by -v. You'll see messages like:
+ Message: Filter ON
+ - Added two different types of filters: A500 and A1200. Thanks to
+ Antti S. Lankila, again. Use --filter=a500 or --filter=a1200,
+ the A1200 case is the default. Both types of filter are
+ but A1200 filter is better tested. We need feedback on A500 filter.
+ - --force-filter was changed to --force-led.
+ - Fixed a bug with getopts. The long options list was not zero
+ terminated, and it had worked by luck so long..
+ - Added good ol' speed hack feature into uade123. Use --speedhack
+ to increase CPU speed for players that extra virtual power. It
+ is useful for players that require more cpu than 68k can give,
+ multichannel oktalyzer for example.
+
+2005-10-27 Heikki Orsila <heikki.orsila@iki.fi>
+ - Made interpolation mode selectable from command line. Use
+ --interpolator=x to choose the interpolation mode, where
+ x = default (no interpolation),
+ rh = rh interpolator (broken atm),
+ crux = crux interpolator (broken atm),
+ cspline = Antti S. Lankila's spline interpolator
+ (This is not recommended for chip songs! The spline
+ spline interpolator is good for natural instruments,
+ but may produce bad sounds with chips.)
+ - Interpolator is selectable from uade.conf file by adding line:
+ interpolator foo
+ Note that using anything else but default is not recommended
+ at the moment.
+ - As per Michael Doering's needs, I added --stderr option to uade123.
+ It will force all terminal output printed onto the stderr, and thus
+ allows piping pure sound data. Example:
+ uade123 --stderr -e raw -f /dev/stdout DW.Platoon |postprocessing
+
+2005-10-27 Heikki Orsila <heikki.orsila@iki.fi>
+ * UADE 1.50-pre7
+ - Antti S. Lankila <alankila@bel.fi> fixed and improved filter
+ behavior. The filter state must be updated even when filtering
+ is not outputted. Output scaling was fixed to the right place
+ so that it does not distort filter state. Unnecessary range
+ scaling of input samples was removed. Some documentation was
+ added about technical properties of the IIR filter.
+ - Filtering by default was not enabled for those people who had an
+ earlier uade2 version installed to their home directory, because
+ make install does not overwrite ~/.uade2/uade.conf. Now the default
+ is hard coded into the source code.
+
+2005-10-27 Heikki Orsila <heikki.orsila@iki.fi>
+ * UADE 1.50-pre6 (tester pre)
+ - Uade core now supports only 16-bits stereo. If 8-bits or mono is
+ needed the sample data can be postprocessed.
+ - Added experimental filtering support. It should be better than the
+ one found from uade1. Thanks to Antti S. Lankila <alankila@bel.fi>
+ for IIR filter coefficients and advice.
+ - New uade.conf options:
+ filter - enable filter emulation
+ no_filter - disable filter emulation
+ filter_off - turn filter always off
+ - New command line options:
+ --filter Enable filter emulation
+ --force-filter=x, where x = 0, or x = 1. Set filter state either
+ off (0) or on (1).
+
+2005-10-16 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added a fuzzy state diagram on client-server interaction from client
+ perspective.
+
+2005-10-08 Heikki Orsila <heikki.orsila@iki.fi>
+ - Unknown keywords in uade.conf are ignored. Old behavior was to
+ terminate uade123 on an unknown keyword.
+ - First try to load uade.conf from ~/.uade2/uade.conf, and then
+ try the global config file ($PREFIX/etc/uade.conf)
+ - Simplify playloop in uade123.
+ - Beautify directory hierarchy scanning by avoiding unnecessary
+ '/' characters.
+ - Started specifying uade client-server protocol. See
+ doc/play_loop_state_diagram.dia.
+ - Removed S3M support. It's not an Amiga format, and thus it doesn't
+ belong to UADE. It might also interfere with other players when
+ UADE is used as an XMMS plugin. Use XMP, modplug or something
+ else for these formats.
+ - 'make check' is now 'make soundcheck' because it's more a sound
+ check than a good test set.
+
+2005-10-03 Heikki Orsila <heikki.orsila@iki.fi>
+ - Action keys made into default behavior for uade123.
+
+2005-09-08 Heikki Orsila <heikki.orsila@iki.fi>
+ - Giulio Canevari pointed out that --panning doesn't work. For
+ some reason I didn't notice that (perhaps didn't test ;-). The
+ problem was false parameters for GNU getopt.
+ - mod2ogg2.sh from Giulio Canevari
+
+2005-09-04 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added -g option to uade123 to only print information about songs.
+ Songs are not played in this mode. All relevant output goes into
+ stdout. This should be useful for scripting people. An example:
+
+ $ uade123 -g /svu/chip/mod/mod.Unit-a-remix 2>/dev/null
+ playername: Protracker & relatives
+ modulename: unit-a-remix
+ formatname: type: Protracker
+ subsong_info: 1 1 1 (cur, min, max)
+ <uade123 quits fast>
+
+2005-09-01 Heikki Orsila <heikki.orsila@iki.fi>
+ - Cygwin fixes. Add cygwin detection to configure script. Makefile
+ should be aware that uade123 is named uade123.exe on cygwin.
+
+2005-08-27 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed a memory copying bug which could cause sound data
+ corruption when skipping 10 seconds forward with uade123. The bug
+ was at playloop.c:273. memmove should be used instead of memcpy (shd)
+ - A patch from Jarno Paananen <jpaana@s2.org>. It fixes use of C99
+ anonymous initializers with sigaction (2) on Cygwin.
+
+2005-07-28 Heikki Orsila <heikki.orsila@iki.fi>
+ * UADE 1.50-pre5 (developer release)
+ - Nothing better to do. Let's release the new version for users to
+ test.
+
+2005-07-25 Heikki Orsila <heikki.orsila@iki.fi>
+ - It seems ALSA lib could fork and consequently terminate a process
+ when used through libao, and we must not consider it an error in
+ our signal handler that catches all dead children. The signal
+ handler assumed that the only child that could die is uade. (shd)
+
+2005-07-24 Heikki Orsila <heikki.orsila@iki.fi>
+ - New keys for interactive mode:
+ [0-9] - Select subsong in range [0, 9]
+ q - Quit player
+ s - Switch between normal and shuffle mode
+ x - Restart current subsong
+ - Added -£ or --no-song-end switches. Song just keeps playing even if
+ the amiga player says it has ended. Dude! You can get pretty weird
+ sounds with this, and sometimes the sound core crashes, and should
+ crash. Fortunately that doesn't kill the simulator :)
+ - Made help print (-h) prettier by aligning tex columns
+ - Added -K or --no-keys to disable action keys (this can be used to
+ override the uade.conf if it enables actions by default).
+
+2005-07-23 Heikki Orsila <heikki.orsila@iki.fi>
+ * UADE 1.50-pre4 (developer release)
+ - Added shell interaction keys into UADE123. The keys can be enabled
+ with -k switch, or adding line "action_keys" into uade.conf.
+ The keys are (mimiking XMMS):
+ z - Previous subsong
+ c - Pause
+ b - Next subsong
+ n - Next song
+ . - Skip 10 seconds forward
+ ENTER - Next song
+ SPACE - Next subsong
+ Does someone want these configurable into uade.conf? Please email
+ me.
+
+2005-07-22 Heikki Orsila <heikki.orsila@iki.fi>
+ * UADE 1.50-pre3 (developer release)
+ - Added a -j to skip x seconds of audio from the beginning. Note that
+ this does not affect timeout parameters in any way. If timeout is
+ 1 minute and skip is 2 minutes, the song will just end before
+ anything is played.
+
+2005-07-21 Heikki Orsila <heikki.orsila@iki.fi>
+ - Added silence timeout
+ - Wrote a config file parser for uade123. Look at uade.conf file
+ for instructions. uade123 tries to load following files in order on
+ startup: BASEDIR/uade.conf and $(HOME)/.uade2/uade.conf. Command
+ line options can override config file parameters. Users of uade123
+ might want to configure timeout, panning and such values as
+ personal defaults. This is a very important feature important over
+ uade 1.0x command line tool.
+ - Restructured uade123 code into different code modules to make
+ maintaining and code reuse easier.
+
+2005-07-18 Heikki Orsila <heikki.orsila@iki.fi>
+ - Fixed a bug in uade123 that prevented it from playing the last
+ subsong of a song.
+
+2005-07-18 Heikki Orsila <heikki.orsila@iki.fi>
+ * UADE 1.50-pre2 (developer release)
+ - uade123 now has eagleplayer fileformat check ignoring feature (-i),
+ panning (-p), song timeout (-t), and subsong timeouts (-w)
+
+2005-07-17 Heikki Orsila <heikki.orsila@iki.fi>
+ - uade123 now uses GNU getopt
+ - uade123 can now output both raw and wav formats by using libao
+ file output mechanism. Wav format is the default. Example:
+ uade123 -e wav -f foo.wav songfile
+ - The sound core now reports to the simulator when audio output should
+ start. Traditionally the simulator has produced audio output from
+ the reboot of the amiga even if it is only useful to output audio
+ after all the lengthy player initializations have been made in
+ the sound core. For example, AHX.Cruisin now has 0.96 seconds less
+ zero samples in the beginning.
+ - Cleaned up sound core a bit. Removed some unused definitions
+ of messages between sound core and the simulator. Removed unused
+ code that was designed to be used when running sound core under a
+ _real_ AmigaOS.
+ - Made uade123 less verbose. Use -v option to get more details.
+ - Renamed uade-trivial.c to 'uade123.c' in src/frontends/uade123
+ - Renamed directory 'trivial' to 'uade123' in src/frontends/
+
+2005-07-15 Heikki Orsila <heikki.orsila@iki.fi>
+ * UADE 1.50-pre1 (developer release)
+ - Lots of changes into uade123
+ - This is just a preview of the new system. There are no interesting
+ features over uade 1.0x versions. This release doesn't even have
+ xmms / beepmp plugins.
+ - Short instructions for testing:
+ $ ./configure && make
+ $ make test
+ $ make install
+ Will install everything to $(HOME)/.uade2/. Then
+ $(HOME)/.uade2/uade123 is the player you can use. This version
+ uses libao for audio output.
+
+2005-07-12 Heikki Orsila <heikki.orsila@iki.fi>
+ - Code in src/amifilemagic.c does amiga fileformats detection. If it's
+ useful for any other project out there, it is now dual licensed
+ under the GNU GPL _and_ Public Domain. By public domain we mean
+ that you can do anything you like with the code, including
+ relicensing arbitrarily for your projects.
+
+2005-07-11 Heikki Orsila <heikki.orsila@iki.fi>
+ - Improved the command line frontend in src/frontends/trivial/,
+ and now it is called uade123. It can now do fileformat detection by
+ content, and load proper players from their installation place.
+ Also, it can play multiple songs in a sequence if one switches to
+ next song with ctrl-c before the song actually ends. If the song
+ ends by itself, the system will crash ;)
+ - Found a bug in amifilemagic by accident. chk_id_offset() function
+ tested patterns of length sizeof(patterns[i]) which is totally
+ wrong. It was corrected to strlen(patterns[i]).
+
+2005-07-09 Heikki Orsila <heikki.orsila@iki.fi>
+ - Started hacking uade. The goal is to release uade 2.00 someday
+ http://board.kohina.com/viewtopic.php?p=3499#3499
+ - These changes start a series. Version 1.50 will be the first public
+ release in this series.
+ - src/frontends/trivial/ can now play single file songs.
+ - Debugging is broken because libao can't handle signals well.
+ - Tons of things missing from the system.
diff --git a/plugins/uade2/uade-2.13/README b/plugins/uade2/uade-2.13/README
new file mode 100644
index 00000000..9ada771a
--- /dev/null
+++ b/plugins/uade2/uade-2.13/README
@@ -0,0 +1,53 @@
+UADE - Unix Amiga Delitracker Emulator
+======================================
+
+UADE is a music player for UNIX platforms that plays music formats used on
+the Amiga computer.
+
+Very short instructions for installing UADE
+===========================================
+
+1. Read INSTALL.readme
+2. Install the program globally or directly to your home directory. Do either
+ ./configure
+ or
+ ./configure --user (makes uade to be installed under ~/.uade2)
+3. make
+4. make install (as root if installed globally, but as the user if configure
+ was given --user)
+
+The program is ready now.
+
+Now you can edit uade.conf, if you want. uade.conf is located at
+$PREFIX/share/uade2/uade.conf or ~/.uade2/uade.conf. If you installed
+globally, you can make a copy of uade.conf to ~/.uade2/.
+
+Fire up xmms, audacious or use the command line tool.
+
+$ uade123 -zr /my/chips
+
+Credits
+=======
+
+See AUTHORS file for credits.
+
+Information sources
+===================
+
+Web site:
+
+ http://zakalwe.fi/uade
+
+Public web forum (most issues should go here):
+
+ http://board.kohina.net/index.php?c=5
+
+Public IRC channel:
+
+ #amigaexotic at IRCNet
+
+Subscribe to new releases at: http://freshmeat.net/projects/uade
+
+Project maintainer:
+ Heikki Orsila
+ heikki.orsila@iki.fi
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/amifilemagic.c b/plugins/uade2/uade-2.13/src/frontends/common/amifilemagic.c
new file mode 100644
index 00000000..9365436c
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/amifilemagic.c
@@ -0,0 +1,1168 @@
+/*
+ Copyright (C) 2000-2005 Heikki Orsila
+ Copyright (C) 2000-2005 Michael Doering
+
+ This module is dual licensed under the GNU GPL and the Public Domain.
+ Hence you may use _this_ module (not another code module) in any way you
+ want in your projects.
+
+ About security:
+
+ This module tries to avoid any buffer overruns by not copying anything but
+ hard coded strings (such as "FC13"). This doesn't
+ copy any data from modules to program memory. Any memory writing with
+ non-hard-coded data is an error by assumption. This module will only
+ determine the format of a given module.
+
+ Occasional memory reads over buffer ranges can occur, but they will of course
+ be fixed when spotted :P The worst that can happen with reading over the
+ buffer range is a core dump :)
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <uadeutils.h>
+#include <amifilemagic.h>
+
+#define FILEMAGIC_DEBUG 0
+
+#if FILEMAGIC_DEBUG
+#define amifiledebug(fmt, args...) do { fprintf(stderr, "%s:%d: %s: " fmt, __FILE__, __LINE__, __func__, ## args); } while(0)
+#else
+#define amifiledebug(fmt, args...)
+#endif
+
+#define WAV_HEADER_LEN 44
+
+enum {
+ MOD_UNDEFINED = 0,
+ MOD_SOUNDTRACKER25_NOISETRACKER10,
+ MOD_NOISETRACKER12,
+ MOD_NOISETRACKER20,
+ MOD_STARTREKKER4,
+ MOD_STARTREKKER8,
+ MOD_AUDIOSCULPTURE4,
+ MOD_AUDIOSCULPTURE8,
+ MOD_PROTRACKER,
+ MOD_FASTTRACKER,
+ MOD_NOISETRACKER,
+ MOD_PTK_COMPATIBLE,
+ MOD_SOUNDTRACKER24
+};
+
+
+#define S15_HEADER_LENGTH 600
+#define S31_HEADER_LENGTH 1084
+
+
+static int chk_id_offset(unsigned char *buf, int bufsize,
+ const char *patterns[], int offset, char *pre);
+
+
+/* Do not use '\0'. They won't work in patterns */
+static const char *offset_0000_patterns[] = {
+ /* ID: Prefix: Desc: */
+ "DIGI Booster", "DIGI", /* Digibooster */
+ "OKTASONG", "OKT", /* Oktalyzer */
+ "SYNTRACKER", "SYNMOD", /* Syntracker */
+ "OBISYNTHPACK", "OSP", /* Synthpack */
+ "SOARV1.0", "SA", /* Sonic Arranger */
+ "AON4", "AON4", /* Art Of Noise (4ch) */
+ "AON8", "AON8", /* Art Of Noise (8ch) */
+ "ARP.", "MTP2", /* HolyNoise / Major Tom */
+ "AmBk", "ABK", /* Amos ABK */
+ "FUCO", "BSI", /* FutureComposer BSI */
+ "MMU2", "DSS", /* DSS */
+ "GLUE", "GLUE", /* GlueMon */
+ "ISM!", "IS", /* In Stereo */
+ "IS20", "IS20", /* In Stereo 2 */
+ "SMOD", "FC13", /* FC 1.3 */
+ "FC14", "FC14", /* FC 1.4 */
+ "MMDC", "MMDC", /* Med packer */
+ "MSOB", "MSO", /* Medley */
+ "MODU", "NTP", /* Novotrade */
+/* HIPPEL-ST CONFLICT: "COSO", "SOC",*/ /* Hippel Coso */
+ "BeEp", "JAM", /* Jamcracker */
+ "ALL ", "DM1", /* Deltamusic 1 */
+ "YMST", "YM", /* MYST ST-YM */
+ "AMC ", "AMC", /* AM-Composer */
+ "P40A", "P40A", /* The Player 4.0a */
+ "P40B", "P40B", /* The Player 4.0b */
+ "P41A", "P41A", /* The Player 4.1a */
+ "P50A", "P50A", /* The Player 5.0a */
+ "P60A", "P60A", /* The Player 6.0a */
+ "P61A", "P61A", /* The Player 6.1a */
+ "SNT!", "PRU2", /* Prorunner 2 */
+ "MEXX_TP2", "TP2", /* Tracker Packer 2 */
+ "CPLX_TP3", "TP3", /* Tracker Packer 3 */
+ "MEXX", "TP1", /* Tracker Packer 2 */
+ "PM40", "PM40", /* Promizer 4.0 */
+ "FC-M", "FC-M", /* FC-M */
+ "E.M.S. V6.", "EMSV6", /* EMS version 6 */
+ "MCMD", "MCMD_org", /* 0x00 MCMD format */
+ "STP3", "STP3", /* Soundtracker Pro 2 */
+ "MTM", "MTM", /* Multitracker */
+ "Extended Module:", "XM", /* Fasttracker2 */
+ "MLEDMODL", "ML", /* Musicline Editor */
+ "FTM", "FTM", /* Face The Music */
+ "MXTX", "MXTX", /* Maxtrax*/
+ "M1.0", "FUZZ", /* Fuzzac*/
+ "MSNG", "TPU", /* Dirk Bialluch*/
+ "YM!", "", /* stplay -- intentionally sabotaged */
+ "ST1.2 ModuleINFO", "", /* Startrekker AM .NT -- intentionally sabotaged */
+ "AudioSculpture10", "", /* Audiosculpture .AS -- intentionally sabotaged */
+ NULL, NULL
+};
+
+static const char *offset_0024_patterns[] = {
+ /* ID: Prefix: Desc: */
+ "UNCLEART", "DL", /* Dave Lowe WT */
+ "DAVELOWE", "DL_deli", /* Dave Lowe Deli */
+ "J.FLOGEL", "JMF", /* Janko Mrsic-Flogel */
+ "BEATHOVEN", "BSS", /* BSS */
+ "FREDGRAY", "GRAY", /* Fred Gray */
+ "H.DAVIES", "HD", /* Howie Davies */
+ "RIFFRAFF", "RIFF", /* Riff Raff */
+ "!SOPROL!", "SPL", /* Soprol */
+ "F.PLAYER", "FP", /* F.Player */
+ "S.PHIPPS", "CORE", /* Core Design */
+ "DAGLISH!", "BDS", /* Benn Daglish */
+ NULL, NULL
+};
+
+
+/* check for 'pattern' in 'buf'.
+ the 'pattern' must lie inside range [0, maxlen) in the buffer.
+ returns true if pattern is at buf[offset], otherwrise false
+ */
+static int patterntest(const unsigned char *buf, const char *pattern,
+ int offset, int bytes, int maxlen)
+{
+ if ((offset + bytes) <= maxlen)
+ return (memcmp(buf + offset, pattern, bytes) == 0) ? 1 : 0;
+ return 0;
+}
+
+
+static int tronictest(unsigned char *buf, size_t bufsize)
+{
+ size_t a = read_be_u16(&buf[0x02]) + read_be_u16(&buf[0x06]) +
+ read_be_u16(&buf[0x0a]) + read_be_u16(&buf[0x0e]) + 0x10;
+
+ if (((a + 2) >= bufsize) || (a & 1))
+ return 0; /* size & btst #0, d1; */
+
+ a = read_be_u16(&buf[a]) + a;
+ if (((a + 8) >= bufsize) || (a & 1))
+ return 0; /*size & btst #0,d1 */
+
+ if (read_be_u32(&buf[a + 4]) != 0x5800b0)
+ return 0;
+
+ amifiledebug("tronic recognized\n");
+
+ return 1;
+}
+
+static int tfmxtest(unsigned char *buf, size_t bufsize, char *pre)
+{
+ if (bufsize <= 0x208)
+ return 0;
+
+ if (strncmp((char *) buf, "TFHD", 4) == 0) {
+ if (buf[0x8] == 0x01) {
+ strcpy(pre, "TFHD1.5"); /* One File TFMX format by Alexis NASR */
+ return 1;
+ } else if (buf[0x8] == 0x02) {
+ strcpy(pre, "TFHDPro");
+ return 1;
+ } else if (buf[0x8] == 0x03) {
+ strcpy(pre, "TFHD7V");
+ return 1;
+ }
+ }
+
+ if (strncasecmp((char *) buf, "TFMX", 4) == 0) {
+ if (strncmp((char *) &buf[4], "-SONG", 5) == 0 ||
+ strncmp((char *) &buf[4], "_SONG ", 6) == 0 ||
+ strncasecmp((char *) &buf[4], "SONG", 4) == 0 ||
+ buf[4] == 0x20) {
+ strcpy(pre, "MDAT"); /*default TFMX: TFMX Pro */
+
+ if (strncmp((char *) &buf[10], "by", 2) == 0 ||
+ strncmp((char *) &buf[16], " ", 2) == 0 ||
+ strncmp((char *) &buf[16], "(Empty)", 7) == 0 ||
+ /* Lethal Zone */
+ (buf[16] == 0x30 && buf[17] == 0x3d) ||
+ (buf[4] == 0x20)){
+
+ if (read_be_u32(&buf[464]) == 0x00000000) {
+ uint16_t x = read_be_u16(&buf[14]);
+ if ((x != 0x0e60) || /* z-out title */
+ (x == 0x0860 && bufsize > 4645 && read_be_u16(&buf[4644]) != 0x090c) || /* metal law */
+ (x == 0x0b20 && bufsize > 5121 && read_be_u16(&buf[5120]) != 0x8c26) || /* bug bomber */
+ (x == 0x0920 && bufsize > 3977 && read_be_u16(&buf[3876]) != 0x9305)) { /* metal preview */
+ strcpy(pre, "TFMX1.5"); /*TFMX 1.0 - 1.6 */
+ }
+ }
+ return 1;
+
+ } else if (((buf[0x0e] == 0x08 && buf[0x0f] == 0xb0) && /* BMWi */
+ (buf[0x140] == 0x00 && buf[0x141] == 0x0b) && /*End tackstep 1st subsong */
+ (buf[0x1d2] == 0x02 && buf[0x1d3] == 0x00) && /*Trackstep datas */
+ (buf[0x200] == 0xff && buf[0x201] == 0x00 && /*First effect */
+ buf[0x202] == 0x00 && buf[0x203] == 0x00 &&
+ buf[0x204] == 0x01 && buf[0x205] == 0xf4 &&
+ buf[0x206] == 0xff && buf[0x207] == 0x00)) ||
+ ((buf[0x0e] == 0x0A && buf[0x0f] == 0xb0) && /* B.C Kid */
+ (buf[0x140] == 0x00 && buf[0x141] == 0x15) && /*End tackstep 1st subsong */
+ (buf[0x1d2] == 0x02 && buf[0x1d3] == 0x00) && /*Trackstep datas */
+ (buf[0x200] == 0xef && buf[0x201] == 0xfe && /*First effect */
+ buf[0x202] == 0x00 && buf[0x203] == 0x03 &&
+ buf[0x204] == 0x00 && buf[0x205] == 0x0d &&
+ buf[0x206] == 0x00 && buf[0x207] == 0x00))) {
+ strcpy(pre, "TFMX7V"); /* "special cases TFMX 7V */
+ return 1;
+
+ } else {
+ int e, i, s, t;
+
+ /* Trackstep datas offset */
+ s = read_be_u32(&buf[0x1d0]);
+ if (s == 0x00000000) {
+ /* unpacked */
+ s = 0x00000800;
+ }
+
+ for (i = 0; i < 0x3d; i += 2) {
+ if (read_be_u16(&buf[0x140 + i]) != 0x0000) { /* subsong */
+ /* Start of subsongs Trackstep data :) */
+ t = read_be_u16(&buf[0x100 + i]) * 16 + s;
+ /* End of subsongs Trackstep data :) */
+ e = read_be_u16(&buf[0x140 + i]) * 16 + s;
+ if (e < bufsize) {
+ for (; t < e && (t + 6) < bufsize; t += 2) {
+ if (read_be_u16(&buf[t]) == 0xeffe &&
+ read_be_u32(&buf[t + 2]) == 0x0003ff00 &&
+ buf[t + 6] == 0x00) {
+ strcpy(pre, "TFMX7V"); /*TFMX 7V */
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/* Calculate Module length: Just need at max 1084 */
+/* data in buf for a */
+/* succesful calculation */
+/* returns: */
+/* -1 for no mod */
+/* 1 for a mod with good length */
+static size_t modlentest(unsigned char *buf, size_t bufsize, size_t filesize,
+ int header)
+{
+ int i;
+ int no_of_instr;
+ int smpl = 0;
+ int plist;
+ int maxpattern = 0;
+
+ if (header > bufsize)
+ return -1; /* no mod */
+
+ if (header == S15_HEADER_LENGTH) {
+ no_of_instr = 15;
+ plist = header - 128;
+ } else if (header == S31_HEADER_LENGTH) {
+ no_of_instr = 31;
+ plist = header - 4 - 128;
+ } else {
+ return -1;
+ }
+
+ for (i = 0; i < 128; i++) {
+ if (buf[plist + i] > maxpattern)
+ maxpattern = buf[plist + i];
+ }
+
+ if (maxpattern > 100)
+ return -1;
+
+ for (i = 0; i < no_of_instr; i++)
+ smpl += 2 * read_be_u16(&buf[42 + i * 30]); /* add sample length in bytes*/
+
+ return header + (maxpattern + 1) * 1024 + smpl;
+}
+
+
+static void modparsing(unsigned char *buf, size_t bufsize, size_t header, int max_pattern, int pfx[], int pfxarg[])
+{
+ int offset;
+ int i, j, fx;
+ unsigned char fxarg;
+
+ for (i = 0; i < max_pattern; i++) {
+ for (j = 0; j < 256; j++) {
+ offset = header + i * 1024 + j * 4;
+
+ if ((offset + 4) > bufsize)
+ return;
+
+ fx = buf[offset + 2] & 0x0f;
+ fxarg = buf[offset + 3];
+
+ if (fx == 0) {
+ if (fxarg != 0 )
+ pfx[fx] += 1;
+ pfxarg[fx] = (pfxarg[fx] > fxarg) ? pfxarg[fx] : fxarg;
+
+ } else if (1 <= fx && fx <= 13) {
+ pfx[fx] +=1;
+ pfxarg[fx] = (pfxarg[fx] > fxarg) ? pfxarg[fx] : fxarg;
+
+ } else if (fx == 14) {
+ pfx[((fxarg >> 4) & 0x0f) + 16] +=1;
+
+ } else if (fx == 15) {
+ if (fxarg > 0x1f)
+ pfx[14] +=1;
+ else
+ pfx[15] +=1;
+ pfxarg[15] = (pfxarg[15] > fxarg) ? pfxarg[15] : fxarg;
+ }
+ }
+ }
+
+}
+
+
+static int mod32check(unsigned char *buf, size_t bufsize, size_t realfilesize,
+ const char *path, int verbose)
+{
+ /* mod patterns at file offset 0x438 */
+ char *mod_patterns[] = { "M.K.", ".M.K", NULL};
+ /* startrekker patterns at file offset 0x438 */
+ char *startrekker_patterns[] = { "FLT4", "FLT8", "EXO4", "EXO8", NULL};
+
+ int max_pattern = 0;
+ int i, j, t, ret;
+ int pfx[32];
+ int pfxarg[32];
+
+ /* instrument var */
+ int vol, slen, srep, sreplen;
+
+ int has_slen_sreplen_zero = 0; /* sreplen empty of non looping instrument */
+ int no_slen_sreplen_zero = 0; /* sreplen */
+
+ int has_slen_sreplen_one = 0;
+ int no_slen_sreplen_one = 0;
+
+ int no_slen_has_volume = 0;
+ int finetune_used = 0;
+
+ size_t calculated_size;
+
+ /* returns: 0 for undefined */
+ /* 1 for a Soundtracker2.5/Noisetracker 1.0 */
+ /* 2 for a Noisetracker 1.2 */
+ /* 3 for a Noisetracker 2.0 */
+ /* 4 for a Startrekker 4ch */
+ /* 5 for a Startrekker 8ch */
+ /* 6 for Audiosculpture 4 ch/fm */
+ /* 7 for Audiosculpture 8 ch/fm */
+ /* 8 for a Protracker */
+ /* 9 for a Fasttracker */
+ /* 10 for a Noisetracker (M&K!) */
+ /* 11 for a PTK Compatible */
+ /* 12 for a Soundtracker 31instr. with repl in bytes */
+
+ /* Special cases first */
+ if (patterntest(buf, "M&K!", (S31_HEADER_LENGTH - 4), 4, bufsize))
+ return MOD_NOISETRACKER; /* Noisetracker (M&K!) */
+
+ if (patterntest(buf, "M!K!", (S31_HEADER_LENGTH - 4), 4, bufsize))
+ return MOD_PROTRACKER; /* Protracker (100 patterns) */
+
+ if (patterntest(buf, "N.T.", (S31_HEADER_LENGTH - 4), 4, bufsize))
+ return MOD_NOISETRACKER20; /* Noisetracker2.x */
+
+ for (i = 0; startrekker_patterns[i]; i++) {
+ if (patterntest(buf, startrekker_patterns[i], (S31_HEADER_LENGTH - 4), 4, bufsize)) {
+ t = 0;
+ for (j = 0; j < 30 * 0x1e; j = j + 0x1e) {
+ if (buf[0x2a + j] == 0 && buf[0x2b + j] == 0 && buf[0x2d + j] != 0) {
+ t = t + 1; /* no of AM instr. */
+ }
+ }
+ if (t > 0) {
+ if (buf[0x43b] == '4'){
+ ret = MOD_AUDIOSCULPTURE4; /* Startrekker 4 AM / ADSC */
+ } else {
+ ret = MOD_AUDIOSCULPTURE8; /* Startrekker 8 AM / ADSC */
+ }
+ } else {
+ if (buf[0x43b] == '4'){
+ ret = MOD_STARTREKKER4; /* Startrekker 4ch */
+ } else {
+ ret = MOD_STARTREKKER8; /* Startrekker 8ch */
+ }
+ }
+ return ret;
+ }
+ }
+
+ calculated_size = modlentest(buf, bufsize, realfilesize, S31_HEADER_LENGTH);
+
+ if (calculated_size == -1)
+ return MOD_UNDEFINED;
+
+
+ for (i = 0; mod_patterns[i]; i++) {
+ if (patterntest(buf, mod_patterns[i], S31_HEADER_LENGTH - 4, 4, bufsize)) {
+ /* seems to be a generic M.K. MOD */
+ /* only spam filesize message when it's a tracker module */
+
+ if (calculated_size != realfilesize) {
+ fprintf(stderr, "uade: file size is %zd but calculated size for a mod file is %zd (%s).\n", realfilesize, calculated_size, path);
+ }
+
+ if (calculated_size > realfilesize) {
+ fprintf(stderr, "uade: file is truncated and won't get played (%s)\n", path);
+ return MOD_UNDEFINED;
+ }
+
+ if (calculated_size < realfilesize) {
+ fprintf(stderr, "uade: file has trailing garbage behind the actual module data. Please fix it. (%s)\n", path);
+ }
+
+ /* parse instruments */
+ for (i = 0; i < 31; i++) {
+ vol = buf[45 + i * 30];
+ slen = ((buf[42 + i * 30] << 8) + buf[43 + i * 30]) * 2;
+ srep = ((buf[46 + i * 30] << 8) + buf[47 + i * 30]) *2;
+ sreplen = ((buf[48 + i * 30] << 8) + buf[49 + i * 30]) * 2;
+ /* fprintf (stderr, "%d, slen: %d, %d (srep %d, sreplen %d), vol: %d\n",i, slen, srep+sreplen,srep, sreplen, vol); */
+
+ if (vol > 64)
+ return MOD_UNDEFINED;
+
+ if (buf[44 + i * 30] != 0) {
+ if (buf[44+i*30] > 15) {
+ return MOD_UNDEFINED;
+ } else {
+ finetune_used++;
+ }
+ }
+
+ if (slen > 0 && (srep + sreplen) > slen) {
+ /* Old Noisetracker /Soundtracker with repeat offset in bytes */
+ return MOD_SOUNDTRACKER24;
+ }
+
+ if (srep == 0) {
+ if (slen > 0) {
+ if (sreplen == 2){
+ has_slen_sreplen_one++;
+ }
+ if (sreplen == 0){
+ has_slen_sreplen_zero++;
+ }
+ } else {
+ if (sreplen > 0){
+ no_slen_sreplen_one++;
+ } else {
+ no_slen_sreplen_zero++;
+ }
+ if (vol > 0)
+ no_slen_has_volume++;
+ }
+ }
+ }
+
+ for (i = 0; i < 128; i++) {
+ if (buf[1080 - 130 + 2 + i] > max_pattern)
+ max_pattern = buf[1080 - 130 + 2 + i];
+ }
+
+ if (max_pattern > 100) {
+ /* pattern number can only be 0 <-> 100 for mod*/
+ return MOD_UNDEFINED;
+ }
+
+ memset (pfx, 0, sizeof (pfx));
+ memset (pfxarg, 0, sizeof (pfxarg));
+ modparsing(buf, bufsize, S31_HEADER_LENGTH-4, max_pattern, pfx, pfxarg);
+
+ /* and now for let's see if we can spot the mod */
+
+ /* FX used: */
+ /* DOC Soundtracker 2.x(2.5): 0,1,2(3,4) a,b,c,d,e,f */
+ /* Noisetracker 1.x: 0,1,2,3,4 a,b,c,d,e,f */
+ /* Noisetracker 2.x: 0,1,2,3,4 a,b,c,d,e,f */
+ /* Protracker: 0,1,2,3,4,5,6,7 9,a,b,c,d,e,f +e## */
+ /* PC tracker: 0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f +e## */
+
+ for (j = 17; j <= 31; j++) {
+ if (pfx[j] != 0 || finetune_used >0) /* Extended fx used */ {
+ if (buf[0x3b7] != 0x7f && buf[0x3b7] != 0x78) {
+ return MOD_FASTTRACKER; /* Definetely Fasttracker*/
+ } else {
+ return MOD_PROTRACKER; /* Protracker*/
+ }
+ }
+ }
+
+ if ((buf[0x3b7] == 0x7f) &&
+ (has_slen_sreplen_zero <= has_slen_sreplen_one) &&
+ (no_slen_sreplen_zero <=no_slen_sreplen_one))
+ return MOD_PROTRACKER; /* Protracker */
+
+ if (buf[0x3b7] >0x7f)
+ return MOD_PTK_COMPATIBLE; /* Protracker compatible */
+
+ if ((buf[0x3b7] == 0) &&
+ (has_slen_sreplen_zero > has_slen_sreplen_one) &&
+ (no_slen_sreplen_zero > no_slen_sreplen_one)){
+ if (pfx[0x10] == 0) {
+ /* probl. Fastracker or Protracker compatible */
+ return MOD_PTK_COMPATIBLE;
+ }
+ /* FIXME: Investigate
+ else {
+ return MOD_PROTRACKER; // probl. Protracker
+ } */
+ }
+
+ if (pfx[0x05] != 0 || pfx[0x06] != 0 || pfx[0x07] != 0 ||
+ pfx[0x09] != 0) {
+ /* Protracker compatible */
+ return MOD_PTK_COMPATIBLE;
+ }
+
+ if ((buf[0x3b7] >0 && buf[0x3b7] <= buf[0x3b6]) &&
+ (has_slen_sreplen_zero <= has_slen_sreplen_one) &&
+ (no_slen_sreplen_zero == 1) &&
+ (no_slen_sreplen_zero <= no_slen_sreplen_one))
+ return MOD_NOISETRACKER12; // Noisetracker 1.2
+
+ if ((buf[0x3b7] <0x80) &&
+ (has_slen_sreplen_zero <= has_slen_sreplen_one) &&
+ (no_slen_sreplen_zero <=no_slen_sreplen_one))
+ return MOD_NOISETRACKER20; // Noisetracker 2.x
+
+ if ((buf[0x3b7] <0x80) &&
+ (pfx[0x0e] ==0) &&
+ (has_slen_sreplen_zero <= has_slen_sreplen_one) &&
+ (no_slen_sreplen_zero >=no_slen_sreplen_one))
+ return MOD_SOUNDTRACKER25_NOISETRACKER10; // Noisetracker 1.x
+
+ return MOD_PTK_COMPATIBLE; // Protracker compatible
+ }
+ }
+
+ return MOD_UNDEFINED;
+}
+
+
+static int mod15check(unsigned char *buf, size_t bufsize, size_t realfilesize,
+ const char *path)
+/* pattern parsing based on Sylvain 'Asle' Chipaux' */
+/* Modinfo-V2 */
+/* */
+/* returns: 0 for an undefined mod */
+/* 1 for a DOC Soundtracker mod */
+/* 2 for a Ultimate ST mod */
+/* 3 for a Mastersoundtracker */
+/* 4 for a SoundtrackerV2.0 -V4.0 */
+{
+ int i = 0, j = 0;
+ int slen = 0;
+ int srep = 0;
+ int sreplen = 0;
+ int vol = 0;
+
+ int noof_slen_zero_sreplen_zero = 0;
+ int noof_slen_zero_vol_zero = 0;
+ int srep_bigger_slen = 0;
+ int srep_bigger_ffff = 0;
+ int st_xy = 0;
+
+ int max_pattern = 1;
+ int pfx[32];
+ int pfxarg[32];
+
+ size_t calculated_size;
+
+ /* sanity checks */
+ if (bufsize < 0x1f3)
+ return 0; /* file too small */
+
+ if (bufsize < 2648+4 || realfilesize <2648+4) /* size 1 pattern + 1x 4 bytes Instrument :) */
+ return 0;
+
+ calculated_size = modlentest(buf, bufsize, realfilesize, S15_HEADER_LENGTH);
+ if (calculated_size == -1)
+ return 0; /* modlentest failed */
+
+ if (calculated_size != realfilesize) {
+ return 0 ;
+ }
+
+ if (calculated_size > realfilesize) {
+ fprintf(stderr, "uade: file is truncated and won't get played (%s)\n", path);
+ return 0 ;
+ }
+
+
+
+ /* check for 15 instruments */
+ if (buf[0x1d6] != 0x00 && buf[0x1d6] < 0x81 && buf[0x1f3] !=1) {
+ for (i = 0; i < 128; i++) { /* pattern list table: 128 posbl. entries */
+ max_pattern=(buf[600 - 130 + 2 + i] > max_pattern) ? buf[600 - 130 + 2 + i] : max_pattern;
+ }
+ if (max_pattern > 63)
+ return 0; /* pattern number can only be 0 <-> 63 for mod15 */
+ } else {
+ return 0;
+ }
+
+ /* parse instruments */
+ for (i = 0; i < 15; i++) {
+ vol = buf[45 + i * 30];
+ slen = ((buf[42 + i * 30] << 8) + buf[43 + i * 30]) * 2;
+ srep = ((buf[46 + i * 30] << 8) + buf[47 + i * 30]);
+ sreplen = ((buf[48 + i * 30] << 8) + buf[49 + i * 30]) * 2;
+ /* fprintf (stderr, "%d, slen: %d, %d (srep %d, sreplen %d), vol: %d\n",i, slen, srep+sreplen,srep, sreplen, vol); */
+
+ if (vol > 64 && buf[44+i*30] != 0) return 0; /* vol and finetune */
+
+ if (slen == 0) {
+
+ if (vol == 0)
+ noof_slen_zero_vol_zero++;
+
+ if (sreplen == 0 )
+ noof_slen_zero_sreplen_zero++;
+
+ } else {
+ if ((srep+sreplen) > slen)
+ srep_bigger_slen++;
+ }
+
+ /* slen < 9999 */
+ slen = (buf[42 + i * 30] << 8) + buf[43 + i * 30];
+ if (slen <= 9999) {
+ /* repeat offset + repeat size*2 < word size */
+ srep = ((buf[48 + i * 30] << 8) + buf[49 + i * 30]) * 2 +
+ ((buf[46 + i * 30] << 8) + buf[47 + i * 30]);
+ if (srep > 0xffff) srep_bigger_ffff++;
+ }
+
+ if (buf[25+i*30] ==':' && buf [22+i*30] == '-' &&
+ ((buf[20+i*30] =='S' && buf [21+i*30] == 'T') ||
+ (buf[20+i*30] =='s' && buf [21+i*30] == 't'))) st_xy++;
+ }
+
+ /* parse pattern data -> fill pfx[] with number of times fx being used*/
+ memset (pfx, 0, sizeof (pfx));
+ memset (pfxarg, 0, sizeof (pfxarg));
+
+ modparsing(buf, bufsize, S15_HEADER_LENGTH, max_pattern, pfx, pfxarg);
+
+ /* and now for let's see if we can spot the mod */
+
+/* FX used: */
+/* Ultimate ST: 0,1,2 */
+/* MasterSoundtracker: 0,1,2, c, e,f */
+/* DOC-Soundtracker V2.2: 0,1,2,a,b,c,d,e,f */
+/* Soundtracker I-VI 0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f*/
+
+
+ /* Check for fx used between 0x3 <-> 0xb for some weird ST II-IV mods */
+ for (j = 0x5; j < 0xa; j++) {
+ if (pfx[j] != 0)
+ return 4; /* ST II-IV */
+ }
+
+ for (j = 0x0c; j < 0x11; j++) {
+ if (pfx[j] != 0) {
+
+ if (pfx[0x0d] != 0 && pfxarg[0x0d] != 0)
+ return 4; /* ST II-IV */
+
+ if (pfx[0x0b] != 0 || pfx[0x0d] != 0 || pfx[0x0a]!= 0 ) {
+ return 1; /* DOC ST */
+ } else {
+ if (pfxarg[1] > 0xe || pfxarg[2] > 0xe)
+ return 1; /* DOC ST */
+
+ return 3; /* Master ST */
+ }
+ }
+ }
+
+ /* pitchbend out of range ? */
+ if ((pfxarg[1] > 0 && pfxarg[1] <0x1f) ||
+ (pfxarg[2] > 0 && pfxarg [2] <0x1f) ||
+ pfx [0] >2) return 1; // ST style Arpeggio, Pitchbends ???
+
+ if (pfx[1] > 0 || pfx[2] > 0)
+ return 2; /* nope UST like fx */
+
+ /* the rest of the files has no fx. so check instruments */
+ if (st_xy!=0 && noof_slen_zero_vol_zero == 0 &&
+ noof_slen_zero_sreplen_zero == 0 && buf[0x1d7] == 120) {
+ return 3;
+ }
+
+ /* no fx, no loops... let's simply guess :)*/
+ if (srep_bigger_slen == 0 && srep_bigger_ffff == 0 &&
+ ((st_xy != 0 && buf[0x1d7] != 120 ) || st_xy==0))
+ return 2;
+
+ return 3; /* anything is played as normal soundtracker */
+}
+
+/* Reject WAV files so that uadefs doesn't cause bad behaviour */
+static int is_wav_file(unsigned char *buf, size_t size)
+{
+ if (size < WAV_HEADER_LEN)
+ return 0;
+
+ if (memcmp(buf, "RIFF", 4))
+ return 0;
+
+ if (memcmp(buf + 8, "WAVEfmt ", 8))
+ return 0;
+
+ if (memcmp(buf + 36, "data", 4))
+ return 0;
+
+ return 1;
+}
+
+void uade_filemagic(unsigned char *buf, size_t bufsize, char *pre,
+ size_t realfilesize, const char *path, int verbose)
+{
+ /* char filemagic():
+ detects formats like e.g.: tfmx1.5, hip, hipc, fc13, fc1.4
+ - tfmx 1.5 checking based on both tfmx DT and tfmxplay by jhp,
+ and the EP by Don Adan/WT.
+ - tfmx 7v checking based on info by don adan, the amore file
+ ripping description and jhp's desc of the tfmx format.
+ - other checks based on e.g. various player sources from Exotica
+ or by checking bytes with a hexeditor
+ by far not complete...
+
+ NOTE: Those Magic ID checks are quite lame compared to the checks the
+ amiga replayer do... well, after all we are not ripping. so they
+ have to do at the moment :)
+ */
+
+ int i, modtype, t;
+
+ struct modtype {
+ int e;
+ char *str;
+ };
+
+ struct modtype mod32types[] = {
+ {.e = MOD_SOUNDTRACKER25_NOISETRACKER10, .str = "MOD_NTK"},
+ {.e = MOD_NOISETRACKER12, .str = "MOD_NTK1"},
+ {.e = MOD_NOISETRACKER20, .str = "MOD_NTK2"},
+ {.e = MOD_STARTREKKER4, .str = "MOD_FLT4"},
+ {.e = MOD_STARTREKKER8, .str = "MOD_FLT8"},
+ {.e = MOD_AUDIOSCULPTURE4, .str = "MOD_ADSC4"},
+ {.e = MOD_AUDIOSCULPTURE8, .str = "MOD_ADSC8"},
+ {.e = MOD_PROTRACKER, .str = "MOD"},
+ {.e = MOD_FASTTRACKER, .str = "MOD_COMP"},
+ {.e = MOD_NOISETRACKER, .str = "MOD_NTKAMP"},
+ {.e = MOD_PTK_COMPATIBLE, .str = "MOD_COMP"},
+ {.e = MOD_SOUNDTRACKER24, .str = "MOD_DOC"},
+ {.str = NULL}
+ };
+
+ struct modtype mod15types[] = {
+ {.e = 1, .str = "MOD15"},
+ {.e = 2, .str = "MOD15_UST"},
+ {.e = 3, .str = "MOD15_MST"},
+ {.e = 4, .str = "MOD15_ST-IV"},
+ {.str = NULL}
+ };
+
+ /* Mark format unknown by default */
+ pre[0] = 0;
+
+ if (is_wav_file(buf, bufsize)) {
+ strcpy(pre, "reject");
+ return;
+ }
+
+ modtype = mod32check(buf, bufsize, realfilesize, path, verbose);
+ if (modtype != MOD_UNDEFINED) {
+ for (t = 0; mod32types[t].str != NULL; t++) {
+ if (modtype == mod32types[t].e) {
+ strcpy(pre, mod32types[t].str);
+ return;
+ }
+ }
+ }
+
+ /* 0x438 == S31_HEADER_LENGTH - 4 */
+ if (((buf[0x438] >= '1' && buf[0x438] <= '3')
+ && (buf[0x439] >= '0' && buf[0x439] <= '9') && buf[0x43a] == 'C'
+ && buf[0x43b] == 'H') || ((buf[0x438] >= '2' && buf[0x438] <= '8')
+ && buf[0x439] == 'C' && buf[0x43a] == 'H'
+ && buf[0x43b] == 'N')
+ || (buf[0x438] == 'T' && buf[0x439] == 'D' && buf[0x43a] == 'Z')
+ || (buf[0x438] == 'O' && buf[0x439] == 'C' && buf[0x43a] == 'T'
+ && buf[0x43b] == 'A') || (buf[0x438] == 'C' && buf[0x439] == 'D'
+ && buf[0x43a] == '8'
+ && buf[0x43b] == '1')) {
+ strcpy(pre, "MOD_PC"); /*Multichannel Tracker */
+
+ } else if (buf[0x2c] == 'S' && buf[0x2d] == 'C' && buf[0x2e] == 'R'
+ && buf[0x2f] == 'M') {
+ strcpy(pre, "S3M"); /*Scream Tracker */
+
+ } else if ((buf[0] == 0x60 && buf[2] == 0x60 && buf[4] == 0x48
+ && buf[5] == 0xe7) || (buf[0] == 0x60 && buf[2] == 0x60
+ && buf[4] == 0x41 && buf[5] == 0xfa)
+ || (buf[0] == 0x60 && buf[1] == 0x00 && buf[4] == 0x60
+ && buf[5] == 0x00 && buf[8] == 0x48 && buf[9] == 0xe7)
+ || (buf[0] == 0x60 && buf[1] == 0x00 && buf[4] == 0x60
+ && buf[5] == 0x00 && buf[8] == 0x60 && buf[9] == 0x00
+ && buf[12] == 0x60 && buf[13] == 0x00 && buf[16] == 0x48
+ && buf[17] == 0xe7)) {
+ strcpy(pre, "SOG"); /* Hippel */
+
+ } else if (buf[0x348] == '.' && buf[0x349] == 'Z' && buf[0x34A] == 'A'
+ && buf[0x34B] == 'D' && buf[0x34c] == 'S' && buf[0x34d] == '8'
+ && buf[0x34e] == '9' && buf[0x34f] == '.') {
+ strcpy(pre, "MKII"); /* Mark II */
+
+ } else if (read_be_u16(&buf[0x00]) == 0x2b7c &&
+ read_be_u16(&buf[0x08]) == 0x2b7c &&
+ read_be_u16(&buf[0x10]) == 0x2b7c &&
+ read_be_u16(&buf[0x18]) == 0x2b7c &&
+ read_be_u32(&buf[0x20]) == 0x303c00ff &&
+ read_be_u32(&buf[0x24]) == 0x32004eb9 &&
+ read_be_u16(&buf[0x2c]) == 0x4e75) {
+ strcpy(pre, "JPO"); /* Steve Turner*/
+
+ } else if (((buf[0] == 0x08 && buf[1] == 0xf9 && buf[2] == 0x00
+ && buf[3] == 0x01) && (buf[4] == 0x00 && buf[5] == 0xbb
+ && buf[6] == 0x41 && buf[7] == 0xfa)
+ && ((buf[0x25c] == 0x4e && buf[0x25d] == 0x75)
+ || (buf[0x25c] == 0x4e && buf[0x25d] == 0xf9)))
+ || ((buf[0] == 0x41 && buf[1] == 0xfa)
+ && (buf[4] == 0xd1 && buf[5] == 0xe8)
+ && (((buf[0x230] == 0x4e && buf[0x231] == 0x75)
+ || (buf[0x230] == 0x4e && buf[0x231] == 0xf9))
+ || ((buf[0x29c] == 0x4e && buf[0x29d] == 0x75)
+ || (buf[0x29c] == 0x4e && buf[0x29d] == 0xf9))
+ ))) {
+ strcpy(pre, "SID1"); /* SidMon1 */
+
+ } else if (buf[0] == 0x4e && buf[1] == 0xfa &&
+ buf[4] == 0x4e && buf[5] == 0xfa &&
+ buf[8] == 0x4e && buf[9] == 0xfa &&
+ buf[2] == 0x00 && buf[6] == 0x06 && buf[10] == 0x07) {
+ if (buf[3] == 0x2a && buf[7] == 0xfc && buf[11] == 0x7c) {
+ strcpy(pre, "SA_old");
+ } else if (buf[3] == 0x1a && buf[7] == 0xc6 && buf[11] == 0x3a) {
+ strcpy(pre, "SA");
+ }
+
+ } else if (buf[0] == 0x4e && buf[1] == 0xfa &&
+ buf[4] == 0x4e && buf[5] == 0xfa &&
+ buf[8] == 0x4e && buf[9] == 0xfa &&
+ buf[0xc] == 0x4e && buf[0xd] == 0xfa) {
+ for (i = 0x10; i < 256; i = i + 2) {
+ if (buf[i + 0] == 0x4e && buf[i + 1] == 0x75 && buf[i + 2] == 0x47
+ && buf[i + 3] == 0xfa && buf[i + 12] == 0x4e && buf[i + 13] == 0x75) {
+ strcpy(pre, "FRED"); /* FRED */
+ break;
+ }
+ }
+
+ } else if (buf[0] == 0x60 && buf[1] == 0x00 &&
+ buf[4] == 0x60 && buf[5] == 0x00 &&
+ buf[8] == 0x60 && buf[9] == 0x00 &&
+ buf[12] == 0x48 && buf[13] == 0xe7) {
+ strcpy(pre, "MA"); /*Music Assembler */
+
+ } else if (buf[0] == 0x00 && buf[1] == 0x00 &&
+ buf[2] == 0x00 && buf[3] == 0x28 &&
+ (buf[7] >= 0x34 && buf[7] <= 0x64) &&
+ buf[0x20] == 0x21 && (buf[0x21] == 0x54 || buf[0x21] == 0x44)
+ && buf[0x22] == 0xff && buf[0x23] == 0xff) {
+ strcpy(pre, "SA-P"); /*SonicArranger Packed */
+
+
+ } else if (buf[0] == 0x4e && buf[1] == 0xfa &&
+ buf[4] == 0x4e && buf[5] == 0xfa &&
+ buf[8] == 0x4e && buf[9] == 0xfa) {
+ t = ((buf[2] * 256) + buf[3]);
+ if (t < bufsize - 9) {
+ if (buf[2 + t] == 0x4b && buf[3 + t] == 0xfa &&
+ buf[6 + t] == 0x08 && buf[7 + t] == 0xad && buf[8 + t] == 0x00
+ && buf[9 + t] == 0x00) {
+ strcpy(pre, "MON"); /*M.O.N */
+ }
+ }
+
+ } else if (buf[0] == 0x02 && buf[1] == 0x39 &&
+ buf[2] == 0x00 && buf[3] == 0x01 &&
+ buf[8] == 0x66 && buf[9] == 0x02 &&
+ buf[10] == 0x4e && buf[11] == 0x75 &&
+ buf[12] == 0x78 && buf[13] == 0x00 &&
+ buf[14] == 0x18 && buf[15] == 0x39) {
+ strcpy(pre, "MON_old"); /*M.O.N_old */
+
+ } else if (buf[0] == 0x48 && buf[1] == 0xe7 && buf[2] == 0xf1
+ && buf[3] == 0xfe && buf[4] == 0x61 && buf[5] == 0x00) {
+ t = ((buf[6] * 256) + buf[7]);
+ if (t < (bufsize - 17)) {
+ for (i = 0; i < 10; i = i + 2) {
+ if (buf[6 + t + i] == 0x47 && buf[7 + t + i] == 0xfa) {
+ strcpy(pre, "DW"); /*Whittaker Type1... FIXME: incomplete */
+ }
+ }
+ }
+
+ } else if (buf[0] == 0x13 && buf[1] == 0xfc &&
+ buf[2] == 0x00 && buf[3] == 0x40 &&
+ buf[8] == 0x4e && buf[9] == 0x71 &&
+ buf[10] == 0x04 && buf[11] == 0x39 &&
+ buf[12] == 0x00 && buf[13] == 0x01 &&
+ buf[18] == 0x66 && buf[19] == 0xf4 &&
+ buf[20] == 0x4e && buf[21] == 0x75 &&
+ buf[22] == 0x48 && buf[23] == 0xe7 &&
+ buf[24] == 0xff && buf[25] == 0xfe) {
+ strcpy(pre, "EX"); /*Fashion Tracker */
+
+/* Magic ID */
+ } else if (buf[0x3a] == 'S' && buf[0x3b] == 'I' && buf[0x3c] == 'D' &&
+ buf[0x3d] == 'M' && buf[0x3e] == 'O' && buf[0x3f] == 'N' &&
+ buf[0x40] == ' ' && buf[0x41] == 'I' && buf[0x42] == 'I') {
+ strcpy(pre, "SID2"); /* SidMon II */
+
+ } else if (buf[0x28] == 'R' && buf[0x29] == 'O' && buf[0x2a] == 'N' &&
+ buf[0x2b] == '_' && buf[0x2c] == 'K' && buf[0x2d] == 'L' &&
+ buf[0x2e] == 'A' && buf[0x2f] == 'R' && buf[0x30] == 'E' &&
+ buf[0x31] == 'N') {
+ strcpy(pre, "CM"); /* Ron Klaren (CustomMade) */
+
+ } else if (buf[0x3e] == 'A' && buf[0x3f] == 'C' && buf[0x40] == 'T'
+ && buf[0x41] == 'I' && buf[0x42] == 'O' && buf[0x43] == 'N'
+ && buf[0x44] == 'A' && buf[0x45] == 'M') {
+ strcpy(pre, "AST"); /*Actionanamics */
+
+ } else if (buf[26] == 'V' && buf[27] == '.' && buf[28] == '2') {
+ strcpy(pre, "BP"); /* Soundmon V2 */
+
+ } else if (buf[26] == 'V' && buf[27] == '.' && buf[28] == '3') {
+ strcpy(pre, "BP3"); /* Soundmon V2.2 */
+
+ } else if (buf[60] == 'S' && buf[61] == 'O' && buf[62] == 'N'
+ && buf[63] == 'G') {
+ strcpy(pre, "SFX13"); /* Sfx 1.3-1.8 */
+
+ } else if (buf[124] == 'S' && buf[125] == 'O' && buf[126] == '3'
+ && buf[127] == '1') {
+ strcpy(pre, "SFX20"); /* Sfx 2.0 */
+
+ } else if (buf[0x1a] == 'E' && buf[0x1b] == 'X' && buf[0x1c] == 'I'
+ && buf[0x1d] == 'T') {
+ strcpy(pre, "AAM"); /*Audio Arts & Magic */
+ } else if (buf[8] == 'E' && buf[9] == 'M' && buf[10] == 'O'
+ && buf[11] == 'D' && buf[12] == 'E' && buf[13] == 'M'
+ && buf[14] == 'I' && buf[15] == 'C') {
+ strcpy(pre, "EMOD"); /* EMOD */
+
+ /* generic ID Check at offset 0x24 */
+
+ } else if (chk_id_offset(buf, bufsize, offset_0024_patterns, 0x24, pre)) {
+
+ /* HIP7 ID Check at offset 0x04 */
+ } else if (patterntest(buf, " **** Player by Jochen Hippel 1990 **** ",
+ 0x04, 40, bufsize)) {
+ strcpy(pre, "S7G"); /* HIP7 */
+
+ /* Magic ID at Offset 0x00 */
+ } else if (buf[0] == 'M' && buf[1] == 'M' && buf[2] == 'D') {
+ if (buf[0x3] >= '0' && buf[0x3] < '3') {
+ /*move.l mmd_songinfo(a0),a1 */
+ int s = (buf[8] << 24) + (buf[9] << 16) + (buf[0xa] << 8) + buf[0xb];
+ if (((int) buf[s + 767]) & (1 << 6)) { /* btst #6, msng_flags(a1); */
+ strcpy(pre, "OCTAMED");
+ /*OCTAMED*/} else {
+ strcpy(pre, "MED");
+ /*MED*/}
+ } else if (buf[0x3] != 'C') {
+ strcpy(pre, "MMD3"); /* mmd3 and above */
+ }
+
+ /* all TFMX format tests here */
+ } else if (tfmxtest(buf, bufsize, pre)) {
+ /* is TFMX, nothing to do here ('pre' set in tfmxtest() */
+
+ } else if (buf[0] == 'T' && buf[1] == 'H' && buf[2] == 'X') {
+ if ((buf[3] == 0x00) || (buf[3] == 0x01)) {
+ strcpy(pre, "AHX"); /* AHX */
+ }
+
+ } else if (buf[1] == 'M' && buf[2] == 'U' && buf[3] == 'G'
+ && buf[4] == 'I' && buf[5] == 'C' && buf[6] == 'I'
+ && buf[7] == 'A' && buf[8] == 'N') {
+ if (buf[9] == '2') {
+ strcpy(pre, "MUG2"); /* Digimugi2 */
+ } else {
+ strcpy(pre, "MUG"); /* Digimugi */
+ }
+
+ } else if (buf[0] == 'L' && buf[1] == 'M' && buf[2] == 'E' && buf[3] == 0x00) {
+ strcpy(pre, "LME"); /* LegLess */
+
+ } else if (buf[0] == 'P' && buf[1] == 'S' && buf[2] == 'A' && buf[3] == 0x00) {
+ strcpy(pre, "PSA"); /* PSA */
+
+ } else if ((buf[0] == 'S' && buf[1] == 'y' && buf[2] == 'n' && buf[3] == 't'
+ && buf[4] == 'h' && buf[6] == '.' && buf[8] == 0x00)
+ && (buf[5] > '1' && buf[5] < '4')) {
+ strcpy(pre, "SYN"); /* Synthesis */
+
+ } else if (buf[0xbc6] == '.' && buf[0xbc7] == 'F' && buf[0xbc8] == 'N'
+ && buf[0xbc9] == 'L') {
+ strcpy(pre, "DM2"); /* Delta 2.0 */
+
+ } else if (buf[0] == 'R' && buf[1] == 'J' && buf[2] == 'P') {
+
+ if (buf[4] == 'S' && buf[5] == 'M' && buf[6] == 'O' && buf[7] == 'D') {
+ strcpy(pre, "RJP"); /* Vectordean (Richard Joseph Player) */
+ } else {
+ strcpy(pre, ""); /* but don't play .ins files */
+ }
+ } else if (buf[0] == 'F' && buf[1] == 'O' && buf[2] == 'R' && buf[3] == 'M') {
+ if (buf[8] == 'S' && buf[9] == 'M' && buf[10] == 'U' && buf[11] == 'S') {
+ strcpy(pre, "SMUS"); /* Sonix */
+ }
+ // } else if (buf[0x00] == 0x00 && buf[0x01] == 0xfe &&
+ // buf[0x30] == 0x00 && buf[0x31] ==0x00 && buf[0x32] ==0x01 && buf[0x33] ==0x40 &&
+ // realfilesize > 332 ){
+ // }
+ // strcpy (pre, "SMUS"); /* Tiny Sonix*/
+
+ } else if (tronictest(buf, bufsize)) {
+ strcpy(pre, "TRONIC"); /* Tronic */
+
+ /* generic ID Check at offset 0x00 */
+ } else if (chk_id_offset(buf, bufsize, offset_0000_patterns, 0x00, pre)) {
+
+ /*magic ids of some modpackers */
+ } else if (buf[0x438] == 'P' && buf[0x439] == 'W' && buf[0x43a] == 'R'
+ && buf[0x43b] == 0x2e) {
+ strcpy(pre, "PPK"); /*Polkapacker */
+
+ } else if (buf[0x100] == 'S' && buf[0x101] == 'K' && buf[0x102] == 'Y'
+ && buf[0x103] == 'T') {
+ strcpy(pre, "SKT"); /*Skytpacker */
+
+ } else if ((buf[0x5b8] == 'I' && buf[0x5b9] == 'T' && buf[0x5ba] == '1'
+ && buf[0x5bb] == '0') || (buf[0x5b8] == 'M' && buf[0x5b9] == 'T'
+ && buf[0x5ba] == 'N'
+ && buf[0x5bb] == 0x00)) {
+ strcpy(pre, "ICE"); /*Ice/Soundtracker 2.6 */
+
+ } else if (buf[0x3b8] == 'K' && buf[0x3b9] == 'R' && buf[0x3ba] == 'I'
+ && buf[0x3bb] == 'S') {
+ strcpy(pre, "KRIS"); /*Kristracker */
+
+ } else if (buf[0] == 'X' && buf[1] == 'P' && buf[2] == 'K' && buf[3] == 'F'&&
+ read_be_u32(&buf[4]) + 8 == realfilesize &&
+ buf[8] == 'S' && buf[9] == 'Q' && buf[10] == 'S' && buf[11] == 'H') {
+ fprintf(stderr, "uade: The file is SQSH packed. Please depack first.\n");
+ strcpy(pre, "packed");
+
+ } else if ((modtype = mod15check(buf, bufsize, realfilesize, path)) != 0) {
+ for (t = 0; mod15types[t].str != NULL; t++) {
+ if (modtype == mod15types[t].e) {
+ strcpy(pre, mod15types[t].str);
+ return;
+ }
+ }
+
+ /* Custom file check */
+ } else if (buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x03
+ && buf[3] == 0xf3) {
+ /*CUSTOM*/ i = (buf[0x0b] * 4) + 0x1c; /* beginning of first chunk */
+
+ if (i < bufsize - 0x42) {
+
+ t = 0;
+ /* unfort. we can't always assume: moveq #-1,d0 rts before "delirium" */
+ /* search 0x40 bytes from here, (enough?) */
+ while ((buf[i + t + 0] != 'D' && buf[i + t + 1] != 'E'
+ && buf[i + t + 2] != 'L' && buf[i + t + 3] != 'I')
+ && (t < 0x40)) {
+ t++;
+ }
+
+ if (t < 0x40) {
+ /* longword after Delirium is rel. offset from first chunk
+ where "hopefully" the delitags are */
+ int s = (buf[i + t + 10] * 256) + buf[i + t + 11] + i; /* 64K */
+ if (s < bufsize - 0x33) {
+ for (i = 0; i < 0x30; i = i + 4) {
+ if (buf[i + s + 0] == 0x80 && buf[i + s + 1] == 0x00 &&
+ buf[i + s + 2] == 0x44 && buf[i + s + 3] == 0x55) {
+ strcpy(pre, "CUST"); /* CUSTOM */
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ } else if (buf[12] == 0x00) {
+ int s = (buf[12] * 256 + buf[13] + 1) * 14;
+ if (s < (bufsize - 91)) {
+ if (buf[80 + s] == 'p' && buf[81 + s] == 'a' && buf[82 + s] == 't'
+ && buf[83 + s] == 't' && buf[87 + s] == 32 && buf[88 + s] == 'p'
+ && buf[89 + s] == 'a' && buf[90 + s] == 't' && buf[91 + s] == 't') {
+ strcpy(pre, "PUMA"); /* Pumatracker */
+ }
+ }
+ }
+}
+
+
+/* We are currently stupid and check only for a few magic IDs at the offsets
+ * chk_id_offset returns 1 on success and sets the right prefix/extension
+ * in pre
+ * TODO: more and less easy check for the rest of the 52 trackerclones
+ */
+static int chk_id_offset(unsigned char *buf, int bufsize,
+ const char *patterns[], int offset, char *pre)
+{
+ int i;
+ for (i = 0; patterns[i]; i = i + 2) {
+ if (patterntest(buf, patterns[i], offset, strlen(patterns[i]), bufsize)) {
+ /* match found */
+ strcpy(pre, patterns[i + 1]);
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/amifilemagic.h b/plugins/uade2/uade-2.13/src/frontends/common/amifilemagic.h
new file mode 100644
index 00000000..45e5cd48
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/amifilemagic.h
@@ -0,0 +1,9 @@
+#ifndef _UADE_AMIFILEMAGIC_H_
+#define _UADE_AMIFILEMAGIC_H_
+
+#include <stdio.h>
+
+void uade_filemagic(unsigned char *buf, size_t bufsize, char *pre,
+ size_t realfilesize, const char *path, int verbose);
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/eagleplayer.c b/plugins/uade2/uade-2.13/src/frontends/common/eagleplayer.c
new file mode 100644
index 00000000..7c8dfce2
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/eagleplayer.c
@@ -0,0 +1,502 @@
+/*
+ * Loads contents of 'eagleplayer.conf'. The file formats are
+ * specified in doc/uade123.1.
+ *
+ * Copyright 2005-2007 Heikki Orsila <heikki.orsila@iki.fi>
+ *
+ * This source code module is dual licensed under GPL and Public Domain.
+ * Hence you may use _this_ module (not another code module) in any you
+ * want in your projects.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <stdint.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "eagleplayer.h"
+#include "ossupport.h"
+#include "amifilemagic.h"
+#include "uadeconf.h"
+#include "unixatomic.h"
+#include "songdb.h"
+#include "support.h"
+#include "uadestate.h"
+
+
+#define OPTION_DELIMITER ","
+
+#define MAX_SUFFIX_LENGTH 16
+
+#define eperror(fmt, args...) do { uadeerror("Eagleplayer.conf error on line %zd: " fmt, lineno, ## args); } while (0)
+
+
+/* Table for associating eagleplayer.conf, song.conf and uade.conf options
+ * together.
+ */
+const struct epconfattr epconf[] = {
+ {.s = "a500", .e = ES_A500, .o = UC_FILTER_TYPE, .c = "a500"},
+ {.s = "a1200", .e = ES_A1200, .o = UC_FILTER_TYPE, .c = "a1200"},
+ {.s = "always_ends", .e = ES_ALWAYS_ENDS, .o = UC_DISABLE_TIMEOUTS},
+ {.s = "broken_song_end", .e = ES_BROKEN_SONG_END, .o = UC_NO_EP_END},
+ {.s = "detect_format_by_content", .e = ES_CONTENT_DETECTION, .o = UC_CONTENT_DETECTION},
+ {.s = "detect_format_by_name", .e = ES_NAME_DETECTION, .o = 0},
+ {.s = "ignore_player_check",.e = ES_IGNORE_PLAYER_CHECK, .o = UC_IGNORE_PLAYER_CHECK},
+ {.s = "led_off", .e = ES_LED_OFF, .o = UC_FORCE_LED_OFF},
+ {.s = "led_on", .e = ES_LED_ON, .o = UC_FORCE_LED_ON},
+ {.s = "never_ends", .e = ES_NEVER_ENDS, .o = 0},
+ {.s = "no_ep_end_detect", .e = ES_BROKEN_SONG_END, .o = UC_NO_EP_END},
+ {.s = "no_filter", .e = ES_NO_FILTER, .o = UC_NO_FILTER},
+ {.s = "no_headphones", .e = ES_NO_HEADPHONES, .o = UC_NO_HEADPHONES},
+ {.s = "no_panning", .e = ES_NO_PANNING, .o = UC_NO_PANNING},
+ {.s = "no_postprocessing", .e = ES_NO_POSTPROCESSING, .o = UC_NO_POSTPROCESSING},
+ {.s = "ntsc", .e = ES_NTSC, .o = UC_NTSC},
+ {.s = "one_subsong", .e = ES_ONE_SUBSONG, .o = UC_ONE_SUBSONG},
+ {.s = "pal", .e = ES_PAL, .o = UC_PAL},
+ {.s = "reject", .e = ES_REJECT, .o = 0},
+ {.s = "speed_hack", .e = ES_SPEED_HACK, .o = UC_SPEED_HACK},
+ {.s = NULL}
+};
+
+
+/* Variables for eagleplayer.conf and song.conf */
+static const struct epconfattr epconf_variables[] = {
+ {.s = "epopt", .t = UA_STRING, .e = ES_EP_OPTION},
+ {.s = "gain", .t = UA_STRING, .e = ES_GAIN},
+ {.s = "interpolator", .t = UA_STRING, .e = ES_RESAMPLER},
+ {.s = "panning", .t = UA_STRING, .e = ES_PANNING},
+ {.s = "player", .t = UA_STRING, .e = ES_PLAYER},
+ {.s = "resampler", .t = UA_STRING, .e = ES_RESAMPLER},
+ {.s = "silence_timeout", .t = UA_STRING, .e = ES_SILENCE_TIMEOUT},
+ {.s = "subsong_timeout", .t = UA_STRING, .e = ES_SUBSONG_TIMEOUT},
+ {.s = "subsongs", .t = UA_STRING, .e = ES_SUBSONGS},
+ {.s = "timeout", .t = UA_STRING, .e = ES_TIMEOUT},
+ {.s = NULL}
+};
+
+
+static int ufcompare(const void *a, const void *b);
+static struct eagleplayerstore *read_eagleplayer_conf(const char *filename);
+
+
+static struct eagleplayer *get_eagleplayer(const char *extension,
+ struct eagleplayerstore *playerstore);
+
+
+static int load_playerstore(struct uade_state *state)
+{
+ static int warnings = 1;
+ char formatsfile[PATH_MAX];
+
+ if (state->playerstore == NULL) {
+ snprintf(formatsfile, sizeof(formatsfile),
+ "%s/eagleplayer.conf", state->config.basedir.name);
+
+ state->playerstore = read_eagleplayer_conf(formatsfile);
+ if (state->playerstore == NULL) {
+ if (warnings) {
+ fprintf(stderr, "Tried to load eagleplayer.conf from %s, but failed\n", formatsfile);
+ }
+ warnings = 0;
+ return 0;
+ }
+
+ if (state->config.verbose)
+ fprintf(stderr, "Loaded eagleplayer.conf: %s\n",
+ formatsfile);
+ }
+
+ return 1;
+}
+
+
+static struct eagleplayer *analyze_file_format(int *content,
+ const char *modulename,
+ struct uade_state *state)
+{
+ struct stat st;
+ char ext[MAX_SUFFIX_LENGTH];
+ FILE *f;
+ struct eagleplayer *contentcandidate = NULL;
+ struct eagleplayer *namecandidate = NULL;
+ char *prefix, *postfix, *t;
+ size_t bufsize, bytesread;
+ uint8_t buf[8192];
+
+ *content = 0;
+
+ if ((f = fopen(modulename, "rb")) == NULL)
+ return NULL;
+
+ if (fstat(fileno(f), &st))
+ uadeerror("Very weird stat error: %s (%s)\n", modulename, strerror(errno));
+
+ bufsize = sizeof buf;
+ bytesread = atomic_fread(buf, 1, bufsize, f);
+ fclose(f);
+ if (bytesread == 0)
+ return NULL;
+ memset(&buf[bytesread], 0, bufsize - bytesread);
+
+ uade_filemagic(buf, bytesread, ext, st.st_size, modulename, state->config.verbose);
+
+ if (strcmp(ext, "reject") == 0)
+ return NULL;
+
+ if (ext[0] != 0 && state->config.verbose)
+ fprintf(stderr, "Content recognized: %s (%s)\n", ext, modulename);
+
+ if (strcmp(ext, "packed") == 0)
+ return NULL;
+
+ if (!load_playerstore(state))
+ return NULL;
+
+ /* First do filename detection (we'll later do content detection) */
+ t = xbasename(modulename);
+
+ if (strlcpy((char *) buf, t, sizeof buf) >= sizeof buf)
+ return NULL;
+
+ t = strchr((char *) buf, '.');
+ if (t == NULL)
+ return NULL;
+
+ *t = 0;
+ prefix = (char *) buf;
+
+ if (strlen(prefix) < MAX_SUFFIX_LENGTH)
+ namecandidate = get_eagleplayer(prefix, state->playerstore);
+
+ if (namecandidate == NULL) {
+ /* Try postfix */
+ t = xbasename(modulename);
+ strlcpy((char *) buf, t, sizeof buf);
+ postfix = strrchr((char *) buf, '.') + 1; /* postfix != NULL */
+
+ if (strlen(postfix) < MAX_SUFFIX_LENGTH)
+ namecandidate = get_eagleplayer(postfix, state->playerstore);
+ }
+
+ /* If filemagic found a match, we'll use player plugins associated with
+ that extension */
+ if (ext[0]) {
+ contentcandidate = get_eagleplayer(ext, state->playerstore);
+ if (contentcandidate != NULL) {
+ /* Do not recognize name detectable eagleplayers by
+ content */
+ if (namecandidate == NULL ||
+ (namecandidate->flags & ES_NAME_DETECTION) == 0) {
+ *content = 1;
+ return contentcandidate;
+ }
+ } else {
+ if (state->config.verbose)
+ fprintf(stderr, "%s not in eagleplayer.conf\n", ext);
+ }
+ }
+
+ if (state->config.verbose)
+ fprintf(stderr, "Format detection by filename\n");
+
+ return namecandidate;
+}
+
+
+static void handle_attribute(struct uade_attribute **attributelist,
+ const struct epconfattr *attr,
+ char *item, size_t len, size_t lineno)
+{
+ struct uade_attribute *a;
+ char *str, *endptr;
+ int success = 0;
+
+ if (item[len] != '=') {
+ fprintf(stderr, "Invalid song item: %s\n", item);
+ return;
+ }
+ str = item + len + 1;
+
+ if ((a = calloc(1, sizeof *a)) == NULL)
+ eperror("No memory for song attribute.\n");
+
+ switch (attr->t) {
+ case UA_DOUBLE:
+ a->d = strtod(str, &endptr);
+ if (*endptr == 0)
+ success = 1;
+ break;
+ case UA_INT:
+ a->i = strtol(str, &endptr, 10);
+ if (*endptr == 0)
+ success = 1;
+ break;
+ case UA_STRING:
+ a->s = strdup(str);
+ if (a->s == NULL)
+ eperror("Out of memory allocating string option for song\n");
+ success = 1;
+ break;
+ default:
+ fprintf(stderr, "Unknown song option: %s\n",
+ item);
+ break;
+ }
+
+ if (success) {
+ a->type = attr->e;
+ a->next = *attributelist;
+ *attributelist = a;
+ } else {
+ fprintf(stderr, "Invalid song option: %s\n", item);
+ free(a);
+ }
+}
+
+
+int uade_song_and_player_attribute(struct uade_attribute **attributelist,
+ int *flags, char *item, size_t lineno)
+{
+ size_t i, len;
+
+ for (i = 0; epconf[i].s != NULL; i++) {
+ if (strcasecmp(item, epconf[i].s) == 0) {
+ *flags |= epconf[i].e;
+ return 1;
+ }
+ }
+
+ for (i = 0; epconf_variables[i].s != NULL; i++) {
+ len = strlen(epconf_variables[i].s);
+ if (strncasecmp(item, epconf_variables[i].s, len) != 0)
+ continue;
+
+ handle_attribute(attributelist, &epconf_variables[i],
+ item, len, lineno);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Compare function for bsearch() and qsort() to sort eagleplayers with
+ respect to name extension. */
+static int ufcompare(const void *a, const void *b)
+{
+ const struct eagleplayermap *ua = a;
+ const struct eagleplayermap *ub = b;
+
+ return strcasecmp(ua->extension, ub->extension);
+}
+
+int uade_is_our_file(const char *modulename, int scanmode,
+ struct uade_state *state)
+{
+ int content;
+ struct eagleplayer *ep;
+
+ ep = analyze_file_format(&content, modulename, state);
+
+ if (!scanmode)
+ state->ep = ep;
+
+ if (ep == NULL)
+ return 0;
+
+ if (content)
+ return 1;
+
+ if (state->config.content_detection && content == 0)
+ return 0;
+
+ if ((ep->flags & ES_CONTENT_DETECTION) != 0)
+ return 0;
+
+ return 1;
+}
+
+static struct eagleplayer *get_eagleplayer(const char *extension,
+ struct eagleplayerstore *ps)
+{
+ struct eagleplayermap *uf = ps->map;
+ struct eagleplayermap *f;
+ struct eagleplayermap key = {.extension = (char *)extension };
+
+ f = bsearch(&key, uf, ps->nextensions, sizeof(uf[0]), ufcompare);
+ if (f == NULL)
+ return NULL;
+
+ return f->player;
+}
+
+/* Read eagleplayer.conf. */
+static struct eagleplayerstore *read_eagleplayer_conf(const char *filename)
+{
+ FILE *f;
+ struct eagleplayer *p;
+ size_t allocated;
+ size_t lineno = 0;
+ struct eagleplayerstore *ps = NULL;
+ size_t exti;
+ size_t i, j;
+ int epwarning;
+
+ f = fopen(filename, "r");
+ if (f == NULL)
+ goto error;
+
+ ps = calloc(1, sizeof ps[0]);
+ if (ps == NULL)
+ eperror("No memory for ps.");
+
+ allocated = 16;
+ if ((ps->players = malloc(allocated * sizeof(ps->players[0]))) == NULL)
+ eperror("No memory for eagleplayer.conf file.\n");
+
+ while (1) {
+ char **items;
+ size_t nitems;
+
+ items = read_and_split_lines(&nitems, &lineno, f, UADE_WS_DELIMITERS);
+ if (items == NULL)
+ break;
+
+ assert(nitems > 0);
+
+ if (ps->nplayers == allocated) {
+ allocated *= 2;
+ ps->players = realloc(ps->players, allocated * sizeof(ps->players[0]));
+ if (ps->players == NULL)
+ eperror("No memory for players.");
+ }
+
+ p = &ps->players[ps->nplayers];
+ ps->nplayers++;
+
+ memset(p, 0, sizeof p[0]);
+
+ p->playername = strdup(items[0]);
+ if (p->playername == NULL)
+ uadeerror("No memory for playername.\n");
+
+ for (i = 1; i < nitems; i++) {
+
+ if (strncasecmp(items[i], "prefixes=", 9) == 0) {
+ char prefixes[UADE_LINESIZE];
+ char *prefixstart = items[i] + 9;
+ char *sp, *s;
+ size_t pos;
+
+ assert(p->nextensions == 0 && p->extensions == NULL);
+
+ p->nextensions = 0;
+ strlcpy(prefixes, prefixstart,
+ sizeof(prefixes));
+ sp = prefixes;
+ while ((s = strsep(&sp, OPTION_DELIMITER)) != NULL) {
+ if (*s == 0)
+ continue;
+ p->nextensions++;
+ }
+
+ p->extensions =
+ malloc((p->nextensions +
+ 1) * sizeof(p->extensions[0]));
+ if (p->extensions == NULL)
+ eperror("No memory for extensions.");
+
+ pos = 0;
+ sp = prefixstart;
+ while ((s = strsep(&sp, OPTION_DELIMITER)) != NULL) {
+ if (*s == 0)
+ continue;
+
+ p->extensions[pos] = strdup(s);
+ if (s == NULL)
+ eperror("No memory for prefix.");
+ pos++;
+ }
+ p->extensions[pos] = NULL;
+ assert(pos == p->nextensions);
+
+ continue;
+ }
+
+ if (strncasecmp(items[i], "comment:", 7) == 0)
+ break;
+
+ if (uade_song_and_player_attribute(&p->attributelist, &p->flags, items[i], lineno))
+ continue;
+
+ fprintf(stderr, "Unrecognized option: %s\n", items[i]);
+ }
+
+ for (i = 0; items[i] != NULL; i++)
+ free(items[i]);
+
+ free(items);
+ }
+
+ fclose(f);
+
+ if (ps->nplayers == 0) {
+ free(ps->players);
+ free(ps);
+ return NULL;
+ }
+
+ for (i = 0; i < ps->nplayers; i++)
+ ps->nextensions += ps->players[i].nextensions;
+
+ ps->map = malloc(sizeof(ps->map[0]) * ps->nextensions);
+ if (ps->map == NULL)
+ eperror("No memory for extension map.");
+
+ exti = 0;
+ epwarning = 0;
+ for (i = 0; i < ps->nplayers; i++) {
+ p = &ps->players[i];
+ if (p->nextensions == 0) {
+ if (epwarning == 0) {
+ fprintf(stderr,
+ "uade warning: %s eagleplayer lacks prefixes in "
+ "eagleplayer.conf, which makes it unusable for any kind of "
+ "file type detection. If you don't want name based file type "
+ "detection for a particular format, use content_detection "
+ "option for the line in eagleplayer.conf.\n",
+ ps->players[i].playername);
+ epwarning = 1;
+ }
+ continue;
+ }
+ for (j = 0; j < p->nextensions; j++) {
+ assert(exti < ps->nextensions);
+ ps->map[exti].player = p;
+ ps->map[exti].extension = p->extensions[j];
+ exti++;
+ }
+ }
+
+ assert(exti == ps->nextensions);
+
+ /* Make the extension map bsearch() ready */
+ qsort(ps->map, ps->nextensions, sizeof(ps->map[0]), ufcompare);
+
+ return ps;
+
+ error:
+ if (ps)
+ free(ps->players);
+ free(ps);
+ if (f != NULL)
+ fclose(f);
+ return NULL;
+}
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/eagleplayer.h b/plugins/uade2/uade-2.13/src/frontends/common/eagleplayer.h
new file mode 100644
index 00000000..fc3497b5
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/eagleplayer.h
@@ -0,0 +1,127 @@
+#ifndef _UADE_EAGLEPLAYER_H_
+#define _UADE_EAGLEPLAYER_H_
+
+#include <stdio.h>
+#include <stdint.h>
+#include <limits.h>
+
+#include "uadeconfstructure.h"
+
+/* We maintain alphabetical order even if that forces us to renumber bits
+ when a new option is added */
+#define ES_A1200 (1 << 0)
+#define ES_A500 (1 << 1)
+#define ES_ALWAYS_ENDS (1 << 2)
+#define ES_BROKEN_SONG_END (1 << 3)
+#define ES_CONTENT_DETECTION (1 << 4)
+#define ES_EP_OPTION (1 << 5)
+#define ES_GAIN (1 << 6)
+#define ES_IGNORE_PLAYER_CHECK (1 << 7)
+#define ES_LED_OFF (1 << 8)
+#define ES_LED_ON (1 << 9)
+#define ES_NAME_DETECTION (1 << 10)
+#define ES_NEVER_ENDS (1 << 11)
+#define ES_NO_FILTER (1 << 12)
+#define ES_NO_HEADPHONES (1 << 13)
+#define ES_NO_PANNING (1 << 14)
+#define ES_NO_POSTPROCESSING (1 << 15)
+#define ES_NTSC (1 << 16)
+#define ES_ONE_SUBSONG (1 << 17)
+#define ES_PAL (1 << 18)
+#define ES_PANNING (1 << 19)
+#define ES_PLAYER (1 << 20)
+#define ES_REJECT (1 << 21)
+#define ES_RESAMPLER (1 << 22)
+#define ES_SILENCE_TIMEOUT (1 << 23)
+#define ES_SPEED_HACK (1 << 24)
+#define ES_SUBSONGS (1 << 25)
+#define ES_SUBSONG_TIMEOUT (1 << 26)
+#define ES_TIMEOUT (1 << 27)
+
+#define UADE_WS_DELIMITERS " \t\n"
+
+struct eagleplayer {
+ char *playername;
+ size_t nextensions;
+ char **extensions;
+ int flags;
+ struct uade_attribute *attributelist;
+};
+
+struct eagleplayermap {
+ char *extension;
+ struct eagleplayer *player;
+};
+
+struct eagleplayerstore {
+ size_t nplayers;
+ struct eagleplayer *players;
+ size_t nextensions;
+ struct eagleplayermap *map;
+};
+
+enum uade_attribute_type {
+ UA_STRING = 1,
+ UA_INT,
+ UA_DOUBLE
+};
+
+struct uade_attribute;
+
+struct uade_attribute {
+ struct uade_attribute *next;
+ enum uade_attribute_type type;
+ char *s;
+ int i;
+ double d;
+};
+
+struct uade_song {
+ char md5[33];
+
+ char module_filename[PATH_MAX];
+
+ char playername[256]; /* Eagleplayer name in players directory */
+ char modulename[256]; /* From score */
+ char formatname[256];
+
+ uint8_t *buf;
+ size_t bufsize;
+
+ int min_subsong;
+ int max_subsong;
+ int cur_subsong;
+
+ int playtime;
+ int flags;
+ int nsubsongs;
+ uint8_t *subsongs;
+ struct uade_attribute *songattributes;
+ struct uade_ep_options ep_options;
+ char *normalisation;
+
+ int64_t out_bytes;
+
+ int64_t silence_count;
+};
+
+struct epconfattr {
+ char *s; /* config file directive/variable name */
+ int e; /* ES_* flags for eagleplayers and songs */
+ int o; /* UC_* flag for uade.conf option */
+ char *c; /* constant for an UC_* flag */
+ enum uade_attribute_type t; /* if variable, its special type */
+};
+
+
+extern const struct epconfattr epconf[];
+
+
+/* FIX: A forward declaration to avoid circular dependency */
+struct uade_state;
+
+int uade_is_our_file(const char *modulename, int scanmode, struct uade_state *state);
+int uade_song_and_player_attribute(struct uade_attribute **attributelist,
+ int *flags, char *item, size_t lineno);
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/effects.c b/plugins/uade2/uade-2.13/src/frontends/common/effects.c
new file mode 100644
index 00000000..c75c859d
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/effects.c
@@ -0,0 +1,490 @@
+/* Effect module for UADE2 frontends.
+
+ Copyright 2005 (C) Antti S. Lankila <alankila@bel.fi>
+
+ This module is licensed under the GNU LGPL.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <math.h>
+
+#include <compilersupport.h>
+
+#include "effects.h"
+
+/*** old headphone effect ***/
+#define UADE_EFFECT_HEADPHONES_DELAY_LENGTH 22
+#define UADE_EFFECT_HEADPHONES_DELAY_DIRECT 0.3
+#define UADE_EFFECT_HEADPHONES_CROSSMIX_VOL 0.80
+
+static float headphones_ap_l[UADE_EFFECT_HEADPHONES_DELAY_LENGTH];
+static float headphones_ap_r[UADE_EFFECT_HEADPHONES_DELAY_LENGTH];
+static float headphones_rc_l[4];
+static float headphones_rc_r[4];
+
+/*** new headphone effect ***/
+
+/* delay time defines the width of the head. 0.5 ms gives us 15 cm virtual distance
+ * between sound arriving to either ear. */
+#define HEADPHONE2_DELAY_TIME 0.49e-3
+#define HEADPHONE2_DELAY_K 0.15
+/* head shadow frequency cutoff */
+#define HEADPHONE2_SHADOW_FREQ 8000.0
+/* high shelve keeps frequencies below cutoff intact and attenuates
+ * the rest in an uniform way. The effect is to make bass more "mono" than "stereo". */
+#define HEADPHONE2_SHELVE_FREQ 100.0
+#define HEADPHONE2_SHELVE_LEVEL -2.0
+
+#define MAXIMUM_SAMPLING_RATE 96000
+#define HEADPHONE2_DELAY_MAX_LENGTH ((int)(MAXIMUM_SAMPLING_RATE*HEADPHONE2_DELAY_TIME+1))
+#define DENORMAL_OFFSET 1E-10
+
+#define NORMALISE_RESOLUTION 10 /* in bits */
+#define NORMALISE_DEFAULT_GAIN 8.0
+#define NORMALISE_MAXIMUM_GAIN 8.0
+
+/* Headphone variables */
+typedef struct {
+ float b0, b1, b2, a1, a2, x[2], y[2];
+} biquad_t;
+
+static float headphone2_ap_l[HEADPHONE2_DELAY_MAX_LENGTH];
+static float headphone2_ap_r[HEADPHONE2_DELAY_MAX_LENGTH];
+static int headphone2_delay_length;
+static biquad_t headphone2_shelve_l;
+static biquad_t headphone2_shelve_r;
+static biquad_t headphone2_rc_l;
+static biquad_t headphone2_rc_r;
+
+/* Normalise variables */
+static int normalise_peak_level;
+static int normalise_historic_maximum_peak;
+static int normalise_oldlevel;
+
+static void gain(int gain_amount, int16_t * sm, int frames);
+static void pan(int pan_amount, int16_t * sm, int frames);
+static void headphones(int16_t * sm, int frames);
+static void headphones2(int16_t * sm, int frames);
+static void normalise(int change_level, int16_t * sm, int frames);
+static int normalise_compute_gain(int peak);
+
+static inline int sampleclip(int x)
+{
+ if (unlikely(x > 32767 || x < -32768)) {
+ if (x > 32767)
+ x = 32767;
+ else
+ x = -32768;
+ }
+ return x;
+}
+
+/* calculate a high shelve filter */
+static void calculate_shelve(double fs, double fc, double g, biquad_t * bq)
+{
+ float A, omega, sn, cs, beta, b0, b1, b2, a0, a1, a2;
+
+ A = powf(10, g / 40);
+ omega = 2 * M_PI * fc / fs;
+ omega = tan(omega / 2) * 2;
+ sn = sin(omega);
+ cs = cos(omega);
+ beta = sqrt(A + A);
+
+ b0 = A * ((A + 1) + (A - 1) * cs + beta * sn);
+ b1 = -2 * A * ((A - 1) + (A + 1) * cs);
+ b2 = A * ((A + 1) + (A - 1) * cs - beta * sn);
+ a0 = (A + 1) - (A - 1) * cs + beta * sn;
+ a1 = 2 * ((A - 1) - (A + 1) * cs);
+ a2 = (A + 1) - (A - 1) * cs - beta * sn;
+
+ bq->b0 = b0 / a0;
+ bq->b1 = b1 / a0;
+ bq->b2 = b2 / a0;
+ bq->a1 = a1 / a0;
+ bq->a2 = a2 / a0;
+}
+
+/* calculate 1st order lowpass filter */
+static void calculate_rc(double fs, double fc, biquad_t * bq)
+{
+ float omega;
+
+ if (fc >= fs / 2) {
+ bq->b0 = 1.0;
+ bq->b1 = 0.0;
+ bq->b2 = 0.0;
+ bq->a1 = 0.0;
+ bq->a2 = 0.0;
+ return;
+ }
+ omega = 2 * M_PI * fc / fs;
+ omega = tan(omega / 2) * 2;
+
+ bq->b0 = 1 / (1 + 1 / omega);
+ bq->b1 = 0;
+ bq->b2 = 0;
+ bq->a1 = -1 + bq->b0;
+ bq->a2 = 0;
+}
+
+static inline float evaluate_biquad(float input, biquad_t * bq)
+{
+ float output = DENORMAL_OFFSET;
+
+ output += input * bq->b0 + bq->x[0] * bq->b1 + bq->x[1] * bq->b2;
+ output -= bq->y[0] * bq->a1 + bq->y[1] * bq->a2;
+
+ bq->x[1] = bq->x[0];
+ bq->x[0] = input;
+
+ bq->y[1] = bq->y[0];
+ bq->y[0] = output;
+
+ return output;
+}
+
+static void reset_biquad(biquad_t * bq)
+{
+ bq->x[0] = bq->x[1] = bq->y[0] = bq->y[1] = 0;
+}
+
+/* Reset effects' state variables.
+ * Call this method between before starting playback */
+void uade_effect_reset_internals(void)
+{
+ /* old headphones */
+ memset(headphones_ap_l, 0, sizeof(headphones_ap_l));
+ memset(headphones_ap_r, 0, sizeof(headphones_ap_r));
+ memset(headphones_rc_l, 0, sizeof(headphones_rc_l));
+ memset(headphones_rc_r, 0, sizeof(headphones_rc_r));
+
+ /* new headphones */
+ memset(headphone2_ap_l, 0, sizeof(headphone2_ap_l));
+ memset(headphone2_ap_r, 0, sizeof(headphone2_ap_r));
+ reset_biquad(&headphone2_shelve_l);
+ reset_biquad(&headphone2_shelve_r);
+ reset_biquad(&headphone2_rc_l);
+ reset_biquad(&headphone2_rc_r);
+
+ normalise_peak_level = 0;
+ normalise_historic_maximum_peak = 0;
+ normalise_oldlevel = 1 << NORMALISE_RESOLUTION;
+}
+
+void uade_effect_disable_all(struct uade_effect *ue)
+{
+ ue->enabled = 0;
+}
+
+void uade_effect_disable(struct uade_effect *ue, uade_effect_t effect)
+{
+ ue->enabled &= ~(1 << effect);
+}
+
+void uade_effect_enable(struct uade_effect *ue, uade_effect_t effect)
+{
+ ue->enabled |= 1 << effect;
+}
+
+/* Returns 1 if effect is enabled, and zero otherwise. Ignores
+ UADE_EFFECT_ALLOW. */
+int uade_effect_is_enabled(struct uade_effect *ue, uade_effect_t effect)
+{
+ return (ue->enabled & (1 << effect)) != 0;
+}
+
+void uade_effect_run(struct uade_effect *ue, int16_t * samples, int frames)
+{
+ if (ue->enabled & (1 << UADE_EFFECT_ALLOW)) {
+ normalise(ue->enabled & (1 << UADE_EFFECT_NORMALISE), samples,
+ frames);
+ if (ue->enabled & (1 << UADE_EFFECT_PAN))
+ pan(ue->pan, samples, frames);
+ if (ue->enabled & (1 << UADE_EFFECT_HEADPHONES))
+ headphones(samples, frames);
+ if (ue->enabled & (1 << UADE_EFFECT_HEADPHONES2) && ue->rate)
+ headphones2(samples, frames);
+ if (ue->enabled & (1 << UADE_EFFECT_GAIN))
+ gain(ue->gain, samples, frames);
+ }
+}
+
+void uade_effect_toggle(struct uade_effect *ue, uade_effect_t effect)
+{
+ ue->enabled ^= 1 << effect;
+}
+
+void uade_effect_set_defaults(struct uade_effect *ue)
+{
+ memset(ue, 0, sizeof(*ue));
+ uade_effect_disable_all(ue);
+ uade_effect_enable(ue, UADE_EFFECT_ALLOW);
+ uade_effect_gain_set_amount(ue, 1.0);
+ uade_effect_pan_set_amount(ue, 0.7);
+}
+
+/* Rate of 0 means undefined. Effects that depend on sample rate must
+ self-check against this because they can not implemented properly */
+void uade_effect_set_sample_rate(struct uade_effect *ue, int rate)
+{
+ assert(rate >= 0);
+ ue->rate = rate;
+
+ if (rate == 0)
+ return;
+
+ calculate_shelve(rate, HEADPHONE2_SHELVE_FREQ, HEADPHONE2_SHELVE_LEVEL,
+ &headphone2_shelve_l);
+ calculate_shelve(rate, HEADPHONE2_SHELVE_FREQ, HEADPHONE2_SHELVE_LEVEL,
+ &headphone2_shelve_r);
+ calculate_rc(rate, HEADPHONE2_SHADOW_FREQ, &headphone2_rc_l);
+ calculate_rc(rate, HEADPHONE2_SHADOW_FREQ, &headphone2_rc_r);
+ headphone2_delay_length = HEADPHONE2_DELAY_TIME * rate + 0.5;
+ if (headphone2_delay_length > HEADPHONE2_DELAY_MAX_LENGTH) {
+ fprintf(stderr, "effects.c: truncating headphone delay line due to samplerate exceeding 96 kHz.\n");
+ headphone2_delay_length = HEADPHONE2_DELAY_MAX_LENGTH;
+ }
+}
+
+void uade_effect_gain_set_amount(struct uade_effect *ue, float amount)
+{
+ assert(amount >= 0.0 && amount <= 128.0);
+ ue->gain = amount * 256.0;
+}
+
+void uade_effect_pan_set_amount(struct uade_effect *ue, float amount)
+{
+ assert(amount >= 0.0 && amount <= 2.0);
+ ue->pan = amount * 256.0 / 2.0;
+}
+
+static int normalise_compute_gain(int peak)
+{
+ if (normalise_historic_maximum_peak == 0) {
+ /* if the peak is not known, we cap gain in an attempt to avoid
+ * boosting silent intros too much. */
+ if (peak < 32768 / NORMALISE_DEFAULT_GAIN)
+ return NORMALISE_DEFAULT_GAIN *
+ (1 << NORMALISE_RESOLUTION);
+ else
+ return (32768 << NORMALISE_RESOLUTION) / peak;
+ } else {
+ int largerpeak;
+ if (peak < normalise_historic_maximum_peak)
+ largerpeak = normalise_historic_maximum_peak;
+ else
+ largerpeak = peak;
+ /* if the peak is known, we use the recorded value but adapt
+ if this rendition comes out louder for some reason (for
+ instance, updated UADE) */
+ if (largerpeak < 32768 / NORMALISE_MAXIMUM_GAIN)
+ return NORMALISE_MAXIMUM_GAIN *
+ (1 << NORMALISE_RESOLUTION);
+ else
+ return (32768 << NORMALISE_RESOLUTION) / largerpeak;
+ }
+}
+
+/* We save gain from maximum known level. This is an one-way street,
+ the gain can * only decrease with time. If the historic level is
+ known and larger, we prefer it. */
+void uade_effect_normalise_serialise(char *buf, size_t len)
+{
+ int peak = normalise_peak_level;
+
+ assert(len > 0);
+
+ if (normalise_historic_maximum_peak > normalise_peak_level)
+ peak = normalise_historic_maximum_peak;
+
+ if (snprintf(buf, len, "v=1,p=%d", peak) >= len) {
+ fprintf(stderr, "normalise effect: buffer too short, gain would be truncated. This is a bug in UADE.\n");
+ exit(-1);
+ }
+}
+
+/* similarly, this should only be called if gain has a positive value,
+ * but we try to recover from misuse. */
+void uade_effect_normalise_unserialise(const char *buf)
+{
+ int version, readcount;
+ float peak;
+
+ normalise_historic_maximum_peak = 0;
+
+ if (buf == NULL)
+ return;
+
+ readcount = sscanf(buf, "v=%d,p=%f", &version, &peak);
+
+ if (readcount == 0) {
+ fprintf(stderr, "normalise effect: gain string invalid: '%s'\n", buf);
+ exit(-1);
+ }
+
+ if (version != 1) {
+ fprintf(stderr, "normalise effect: unrecognized gain version: '%s'\n", buf);
+ exit(-1);
+ }
+
+ if (readcount != 2) {
+ fprintf(stderr, "Could not read peak value for version 1: '%s'\n", buf);
+ exit(-1);
+ }
+
+ if (peak >= 0.0 && peak <= 1.0) {
+ normalise_oldlevel = normalise_historic_maximum_peak =
+ 32768 * peak;
+ } else {
+ fprintf(stderr, "normalise effect: invalid peak level: '%s'\n", buf);
+ }
+}
+
+static void normalise(int change_level, int16_t * sm, int frames)
+{
+ int i;
+
+ /* Negative side is mirrored. but positive side gains by 1.
+ * This is to make both semiwaves have same max. */
+ for (i = 0; i < 2 * frames; i += 1) {
+ int tmp = sm[i];
+ tmp = (tmp >= 0) ? tmp + 1 : -tmp;
+ if (tmp > normalise_peak_level)
+ normalise_peak_level = tmp;
+ }
+
+ /* Slight clipping may result in first playback while the system
+ * adjusts. With a bit of "advance warning" of clipping about to
+ * occur, the level begins to adjust as soon as the buffer
+ * begins. Typical adjustment times are not large -- a few hundred
+ * samples are to be expected -- and the clipping should only
+ * occur on the first rendition of the song, if at all. */
+ if (change_level) {
+ int newlevel = normalise_compute_gain(normalise_peak_level);
+
+ for (i = 0; i < 2 * frames; i += 1) {
+ /* same gain for the frame */
+ if ((i & 1) == 0) {
+ if (normalise_oldlevel < newlevel)
+ normalise_oldlevel += 1;
+ if (normalise_oldlevel > newlevel)
+ normalise_oldlevel -= 1;
+ }
+ sm[i] =
+ sampleclip((sm[i] *
+ normalise_oldlevel) >>
+ NORMALISE_RESOLUTION);
+ }
+ }
+}
+
+static void gain(int gain_amount, int16_t * sm, int frames)
+{
+ int i;
+ for (i = 0; i < 2 * frames; i += 1)
+ sm[i] = sampleclip((sm[i] * gain_amount) >> 8);
+}
+
+/* Panning effect. Turns stereo into mono in a specific degree */
+static void pan(int pan_amount, int16_t * sm, int frames)
+{
+ int i, l, r, m;
+ for (i = 0; i < frames; i += 1) {
+ l = sm[0];
+ r = sm[1];
+ m = (r - l) * pan_amount;
+ sm[0] = ((l << 8) + m) >> 8;
+ sm[1] = ((r << 8) - m) >> 8;
+ sm += 2;
+ }
+}
+
+/* All-pass delay. Its purpose is to confuse the phase of the sound a bit
+ * and also provide some delay to locate the source outside the head. This
+ * seems to work better than a pure delay line. */
+static float headphones_allpass_delay(float in, float *state)
+{
+ int i;
+ float tmp, output;
+
+ tmp = in - UADE_EFFECT_HEADPHONES_DELAY_DIRECT * state[0];
+ output = state[0] + UADE_EFFECT_HEADPHONES_DELAY_DIRECT * tmp;
+
+ /* FIXME: use modulo and index */
+ for (i = 1; i < UADE_EFFECT_HEADPHONES_DELAY_LENGTH; i += 1)
+ state[i - 1] = state[i];
+ state[UADE_EFFECT_HEADPHONES_DELAY_LENGTH - 1] = tmp;
+
+ return output;
+}
+
+static float headphones_lpf(float in, float *state)
+{
+ float out = in * 0.53;
+ out += 0.47 * state[0];
+ state[0] = out;
+
+ return out;
+}
+
+/* A real implementation would simply perform FIR with recorded HRTF data. */
+static void headphones(int16_t * sm, int frames)
+{
+ int i;
+ float ld, rd;
+ int l_final, r_final;
+ for (i = 0; i < frames; i += 1) {
+ ld = headphones_allpass_delay(sm[0], headphones_ap_l);
+ rd = headphones_allpass_delay(sm[1], headphones_ap_r);
+ ld = headphones_lpf(ld, headphones_rc_l);
+ rd = headphones_lpf(rd, headphones_rc_r);
+
+ l_final =
+ (sm[0] + rd * UADE_EFFECT_HEADPHONES_CROSSMIX_VOL) / 2;
+ r_final =
+ (sm[1] + ld * UADE_EFFECT_HEADPHONES_CROSSMIX_VOL) / 2;
+ sm[0] = sampleclip(l_final);
+ sm[1] = sampleclip(r_final);
+
+ sm += 2;
+ }
+}
+
+static float headphone2_allpass_delay(float in, float *state)
+{
+ int i;
+ float tmp, output;
+
+ tmp = in - HEADPHONE2_DELAY_K * state[0];
+ output = state[0] + HEADPHONE2_DELAY_K * tmp;
+
+ /* FIXME: use modulo and index */
+ for (i = 1; i < headphone2_delay_length; i += 1)
+ state[i - 1] = state[i];
+ state[headphone2_delay_length - 1] = tmp;
+
+ return output;
+}
+
+static void headphones2(int16_t * sm, int frames)
+{
+ int i;
+ for (i = 0; i < frames; i += 1) {
+ float ld, rd;
+
+ ld = headphone2_allpass_delay(sm[0], headphone2_ap_l);
+ rd = headphone2_allpass_delay(sm[1], headphone2_ap_r);
+ ld = evaluate_biquad(ld, &headphone2_rc_l);
+ rd = evaluate_biquad(rd, &headphone2_rc_r);
+ ld = evaluate_biquad(ld, &headphone2_shelve_l);
+ rd = evaluate_biquad(rd, &headphone2_shelve_r);
+
+ sm[0] = sampleclip((sm[0] + rd) / 2);
+ sm[1] = sampleclip((sm[1] + ld) / 2);
+ sm += 2;
+ }
+}
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/effects.h b/plugins/uade2/uade-2.13/src/frontends/common/effects.h
new file mode 100644
index 00000000..57a779df
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/effects.h
@@ -0,0 +1,42 @@
+#ifndef _UADE2_EFFECTS_H_
+#define _UADE2_EFFECTS_H_
+
+#include <stdint.h>
+
+typedef enum {
+ UADE_EFFECT_ALLOW,
+ UADE_EFFECT_GAIN,
+ UADE_EFFECT_HEADPHONES,
+ UADE_EFFECT_HEADPHONES2,
+ UADE_EFFECT_PAN,
+ UADE_EFFECT_NORMALISE,
+} uade_effect_t;
+
+struct uade_effect {
+ uade_effect_t enabled;
+ int gain;
+ int pan;
+ int rate;
+};
+
+void uade_effect_disable(struct uade_effect *ue, uade_effect_t effect);
+void uade_effect_disable_all(struct uade_effect *ue);
+void uade_effect_enable(struct uade_effect *ue, uade_effect_t effect);
+int uade_effect_is_enabled(struct uade_effect *ue, uade_effect_t effect);
+void uade_effect_set_defaults(struct uade_effect *ue);
+void uade_effect_set_sample_rate(struct uade_effect *ue, int rate);
+void uade_effect_toggle(struct uade_effect *ue, uade_effect_t effect);
+
+/* effect-specific knobs */
+void uade_effect_gain_set_amount(struct uade_effect *ue, float amount);
+void uade_effect_normalise_unserialise(const char *buf);
+void uade_effect_normalise_serialise(char *buf, size_t len);
+void uade_effect_pan_set_amount(struct uade_effect *ue, float amount);
+
+/* reset state at start of song */
+void uade_effect_reset_internals(void);
+
+/* process n frames of sample buffer */
+void uade_effect_run(struct uade_effect *ue, int16_t * sample, int frames);
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/md5.c b/plugins/uade2/uade-2.13/src/frontends/common/md5.c
new file mode 100644
index 00000000..7614ea48
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/md5.c
@@ -0,0 +1,247 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include <string.h> /* for memcpy() */
+#include "md5.h"
+
+#if __BYTE_ORDER == 1234
+#define byteReverse(buf, len) /* Nothing */
+#else
+static void byteReverse(unsigned char *buf, unsigned longs);
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+ uint32_t t;
+ do {
+ t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(uint32_t *) buf = t;
+ buf += 4;
+ } while (--longs);
+}
+#endif
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(MD5_CTX *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len)
+{
+ uint32_t t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], MD5_CTX *ctx)
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((uint32_t *) ctx->in)[14] = ctx->bits[0];
+ ((uint32_t *) ctx->in)[15] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ byteReverse((unsigned char *) ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset((char *) ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(uint32_t buf[4], uint32_t const in[16])
+{
+ uint32_t a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/md5.copyright b/plugins/uade2/uade-2.13/src/frontends/common/md5.copyright
new file mode 100644
index 00000000..72b040b3
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/md5.copyright
@@ -0,0 +1,8 @@
+The algorithm is due to Ron Rivest. This code was written by Colin
+Plumb in 1993, no copyright is claimed. This code is in the public
+domain; do with it what you wish.
+.Pp
+Equivalent code is available from RSA Data Security, Inc.
+This code has been tested against that, and is equivalent,
+except that you don't need to include two pages of legalese
+with every copy.
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/md5.h b/plugins/uade2/uade-2.13/src/frontends/common/md5.h
new file mode 100644
index 00000000..6f471e3b
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/md5.h
@@ -0,0 +1,21 @@
+#ifndef _UADE_MD5_H_
+#define _UADE_MD5_H_
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#define MD5_HASHBYTES 16
+
+typedef struct MD5Context {
+ uint32_t buf[4];
+ uint32_t bits[2];
+ unsigned char in[64];
+} MD5_CTX;
+
+void MD5Init(MD5_CTX *context);
+void MD5Update(MD5_CTX *context, unsigned char const *buf,
+ unsigned len);
+void MD5Final(unsigned char digest[MD5_HASHBYTES], MD5_CTX *context);
+void MD5Transform(uint32_t buf[4], uint32_t const in[16]);
+
+#endif /* !_UADE_MD5_H_ */
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/songdb.c b/plugins/uade2/uade-2.13/src/frontends/common/songdb.c
new file mode 100644
index 00000000..b7d79165
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/songdb.c
@@ -0,0 +1,798 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "songdb.h"
+#include "uadeconf.h"
+#include "md5.h"
+#include "unixatomic.h"
+#include "ossupport.h"
+#include "uadeconfig.h"
+#include "support.h"
+#include "uadeconstants.h"
+
+#define NORM_ID "n="
+#define NORM_ID_LENGTH 2
+
+#define eserror(fmt, args...) do { fprintf(stderr, "song.conf error on line %zd: " fmt "\n", lineno, ## args); exit(-1); } while (0)
+
+
+struct eaglesong {
+ int flags;
+ char md5[33];
+ struct uade_attribute *attributes;
+};
+
+struct persub {
+ int sub;
+ char *normalisation;
+};
+
+static struct uade_content *contentchecksums;
+static size_t nccused; /* number of valid entries in content db */
+static size_t nccalloc; /* number of allocated entries for content db */
+static int ccmodified;
+static int cccorrupted;
+
+static int nsongs;
+static struct eaglesong *songstore;
+
+static int escompare(const void *a, const void *b);
+static struct uade_content *get_content(const char *md5);
+
+
+static void add_sub_normalisation(struct uade_content *n, char *normalisation)
+{
+ struct persub *subinfo;
+ char *endptr;
+
+ subinfo = malloc(sizeof(*subinfo));
+ if (subinfo == NULL)
+ uadeerror("Can't allocate memory for normalisation entry\n");
+
+ subinfo->sub = strtol(normalisation, &endptr, 10);
+ if (*endptr != ',' || subinfo->sub < 0) {
+ fprintf(stderr, "Invalid normalisation entry: %s\n", normalisation);
+ return;
+ }
+
+ subinfo->normalisation = strdup(endptr + 1);
+ if (subinfo->normalisation == NULL)
+ uadeerror("Can't allocate memory for normalisation string\n");
+
+ vplist_append(n->subs, subinfo);
+}
+
+/* Compare function for bsearch() and qsort() to sort songs with respect
+ to their md5sums */
+static int contentcompare(const void *a, const void *b)
+{
+ return strcasecmp(((struct uade_content *)a)->md5,
+ ((struct uade_content *)b)->md5);
+}
+
+static int escompare(const void *a, const void *b)
+{
+ return strcasecmp(((struct eaglesong *)a)->md5,
+ ((struct eaglesong *)b)->md5);
+}
+
+static struct uade_content *get_content(const char *md5)
+{
+ struct uade_content key;
+
+ if (contentchecksums == NULL)
+ return NULL;
+
+ memset(&key, 0, sizeof key);
+ strlcpy(key.md5, md5, sizeof key.md5);
+
+ return bsearch(&key, contentchecksums, nccused,
+ sizeof contentchecksums[0], contentcompare);
+}
+
+static struct uade_content *create_content_checksum(const char *md5,
+ uint32_t playtime)
+{
+ struct uade_content *n;
+
+ if (nccused == nccalloc) {
+ nccalloc = MAX(nccalloc * 2, 16);
+ n = realloc(contentchecksums,
+ nccalloc * sizeof(struct uade_content));
+ if (n == NULL) {
+ fprintf(stderr,
+ "uade: No memory for new content checksums.\n");
+ return NULL;
+ }
+ contentchecksums = n;
+ }
+
+ n = &contentchecksums[nccused];
+
+ if (md5 == NULL)
+ return n;
+
+ nccused++;
+
+ ccmodified = 1;
+
+ memset(n, 0, sizeof(*n));
+ strlcpy(n->md5, md5, sizeof(n->md5));
+ n->playtime = playtime;
+
+ n->subs = vplist_create(1);
+
+ return n;
+}
+
+static void md5_from_buffer(char *dest, size_t destlen,
+ uint8_t * buf, size_t bufsize)
+{
+ uint8_t md5[16];
+ int ret;
+ MD5_CTX ctx;
+ MD5Init(&ctx);
+ MD5Update(&ctx, buf, bufsize);
+ MD5Final(md5, &ctx);
+ ret =
+ snprintf(dest, destlen,
+ "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
+ md5[0], md5[1], md5[2], md5[3], md5[4], md5[5], md5[6],
+ md5[7], md5[8], md5[9], md5[10], md5[11], md5[12], md5[13],
+ md5[14], md5[15]);
+ if (ret >= destlen || ret != 32) {
+ fprintf(stderr, "md5 buffer error (%d/%zd)\n", ret, destlen);
+ exit(1);
+ }
+}
+
+static void update_playtime(struct uade_content *n, uint32_t playtime)
+{
+ if (n->playtime != playtime) {
+ ccmodified = 1;
+ n->playtime = playtime;
+ }
+}
+
+static void sort_content_checksums(void)
+{
+ if (contentchecksums == NULL)
+ return;
+
+ qsort(contentchecksums, nccused, sizeof contentchecksums[0],
+ contentcompare);
+}
+
+/* replace must be zero if content db is unsorted */
+struct uade_content *uade_add_playtime(const char *md5, uint32_t playtime)
+{
+ struct uade_content *n;
+
+ /* If content db hasn't been read into memory already, it is not used */
+ if (contentchecksums == NULL)
+ return NULL;
+
+ /* Do not record song shorter than 3 secs */
+ if (playtime < 3000)
+ return NULL;
+
+ if (strlen(md5) != 32)
+ return NULL;
+
+ n = get_content(md5);
+ if (n != NULL) {
+ update_playtime(n, playtime);
+ return n;
+ }
+
+ n = create_content_checksum(md5, playtime);
+
+ sort_content_checksums();
+
+ return n;
+}
+
+void uade_lookup_volume_normalisation(struct uade_state *state)
+{
+ size_t i, nsubs;
+ struct uade_effect *ue = &state->effects;
+ struct uade_config *uc = &state->config;
+ struct uade_song *us = state->song;
+ struct uade_content *content = get_content(us->md5);
+
+ if (content != NULL) {
+
+ nsubs = vplist_len(content->subs);
+
+ for (i = 0; i < nsubs; i++) {
+
+ struct persub *subinfo = vplist_get(content->subs, i);
+
+ if (subinfo->sub == us->cur_subsong) {
+ uade_set_config_option(uc, UC_NORMALISE,
+ subinfo->normalisation);
+ uade_effect_normalise_unserialise(uc->
+ normalise_parameter);
+ uade_effect_enable(ue, UADE_EFFECT_NORMALISE);
+ break;
+ }
+ }
+ }
+}
+
+static void get_song_flags_and_attributes_from_songstore(struct uade_song *us)
+{
+ struct eaglesong key;
+ struct eaglesong *es;
+
+ if (songstore != NULL) {
+ /* Lookup md5 from the songdb */
+ strlcpy(key.md5, us->md5, sizeof key.md5);
+ es = bsearch(&key, songstore, nsongs, sizeof songstore[0], escompare);
+
+ if (es != NULL) {
+ /* Found -> copy flags and attributes from database */
+ us->flags |= es->flags;
+ us->songattributes = es->attributes;
+ }
+ }
+}
+
+int uade_alloc_song(struct uade_state *state, const char *filename)
+{
+ struct uade_song *us;
+ struct uade_content *content;
+
+ state->song = NULL;
+
+ us = calloc(1, sizeof *us);
+ if (us == NULL)
+ goto error;
+
+ strlcpy(us->module_filename, filename, sizeof us->module_filename);
+
+ us->buf = atomic_read_file(&us->bufsize, filename);
+ if (us->buf == NULL)
+ goto error;
+
+ /* Compute an md5sum of the song */
+ md5_from_buffer(us->md5, sizeof us->md5, us->buf, us->bufsize);
+
+ /* Needs us->md5 sum */
+ get_song_flags_and_attributes_from_songstore(us);
+
+ /* Lookup playtime from content database */
+ us->playtime = -1;
+ content = get_content(us->md5);
+ if (content != NULL && content->playtime > 0)
+ us->playtime = content->playtime;
+
+ /* We can't know subsong numbers yet. The eagleplayer will report them
+ * in the playback state */
+ us->min_subsong = us->max_subsong = us->cur_subsong = -1;
+
+ state->song = us;
+ return 1;
+
+ error:
+ if (us != NULL) {
+ free(us->buf);
+ free(us);
+ }
+ return 0;
+}
+
+static int uade_open_and_lock(const char *filename, int create)
+{
+ int fd, ret;
+ fd = open(filename, O_RDWR);
+ if (fd < 0) {
+ if (errno == ENOENT && create) {
+ fd = open(filename, O_RDWR | O_CREAT,
+ S_IRUSR | S_IWUSR);
+ if (fd < 0)
+ return -1;
+ } else {
+ return -1;
+ }
+ }
+#ifndef UADE_HAVE_CYGWIN
+ ret = lockf(fd, F_LOCK, 0);
+ if (ret) {
+ fprintf(stderr, "uade: Unable to lock song.conf: %s (%s)\n",
+ filename, strerror(errno));
+ atomic_close(fd);
+ return -1;
+ }
+#endif
+
+ return fd;
+}
+
+
+static struct uade_content *store_playtime(const char *md5, long playtime,
+ int *newccmodified,
+ size_t oldnccused)
+{
+ struct uade_content *n = NULL;
+
+ if (oldnccused > 0) {
+ struct uade_content key;
+ memset(&key, 0, sizeof key);
+ strlcpy(key.md5, md5, sizeof key.md5);
+
+ /* We use "oldnccused" here as the length, while new entries
+ are added in unsorted manner to the end of the array */
+ n = bsearch(&key, contentchecksums, oldnccused,
+ sizeof contentchecksums[0], contentcompare);
+ if (n == NULL)
+ /* new songs on disk db -> merge -> need saving */
+ *newccmodified = 1;
+ }
+
+ /* We value a playtime determined during run-time over
+ a database value */
+ if (n == NULL) {
+ /* Note, create_content_checksum() makes "ccmodified"
+ true, which we work-around later with the "newccmodified" */
+ n = create_content_checksum(md5, (uint32_t) playtime);
+ }
+
+ if (n == NULL) {
+ /* No memory, fuck. We shouldn't save anything to
+ avoid losing data. */
+ fprintf(stderr,
+ "uade: Warning, no memory for the song database\n");
+ cccorrupted = 1;
+ }
+
+ return n;
+}
+
+
+
+int uade_read_content_db(const char *filename)
+{
+ char line[1024];
+ FILE *f;
+ size_t lineno = 0;
+ long playtime;
+ int i, j, nexti;
+ char *id, *eptr;
+ char numberstr[1024];
+ char *md5;
+
+ /* We make backups of some variables because following loop will
+ make it always true, which is not what we want. The end result should
+ be that ccmodified is true in following cases only:
+ 1. the in-memory db is already dirty
+ 2. the in-memory db gets new data from disk db (merge operation)
+ Otherwise ccmodified should be false. */
+ int newccmodified = ccmodified;
+ size_t oldnccused = nccused;
+ int fd;
+ struct uade_content *n;
+
+ /* Try to create a database if it doesn't exist */
+ if (contentchecksums == NULL
+ && create_content_checksum(NULL, 0) == NULL)
+ return 0;
+
+ fd = uade_open_and_lock(filename, 0);
+ if (fd < 0) {
+ fprintf(stderr, "uade: Can not find %s\n", filename);
+ return 0;
+ }
+
+ f = fdopen(fd, "r");
+ if (f == NULL) {
+ fprintf(stderr, "uade: Can not create FILE structure for %s\n",
+ filename);
+ close(fd);
+ return 0;
+ }
+
+ while (xfgets(line, sizeof line, f) != NULL) {
+ lineno++;
+
+ if (line[0] == '#')
+ continue;
+
+ md5 = line;
+ i = skip_and_terminate_word(line, 0);
+ if (i < 0)
+ continue; /* playtime doesn't exist */
+
+ for (j = 0; isxdigit(line[j]); j++);
+
+ if (j != 32)
+ continue; /* is not a valid md5sum */
+
+ /* Grab and validate playtime (in milliseconds) */
+ nexti = skip_and_terminate_word(line, i);
+
+ playtime = strtol(&line[i], &eptr, 10);
+ if (*eptr != 0 || playtime < 0) {
+ fprintf(stderr, "Invalid playtime for md5 %s on contentdb line %zd: %s\n", md5, lineno, numberstr);
+ continue;
+ }
+
+ n = store_playtime(md5, playtime, &newccmodified, oldnccused);
+ if (n == NULL)
+ continue;
+
+ i = nexti; /* Note, it could be that i < 0 */
+
+ /* Get rest of the directives in a loop */
+ while (i >= 0) {
+ id = &line[i];
+ i = skip_and_terminate_word(line, i);
+
+ /* Subsong volume normalisation: n=sub1,XXX */
+ if (strncmp(id, NORM_ID, NORM_ID_LENGTH) == 0) {
+ id += NORM_ID_LENGTH;
+ add_sub_normalisation(n, id);
+ } else {
+ fprintf(stderr, "Unknown contentdb directive on line %zd: %s\n", lineno, id);
+ }
+ }
+ }
+ fclose(f);
+
+ ccmodified = newccmodified;
+
+ sort_content_checksums();
+
+ return 1;
+}
+
+int uade_read_song_conf(const char *filename)
+{
+ FILE *f = NULL;
+ struct eaglesong *s;
+ size_t allocated;
+ size_t lineno = 0;
+ size_t i;
+ int fd;
+
+ fd = uade_open_and_lock(filename, 1);
+ /* open_and_lock() may fail without harm (it's actually supposed to
+ fail if the process does not have lock (write) permissions to
+ the song.conf file */
+
+ f = fopen(filename, "r");
+ if (f == NULL)
+ goto error;
+
+ nsongs = 0;
+ allocated = 16;
+ songstore = calloc(allocated, sizeof songstore[0]);
+ if (songstore == NULL)
+ eserror("No memory for song store.");
+
+ while (1) {
+ char **items;
+ size_t nitems;
+
+ items = read_and_split_lines(&nitems, &lineno, f,
+ UADE_WS_DELIMITERS);
+ if (items == NULL)
+ break;
+
+ assert(nitems > 0);
+
+ if (nsongs == allocated) {
+ allocated *= 2;
+ songstore = realloc(songstore, allocated * sizeof(songstore[0]));
+ if (songstore == NULL)
+ eserror("No memory for players.");
+ }
+
+ s = &songstore[nsongs];
+ nsongs++;
+
+ memset(s, 0, sizeof s[0]);
+
+ if (strncasecmp(items[0], "md5=", 4) != 0) {
+ fprintf(stderr, "Line %zd must begin with md5= in %s\n",
+ lineno, filename);
+ free(items);
+ continue;
+ }
+ if (strlcpy(s->md5, items[0] + 4, sizeof s->md5) !=
+ ((sizeof s->md5) - 1)) {
+ fprintf(stderr,
+ "Line %zd in %s has too long an md5sum.\n",
+ lineno, filename);
+ free(items);
+ continue;
+ }
+
+ for (i = 1; i < nitems; i++) {
+ if (strncasecmp(items[i], "comment:", 7) == 0)
+ break;
+ if (uade_song_and_player_attribute(&s->attributes, &s->flags, items[i], lineno))
+ continue;
+ fprintf(stderr, "song option %s is invalid\n", items[i]);
+ }
+
+ for (i = 0; items[i] != NULL; i++)
+ free(items[i]);
+
+ free(items);
+ }
+
+ fclose(f);
+
+ /* we may not have the file locked */
+ if (fd >= 0)
+ atomic_close(fd); /* lock is closed too */
+
+ /* Sort MD5 sums for binary searching songs */
+ qsort(songstore, nsongs, sizeof songstore[0], escompare);
+ return 1;
+
+ error:
+ if (f)
+ fclose(f);
+ if (fd >= 0)
+ atomic_close(fd);
+ return 0;
+}
+
+void uade_save_content_db(const char *filename)
+{
+ int fd;
+ FILE *f;
+ size_t i;
+
+ if (ccmodified == 0 || cccorrupted)
+ return;
+
+ fd = uade_open_and_lock(filename, 1);
+ if (fd < 0) {
+ fprintf(stderr, "uade: Can not write content db: %s\n",
+ filename);
+ return;
+ }
+
+ f = fdopen(fd, "w");
+ if (f == NULL) {
+ fprintf(stderr,
+ "uade: Can not create a FILE structure for content db: %s\n",
+ filename);
+ close(fd);
+ return;
+ }
+
+ for (i = 0; i < nccused; i++) {
+ char str[1024];
+ size_t subi, nsubs;
+ size_t bindex, bleft;
+ struct uade_content *n = &contentchecksums[i];
+
+ str[0] = 0;
+
+ bindex = 0;
+ bleft = sizeof(str);
+
+ nsubs = vplist_len(n->subs);
+
+ for (subi = 0; subi < nsubs; subi++) {
+ struct persub *sub = vplist_get(n->subs, subi);
+ int ret;
+ ret =
+ snprintf(&str[bindex], bleft, NORM_ID "%s ",
+ sub->normalisation);
+ if (ret >= bleft) {
+ fprintf(stderr,
+ "Too much subsong infos for %s\n",
+ n->md5);
+ break;
+ }
+ bleft -= ret;
+ bindex += ret;
+ }
+
+ fprintf(f, "%s %u %s\n", n->md5, (unsigned int)n->playtime,
+ str);
+ }
+
+ ccmodified = 0;
+
+ fclose(f);
+ fprintf(stderr, "uade: Saved %zd entries into content db.\n", nccused);
+}
+
+int uade_test_silence(void *buf, size_t size, struct uade_state *state)
+{
+ int i, s, exceptioncount;
+ int16_t *sm;
+ int nsamples;
+ int64_t count = state->song->silence_count;
+ int end = 0;
+
+ if (state->config.silence_timeout < 0)
+ return 0;
+
+ exceptioncount = 0;
+ sm = buf;
+ nsamples = size / 2;
+
+ for (i = 0; i < nsamples; i++) {
+ s = (sm[i] >= 0) ? sm[i] : -sm[i];
+ if (s >= (32767 * 1 / 100)) {
+ exceptioncount++;
+ if (exceptioncount >= (size * 2 / 100)) {
+ count = 0;
+ break;
+ }
+ }
+ }
+
+ if (i == nsamples) {
+ count += size;
+ if (count / (UADE_BYTES_PER_FRAME * state->config.frequency) >= state->config.silence_timeout) {
+ count = 0;
+ end = 1;
+ }
+ }
+
+ state->song->silence_count = count;
+
+ return end;
+}
+
+void uade_unalloc_song(struct uade_state *state)
+{
+ free(state->song->buf);
+ state->song->buf = NULL;
+
+ free(state->song);
+ state->song = NULL;
+}
+
+int uade_update_song_conf(const char *songconfin, const char *songconfout,
+ const char *songname, const char *options)
+{
+ int ret;
+ int fd;
+ char md5[33];
+ void *mem = NULL;
+ size_t filesize, newsize;
+ int found = 0;
+ size_t inputsize;
+ char *input, *inputptr, *outputptr;
+ size_t inputoffs;
+ char newline[256];
+ size_t i;
+ int need_newline = 0;
+
+ if (strlen(options) > 128) {
+ fprintf(stderr, "Too long song.conf options.\n");
+ return 0;
+ }
+
+ fd = uade_open_and_lock(songconfout, 1);
+
+ input = atomic_read_file(&inputsize, songconfin);
+ if (input == NULL) {
+ fprintf(stderr, "Can not read song.conf: %s\n", songconfin);
+ atomic_close(fd); /* closes the lock too */
+ return 0;
+ }
+
+ newsize = inputsize + strlen(options) + strlen(songname) + 64;
+ mem = realloc(input, newsize);
+ if (mem == NULL) {
+ fprintf(stderr,
+ "Can not realloc the input file buffer for song.conf.\n");
+ free(input);
+ atomic_close(fd); /* closes the lock too */
+ return 0;
+ }
+ input = mem;
+
+ mem = atomic_read_file(&filesize, songname);
+ if (mem == NULL)
+ goto error;
+
+ md5_from_buffer(md5, sizeof md5, mem, filesize);
+
+ inputptr = outputptr = input;
+ inputoffs = 0;
+
+ while (inputoffs < inputsize) {
+ if (inputptr[0] == '#')
+ goto copyline;
+
+ if ((inputoffs + 37) >= inputsize)
+ goto copyline;
+
+ if (strncasecmp(inputptr, "md5=", 4) != 0)
+ goto copyline;
+
+ if (strncasecmp(inputptr + 4, md5, 32) == 0) {
+ if (found) {
+ fprintf(stderr,
+ "Warning: dupe entry in song.conf: %s (%s)\n"
+ "Need manual resolving.\n", songname,
+ md5);
+ goto copyline;
+ }
+ found = 1;
+ snprintf(newline, sizeof newline, "md5=%s\t%s\n", md5,
+ options);
+
+ /* Skip this line. It will be appended later to the end of the buffer */
+ for (i = inputoffs; i < inputsize; i++) {
+ if (input[i] == '\n') {
+ i = i + 1 - inputoffs;
+ break;
+ }
+ }
+ if (i == inputsize) {
+ i = inputsize - inputoffs;
+ found = 0;
+ need_newline = 1;
+ }
+ inputoffs += i;
+ inputptr += i;
+ continue;
+ }
+
+ copyline:
+ /* Copy the line */
+ for (i = inputoffs; i < inputsize; i++) {
+ if (input[i] == '\n') {
+ i = i + 1 - inputoffs;
+ break;
+ }
+ }
+ if (i == inputsize) {
+ i = inputsize - inputoffs;
+ need_newline = 1;
+ }
+ memmove(outputptr, inputptr, i);
+ inputoffs += i;
+ inputptr += i;
+ outputptr += i;
+ }
+
+ if (need_newline) {
+ snprintf(outputptr, 2, "\n");
+ outputptr += 1;
+ }
+
+ /* there is enough space */
+ ret = snprintf(outputptr, PATH_MAX + 256, "md5=%s\t%s\tcomment %s\n",
+ md5, options, songname);
+ outputptr += ret;
+
+ if (ftruncate(fd, 0)) {
+ fprintf(stderr, "Can not truncate the file.\n");
+ goto error;
+ }
+
+ /* Final file size */
+ i = (size_t) (outputptr - input);
+
+ if (atomic_write(fd, input, i) < i)
+ fprintf(stderr,
+ "Unable to write file contents back. Data loss happened. CRAP!\n");
+
+ error:
+ atomic_close(fd); /* Closes the lock too */
+ free(input);
+ free(mem);
+ return 1;
+}
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/songdb.h b/plugins/uade2/uade-2.13/src/frontends/common/songdb.h
new file mode 100644
index 00000000..8cbba160
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/songdb.h
@@ -0,0 +1,24 @@
+#ifndef _UADE_SONGDB_H_
+#define _UADE_SONGDB_H_
+
+#include "uadestate.h"
+#include "vplist.h"
+
+struct uade_content {
+ char md5[33];
+ uint32_t playtime; /* in milliseconds */
+ struct vplist *subs;
+};
+
+struct uade_content *uade_add_playtime(const char *md5, uint32_t playtime);
+int uade_alloc_song(struct uade_state *state, const char *filename);
+void uade_lookup_volume_normalisation(struct uade_state *state);
+int uade_read_content_db(const char *filename);
+int uade_read_song_conf(const char *filename);
+void uade_save_content_db(const char *filename);
+int uade_test_silence(void *buf, size_t size, struct uade_state *state);
+void uade_unalloc_song(struct uade_state *state);
+int uade_update_song_conf(const char *songconfin, const char *songconfout,
+ const char *songname, const char *options);
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/songinfo.c b/plugins/uade2/uade-2.13/src/frontends/common/songinfo.c
new file mode 100644
index 00000000..5997b183
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/songinfo.c
@@ -0,0 +1,721 @@
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdint.h>
+#include <ctype.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "songinfo.h"
+#include "uadeutils.h"
+#include "ossupport.h"
+#include "amifilemagic.h"
+#include "support.h"
+
+
+static void asciiline(char *dst, unsigned char *buf)
+{
+ int i, c;
+ for (i = 0; i < 16; i++) {
+ c = buf[i];
+ if (isgraph(c) || c == ' ') {
+ dst[i] = c;
+ } else {
+ dst[i] = '.';
+ }
+ }
+ dst[i] = 0;
+}
+
+static int hexdump(char *info, size_t maxlen, char *filename, size_t toread)
+{
+ FILE *f;
+ size_t rb, ret;
+ uint8_t *buf;
+
+ assert(maxlen >= 8192);
+
+ f = fopen(filename, "rb");
+ if (f == NULL)
+ return 0;
+
+ buf = malloc(toread);
+ if (buf == NULL)
+ return 0;
+
+ rb = 0;
+ while (rb < toread) {
+ ret = fread(&buf[rb], 1, toread - rb, f);
+ if (ret == 0)
+ break;
+ rb += ret;
+ }
+
+ if (rb > 0) {
+ size_t roff = 0;
+ size_t woff = 0;
+
+ while (roff < rb) {
+ int iret;
+
+ if (woff >= maxlen)
+ break;
+
+ if (woff + 32 >= maxlen) {
+ strcpy(&info[woff], "\nbuffer overflow...\n");
+ woff += strlen(&info[woff]);
+ break;
+ }
+
+ iret = snprintf(&info[woff], maxlen - woff, "%.3zx: ",
+ roff);
+ assert(iret > 0);
+ woff += iret;
+
+ if (woff >= maxlen)
+ break;
+
+ if (roff + 16 > rb) {
+ iret = snprintf(&info[woff], maxlen - woff,
+ "Aligned line ");
+ assert(iret > 0);
+ woff += iret;
+
+ } else {
+ char dbuf[17];
+ asciiline(dbuf, &buf[roff]);
+ iret = snprintf(&info[woff], maxlen - woff,
+ "%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x |%s|",
+ buf[roff + 0], buf[roff + 1],
+ buf[roff + 2], buf[roff + 3],
+ buf[roff + 4], buf[roff + 5],
+ buf[roff + 6], buf[roff + 7],
+ buf[roff + 8], buf[roff + 9],
+ buf[roff + 10], buf[roff + 11],
+ buf[roff + 12], buf[roff + 13],
+ buf[roff + 14], buf[roff + 15],
+ dbuf);
+ assert(iret > 0);
+ woff += iret;
+ }
+
+ if (woff >= maxlen)
+ break;
+
+ iret = snprintf(&info[woff], maxlen - woff, "\n");
+ woff += iret;
+
+ roff += 16;
+ }
+
+ if (woff >= maxlen)
+ woff = maxlen - 1;
+ info[woff] = 0;
+ }
+
+ fclose(f);
+ free(buf);
+ return rb == 0;
+}
+
+static size_t find_tag(uint8_t * buf, size_t startoffset, size_t buflen,
+ uint8_t * tag, size_t taglen)
+{
+ uint8_t *treasure;
+
+ if (startoffset >= buflen)
+ return -1;
+
+ treasure = memmem(buf + startoffset, buflen - startoffset, tag, taglen);
+ if (treasure == NULL)
+ return -1;
+
+ return (size_t) (treasure - buf);
+}
+
+static int string_checker(unsigned char *str, size_t off, size_t maxoff)
+{
+ assert(maxoff > 0);
+ while (off < maxoff) {
+ if (*str == 0)
+ return 1;
+ off++;
+ str++;
+ }
+ return 0;
+}
+
+/* Wanted Team's loadseg modules */
+static void process_WTWT_mod(char *credits, size_t credits_len,
+ unsigned char *buf, size_t len, char *lo,
+ char *hi, int rel)
+{
+ int offset, txt_offset, chunk;
+ char tmpstr[256];
+
+ /* check for Magic ID */
+ offset = find_tag((uint8_t *) buf, 0, len, (uint8_t *) lo, 4);
+ if (offset == -1)
+ return;
+
+ offset =
+ find_tag((uint8_t *) buf, offset + 4, offset + 8, (uint8_t *) hi,
+ 4);
+ if (offset == -1)
+ return;
+
+ chunk = offset - 8; /* here's where our first chunk should be */
+ offset = offset + rel; /* offset to our info pointers */
+
+ if (chunk < len && offset < len) {
+ txt_offset = read_be_u32(buf + offset) + chunk;
+ if (txt_offset < len && txt_offset != chunk) {
+ if (!string_checker(buf, txt_offset, len))
+ return;
+ snprintf(tmpstr, sizeof tmpstr, "\nMODULENAME:\n %s\n",
+ buf + txt_offset);
+ strlcat(credits, tmpstr, credits_len);
+
+ }
+ txt_offset = read_be_u32(buf + offset + 4) + chunk;
+ if (txt_offset < len && txt_offset != chunk) {
+ if (!string_checker(buf, txt_offset, len))
+ return;
+ snprintf(tmpstr, sizeof tmpstr, "\nAUTHORNAME:\n %s\n",
+ buf + txt_offset);
+ strlcat(credits, tmpstr, credits_len);
+ }
+
+ txt_offset = read_be_u32(buf + offset + 8) + chunk;
+ if (txt_offset < len && txt_offset != chunk) {
+ if (!string_checker(buf, txt_offset, len))
+ return;
+ snprintf(tmpstr, sizeof tmpstr, "\nSPECIALINFO:\n %s",
+ buf + txt_offset);
+ strlcat(credits, tmpstr, credits_len);
+ }
+ }
+}
+
+/* Get the info out of the AHX module data*/
+static void process_ahx_mod(char *credits, size_t credits_len,
+ unsigned char *buf, size_t len)
+{
+ int i;
+ size_t offset;
+ char tmpstr[256];
+
+ if (len < 13)
+ return;
+
+ offset = read_be_u16(buf + 4);
+
+ if (offset >= len)
+ return;
+
+ if (!string_checker(buf, offset, len))
+ return;
+
+ snprintf(tmpstr, sizeof tmpstr, "\nSong title: %s\n", buf + offset);
+ strlcat(credits, tmpstr, credits_len);
+
+ for (i = 0; i < buf[12]; i++) {
+ if (!string_checker(buf, offset, len))
+ break;
+ offset = offset + 1 + strlen((char *)buf + offset);
+ if (offset < len) {
+ snprintf(tmpstr, 256, "\n %s", buf + offset);
+ strlcat(credits, tmpstr, credits_len);
+ }
+ }
+}
+
+/* Get the info out of the protracker module data*/
+static void process_ptk_mod(char *credits, size_t credits_len, int inst,
+ uint8_t * buf, size_t len)
+{
+ int i;
+ char tmpstr[256];
+
+ if (!string_checker(buf, 0, len))
+ return;
+
+ snprintf(tmpstr, 35, "\nSong title: %s", buf);
+ strlcat(credits, tmpstr, credits_len);
+
+ if (inst == 31) {
+ if (len >= 0x43c) {
+ snprintf(tmpstr, sizeof tmpstr,
+ "\nmax positions: %d\n", buf[0x3b6]);
+ strlcat(credits, tmpstr, credits_len);
+ }
+ } else {
+ if (len >= 0x1da) {
+ snprintf(tmpstr, sizeof tmpstr,
+ "\nmax positions: %d\n", buf[0x1d6]);
+ strlcat(credits, tmpstr, credits_len);
+ }
+ }
+
+ snprintf(tmpstr, sizeof tmpstr, "\nINST - NAME SIZE VOL FINE LSTART LSIZE\n");
+ strlcat(credits, tmpstr, credits_len);
+ if (len >= (0x14 + inst * 0x1e)) {
+ for (i = 0; i < inst; i++) {
+ if (!string_checker(buf, 0x14 + i * 0x1e, len))
+ break;
+ snprintf(tmpstr, sizeof tmpstr, "[%2d] - ", i + 1);
+ strlcat(credits, tmpstr, credits_len);
+ snprintf(tmpstr, 23, "%-23s", buf + 0x14 + (i * 0x1e));
+ strlcat(credits, tmpstr, credits_len);
+ snprintf(tmpstr, sizeof tmpstr,
+ " %6d %2d %2d %6d %6d\n",
+ read_be_u16(buf + 42 + i * 0x1e) * 2,
+ buf[45 + i * 0x1e], buf[44 + i * 0x1e],
+ read_be_u16(buf + 46 + i * 0x1e) * 2,
+ read_be_u16(buf + 48 + i * 0x1e) * 2);
+ strlcat(credits, tmpstr, credits_len);
+ }
+ }
+}
+
+/* Get the info out of the digibooster module data*/
+static void process_digi_mod(char *credits, size_t credits_len,
+ uint8_t * buf, size_t len)
+{
+ int i;
+ char tmpstr[256];
+
+ if (len < (642 + 0x30 * 0x1e))
+ return;
+
+ if (!string_checker(buf, 610, len))
+ return;
+
+ snprintf(tmpstr, 0x2f, "\nSong title: %s \n", buf + 610);
+ strlcat(credits, tmpstr, credits_len);
+
+ snprintf(tmpstr, sizeof tmpstr, "max positions: %d\n", buf[47]);
+ strlcat(credits, tmpstr, credits_len);
+
+ snprintf(tmpstr, sizeof tmpstr, "\nINST - NAME SIZE VOL FINE LSTART LSIZE\n");
+ strlcat(credits, tmpstr, credits_len);
+ if (len >= (642 + 0x1f * 0x1e)) {
+ for (i = 0; i < 0x1f; i++) {
+ if (!string_checker(buf, 642 + i * 0x1e, len))
+ break;
+ snprintf(tmpstr, sizeof tmpstr, "[%2d] - ", i + 1);
+ strlcat(credits, tmpstr, credits_len);
+ snprintf(tmpstr, 30, "%-30s", buf + 642 + (i * 0x1e));
+ strlcat(credits, tmpstr, credits_len);
+ snprintf(tmpstr, sizeof tmpstr,
+ " %11d %2d %3d %11d %11d\n",
+ read_be_u32(buf + 176 + i * 4), buf[548 + i],
+ buf[579 + i], read_be_u32(buf + 300 + i * 4),
+ read_be_u32(buf + 424 + i * 4));
+ strlcat(credits, tmpstr, credits_len);
+ }
+ }
+}
+
+/* Get the info out of custom song. FIX ME, clean this function. */
+static void process_custom(char *credits, size_t credits_len,
+ unsigned char *buf, size_t len)
+{
+ char tmpstr[1024];
+ unsigned char *hunk;
+ unsigned char *tag_table;
+ int hunk_size;
+ int table_size;
+
+ int i;
+ int offset;
+ unsigned int x, y;
+ unsigned char startpattern[4] = { 0x70, 0xff, 0x4e, 0x75 };
+
+ if (len < 4)
+ return;
+
+ if (read_be_u32(buf) != 0x000003f3)
+ return;
+
+ i = find_tag(buf, 0, len, startpattern, sizeof startpattern);
+ if (i == -1 || (i + 12) >= len)
+ return;
+
+ if (strncmp((char *)buf + i + 4, "DELIRIUM", 8) != 0 &&
+ strncmp((char *)buf + i + 4, "EPPLAYER", 8) != 0) {
+ return;
+ }
+
+ /* Hunk found */
+ hunk = buf + i;
+ hunk_size = len - i;
+
+ if (16 + i + 5 >= hunk_size)
+ return;
+
+ /* Check if $VER is available */
+ if (!memcmp(&hunk[16], "$VER:", 5)) {
+ offset = 16 + 5;
+ while (offset < hunk_size) {
+ if (memcmp(&hunk[offset], " ", 1))
+ break;
+ offset++;
+ }
+ if (offset >= hunk_size)
+ return;
+
+ if ((offset + strlen((char *)hunk + offset) + 1) >
+ ((size_t) hunk_size))
+ return;
+
+ snprintf(tmpstr, sizeof tmpstr, "\nVERSION:\n%s\n\n",
+ hunk + offset);
+ strlcat(credits, tmpstr, credits_len);
+ }
+
+ offset = read_be_u32(hunk + 12);
+ if (offset < 0) {
+ return;
+ }
+
+ tag_table = hunk + offset;
+
+ if (tag_table >= &buf[len])
+ return;
+
+ table_size = ((int)(&buf[len] - tag_table)) / 8;
+
+ if (table_size <= 0)
+ return;
+
+ /* check all tags in this loop */
+ for (i = 0; i < table_size; i += 2) {
+ x = read_be_u32(tag_table + 4 * i);
+ y = read_be_u32(tag_table + 4 * (i + 1));
+
+ if (!x)
+ break;
+
+ switch (x) {
+ case 0x8000445a:
+ if (y >= ((unsigned int)hunk_size))
+ return;
+ if ((y + strlen((char *)hunk + y) + 1) >
+ ((size_t) hunk_size))
+ return;
+ snprintf(tmpstr, sizeof tmpstr, "\nCREDITS:\n%s\n\n",
+ hunk + y);
+ strlcat(credits, tmpstr, credits_len);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * Get the info out of the Deltamusic 2 module data
+ */
+static void process_dm2_mod(char *credits, size_t credits_len,
+ unsigned char *buf, size_t len)
+{
+ char tmpstr[256];
+ if (!string_checker(buf, 0x148, len))
+ return;
+ snprintf(tmpstr, sizeof tmpstr, "\nRemarks:\n%s", buf + 0x148);
+ strlcat(credits, tmpstr, credits_len);
+}
+
+static int process_module(char *credits, size_t credits_len, char *filename)
+{
+ FILE *modfile;
+ struct stat st;
+ size_t modfilelen;
+ unsigned char *buf;
+ char pre[11];
+ char tmpstr[256];
+ size_t rb;
+
+ if (!(modfile = fopen(filename, "rb")))
+ return 0;
+
+ if (fstat(fileno(modfile), &st))
+ return 0;
+
+ modfilelen = st.st_size;
+
+ if ((buf = malloc(modfilelen)) == NULL) {
+ fprintf(stderr, "uade: can't allocate mem in process_module()");
+ fclose(modfile);
+ return 0;
+ }
+
+ rb = 0;
+ while (rb < modfilelen) {
+ size_t ret = fread(&buf[rb], 1, modfilelen - rb, modfile);
+ if (ret == 0)
+ break;
+ rb += ret;
+ }
+
+ fclose(modfile);
+
+ if (rb < modfilelen) {
+ fprintf(stderr, "uade: song info could not read %s fully\n",
+ filename);
+ free(buf);
+ return 0;
+ }
+
+ snprintf(tmpstr, sizeof tmpstr, "UADE2 MODINFO:\n\nFile name: %s\nFile length: %zd bytes\n", filename, modfilelen);
+ strlcpy(credits, tmpstr, credits_len);
+
+ /* Get filetype in pre */
+ uade_filemagic(buf, modfilelen, pre, modfilelen, filename, 0);
+
+ snprintf(tmpstr, sizeof tmpstr, "File prefix: %s.*\n", pre);
+ strlcat(credits, tmpstr, credits_len);
+
+ if (strcasecmp(pre, "CUST") == 0) {
+ /* CUST */
+ process_custom(credits, credits_len, buf, modfilelen);
+
+ } else if (strcasecmp(pre, "DM2") == 0) {
+ /* DM2 */
+ process_dm2_mod(credits, credits_len, buf, modfilelen);
+
+ } else if (strcasecmp(pre, "DIGI") == 0) {
+ /* DIGIBooster */
+ process_digi_mod(credits, credits_len, buf, modfilelen);
+
+ } else if ((strcasecmp(pre, "AHX") == 0) ||
+ (strcasecmp(pre, "THX") == 0)) {
+ /* AHX */
+ process_ahx_mod(credits, credits_len, buf, modfilelen);
+
+ } else if ((strcasecmp(pre, "MOD15") == 0) ||
+ (strcasecmp(pre, "MOD15_UST") == 0) ||
+ (strcasecmp(pre, "MOD15_MST") == 0) ||
+ (strcasecmp(pre, "MOD15_ST-IV") == 0)) {
+ /*MOD15 */
+ process_ptk_mod(credits, credits_len, 15, buf, modfilelen);
+
+ } else if ((strcasecmp(pre, "MOD") == 0) ||
+ (strcasecmp(pre, "MOD_DOC") == 0) ||
+ (strcasecmp(pre, "MOD_NTK") == 0) ||
+ (strcasecmp(pre, "MOD_NTK1") == 0) ||
+ (strcasecmp(pre, "MOD_NTK2") == 0) ||
+ (strcasecmp(pre, "MOD_FLT4") == 0) ||
+ (strcasecmp(pre, "MOD_FLT8") == 0) ||
+ (strcasecmp(pre, "MOD_ADSC4") == 0) ||
+ (strcasecmp(pre, "MOD_ADSC8") == 0) ||
+ (strcasecmp(pre, "MOD_COMP") == 0) ||
+ (strcasecmp(pre, "MOD_NTKAMP") == 0) ||
+ (strcasecmp(pre, "PPK") == 0) ||
+ (strcasecmp(pre, "MOD_PC") == 0) ||
+ (strcasecmp(pre, "ICE") == 0) ||
+ (strcasecmp(pre, "ADSC") == 0)) {
+ /*MOD*/
+ process_ptk_mod(credits, credits_len, 31, buf, modfilelen);
+ } else if (strcasecmp(pre, "DL") == 0) {
+ process_WTWT_mod(credits, credits_len, buf, modfilelen, "UNCL",
+ "EART", 0x28);
+ } else if (strcasecmp(pre, "BSS") == 0) {
+ process_WTWT_mod(credits, credits_len, buf, modfilelen, "BEAT",
+ "HOVE", 0x1c);
+ } else if (strcasecmp(pre, "GRAY") == 0) {
+ process_WTWT_mod(credits, credits_len, buf, modfilelen, "FRED",
+ "GRAY", 0x10);
+ } else if (strcasecmp(pre, "JMF") == 0) {
+ process_WTWT_mod(credits, credits_len, buf, modfilelen, "J.FL",
+ "OGEL", 0x14);
+ } else if (strcasecmp(pre, "SPL") == 0) {
+ process_WTWT_mod(credits, credits_len, buf, modfilelen, "!SOP",
+ "ROL!", 0x10);
+ } else if (strcasecmp(pre, "HD") == 0) {
+ process_WTWT_mod(credits, credits_len, buf, modfilelen, "H.DA",
+ "VIES", 24);
+ } else if (strcasecmp(pre, "RIFF") == 0) {
+ process_WTWT_mod(credits, credits_len, buf, modfilelen, "RIFF",
+ "RAFF", 0x14);
+ } else if (strcasecmp(pre, "FP") == 0) {
+ process_WTWT_mod(credits, credits_len, buf, modfilelen, "F.PL",
+ "AYER", 0x8);
+ } else if (strcasecmp(pre, "CORE") == 0) {
+ process_WTWT_mod(credits, credits_len, buf, modfilelen, "S.PH",
+ "IPPS", 0x20);
+ } else if (strcasecmp(pre, "BDS") == 0) {
+ process_WTWT_mod(credits, credits_len, buf, modfilelen, "DAGL",
+ "ISH!", 0x14);
+ }
+
+ free(buf);
+
+ return 0;
+}
+
+int uade_generate_song_title(char *title, size_t dstlen,
+ struct uade_state *state)
+{
+ size_t srcoffs;
+ size_t dstoffs;
+ size_t srclen;
+ char *format;
+ char *bname;
+ char p[64];
+ char *default_format = "%F %X [%P]";
+ struct uade_song *us = state->song;
+ struct uade_config *uc = &state->config;
+
+ /* %A min subsong
+ %B cur subsong
+ %C max subsong
+ %F file base name (us->module_filename)
+ %P player name
+ %T title
+ %X print subsong info if more than one subsong exist
+ */
+
+ format = uc->song_title;
+
+ if (format == NULL)
+ format = default_format;
+
+ if (strcmp("default", format) == 0)
+ format = default_format;
+
+ if ((srclen = strlen(format)) == 0) {
+ fprintf(stderr, "Warning: empty song_title format string.\n");
+ return 1;
+ }
+
+ if (dstlen == 0)
+ return 1;
+
+ if (strlen(us->module_filename) == 0)
+ return 1;
+
+ bname = xbasename(us->module_filename);
+
+ p[0] = 0;
+ if (us->formatname[0] == 0) {
+ if (us->playername[0] == 0) {
+ strlcpy(p, "Custom", sizeof p);
+ } else {
+ strlcpy(p, us->playername, sizeof p);
+ }
+ } else {
+ if (strncmp(us->formatname, "type: ", 6) == 0) {
+ strlcpy(p, us->formatname + 6, sizeof p);
+ } else {
+ strlcpy(p, us->formatname, sizeof p);
+ }
+ }
+
+ srcoffs = dstoffs = 0;
+
+ title[0] = 0;
+
+ while (dstoffs < dstlen) {
+ char c;
+ if (srcoffs >= srclen)
+ break;
+
+ if ((c = format[srcoffs]) == 0)
+ break;
+
+ if (c != '%') {
+ title[dstoffs++] = format[srcoffs++];
+ } else {
+ size_t inc;
+ char *dat = NULL;
+ char tmp[32];
+
+ if ((srcoffs + 1) >= srclen) {
+ fprintf(stderr, "Error: no identifier given in song title format: %s\n", format);
+ title[dstoffs] = 0;
+ return 1;
+ }
+
+ c = format[srcoffs + 1];
+
+ switch (c) {
+ case 'A':
+ snprintf(tmp, sizeof tmp, "%d",
+ us->min_subsong);
+ dat = tmp;
+ break;
+ case 'B':
+ snprintf(tmp, sizeof tmp, "%d",
+ us->cur_subsong);
+ dat = tmp;
+ break;
+ case 'C':
+ snprintf(tmp, sizeof tmp, "%d",
+ us->max_subsong);
+ dat = tmp;
+ break;
+ case 'F':
+ dat = bname;
+ break;
+ case 'P':
+ dat = p;
+ break;
+ case 'T':
+ dat = us->modulename;
+ if (strcmp("<no songtitle>", dat) == 0)
+ dat[0] = 0;
+ if (dat[0] == 0)
+ dat = bname;
+ break;
+ case 'X':
+ if (us->min_subsong == us->max_subsong) {
+ tmp[0] = 0;
+ } else {
+ snprintf(tmp, sizeof tmp, "(%d/%d)",
+ us->cur_subsong,
+ us->max_subsong);
+ }
+ dat = tmp;
+ break;
+ default:
+ fprintf(stderr,
+ "Unknown identifier %%%c in song_title format: %s\n",
+ c, format);
+ title[dstoffs] = 0;
+ return 1;
+ }
+ inc = strlcpy(&title[dstoffs], dat, dstlen - dstoffs);
+ srcoffs += 2;
+ dstoffs += inc;
+ }
+ }
+
+ if (dstoffs < dstlen)
+ title[dstoffs] = 0;
+ else
+ title[dstlen - 1] = 0;
+
+ return 0;
+}
+
+/* Returns zero on success, non-zero otherwise. */
+int uade_song_info(char *info, size_t maxlen, char *filename,
+ enum song_info_type type)
+{
+ switch (type) {
+ case UADE_MODULE_INFO:
+ return process_module(info, maxlen, filename);
+ case UADE_HEX_DUMP_INFO:
+ return hexdump(info, maxlen, filename, 2048);
+ default:
+ fprintf(stderr, "Illegal info requested.\n");
+ exit(-1);
+ }
+ return 0;
+}
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/songinfo.h b/plugins/uade2/uade-2.13/src/frontends/common/songinfo.h
new file mode 100644
index 00000000..e0abd059
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/songinfo.h
@@ -0,0 +1,19 @@
+#ifndef _UADE_SONG_INFO_
+#define _UADE_SONG_INFO_
+
+#include <stdio.h>
+
+#include "uadestate.h"
+
+enum song_info_type {
+ UADE_MODULE_INFO = 0,
+ UADE_HEX_DUMP_INFO,
+ UADE_NUMBER_OF_INFOS
+};
+
+int uade_generate_song_title(char *title, size_t dstlen,
+ struct uade_state *state);
+int uade_song_info(char *info, size_t maxlen, char *filename,
+ enum song_info_type type);
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/support.c b/plugins/uade2/uade-2.13/src/frontends/common/support.c
new file mode 100644
index 00000000..852d4c0e
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/support.c
@@ -0,0 +1,183 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "support.h"
+#include "ossupport.h"
+
+/* Zero terminate the current word. Returns -1 is *s == 0 or the next word
+ does not exist. Otherwise returns offset to the beginning of next word. */
+int skip_and_terminate_word(char *s, int i)
+{
+ i = skipnws(s, i);
+ if (i < 0)
+ return -1;
+
+ /* Zero terminate word */
+ s[i] = 0;
+
+ i = skipws(s, i + 1);
+ if (i < 0)
+ return -1;
+
+ return i;
+}
+
+char *xbasename(const char *s)
+{
+ char *t = strrchr(s, (int) '/');
+ if (t == NULL) {
+ t = (char *) s;
+ } else {
+ t++;
+ }
+ return t;
+}
+
+/*
+ * Split a string into 2 whitespace separated fields returned in "key" and
+ * "value". If more than 2 fields are found, they are cut off by zero
+ * terminating "key" and "value" inside the string. If "value" is not found,
+ * *value is set to NULL. If "key" is not found, *key is set to NULL.
+ * If something is found, both *key and *value become pointers inside the
+ * string s.
+ *
+ * Return values:
+ * - 0 if neither "key" nor "value" is found
+ * - 1 if only "key" is found
+ * - 2 if both "key" and "value" are found
+ */
+int get_two_ws_separated_fields(char **key, char **value, char *s)
+{
+ int i;
+
+ *key = NULL;
+ *value = NULL;
+
+ i = skipws(s, 0); /* Skip initial whitespace */
+
+ if (i < 0)
+ return 0; /* We got nothing */
+
+ *key = s + i;
+
+ i = skip_and_terminate_word(s, i);
+
+ if (i < 0)
+ return 1; /* We got a "key", but not a "value" */
+
+ *value = s + i;
+
+ skip_and_terminate_word(s, i);
+
+ return 2; /* We got both a "key" and a "value" */
+}
+
+/*
+ * Skip whitespace characters in string starting from offset i. Returns offset
+ * j >= i as the next non-whitespace character offset, or -1 if non-whitespace
+ * are not found.
+ */
+int skipws(const char *s, int i)
+{
+ while (isspace(s[i]))
+ i++;
+
+ if (s[i] == 0)
+ return -1;
+
+ return i;
+}
+
+/*
+ * Skip non-whitespace characters in string starting from offset i. Returns
+ * offset j >= i as the next whitespace character offset, or -1 if no
+ * whitespace if found.
+ */
+int skipnws(const char *s, int i)
+{
+ while (!isspace(s[i]) && s[i] != 0)
+ i++;
+
+ if (s[i] == 0)
+ return -1;
+
+ return i;
+}
+
+
+/* Split line with respect to white space. */
+char **read_and_split_lines(size_t *nitems, size_t *lineno, FILE *f,
+ const char *delim)
+{
+ char line[UADE_LINESIZE], templine[UADE_LINESIZE];
+ char **items = NULL;
+ size_t pos;
+ char *sp, *s;
+
+ *nitems = 0;
+
+ while (xfgets(line, sizeof line, f) != NULL) {
+
+ if (lineno != NULL)
+ (*lineno)++;
+
+ /* Skip, if a comment line */
+ if (line[0] == '#')
+ continue;
+
+ /* strsep() modifies line that it touches, so we make a copy
+ of it, and then count the number of items on the line */
+ strlcpy(templine, line, sizeof(templine));
+ sp = templine;
+ while ((s = strsep(&sp, delim)) != NULL) {
+ if (*s == 0)
+ continue;
+ (*nitems)++;
+ }
+
+ if (*nitems > 0)
+ break;
+ }
+
+ if (*nitems == 0)
+ return NULL;
+
+ if ((items = malloc(sizeof(items[0]) * (*nitems + 1))) == NULL)
+ uadeerror("No memory for nws items.\n");
+
+ sp = line;
+ pos = 0;
+ while ((s = strsep(&sp, delim)) != NULL) {
+ if (*s == 0)
+ continue;
+
+ if ((items[pos] = strdup(s)) == NULL)
+ uadeerror("No memory for an nws item.\n");
+
+ pos++;
+ }
+ items[pos] = NULL;
+ assert(pos == *nitems);
+
+ return items;
+}
+
+
+char *xfgets(char *s, int size, FILE *stream)
+{
+ char *ret;
+
+ while (1) {
+ ret = fgets(s, size, stream);
+ if (ret != NULL)
+ break;
+
+ if (feof(stream))
+ break;
+ }
+
+ return ret;
+}
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/support.h b/plugins/uade2/uade-2.13/src/frontends/common/support.h
new file mode 100644
index 00000000..1b32fe92
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/support.h
@@ -0,0 +1,31 @@
+#ifndef _UADE_SUPPORT_H_
+#define _UADE_SUPPORT_H_
+
+#include <stdio.h>
+
+#define UADE_LINESIZE 1024
+
+#define uadeerror(fmt, args...) do { fprintf(stderr, "uade: " fmt, ## args); exit(1); } while (0)
+
+#define MAX(x, y) ((x) >= (y) ? (x) : (y))
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+
+
+char *xbasename(const char *path);
+
+int get_two_ws_separated_fields(char **key, char **value, char *s);
+
+int skipnws(const char *s, int i);
+
+int skip_and_terminate_word(char *s, int i);
+
+int skipws(const char *s, int i);
+
+char **read_and_split_lines(size_t *nitems, size_t *lineno, FILE *f,
+ const char *delim);
+
+/* Same as fgets(), but guarantees that feof() or ferror() have happened
+ when xfgets() returns NULL */
+char *xfgets(char *s, int size, FILE *stream);
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/uadeconf.c b/plugins/uade2/uade-2.13/src/frontends/common/uadeconf.c
new file mode 100644
index 00000000..17300340
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/uadeconf.c
@@ -0,0 +1,888 @@
+/* Handle uade.conf file
+
+ Copyright (C) 2005 Heikki Orsila <heikki.orsila@iki.fi>
+
+ This source code module is dual licensed under GPL and Public Domain.
+ Hence you may use _this_ module (not another code module) in any way you
+ want in your projects.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "ossupport.h"
+#include "uadeconf.h"
+#include "uadeconfig.h"
+#include "amigafilter.h"
+#include "uadeconstants.h"
+#include "songdb.h"
+#include "uadeutils.h"
+#include "support.h"
+
+static int uade_set_silence_timeout(struct uade_config *uc, const char *value);
+static int uade_set_subsong_timeout(struct uade_config *uc, const char *value);
+static int uade_set_timeout(struct uade_config *uc, const char *value);
+
+
+struct uade_conf_opts {
+ char *str;
+ int l;
+ enum uade_option e;
+};
+
+/* List of uade.conf options. The list includes option name, minimum
+ string match length for the option name and its enum code. */
+static const struct uade_conf_opts uadeconfopts[] = {
+ {.str = "action_keys", .l = 2, .e = UC_ACTION_KEYS},
+ {.str = "ao_option", .l = 2, .e = UC_AO_OPTION},
+ {.str = "buffer_time", .l = 1, .e = UC_BUFFER_TIME},
+ {.str = "cygwin", .l = 1, .e = UC_CYGWIN_DRIVE_WORKAROUND},
+ {.str = "detect_format_by_detection", .l = 18, .e = UC_CONTENT_DETECTION},
+ {.str = "disable_timeout", .l = 1, .e = UC_DISABLE_TIMEOUTS},
+ {.str = "enable_timeout", .l = 2, .e = UC_ENABLE_TIMEOUTS},
+ {.str = "ep_option", .l = 2, .e = UC_EAGLEPLAYER_OPTION},
+ {.str = "filter_type", .l = 2, .e = UC_FILTER_TYPE},
+ {.str = "force_led_off", .l = 12, .e = UC_FORCE_LED_OFF},
+ {.str = "force_led_on", .l = 12, .e = UC_FORCE_LED_ON},
+ {.str = "force_led", .l = 9, .e = UC_FORCE_LED},
+ {.str = "frequency", .l = 2, .e = UC_FREQUENCY},
+ {.str = "gain", .l = 1, .e = UC_GAIN},
+ {.str = "headphones", .l = 11, .e = UC_HEADPHONES},
+ {.str = "headphones2", .l = 11, .e = UC_HEADPHONES2},
+ {.str = "headphone", .l = 11, .e = UC_HEADPHONES},
+ {.str = "ignore_player_check", .l = 2, .e = UC_IGNORE_PLAYER_CHECK},
+ {.str = "interpolator", .l = 2, .e = UC_RESAMPLER},
+ {.str = "magic_detection", .l = 1, .e = UC_CONTENT_DETECTION},
+ {.str = "no_ep_end_detect", .l = 4, .e = UC_NO_EP_END},
+ {.str = "no_filter", .l = 4, .e = UC_NO_FILTER},
+ {.str = "no_song_end", .l = 4, .e = UC_NO_EP_END},
+ {.str = "normalise", .l = 1, .e = UC_NORMALISE},
+ {.str = "ntsc", .l = 2, .e = UC_NTSC},
+ {.str = "one_subsong", .l = 1, .e = UC_ONE_SUBSONG},
+ {.str = "pal", .l = 3, .e = UC_PAL},
+ {.str = "panning_value", .l = 3, .e = UC_PANNING_VALUE},
+ {.str = "random_play", .l = 3, .e = UC_RANDOM_PLAY},
+ {.str = "recursive_mode", .l = 3, .e = UC_RECURSIVE_MODE},
+ {.str = "resampler", .l = 3, .e = UC_RESAMPLER},
+ {.str = "silence_timeout_value", .l = 2, .e = UC_SILENCE_TIMEOUT_VALUE},
+ {.str = "song_title", .l = 2, .e = UC_SONG_TITLE},
+ {.str = "speed_hack", .l = 2, .e = UC_SPEED_HACK},
+ {.str = "subsong_timeout_value", .l = 2, .e = UC_SUBSONG_TIMEOUT_VALUE},
+ {.str = "timeout_value", .l = 1, .e = UC_TIMEOUT_VALUE},
+ {.str = "verbose", .l = 1, .e = UC_VERBOSE},
+ {.str = NULL} /* END OF LIST */
+};
+
+
+/* Map an uade.conf option to an enum */
+static enum uade_option map_str_to_option(const char *key)
+{
+ size_t i;
+
+ for (i = 0; uadeconfopts[i].str != NULL; i++) {
+ if (strncmp(key, uadeconfopts[i].str, uadeconfopts[i].l) == 0)
+ return uadeconfopts[i].e;
+ }
+
+ return 0;
+}
+
+/* The function sets the default options. No *_set variables are set because
+ we don't want any option to become mergeable by default. See
+ uade_merge_configs(). */
+void uade_config_set_defaults(struct uade_config *uc)
+{
+ memset(uc, 0, sizeof(*uc));
+ uc->action_keys = 1;
+ strlcpy(uc->basedir.name, UADE_CONFIG_BASE_DIR, sizeof uc->basedir.name);
+ uade_set_filter_type(uc, NULL);
+ uc->frequency = UADE_DEFAULT_FREQUENCY;
+ uc->gain = 1.0;
+ uc->panning = 0.7;
+ uc->silence_timeout = 20;
+ uc->subsong_timeout = 512;
+ uc->timeout = -1;
+ uc->use_timeouts = 1;
+}
+
+double uade_convert_to_double(const char *value, double def, double low,
+ double high, const char *type)
+{
+ char *endptr, *newvalue;
+ char newseparator;
+ double v;
+
+ if (value == NULL)
+ return def;
+
+ v = strtod(value, &endptr);
+
+ /* Decimal separator conversion, if needed */
+ if (*endptr == ',' || *endptr == '.') {
+ newvalue = strdup(value);
+ if (newvalue == NULL)
+ uade_error("Out of memory\n");
+
+ newseparator = (*endptr == ',') ? '.' : ',';
+
+ newvalue[(intptr_t) endptr - (intptr_t) value] = newseparator;
+
+ v = strtod(newvalue, &endptr);
+ free(newvalue);
+ }
+
+ if (*endptr != 0 || v < low || v > high) {
+ fprintf(stderr, "Invalid %s value: %s\n", type, value);
+ v = def;
+ }
+
+ return v;
+}
+
+static void uade_add_ep_option(struct uade_ep_options *opts, const char *s)
+{
+ size_t freespace = sizeof(opts->o) - opts->s;
+
+ if (strlcpy(&opts->o[opts->s], s, freespace) >= freespace) {
+ fprintf(stderr, "Warning: uade eagleplayer option overflow: %s\n", s);
+ return;
+ }
+
+ opts->s += strlen(s) + 1;
+}
+
+static int handle_attributes(struct uade_config *uc, struct uade_song *us,
+ char *playername, size_t playernamelen,
+ int flags, struct uade_attribute *attributelist)
+{
+ struct uade_attribute *a;
+ size_t i;
+
+ for (i = 0; epconf[i].s != NULL; i++) {
+
+ if (epconf[i].o == 0)
+ continue;
+
+ if ((flags & epconf[i].e) == 0)
+ continue;
+
+ uade_set_config_option(uc, epconf[i].o, epconf[i].c);
+ }
+
+ if (flags & ES_NEVER_ENDS)
+ fprintf(stderr, "uade: ES_NEVER_ENDS is not implemented. What should it do?\n");
+
+ if (flags & ES_REJECT)
+ return -1;
+
+ a = attributelist;
+
+ while (a != NULL) {
+
+ switch (a->type) {
+ case ES_EP_OPTION:
+ if (uc->verbose)
+ fprintf(stderr, "Using eagleplayer option %s\n", a->s);
+ uade_add_ep_option(&us->ep_options, a->s);
+ break;
+
+ case ES_GAIN:
+ uade_set_config_option(uc, UC_GAIN, a->s);
+ break;
+
+ case ES_RESAMPLER:
+ uade_set_config_option(uc, UC_RESAMPLER, a->s);
+ break;
+
+ case ES_PANNING:
+ uade_set_config_option(uc, UC_PANNING_VALUE, a->s);
+ break;
+
+ case ES_PLAYER:
+ if (playername) {
+ snprintf(playername, playernamelen, "%s/players/%s", uc->basedir.name, a->s);
+ } else {
+ fprintf(stderr, "Error: attribute handling was given playername == NULL.\n");
+ }
+ break;
+
+ case ES_SILENCE_TIMEOUT:
+ uade_set_config_option(uc, UC_SILENCE_TIMEOUT_VALUE, a->s);
+ break;
+
+ case ES_SUBSONGS:
+ fprintf(stderr, "Subsongs not implemented.\n");
+ break;
+
+ case ES_SUBSONG_TIMEOUT:
+ uade_set_config_option(uc, UC_SUBSONG_TIMEOUT_VALUE, a->s);
+ break;
+
+ case ES_TIMEOUT:
+ uade_set_config_option(uc, UC_TIMEOUT_VALUE, a->s);
+ break;
+
+ default:
+ fprintf(stderr, "Unknown song attribute integer: 0x%x\n", a->type);
+ break;
+ }
+
+ a = a->next;
+ }
+
+ return 0;
+}
+
+int uade_set_song_attributes(struct uade_state *state,
+ char *playername, size_t playernamelen)
+{
+ struct uade_song *us = state->song;
+ struct uade_config *uc = &state->config;
+
+ if (us->normalisation)
+ uade_set_config_option(uc, UC_NORMALISE, us->normalisation);
+
+ return handle_attributes(uc, us, playername, playernamelen,
+ us->flags, us->songattributes);
+}
+
+int uade_load_config(struct uade_config *uc, const char *filename)
+{
+ char line[256];
+ FILE *f;
+ char *key, *value;
+ int linenumber = 0;
+ enum uade_option opt;
+
+ if ((f = fopen(filename, "r")) == NULL)
+ return 0;
+
+ uade_config_set_defaults(uc);
+
+ while (xfgets(line, sizeof(line), f) != NULL) {
+ linenumber++;
+
+ /* Skip comment lines */
+ if (line[0] == '#')
+ continue;
+
+ if (!get_two_ws_separated_fields(&key, &value, line))
+ continue; /* Skip an empty line */
+
+ opt = map_str_to_option(key);
+
+ if (opt) {
+ uade_set_config_option(uc, opt, value);
+ } else {
+ fprintf(stderr, "Unknown config key in %s on line %d: %s\n", filename, linenumber, key);
+ }
+ }
+
+ fclose(f);
+ return 1;
+}
+
+int uade_load_initial_config(char *uadeconfname, size_t maxlen,
+ struct uade_config *uc, struct uade_config *ucbase)
+{
+ int loaded;
+ char *home;
+
+ assert(maxlen > 0);
+ uadeconfname[0] = 0;
+
+ uade_config_set_defaults(uc);
+
+ loaded = 0;
+
+ /* First try to load from forced base dir (testing mode) */
+ if (ucbase != NULL && ucbase->basedir_set) {
+ snprintf(uadeconfname, maxlen, "%s/uade.conf",
+ ucbase->basedir.name);
+ loaded = uade_load_config(uc, uadeconfname);
+ }
+
+ home = uade_open_create_home();
+
+ /* Second, try to load config from ~/.uade2/uade.conf */
+ if (loaded == 0 && home != NULL) {
+ snprintf(uadeconfname, maxlen, "%s/.uade2/uade.conf", home);
+ loaded = uade_load_config(uc, uadeconfname);
+ }
+
+ /* Third, try to load from install path */
+ if (loaded == 0) {
+ snprintf(uadeconfname, maxlen, "%s/uade.conf",
+ uc->basedir.name);
+ loaded = uade_load_config(uc, uadeconfname);
+ }
+
+ return loaded;
+}
+
+int uade_load_initial_song_conf(char *songconfname, size_t maxlen,
+ struct uade_config *uc,
+ struct uade_config *ucbase)
+{
+ int loaded = 0;
+ char *home;
+
+ assert(maxlen > 0);
+ songconfname[0] = 0;
+
+ /* Used for testing */
+ if (ucbase != NULL && ucbase->basedir_set) {
+ snprintf(songconfname, maxlen, "%s/song.conf",
+ ucbase->basedir.name);
+ loaded = uade_read_song_conf(songconfname);
+ }
+
+ /* Avoid unwanted home directory creation for test mode */
+ if (loaded)
+ return loaded;
+
+ home = uade_open_create_home();
+
+ /* Try to load from home dir */
+ if (loaded == 0 && home != NULL) {
+ snprintf(songconfname, maxlen, "%s/.uade2/song.conf", home);
+ loaded = uade_read_song_conf(songconfname);
+ }
+
+ /* No? Try install path */
+ if (loaded == 0) {
+ snprintf(songconfname, maxlen, "%s/song.conf",
+ uc->basedir.name);
+ loaded = uade_read_song_conf(songconfname);
+ }
+
+ return loaded;
+}
+
+void uade_merge_configs(struct uade_config *ucd, const struct uade_config *ucs)
+{
+#define MERGE_OPTION(y) do { if (ucs->y##_set) ucd->y = ucs->y; } while (0)
+
+ MERGE_OPTION(action_keys);
+ MERGE_OPTION(ao_options);
+ MERGE_OPTION(basedir);
+ MERGE_OPTION(buffer_time);
+ MERGE_OPTION(content_detection);
+ MERGE_OPTION(cygwin_drive_workaround);
+ MERGE_OPTION(ep_options);
+ MERGE_OPTION(filter_type);
+ MERGE_OPTION(frequency);
+ MERGE_OPTION(gain);
+ MERGE_OPTION(gain_enable);
+ MERGE_OPTION(headphones);
+ MERGE_OPTION(headphones2);
+ MERGE_OPTION(ignore_player_check);
+ MERGE_OPTION(led_forced);
+ MERGE_OPTION(led_state);
+ MERGE_OPTION(no_ep_end);
+ MERGE_OPTION(no_filter);
+ MERGE_OPTION(no_postprocessing);
+
+ /* Special merge -> don't use MERGE_OPTION macro */
+ if (ucs->normalise_set && ucs->normalise) {
+ ucd->normalise = 1;
+ if (ucs->normalise_parameter != NULL)
+ ucd->normalise_parameter = ucs->normalise_parameter;
+ }
+
+ MERGE_OPTION(one_subsong);
+ MERGE_OPTION(panning);
+ MERGE_OPTION(panning_enable);
+ MERGE_OPTION(random_play);
+ MERGE_OPTION(recursive_mode);
+ MERGE_OPTION(resampler);
+ MERGE_OPTION(silence_timeout);
+ MERGE_OPTION(song_title);
+ MERGE_OPTION(speed_hack);
+ MERGE_OPTION(subsong_timeout);
+
+ MERGE_OPTION(timeout);
+ MERGE_OPTION(use_timeouts);
+ if (ucs->timeout_set) {
+ ucd->use_timeouts = 1;
+ ucd->use_timeouts_set = 1;
+ }
+
+ MERGE_OPTION(use_text_scope);
+ MERGE_OPTION(use_ntsc);
+ MERGE_OPTION(verbose);
+}
+
+char *uade_open_create_home(void)
+{
+ /* Create ~/.uade2 directory if it does not exist */
+ char *home = getenv("HOME");
+ if (home) {
+ char name[PATH_MAX];
+ struct stat st;
+ snprintf(name, sizeof name, "%s/.uade2", home);
+ if (stat(name, &st) != 0)
+ mkdir(name, S_IRUSR | S_IWUSR | S_IXUSR);
+ }
+
+ return home;
+}
+
+int uade_parse_subsongs(int **subsongs, char *option)
+{
+ char substr[256];
+ char *sp, *str;
+ size_t pos;
+ int nsubsongs;
+
+ nsubsongs = 0;
+ *subsongs = NULL;
+
+ if (strlcpy(substr, option, sizeof subsongs) >= sizeof subsongs) {
+ fprintf(stderr, "Too long a subsong option: %s\n", option);
+ return -1;
+ }
+
+ sp = substr;
+ while ((str = strsep(&sp, ",")) != NULL) {
+ if (*str == 0)
+ continue;
+ nsubsongs++;
+ }
+
+ *subsongs = malloc((nsubsongs + 1) * sizeof((*subsongs)[0]));
+ if (*subsongs == NULL) {
+ fprintf(stderr, "No memory for subsongs.\n");
+ return -1;
+ }
+
+ strlcpy(substr, option, sizeof subsongs);
+
+ pos = 0;
+ sp = substr;
+ while ((str = strsep(&sp, ",")) != NULL) {
+ if (*str == 0)
+ continue;
+ (*subsongs)[pos] = atoi(str);
+ pos++;
+ }
+
+ (*subsongs)[pos] = -1;
+ assert(pos == nsubsongs);
+
+ return nsubsongs;
+}
+
+void uade_set_effects(struct uade_state *state)
+{
+ struct uade_effect *effects = &state->effects;
+ struct uade_config *uc = &state->config;
+
+ uade_effect_set_defaults(effects);
+
+ if (uc->no_postprocessing)
+ uade_effect_disable(effects, UADE_EFFECT_ALLOW);
+
+ if (uc->gain_enable) {
+ uade_effect_gain_set_amount(effects, uc->gain);
+ uade_effect_enable(effects, UADE_EFFECT_GAIN);
+ }
+
+ if (uc->headphones)
+ uade_effect_enable(effects, UADE_EFFECT_HEADPHONES);
+
+ if (uc->headphones2)
+ uade_effect_enable(effects, UADE_EFFECT_HEADPHONES2);
+
+ if (uc->normalise) {
+ uade_effect_normalise_unserialise(uc->normalise_parameter);
+ uade_effect_enable(effects, UADE_EFFECT_NORMALISE);
+ }
+
+ if (uc->panning_enable) {
+ uade_effect_pan_set_amount(effects, uc->panning);
+ uade_effect_enable(effects, UADE_EFFECT_PAN);
+ }
+
+ uade_effect_set_sample_rate(effects, uc->frequency);
+}
+
+void uade_set_config_option(struct uade_config *uc, enum uade_option opt,
+ const char *value)
+{
+ char *endptr;
+ long x;
+
+#define SET_OPTION(opt, value) do { uc->opt = (value); uc->opt##_set = 1; } while (0)
+
+ switch (opt) {
+ case UC_ACTION_KEYS:
+ if (value != NULL) {
+ uc->action_keys_set = 1;
+ if (!strcasecmp(value, "on") || !strcmp(value, "1")) {
+ uc->action_keys = 1;
+ } else if (!strcasecmp(value, "off") ||
+ !strcmp(value, "0")) {
+ uc->action_keys = 0;
+ } else {
+ fprintf(stderr,
+ "uade.conf: Unknown setting for action keys: %s\n",
+ value);
+ }
+ }
+ break;
+
+ case UC_AO_OPTION:
+ strlcat(uc->ao_options.o, value, sizeof uc->ao_options.o);
+ strlcat(uc->ao_options.o, "\n", sizeof uc->ao_options.o);
+ uc->ao_options_set = 1;
+ break;
+
+ case UC_BASE_DIR:
+ if (value != NULL) {
+ strlcpy(uc->basedir.name, value,
+ sizeof uc->basedir.name);
+ uc->basedir_set = 1;
+ } else {
+ fprintf(stderr, "uade: Passed NULL to UC_BASE_DIR.\n");
+ }
+ break;
+
+ case UC_BUFFER_TIME:
+ if (value != NULL) {
+ uc->buffer_time_set = 1;
+ uc->buffer_time = strtol(value, &endptr, 10);
+ if (uc->buffer_time <= 0 || *endptr != 0) {
+ fprintf(stderr, "Invalid buffer_time: %s\n",
+ value);
+ uc->buffer_time = 0;
+ }
+ } else {
+ fprintf(stderr,
+ "uade: Passed NULL to UC_BUFFER_TIME.\n");
+ }
+ break;
+
+ case UC_CONTENT_DETECTION:
+ SET_OPTION(content_detection, 1);
+ break;
+
+ case UC_CYGWIN_DRIVE_WORKAROUND:
+ SET_OPTION(cygwin_drive_workaround, 1);
+ break;
+
+ case UC_DISABLE_TIMEOUTS:
+ SET_OPTION(use_timeouts, 0);
+ break;
+
+ case UC_ENABLE_TIMEOUTS:
+ SET_OPTION(use_timeouts, 1);
+ break;
+
+ case UC_EAGLEPLAYER_OPTION:
+ if (value != NULL) {
+ uade_add_ep_option(&uc->ep_options, value);
+ uc->ep_options_set = 1;
+ } else {
+ fprintf(stderr,
+ "uade: Passed NULL to UC_EAGLEPLAYER_OPTION.\n");
+ }
+ break;
+
+ case UC_FILTER_TYPE:
+ SET_OPTION(no_filter, 0);
+
+ if (value != NULL) {
+ if (strcasecmp(value, "none") != 0) {
+ /* Filter != NONE */
+ uade_set_filter_type(uc, value);
+ uc->filter_type_set = 1;
+ } else {
+ /* Filter == NONE */
+ uc->no_filter = 1;
+ }
+ }
+ break;
+
+ case UC_FORCE_LED:
+ if (value == NULL) {
+ fprintf(stderr, "uade: UC_FORCE_LED value is NULL\n");
+ break;
+ }
+ if (strcasecmp(value, "off") == 0 || strcmp(value, "0") == 0) {
+ uc->led_state = 0;
+ } else if (strcasecmp(value, "on") == 0
+ || strcmp(value, "1") == 0) {
+ uc->led_state = 1;
+ } else {
+ fprintf(stderr, "Unknown force led argument: %s\n",
+ value);
+ break;
+ }
+ uc->led_state_set = 1;
+
+ SET_OPTION(led_forced, 1);
+ break;
+
+ case UC_FORCE_LED_OFF:
+ SET_OPTION(led_forced, 1);
+ SET_OPTION(led_state, 0);
+ break;
+
+ case UC_FORCE_LED_ON:
+ SET_OPTION(led_forced, 1);
+ SET_OPTION(led_state, 1);
+ break;
+
+ case UC_FREQUENCY:
+ if (value == NULL) {
+ fprintf(stderr, "uade: UC_FREQUENCY value is NULL\n");
+ break;
+ }
+ x = strtol(value, &endptr, 10);
+ if (*endptr != 0) {
+ fprintf(stderr, "Invalid frequency number: %s\n",
+ value);
+ break;
+ }
+ /* The upper bound is NTSC Amigas bus freq */
+ if (x < 1 || x > 3579545) {
+ fprintf(stderr, "Frequency out of bounds: %ld\n", x);
+ x = UADE_DEFAULT_FREQUENCY;
+ }
+ SET_OPTION(frequency, x);
+ break;
+
+ case UC_GAIN:
+ if (value == NULL) {
+ fprintf(stderr, "uade: UC_GAIN value is NULL\n");
+ break;
+ }
+ SET_OPTION(gain_enable, 1);
+ SET_OPTION(gain, uade_convert_to_double(value, 1.0, 0.0, 128.0, "gain"));
+ break;
+
+ case UC_HEADPHONES:
+ SET_OPTION(headphones, 1);
+ break;
+
+ case UC_HEADPHONES2:
+ SET_OPTION(headphones2, 1);
+ break;
+
+ case UC_IGNORE_PLAYER_CHECK:
+ SET_OPTION(ignore_player_check, 1);
+ break;
+
+ case UC_RESAMPLER:
+ if (value == NULL) {
+ fprintf(stderr, "uade.conf: No resampler given.\n");
+ break;
+ }
+ uc->resampler = strdup(value);
+ if (uc->resampler != NULL) {
+ uc->resampler_set = 1;
+ } else {
+ fprintf(stderr, "uade.conf: no memory for resampler.\n");
+ }
+ break;
+
+ case UC_NO_EP_END:
+ SET_OPTION(no_ep_end, 1);
+ break;
+
+ case UC_NO_FILTER:
+ SET_OPTION(no_filter, 1);
+ break;
+
+ case UC_NO_HEADPHONES:
+ SET_OPTION(headphones, 0);
+ SET_OPTION(headphones2, 0);
+ break;
+
+ case UC_NO_PANNING:
+ SET_OPTION(panning_enable, 0);
+ break;
+
+ case UC_NO_POSTPROCESSING:
+ SET_OPTION(no_postprocessing, 1);
+ break;
+
+ case UC_NORMALISE:
+ if (value == NULL) {
+ fprintf(stderr, "uade: UC_NORMALISE is NULL\n");
+ break;
+ }
+ SET_OPTION(normalise, 1);
+ uc->normalise_parameter = (char *) value;
+ break;
+
+ case UC_NTSC:
+ SET_OPTION(use_ntsc, 1);
+ break;
+
+ case UC_ONE_SUBSONG:
+ SET_OPTION(one_subsong, 1);
+ break;
+
+ case UC_PAL:
+ SET_OPTION(use_ntsc, 0);
+ break;
+
+ case UC_PANNING_VALUE:
+ if (value == NULL) {
+ fprintf(stderr, "uade: UC_PANNING_VALUE is NULL\n");
+ break;
+ }
+ SET_OPTION(panning_enable, 1);
+ SET_OPTION(panning, uade_convert_to_double(value, 0.0, 0.0, 2.0, "panning"));
+ break;
+
+ case UC_RANDOM_PLAY:
+ SET_OPTION(random_play, 1);
+ break;
+
+ case UC_RECURSIVE_MODE:
+ SET_OPTION(recursive_mode, 1);
+ break;
+
+ case UC_SILENCE_TIMEOUT_VALUE:
+ if (value == NULL) {
+ fprintf(stderr,
+ "uade: UC_SILENCE_TIMEOUT_VALUE is NULL\n");
+ break;
+ }
+ uade_set_silence_timeout(uc, value);
+ break;
+
+ case UC_SONG_TITLE:
+ if (value == NULL) {
+ fprintf(stderr, "uade: No song_title format given.\n");
+ break;
+ }
+ if ((uc->song_title = strdup(value)) == NULL) {
+ fprintf(stderr, "No memory for song title format\n");
+ } else {
+ uc->song_title_set = 1;
+ }
+ break;
+
+ case UC_SPEED_HACK:
+ SET_OPTION(speed_hack, 1);
+ break;
+
+ case UC_SUBSONG_TIMEOUT_VALUE:
+ if (value == NULL) {
+ fprintf(stderr,
+ "uade: UC_SUBSONG_TIMEOUT_VALUE is NULL\n");
+ break;
+ }
+ uade_set_subsong_timeout(uc, value);
+ break;
+
+ case UC_TIMEOUT_VALUE:
+ if (value == NULL) {
+ fprintf(stderr, "uade: UC_TIMEOUT_VALUE is NULL\n");
+ break;
+ }
+ uade_set_timeout(uc, value);
+ break;
+
+ case UC_USE_TEXT_SCOPE:
+ SET_OPTION(use_text_scope, 1);
+ break;
+
+ case UC_VERBOSE:
+ SET_OPTION(verbose, 1);
+ break;
+
+ default:
+ fprintf(stderr, "uade_set_config_option(): unknown enum: %d\n",
+ opt);
+ exit(1);
+ }
+}
+
+void uade_set_ep_attributes(struct uade_state *state)
+{
+ handle_attributes(&state->config, state->song, NULL, 0, state->ep->flags, state->ep->attributelist);
+}
+
+void uade_set_filter_type(struct uade_config *uc, const char *model)
+{
+ uc->filter_type = FILTER_MODEL_A500;
+
+ if (model == NULL)
+ return;
+
+ /* a500 and a500e are the same */
+ if (strncasecmp(model, "a500", 4) == 0) {
+ uc->filter_type = FILTER_MODEL_A500;
+
+ /* a1200 and a1200e are the same */
+ } else if (strncasecmp(model, "a1200", 5) == 0) {
+ uc->filter_type = FILTER_MODEL_A1200;
+
+ } else {
+ fprintf(stderr, "Unknown filter model: %s\n", model);
+ }
+}
+
+static int uade_set_silence_timeout(struct uade_config *uc, const char *value)
+{
+ char *endptr;
+ int t;
+ if (value == NULL) {
+ return -1;
+ }
+ t = strtol(value, &endptr, 10);
+ if (*endptr != 0 || t < -1) {
+ fprintf(stderr, "Invalid silence timeout value: %s\n", value);
+ return -1;
+ }
+ uc->silence_timeout = t;
+ uc->silence_timeout_set = 1;
+ return 0;
+}
+
+static int uade_set_subsong_timeout(struct uade_config *uc, const char *value)
+{
+ char *endptr;
+ int t;
+ if (value == NULL) {
+ return -1;
+ }
+ t = strtol(value, &endptr, 10);
+ if (*endptr != 0 || t < -1) {
+ fprintf(stderr, "Invalid subsong timeout value: %s\n", value);
+ return -1;
+ }
+ uc->subsong_timeout = t;
+ uc->subsong_timeout_set = 1;
+ return 0;
+}
+
+static int uade_set_timeout(struct uade_config *uc, const char *value)
+{
+ char *endptr;
+ int t;
+ if (value == NULL) {
+ return -1;
+ }
+ t = strtol(value, &endptr, 10);
+ if (*endptr != 0 || t < -1) {
+ fprintf(stderr, "Invalid timeout value: %s\n", value);
+ return -1;
+ }
+ uc->timeout = t;
+ uc->timeout_set = 1;
+ return 0;
+}
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/uadeconf.h b/plugins/uade2/uade-2.13/src/frontends/common/uadeconf.h
new file mode 100644
index 00000000..62b11ef9
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/uadeconf.h
@@ -0,0 +1,27 @@
+#ifndef _UADE_FRONTEND_CONFIG_H_
+#define _UADE_FRONTEND_CONFIG_H_
+
+#include <uadestate.h>
+
+void uade_config_set_defaults(struct uade_config *uc);
+double uade_convert_to_double(const char *value, double def,
+ double low, double high, const char *type);
+int uade_load_config(struct uade_config *uc, const char *filename);
+int uade_load_initial_config(char *uadeconfname, size_t maxlen,
+ struct uade_config *uc,
+ struct uade_config *ucbase);
+int uade_load_initial_song_conf(char *songconfname, size_t maxlen,
+ struct uade_config *uc,
+ struct uade_config *ucbase);
+void uade_merge_configs(struct uade_config *ucd, const struct uade_config *ucs);
+char *uade_open_create_home(void);
+int uade_parse_subsongs(int **subsongs, char *option);
+void uade_set_config_option(struct uade_config *uc, enum uade_option opt,
+ const char *value);
+void uade_set_effects(struct uade_state *state);
+void uade_set_ep_attributes(struct uade_state *state);
+int uade_set_song_attributes(struct uade_state *state, char *playername,
+ size_t playernamelen);
+void uade_set_filter_type(struct uade_config *uc, const char *value);
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/uadeconfstructure.h b/plugins/uade2/uade-2.13/src/frontends/common/uadeconfstructure.h
new file mode 100644
index 00000000..d6cff1e0
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/uadeconfstructure.h
@@ -0,0 +1,139 @@
+#ifndef _UADECONF_STRUCTURE_H_
+#define _UADECONF_STRUCTURE_H_
+
+#include <limits.h>
+
+enum uade_option {
+ UC_ACTION_KEYS = 0x1000,
+ UC_AO_OPTION,
+ UC_BASE_DIR,
+ UC_BUFFER_TIME,
+ UC_CONTENT_DETECTION,
+ UC_CYGWIN_DRIVE_WORKAROUND,
+ UC_DISABLE_TIMEOUTS,
+ UC_ENABLE_TIMEOUTS,
+ UC_EAGLEPLAYER_OPTION,
+ UC_FILTER_TYPE,
+ UC_FORCE_LED_OFF,
+ UC_FORCE_LED_ON,
+ UC_FORCE_LED,
+ UC_FREQUENCY,
+ UC_GAIN,
+ UC_HEADPHONES,
+ UC_HEADPHONES2,
+ UC_IGNORE_PLAYER_CHECK,
+ UC_NO_FILTER,
+ UC_NO_HEADPHONES,
+ UC_NO_PANNING,
+ UC_NO_POSTPROCESSING,
+ UC_NO_EP_END,
+ UC_NORMALISE,
+ UC_NTSC,
+ UC_ONE_SUBSONG,
+ UC_PAL,
+ UC_PANNING_VALUE,
+ UC_RANDOM_PLAY,
+ UC_RECURSIVE_MODE,
+ UC_RESAMPLER,
+ UC_SILENCE_TIMEOUT_VALUE,
+ UC_SONG_TITLE,
+ UC_SPEED_HACK,
+ UC_SUBSONG_TIMEOUT_VALUE,
+ UC_TIMEOUT_VALUE,
+ UC_USE_TEXT_SCOPE,
+ UC_VERBOSE
+};
+
+struct uade_dir {
+ char name[PATH_MAX];
+};
+
+struct uade_ep_options {
+ char o[256];
+ size_t s;
+};
+
+struct uade_ao_options {
+ char o[256];
+};
+
+#define UADE_CHAR_CONFIG(x) char x; char x##_set;
+#define UADE_FLOAT_CONFIG(x) float x; char x##_set;
+#define UADE_INT_CONFIG(x) int x; char x##_set;
+
+/* All the options are put into an instance of this structure.
+ * There can be many structures, one for uade.conf and the other for
+ * command line options. Then these structures are then merged together
+ * to know the complete behavior for each case. Note, these structures
+ * can be conflicting, so the options are merged in following order
+ * so that the last merge will determine true behavior:
+ *
+ * 1. set uade.conf options
+ * 2. set eagleplayer attributes
+ * 3. set song attributes
+ * 4. set command line options
+ *
+ * Merging works by looking at X_set members of this structure. X_set
+ * member indicates that feature X has explicitly been set, so the
+ * merge will notice the change in value.
+ */
+struct uade_config {
+ UADE_CHAR_CONFIG(action_keys);
+
+ struct uade_ao_options ao_options;
+ char ao_options_set;
+
+ struct uade_dir basedir;
+ char basedir_set;
+
+ UADE_INT_CONFIG(buffer_time);
+ UADE_CHAR_CONFIG(content_detection);
+ UADE_CHAR_CONFIG(cygwin_drive_workaround);
+
+ struct uade_ep_options ep_options;
+ char ep_options_set;
+
+ UADE_CHAR_CONFIG(filter_type);
+ UADE_INT_CONFIG(frequency);
+ UADE_CHAR_CONFIG(led_forced);
+ UADE_CHAR_CONFIG(led_state);
+
+ UADE_CHAR_CONFIG(gain_enable);
+ /* should be removed of uade_effect integrated */
+ UADE_FLOAT_CONFIG(gain);
+
+ UADE_CHAR_CONFIG(headphones);
+ UADE_CHAR_CONFIG(headphones2);
+ UADE_CHAR_CONFIG(ignore_player_check);
+
+ char *resampler;
+ char resampler_set;
+
+ UADE_CHAR_CONFIG(no_ep_end);
+ UADE_CHAR_CONFIG(no_filter);
+ UADE_CHAR_CONFIG(no_postprocessing);
+
+ UADE_CHAR_CONFIG(normalise);
+ /* no normalise_parameter_set entry, use manual merging code */
+ char *normalise_parameter;
+
+ UADE_CHAR_CONFIG(one_subsong);
+ UADE_FLOAT_CONFIG(panning); /* should be removed */
+ UADE_CHAR_CONFIG(panning_enable);
+ UADE_CHAR_CONFIG(random_play);
+ UADE_CHAR_CONFIG(recursive_mode);
+ UADE_INT_CONFIG(silence_timeout);
+
+ char *song_title;
+ char song_title_set;
+
+ UADE_CHAR_CONFIG(speed_hack);
+ UADE_INT_CONFIG(subsong_timeout);
+ UADE_INT_CONFIG(timeout);
+ UADE_CHAR_CONFIG(use_text_scope);
+ UADE_CHAR_CONFIG(use_timeouts);
+ UADE_CHAR_CONFIG(use_ntsc);
+ UADE_CHAR_CONFIG(verbose);
+};
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/uadecontrol.c b/plugins/uade2/uade-2.13/src/frontends/common/uadecontrol.c
new file mode 100644
index 00000000..66e3eac8
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/uadecontrol.c
@@ -0,0 +1,249 @@
+/* uadecontrol.c is a helper module to control uade core through IPC:
+
+ Copyright (C) 2005 Heikki Orsila <heikki.orsila@iki.fi>
+
+ This source code module is dual licensed under GPL and Public Domain.
+ Hence you may use _this_ module (not another code module) in any way you
+ want in your projects.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#include "uadecontrol.h"
+#include "ossupport.h"
+#include "sysincludes.h"
+#include "uadeconstants.h"
+#include "songdb.h"
+
+static void subsong_control(int subsong, int command, struct uade_ipc *ipc);
+
+void uade_change_subsong(struct uade_state *state)
+{
+ state->song->silence_count = 0;
+
+ uade_lookup_volume_normalisation(state);
+
+ subsong_control(state->song->cur_subsong, UADE_COMMAND_CHANGE_SUBSONG, &state->ipc);
+}
+
+int uade_read_request(struct uade_ipc *ipc)
+{
+ uint32_t left = UADE_MAX_MESSAGE_SIZE - sizeof(struct uade_msg);
+ if (uade_send_u32(UADE_COMMAND_READ, left, ipc)) {
+ fprintf(stderr, "\ncan not send read command\n");
+ return 0;
+ }
+ return left;
+}
+
+static int send_ep_options(struct uade_ep_options *eo, struct uade_ipc *ipc)
+{
+ if (eo->s > 0) {
+ size_t i = 0;
+ while (i < eo->s) {
+ char *s = &eo->o[i];
+ size_t l = strlen(s) + 1;
+ assert((i + l) <= eo->s);
+ if (uade_send_string
+ (UADE_COMMAND_SET_PLAYER_OPTION, s, ipc)) {
+ fprintf(stderr,
+ "Can not send eagleplayer option.\n");
+ return -1;
+ }
+ i += l;
+ }
+ }
+ return 0;
+}
+
+void uade_send_filter_command(struct uade_state *state)
+{
+ struct uade_config *uadeconf = &state->config;
+ struct uade_ipc *ipc = &state->ipc;
+
+ int filter_type = uadeconf->filter_type;
+ int filter_state = uadeconf->led_state;
+ int force_filter = uadeconf->led_forced;
+
+ if (uadeconf->no_filter)
+ filter_type = 0;
+
+ /* Note that filter state is not normally forced */
+ filter_state = force_filter ? (2 + (filter_state & 1)) : 0;
+
+ if (uade_send_two_u32s
+ (UADE_COMMAND_FILTER, filter_type, filter_state, ipc)) {
+ fprintf(stderr, "Can not setup filters.\n");
+ exit(-1);
+ }
+}
+
+static void send_resampling_command(struct uade_ipc *ipc,
+ struct uade_config *uadeconf)
+{
+ char *mode = uadeconf->resampler;
+ if (mode != NULL) {
+ if (strlen(mode) == 0) {
+ fprintf(stderr, "Resampling mode may not be empty.\n");
+ exit(-1);
+ }
+ if (uade_send_string
+ (UADE_COMMAND_SET_RESAMPLING_MODE, mode, ipc)) {
+ fprintf(stderr, "Can not set resampling mode.\n");
+ exit(-1);
+ }
+ }
+}
+
+static void subsong_control(int subsong, int command, struct uade_ipc *ipc)
+{
+ assert(subsong >= 0 && subsong < 256);
+ if (uade_send_u32(command, (uint32_t) subsong, ipc) < 0) {
+ fprintf(stderr, "Could not changet subsong\n");
+ exit(-1);
+ }
+}
+
+void uade_set_subsong(int subsong, struct uade_ipc *ipc)
+{
+ subsong_control(subsong, UADE_COMMAND_SET_SUBSONG, ipc);
+}
+
+int uade_song_initialization(const char *scorename,
+ const char *playername,
+ const char *modulename,
+ struct uade_state *state)
+{
+ uint8_t space[UADE_MAX_MESSAGE_SIZE];
+ struct uade_msg *um = (struct uade_msg *)space;
+ struct uade_ipc *ipc = &state->ipc;
+ struct uade_config *uc = &state->config;
+ struct uade_song *us = state->song;
+
+ if (uade_send_string(UADE_COMMAND_SCORE, scorename, ipc)) {
+ fprintf(stderr, "Can not send score name.\n");
+ goto cleanup;
+ }
+
+ if (uade_send_string(UADE_COMMAND_PLAYER, playername, ipc)) {
+ fprintf(stderr, "Can not send player name.\n");
+ goto cleanup;
+ }
+
+ if (uade_send_string(UADE_COMMAND_MODULE, modulename, ipc)) {
+ fprintf(stderr, "Can not send module name.\n");
+ goto cleanup;
+ }
+
+ if (uade_send_short_message(UADE_COMMAND_TOKEN, ipc)) {
+ fprintf(stderr, "Can not send token after module.\n");
+ goto cleanup;
+ }
+
+ printf ("uade_song_initialization: receive message\n");
+ if (uade_receive_message(um, sizeof(space), ipc) <= 0) {
+ fprintf(stderr, "Can not receive acknowledgement.\n");
+ goto cleanup;
+ }
+
+ if (um->msgtype == UADE_REPLY_CANT_PLAY) {
+ if (uade_receive_short_message(UADE_COMMAND_TOKEN, ipc)) {
+ fprintf(stderr,
+ "Can not receive token in main loop.\n");
+ exit(-1);
+ }
+ return UADECORE_CANT_PLAY;
+ }
+
+ if (um->msgtype != UADE_REPLY_CAN_PLAY) {
+ fprintf(stderr, "Unexpected reply from uade: %u\n",
+ (unsigned int)um->msgtype);
+ goto cleanup;
+ }
+
+ if (uade_receive_short_message(UADE_COMMAND_TOKEN, ipc) < 0) {
+ fprintf(stderr, "Can not receive token after play ack.\n");
+ goto cleanup;
+ }
+
+ if (uc->ignore_player_check) {
+ if (uade_send_short_message(UADE_COMMAND_IGNORE_CHECK, ipc) < 0) {
+ fprintf(stderr, "Can not send ignore check message.\n");
+ goto cleanup;
+ }
+ }
+
+ if (uc->no_ep_end) {
+ if (uade_send_short_message
+ (UADE_COMMAND_SONG_END_NOT_POSSIBLE, ipc) < 0) {
+ fprintf(stderr,
+ "Can not send 'song end not possible'.\n");
+ goto cleanup;
+ }
+ }
+
+ uade_send_filter_command(state);
+
+ send_resampling_command(ipc, uc);
+
+ if (uc->speed_hack) {
+ if (uade_send_short_message(UADE_COMMAND_SPEED_HACK, ipc)) {
+ fprintf(stderr, "Can not send speed hack command.\n");
+ goto cleanup;
+ }
+ }
+
+ if (uc->use_ntsc) {
+ if (uade_send_short_message(UADE_COMMAND_SET_NTSC, ipc)) {
+ fprintf(stderr, "Can not send ntsc command.\n");
+ goto cleanup;
+ }
+ }
+
+ if (uc->frequency != UADE_DEFAULT_FREQUENCY) {
+ if (uade_send_u32
+ (UADE_COMMAND_SET_FREQUENCY, uc->frequency, ipc)) {
+ fprintf(stderr, "Can not send frequency.\n");
+ goto cleanup;
+ }
+ }
+
+ if (uc->use_text_scope) {
+ if (uade_send_short_message(UADE_COMMAND_USE_TEXT_SCOPE, ipc)) {
+ fprintf(stderr, "Can not send use text scope command.\n");
+ goto cleanup;
+ }
+ }
+
+ if (send_ep_options(&us->ep_options, ipc) ||
+ send_ep_options(&uc->ep_options, ipc))
+ goto cleanup;
+
+ printf ("uade_song_initialization: success\n");
+
+ return 0;
+
+ cleanup:
+ return UADECORE_INIT_ERROR;
+}
+
+void uade_spawn(struct uade_state *state, const char *uadename,
+ const char *configname)
+{
+ uade_arch_spawn(&state->ipc, &state->pid, uadename);
+
+ if (uade_send_string(UADE_COMMAND_CONFIG, configname, &state->ipc)) {
+ fprintf(stderr, "Can not send config name: %s\n",
+ strerror(errno));
+ kill(state->pid, SIGTERM);
+ state->pid = 0;
+ abort();
+ }
+}
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/uadecontrol.h b/plugins/uade2/uade-2.13/src/frontends/common/uadecontrol.h
new file mode 100644
index 00000000..769521a9
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/uadecontrol.h
@@ -0,0 +1,24 @@
+#ifndef _UADE_CONTROL_
+#define _UADE_CONTROL_
+
+#include <sys/types.h>
+
+#include <uadestate.h>
+
+enum {
+ UADECORE_INIT_OK = 0,
+ UADECORE_INIT_ERROR,
+ UADECORE_CANT_PLAY
+};
+
+void uade_change_subsong(struct uade_state *state);
+int uade_read_request(struct uade_ipc *ipc);
+void uade_send_filter_command(struct uade_state *state);
+void uade_set_subsong(int subsong, struct uade_ipc *ipc);
+int uade_song_initialization(const char *scorename, const char *playername,
+ const char *modulename,
+ struct uade_state *state);
+void uade_spawn(struct uade_state *state, const char *uadename,
+ const char *configname);
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/uadestate.h b/plugins/uade2/uade-2.13/src/frontends/common/uadestate.h
new file mode 100644
index 00000000..7014a30a
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/uadestate.h
@@ -0,0 +1,25 @@
+#ifndef _UADE_STATE_H_
+#define _UADE_STATE_H_
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <eagleplayer.h>
+#include <effects.h>
+#include <uadeipc.h>
+
+struct uade_state {
+ /* Per song members */
+ struct uade_config config;
+ struct uade_song *song;
+ struct uade_effect effects;
+ struct eagleplayer *ep;
+
+ /* Permanent members */
+ int validconfig;
+ struct eagleplayerstore *playerstore;
+ struct uade_ipc ipc;
+ pid_t pid;
+};
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/unixwalkdir.c b/plugins/uade2/uade-2.13/src/frontends/common/unixwalkdir.c
new file mode 100644
index 00000000..292976d7
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/unixwalkdir.c
@@ -0,0 +1,69 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <unixwalkdir.h>
+
+void *uade_walk_directories(const char *dirname,
+ void *(*fn) (const char *file,
+ enum uade_wtype wtype, void *opaque),
+ void *opaque)
+{
+ char *dename;
+ DIR *dir;
+ size_t namelen;
+ struct dirent *de;
+ void *ret = NULL;
+ struct stat st;
+ enum uade_wtype wtype;
+
+ namelen = strlen(dirname) + 256 + 2;
+ if ((dename = malloc(namelen)) == NULL)
+ return NULL;
+
+ if ((dir = opendir(dirname)) == NULL)
+ return NULL;
+
+ while ((de = readdir(dir)) != NULL) {
+
+ if (strcmp(de->d_name, ".") == 0
+ || strcmp(de->d_name, "..") == 0)
+ continue;
+
+ if (snprintf(dename, namelen, "%s/%s", dirname, de->d_name) >=
+ namelen) {
+ fprintf(stderr, "interesting: too long a filename\n");
+ continue;
+ }
+
+ if (lstat(dename, &st))
+ continue;
+
+ if (S_ISREG(st.st_mode))
+ wtype = UADE_WALK_REGULAR_FILE;
+ else if (S_ISDIR(st.st_mode))
+ wtype = UADE_WALK_DIRECTORY;
+ else if (S_ISLNK(st.st_mode))
+ wtype = UADE_WALK_SYMLINK;
+ else
+ wtype = UADE_WALK_SPECIAL;
+
+ if ((ret = fn(dename, wtype, opaque)) != NULL)
+ break;
+
+ if (wtype == UADE_WALK_DIRECTORY) {
+ if ((ret =
+ uade_walk_directories(dename, fn, opaque)) != NULL)
+ break;
+ }
+ }
+
+ closedir(dir);
+ free(dename);
+
+ return ret;
+}
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/unixwalkdir.h b/plugins/uade2/uade-2.13/src/frontends/common/unixwalkdir.h
new file mode 100644
index 00000000..69844f47
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/unixwalkdir.h
@@ -0,0 +1,16 @@
+#ifndef _UADE_UNIXWALKDIR_H_
+#define _UADE_UNIXWALKDIR_H_
+
+enum uade_wtype {
+ UADE_WALK_REGULAR_FILE = 1,
+ UADE_WALK_DIRECTORY,
+ UADE_WALK_SYMLINK,
+ UADE_WALK_SPECIAL
+};
+
+void *uade_walk_directories(const char *dirname,
+ void *(*fn) (const char *file,
+ enum uade_wtype wtype, void *opaque),
+ void *opaque);
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/vplist.c b/plugins/uade2/uade-2.13/src/frontends/common/vplist.c
new file mode 100644
index 00000000..5546f54d
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/vplist.c
@@ -0,0 +1,115 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "vplist.h"
+
+
+#define VPLIST_BASIC_LENGTH 5
+
+
+static void shrink_vplist(struct vplist *v, size_t newsize)
+{
+ size_t ncopied = v->tail - v->head;
+ void **newl;
+ if (newsize >= v->allocated) {
+ fprintf(stderr, "vplist not shrinked.\n");
+ return;
+ }
+ memmove(v->l, &v->l[v->head], ncopied * sizeof(v->l[0]));
+ v->head = 0;
+ v->tail = ncopied;
+ v->allocated = newsize;
+ if ((newl = realloc(v->l, v->allocated * sizeof(v->l[0]))) == NULL) {
+ fprintf(stderr, "Not enough memory for shrinking vplist.\n");
+ exit(-1);
+ }
+ v->l = newl;
+}
+
+
+void vplist_grow(struct vplist *v)
+{
+ size_t newsize = v->allocated * 2;
+ void **newl;
+ if (newsize == 0)
+ newsize = VPLIST_BASIC_LENGTH;
+ newl = realloc(v->l, newsize * sizeof(v->l[0]));
+ if (newl == NULL) {
+ fprintf(stderr, "Not enough memory for growing vplist.\n");
+ exit(-1);
+ }
+ v->l = newl;
+ v->allocated = newsize;
+}
+
+
+struct vplist *vplist_create(size_t initial_length)
+{
+ struct vplist *v;
+ if ((v = calloc(1, sizeof(*v))) == NULL) {
+ fprintf(stderr, "No memory for vplist.\n");
+ exit(-1);
+ }
+ if (initial_length == 0)
+ initial_length = VPLIST_BASIC_LENGTH;
+ v->allocated = initial_length;
+ if ((v->l = malloc(v->allocated * sizeof(v->l[0]))) == NULL) {
+ fprintf(stderr, "Can not create a vplist.\n");
+ exit(-1);
+ }
+ return v;
+}
+
+
+void vplist_flush(struct vplist *v)
+{
+ v->head = v->tail = 0;
+ if (v->allocated >= (2 * VPLIST_BASIC_LENGTH))
+ shrink_vplist(v, VPLIST_BASIC_LENGTH);
+}
+
+
+void vplist_free(struct vplist *v)
+{
+ free(v->l);
+ memset(v, 0, sizeof(*v));
+ free(v);
+}
+
+
+void *vplist_pop_head(struct vplist *v)
+{
+ void *item;
+
+ if (v->head == v->tail) {
+ fprintf(stderr, "Error: can not pop head from an empty vplist.\n");
+ exit(-1);
+ }
+
+ item = v->l[v->head++];
+
+ /* If 3/4 of a list is unused, free half the list */
+ if (v->allocated >= VPLIST_BASIC_LENGTH && v->head >= ((v->allocated / 4) * 3))
+ shrink_vplist(v, v->allocated / 2);
+
+ return item;
+}
+
+
+void *vplist_pop_tail(struct vplist *v)
+{
+ void *item;
+
+ if (v->head == v->tail) {
+ fprintf(stderr, "Error: can not pop tail from an empty vplist.\n");
+ exit(-1);
+ }
+
+ item = v->l[v->tail--];
+
+ /* If 3/4 of a list is unused, free half the list */
+ if (v->allocated >= VPLIST_BASIC_LENGTH && v->tail < (v->allocated / 4))
+ shrink_vplist(v, v->allocated / 2);
+
+ return item;
+}
diff --git a/plugins/uade2/uade-2.13/src/frontends/common/vplist.h b/plugins/uade2/uade-2.13/src/frontends/common/vplist.h
new file mode 100644
index 00000000..ef79f5bd
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/frontends/common/vplist.h
@@ -0,0 +1,44 @@
+#ifndef _SHD_VPLIST_H_
+#define _SHD_VPLIST_H_
+
+#include <stdio.h>
+#include <assert.h>
+
+
+struct vplist {
+ size_t head;
+ size_t tail;
+ size_t allocated;
+ void **l;
+};
+
+
+struct vplist *vplist_create(size_t initial_length);
+void vplist_flush(struct vplist *v);
+void vplist_free(struct vplist *v);
+void vplist_grow(struct vplist *v);
+void *vplist_pop_head(struct vplist *v);
+void *vplist_pop_tail(struct vplist *v);
+
+
+static inline void vplist_append(struct vplist *v, void *item)
+{
+ if (v->tail == v->allocated)
+ vplist_grow(v);
+ v->l[v->tail++] = item;
+}
+
+
+static inline void *vplist_get(struct vplist *v, size_t i)
+{
+ assert(i < (v->tail - v->head));
+ return v->l[v->head + i];
+}
+
+
+static inline size_t vplist_len(struct vplist *v)
+{
+ return v->tail - v->head;
+}
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/include/.gitignore b/plugins/uade2/uade-2.13/src/include/.gitignore
new file mode 100644
index 00000000..c74efa80
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/.gitignore
@@ -0,0 +1,4 @@
+compilersupport.h
+ossupport.h
+sysincludes.h
+uadeconfig.h
diff --git a/plugins/uade2/uade-2.13/src/include/amigafilter.h b/plugins/uade2/uade-2.13/src/include/amigafilter.h
new file mode 100644
index 00000000..761fd33f
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/amigafilter.h
@@ -0,0 +1,10 @@
+#ifndef _UADE_AMIGA_FILTER_H_
+#define _UADE_AMIGA_FILTER_H_
+
+enum {
+ FILTER_MODEL_A500 = 1,
+ FILTER_MODEL_A1200,
+ FILTER_MODEL_UPPER_BOUND
+};
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/include/amigamsg.h b/plugins/uade2/uade-2.13/src/include/amigamsg.h
new file mode 100644
index 00000000..457529c3
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/amigamsg.h
@@ -0,0 +1,24 @@
+#ifndef _AMIGAMSG_H_
+#define _AMIGAMSG_H_
+
+enum amigamsg {
+ AMIGAMSG_SETSUBSONG = 1,
+ AMIGAMSG_SONG_END,
+ AMIGAMSG_PLAYERNAME,
+ AMIGAMSG_MODULENAME,
+ AMIGAMSG_SUBSINFO,
+ AMIGAMSG_CHECKERROR,
+ AMIGAMSG_SCORECRASH,
+ AMIGAMSG_SCOREDEAD,
+ AMIGAMSG_GENERALMSG,
+ AMIGAMSG_NTSC,
+ AMIGAMSG_FORMATNAME,
+ AMIGAMSG_LOADFILE,
+ AMIGAMSG_READ,
+ AMIGAMSG_FILESIZE,
+ AMIGAMSG_TIME_CRITICAL,
+ AMIGAMSG_GET_INFO,
+ AMIGAMSG_START_OUTPUT
+};
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/include/audio.h b/plugins/uade2/uade-2.13/src/include/audio.h
new file mode 100644
index 00000000..5716f5f9
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/audio.h
@@ -0,0 +1,57 @@
+ /*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * Sound emulation stuff
+ *
+ * Copyright 1995, 1996, 1997 Bernd Schmidt
+ */
+
+#ifndef _UADE_AUDIO_H_
+#define _UADE_AUDIO_H_
+
+#include "sinctable.h"
+
+#define AUDIO_DEBUG 0
+/* Queue length 256 implies minimum emulated period of 8. This should be
+ * sufficient for all imaginable purposes. This must be power of two. */
+#define SINC_QUEUE_LENGTH 256
+
+typedef struct {
+ int time, output;
+} sinc_queue_t;
+
+extern struct audio_channel_data {
+ unsigned long adk_mask;
+ unsigned long evtime;
+ unsigned char dmaen, intreq2, data_written;
+ uaecptr lc, pt;
+
+ int state, wper, wlen;
+ int current_sample;
+ int sample_accum, sample_accum_time;
+ int output_state;
+ sinc_queue_t sinc_queue[SINC_QUEUE_LENGTH];
+ int sinc_queue_time;
+ int sinc_queue_head;
+ int vol;
+ uae_u16 dat, nextdat, per, len;
+
+ /* Debug variables */
+ uaecptr ptend, nextdatpt, nextdatptend, datpt, datptend;
+} audio_channel[4];
+
+extern void AUDxDAT (int nr, uae_u16 value);
+extern void AUDxVOL (int nr, uae_u16 value);
+extern void AUDxPER (int nr, uae_u16 value);
+extern void AUDxLCH (int nr, uae_u16 value);
+extern void AUDxLCL (int nr, uae_u16 value);
+extern void AUDxLEN (int nr, uae_u16 value);
+
+void audio_reset (void);
+void audio_set_filter(int filter_type, int filter_force);
+void audio_set_rate (int rate);
+void audio_set_resampler(char *name);
+void audio_use_text_scope(void);
+void update_audio (void);
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/include/cia.h b/plugins/uade2/uade-2.13/src/include/cia.h
new file mode 100644
index 00000000..558b11c0
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/cia.h
@@ -0,0 +1,26 @@
+ /*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * CIA chip support
+ *
+ * (c) 1995 Bernd Schmidt
+ */
+
+extern void CIA_reset(void);
+extern void CIA_vsync_handler(void);
+extern void CIA_hsync_handler(void);
+extern void CIA_handler(void);
+
+extern void diskindex_handler(void);
+
+extern void dumpcia(void);
+
+extern unsigned int ciaaicr,ciaaimask,ciabicr,ciabimask;
+extern unsigned int ciaacra,ciaacrb,ciabcra,ciabcrb;
+extern unsigned int ciaapra, ciabpra;
+extern unsigned long ciaata,ciaatb,ciabta,ciabtb;
+extern unsigned long ciaatod,ciabtod,ciaatol,ciabtol,ciaaalarm,ciabalarm;
+extern int ciaatlatch,ciabtlatch;
+
+extern unsigned int gui_ledstate;
+extern int gui_ledstate_forced;
diff --git a/plugins/uade2/uade-2.13/src/include/commpipe.h b/plugins/uade2/uade-2.13/src/include/commpipe.h
new file mode 100644
index 00000000..c7f4d814
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/commpipe.h
@@ -0,0 +1,155 @@
+ /*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * Communication between threads
+ *
+ * Copyright 1997, 2001 Bernd Schmidt
+ */
+
+typedef union {
+ int i;
+ uae_u32 u32;
+ void *pv;
+} uae_pt;
+
+/* These currently require the maximum size to be known at initialization
+ * time, but it wouldn't be hard to use a "normal" pipe as an extension once the
+ * user-level one gets full.
+ * We queue up to chunks pieces of data before signalling the other thread to
+ * avoid overhead. */
+
+typedef struct {
+ uae_sem_t lock;
+ uae_sem_t reader_wait;
+ uae_sem_t writer_wait;
+ uae_pt *data;
+ int size, chunks;
+ volatile int rdp, wrp;
+ volatile int writer_waiting;
+ volatile int reader_waiting;
+} smp_comm_pipe;
+
+static inline void init_comm_pipe (smp_comm_pipe *p, int size, int chunks)
+{
+ p->data = (uae_pt *)malloc (size*sizeof (uae_pt));
+ p->size = size;
+ p->chunks = chunks;
+ p->rdp = p->wrp = 0;
+ p->reader_waiting = 0;
+ p->writer_waiting = 0;
+ uae_sem_init (&p->lock, 0, 1);
+ uae_sem_init (&p->reader_wait, 0, 0);
+ uae_sem_init (&p->writer_wait, 0, 0);
+}
+
+static inline void destroy_comm_pipe (smp_comm_pipe *p)
+{
+ uae_sem_destroy (&p->lock);
+ uae_sem_destroy (&p->reader_wait);
+ uae_sem_destroy (&p->writer_wait);
+}
+
+static inline void maybe_wake_reader (smp_comm_pipe *p, int no_buffer)
+{
+ if (p->reader_waiting
+ && (no_buffer || ((p->wrp - p->rdp + p->size) % p->size) >= p->chunks))
+ {
+ p->reader_waiting = 0;
+ uae_sem_post (&p->reader_wait);
+ }
+}
+
+static inline void write_comm_pipe_pt (smp_comm_pipe *p, uae_pt data, int no_buffer)
+{
+ int nxwrp = (p->wrp + 1) % p->size;
+
+ if (p->reader_waiting) {
+ /* No need to do all the locking */
+ p->data[p->wrp] = data;
+ p->wrp = nxwrp;
+ maybe_wake_reader (p, no_buffer);
+ return;
+ }
+
+ uae_sem_wait (&p->lock);
+ if (nxwrp == p->rdp) {
+ /* Pipe full! */
+ p->writer_waiting = 1;
+ uae_sem_post (&p->lock);
+ /* Note that the reader could get in between here and do a
+ * sem_post on writer_wait before we wait on it. That's harmless.
+ * There's a similar case in read_comm_pipe_int_blocking. */
+ uae_sem_wait (&p->writer_wait);
+ uae_sem_wait (&p->lock);
+ }
+ p->data[p->wrp] = data;
+ p->wrp = nxwrp;
+ maybe_wake_reader (p, no_buffer);
+ uae_sem_post (&p->lock);
+}
+
+static inline uae_pt read_comm_pipe_pt_blocking (smp_comm_pipe *p)
+{
+ uae_pt data;
+
+ uae_sem_wait (&p->lock);
+ if (p->rdp == p->wrp) {
+ p->reader_waiting = 1;
+ uae_sem_post (&p->lock);
+ uae_sem_wait (&p->reader_wait);
+ uae_sem_wait (&p->lock);
+ }
+ data = p->data[p->rdp];
+ p->rdp = (p->rdp + 1) % p->size;
+
+ /* We ignore chunks here. If this is a problem, make the size bigger in the init call. */
+ if (p->writer_waiting) {
+ p->writer_waiting = 0;
+ uae_sem_post (&p->writer_wait);
+ }
+ uae_sem_post (&p->lock);
+ return data;
+}
+
+static inline int comm_pipe_has_data (smp_comm_pipe *p)
+{
+ return p->rdp != p->wrp;
+}
+
+static inline int read_comm_pipe_int_blocking (smp_comm_pipe *p)
+{
+ uae_pt foo = read_comm_pipe_pt_blocking (p);
+ return foo.i;
+}
+static inline uae_u32 read_comm_pipe_u32_blocking (smp_comm_pipe *p)
+{
+ uae_pt foo = read_comm_pipe_pt_blocking (p);
+ return foo.u32;
+}
+
+static inline void *read_comm_pipe_pvoid_blocking (smp_comm_pipe *p)
+{
+ uae_pt foo = read_comm_pipe_pt_blocking (p);
+ return foo.pv;
+}
+
+static inline void write_comm_pipe_int (smp_comm_pipe *p, int data, int no_buffer)
+{
+ uae_pt foo;
+ foo.i = data;
+ write_comm_pipe_pt (p, foo, no_buffer);
+}
+
+static inline void write_comm_pipe_u32 (smp_comm_pipe *p, int data, int no_buffer)
+{
+ uae_pt foo;
+ foo.u32 = data;
+ write_comm_pipe_pt (p, foo, no_buffer);
+}
+
+static inline void write_comm_pipe_pvoid (smp_comm_pipe *p, void *data, int no_buffer)
+{
+ uae_pt foo;
+ foo.pv = data;
+ write_comm_pipe_pt (p, foo, no_buffer);
+}
diff --git a/plugins/uade2/uade-2.13/src/include/compiler.h b/plugins/uade2/uade-2.13/src/include/compiler.h
new file mode 100644
index 00000000..545dd6a4
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/compiler.h
@@ -0,0 +1,111 @@
+ /*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * m68k -> i386 compiler
+ *
+ * (c) 1995 Bernd Schmidt
+ */
+
+typedef uaecptr (*code_execfunc)(void);
+
+struct code_page {
+ struct code_page *next;
+ uae_u32 allocmask;
+};
+
+struct hash_block {
+ struct hash_block *lru_next, *lru_prev;
+ struct hash_entry *he_first;
+
+ struct code_page *cpage;
+ int alloclen;
+ uae_u32 page_allocmask;
+ char *compile_start;
+
+ int nrefs;
+
+ int translated:1;
+ int untranslatable:1;
+ int allocfailed:1;
+};
+
+struct hash_entry {
+ code_execfunc execute; /* For the sake of the stubs in X86.S */
+ struct hash_entry *next,*prev;
+ struct hash_entry *next_same_block, *lru_next, *lru_prev;
+ struct hash_block *block;
+
+ uaecptr addr;
+ uae_u32 matchword;
+ int ncalls:8;
+ int locked:1;
+ int cacheflush:1;
+};
+
+extern int nr_bbs_start;
+extern uae_u8 nr_bbs_to_run;
+extern code_execfunc exec_me;
+
+#ifdef USE_COMPILER
+static inline void run_compiled_code(void)
+{
+
+ /*if (regs.spcflags == SPCFLAG_EXEC && may_run_compiled) {*/
+ while (regs.spcflags == SPCFLAG_EXEC) {
+ uaecptr newpc;
+ regs.spcflags = 0;
+ /* newpc = (*exec_me)();*/
+ __asm__ __volatile__ ("pushl %%ebp; call *%1; popl %%ebp" : "=a" (newpc) : "r" (exec_me) :
+ "%eax", "%edx", "%ecx", "%ebx",
+ "%edi", "%esi", "memory", "cc");
+ if (nr_bbs_to_run == 0) {
+ struct hash_entry *h = (struct hash_entry *)newpc;
+ regs.spcflags = SPCFLAG_EXEC;
+ exec_me = h->execute;
+ regs.pc = h->addr;
+ regs.pc_p = regs.pc_oldp = get_real_address(h->addr);
+ nr_bbs_to_run = nr_bbs_start;
+ } else
+ m68k_setpc_fast(newpc);
+ do_cycles();
+ }
+/*} else */
+ regs.spcflags &= ~SPCFLAG_EXEC;
+}
+
+extern void compiler_init(void);
+extern void possible_loadseg(void);
+
+extern void m68k_do_rts(void);
+extern void m68k_do_bsr(uaecptr, uae_s32);
+extern void m68k_do_jsr(uaecptr, uaecptr);
+extern void compiler_flush_jsr_stack(void);
+
+#else
+
+#define run_compiled_code() do { ; } while (0)
+#define compiler_init() do { ; } while (0)
+#define possible_loadseg() do { ; } while (0)
+#define compiler_flush_jsr_stack() do { ; } while (0)
+
+static inline void m68k_do_rts(void)
+{
+ m68k_setpc(get_long(m68k_areg(regs, 7)));
+ m68k_areg(regs, 7) += 4;
+}
+
+static inline void m68k_do_bsr(uaecptr oldpc, uae_s32 offset)
+{
+ m68k_areg(regs, 7) -= 4;
+ put_long(m68k_areg(regs, 7), oldpc);
+ m68k_incpc(offset);
+}
+
+static inline void m68k_do_jsr(uaecptr oldpc, uaecptr dest)
+{
+ m68k_areg(regs, 7) -= 4;
+ put_long(m68k_areg(regs, 7), oldpc);
+ m68k_setpc(dest);
+}
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/include/custom.h b/plugins/uade2/uade-2.13/src/include/custom.h
new file mode 100644
index 00000000..15e3d689
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/custom.h
@@ -0,0 +1,115 @@
+ /*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * custom chip support
+ *
+ * (c) 1995 Bernd Schmidt
+ */
+
+/* These are the masks that are ORed together in the chipset_mask option.
+ * If CSMASK_AGA is set, the ECS bits are guaranteed to be set as well. */
+#define CSMASK_ECS_AGNUS 1
+#define CSMASK_ECS_DENISE 2
+#define CSMASK_AGA 4
+
+extern void custom_init (void);
+extern void customreset (void);
+extern int intlev (void);
+extern void dumpcustom (void);
+
+extern void do_disk (void);
+
+extern void notice_new_xcolors (void);
+extern void notice_screen_contents_lost (void);
+extern void init_row_map (void);
+
+extern int picasso_requested_on;
+extern int picasso_on;
+
+/* Set to 1 to leave out the current frame in average frame time calculation.
+ * Useful if the debugger was active. */
+extern int bogusframe;
+
+extern uae_u16 dmacon;
+extern uae_u16 intena,intreq;
+
+extern int current_hpos (void);
+
+static inline int dmaen (unsigned int dmamask)
+{
+ return (dmamask & dmacon) && (dmacon & 0x200);
+}
+
+#define SPCFLAG_STOP 2
+#define SPCFLAG_DISK 4
+#define SPCFLAG_INT 8
+#define SPCFLAG_BRK 16
+#define SPCFLAG_EXTRA_CYCLES 32
+#define SPCFLAG_TRACE 64
+#define SPCFLAG_DOTRACE 128
+#define SPCFLAG_DOINT 256
+#define SPCFLAG_BLTNASTY 512
+#define SPCFLAG_EXEC 1024
+#define SPCFLAG_MODE_CHANGE 8192
+
+extern int dskdmaen;
+extern uae_u16 adkcon;
+
+extern unsigned int joy0dir, joy1dir;
+extern int joy0button, joy1button;
+
+extern void INTREQ (uae_u16);
+extern uae_u16 INTREQR (void);
+
+/* maximums for statically allocated tables */
+
+/* PAL/NTSC values */
+
+/* The HRM says: The vertical blanking area (PAL) ranges from line 0 to line 29,
+ * and no data can be displayed there. Nevertheless, we lose some overscan data
+ * if minfirstline is set to 29. */
+
+#define MAXHPOS_PAL 227
+#define MAXHPOS_NTSC 227
+#define MAXVPOS_PAL 312
+#define MAXVPOS_NTSC 262
+#define MINFIRSTLINE_PAL 21
+#define MINFIRSTLINE_NTSC 18
+#define VBLANK_ENDLINE_PAL 29
+#define VBLANK_ENDLINE_NTSC 24
+#define VBLANK_HZ_PAL 50
+#define VBLANK_HZ_NTSC 60
+
+#define SOUNDTICKS_PAL 3546895
+#define SOUNDTICKS_NTSC 3579545
+
+#define MAXHPOS (MAXHPOS_PAL)
+#define MAXVPOS (MAXVPOS_PAL)
+#define SOUNDTICKS (SOUNDTICKS_PAL)
+
+extern int maxhpos, maxvpos, minfirstline, vblank_endline, numscrlines, vblank_hz;
+extern unsigned long syncbase;
+#define NUMSCRLINES (maxvpos+1-minfirstline+1)
+
+#define DMA_AUD0 0x0001
+#define DMA_AUD1 0x0002
+#define DMA_AUD2 0x0004
+#define DMA_AUD3 0x0008
+#define DMA_DISK 0x0010
+#define DMA_SPRITE 0x0020
+#define DMA_BLITTER 0x0040
+#define DMA_COPPER 0x0080
+#define DMA_BITPLANE 0x0100
+#define DMA_BLITPRI 0x0400
+
+extern unsigned long frametime, timeframes;
+
+/* 50 words give you 800 horizontal pixels. An A500 can't do that, so it ought
+ * to be enough. Don't forget to update the definition in genp2c.c as well. */
+#define MAX_WORDS_PER_LINE 50
+
+extern uae_u32 hirestab_h[256][2];
+extern uae_u32 lorestab_h[256][4];
+
+extern uae_u32 hirestab_l[256][1];
+extern uae_u32 lorestab_l[256][2];
diff --git a/plugins/uade2/uade-2.13/src/include/debug.h b/plugins/uade2/uade-2.13/src/include/debug.h
new file mode 100644
index 00000000..8ca10ab5
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/debug.h
@@ -0,0 +1,25 @@
+ /*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * Debugger
+ *
+ * (c) 1995 Bernd Schmidt
+ *
+ */
+
+#define MAX_HIST 10000
+
+extern int firsthist;
+extern int lasthist;
+extern int debugging;
+extern int debug_interrupt_happened;
+
+#ifdef NEED_TO_DEBUG_BADLY
+extern struct regstruct history[MAX_HIST];
+extern union flagu historyf[MAX_HIST];
+#else
+extern uaecptr history[MAX_HIST];
+#endif
+
+extern void debug(void);
+extern void activate_debugger(void);
diff --git a/plugins/uade2/uade-2.13/src/include/events.h b/plugins/uade2/uade-2.13/src/include/events.h
new file mode 100644
index 00000000..4b692650
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/events.h
@@ -0,0 +1,83 @@
+ /*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * Events
+ * These are best for low-frequency events. Having too many of them,
+ * or using them for events that occur too frequently, can cause massive
+ * slowdown.
+ *
+ * Copyright 1995-1998 Bernd Schmidt
+ */
+
+extern void reset_frame_rate_hack (void);
+extern int rpt_available;
+
+extern unsigned long int cycles, nextevent, is_lastline;
+extern unsigned long int sample_evtime;
+typedef void (*evfunc)(void);
+
+struct ev
+{
+ int active;
+ unsigned long int evtime, oldcycles;
+ evfunc handler;
+};
+
+enum {
+ ev_hsync, ev_copper, ev_cia,
+ ev_blitter, ev_diskblk, ev_diskindex,
+ ev_max
+};
+
+extern struct ev eventtab[ev_max];
+
+static void events_schedule (void)
+{
+ unsigned long int mintime = ~0L;
+ unsigned long int eventtime;
+ /* HSYNC */
+ if(eventtab[ev_hsync].active) {
+ eventtime = eventtab[ev_hsync].evtime - cycles;
+ if (eventtime < mintime) mintime = eventtime;
+ }
+ /* AUDIO */
+#if 0
+ if(eventtab[ev_audio].active) {
+ eventtime = eventtab[ev_audio].evtime - cycles;
+ if (eventtime < mintime) mintime = eventtime;
+ }
+#endif
+ /* CIA */
+ if(eventtab[ev_cia].active) {
+ eventtime = eventtab[ev_cia].evtime - cycles;
+ if (eventtime < mintime) mintime = eventtime;
+ }
+ nextevent = cycles + mintime;
+}
+
+static void do_cycles_slow (unsigned long cycles_to_add) {
+ if ((nextevent - cycles) <= cycles_to_add) {
+ for (; cycles_to_add != 0; cycles_to_add--) {
+ if (++cycles == nextevent) {
+ /* HSYNC */
+ if(eventtab[ev_hsync].active && eventtab[ev_hsync].evtime == cycles) {
+ (*eventtab[ev_hsync].handler)();
+ }
+ /* AUDIO */
+#if 0
+ if(eventtab[ev_audio].active && eventtab[ev_audio].evtime == cycles) {
+ (*eventtab[ev_audio].handler)();
+ }
+#endif
+ /* CIA */
+ if(eventtab[ev_cia].active && eventtab[ev_cia].evtime == cycles) {
+ (*eventtab[ev_cia].handler)();
+ }
+ events_schedule();
+ }
+ }
+ }
+ cycles += cycles_to_add;
+}
+
+#define do_cycles do_cycles_slow
diff --git a/plugins/uade2/uade-2.13/src/include/execlib.h b/plugins/uade2/uade-2.13/src/include/execlib.h
new file mode 100644
index 00000000..c0777221
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/execlib.h
@@ -0,0 +1,40 @@
+ /*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * Miscellaneous bits for exec emulation
+ *
+ * Copyright 1996 Bernd Schmidt
+ */
+
+#define CMD_INVALID 0
+#define CMD_RESET 1
+#define CMD_READ 2
+#define CMD_WRITE 3
+#define CMD_UPDATE 4
+#define CMD_CLEAR 5
+#define CMD_STOP 6
+#define CMD_START 7
+#define CMD_FLUSH 8
+#define CMD_NONSTD 9
+
+#define NT_TASK 1
+#define NT_DEVICE 3
+#define NT_MSGPORT 4
+#define NT_MESSAGE 5
+#define NT_FREEMSG 6
+#define NT_REPLYMSG 7
+#define NT_RESOURCE 8
+#define NT_LIBRARY 9
+#define NT_SIGNALSEM 15
+
+#ifndef MEMF_PUBLIC /* protection for AmigaDOS */
+#define MEMF_PUBLIC 1
+#define MEMF_CHIP 2
+#define MEMF_FAST 4
+#define MEMF_LOCAL 256
+#define MEMF_24BITDMA 512
+#define MEMF_CLEAR (1<<16)
+#define MEMF_LARGEST (1<<17)
+#define MEMF_REVERSE (1<<18)
+#define MEMF_TOTAL (1<<19)
+#endif
diff --git a/plugins/uade2/uade-2.13/src/include/gensound.h b/plugins/uade2/uade-2.13/src/include/gensound.h
new file mode 100644
index 00000000..63daeb04
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/gensound.h
@@ -0,0 +1,19 @@
+ /*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * Prototypes for general sound related functions
+ * This use to be called sound.h, but that causes confusion
+ *
+ * Copyright 1997 Bernd Schmidt
+ */
+
+extern int sound_available;
+
+/* Determine if we can produce any sound at all. This can be only a guess;
+ * if unsure, say yes. Any call to init_sound may change the value. */
+extern int setup_sound (void);
+
+extern void set_sound_freq (int x);
+extern void init_sound (void);
+extern void flush_sound (void);
+extern void close_sound (void);
diff --git a/plugins/uade2/uade-2.13/src/include/memory.h b/plugins/uade2/uade-2.13/src/include/memory.h
new file mode 100644
index 00000000..96a967b5
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/memory.h
@@ -0,0 +1,181 @@
+ /*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * memory management
+ *
+ * Copyright 1995 Bernd Schmidt
+ */
+
+/* Enabling this adds one additional native memory reference per 68k memory
+ * access, but saves one shift (on the x86). Enabling this is probably
+ * better for the cache. My favourite benchmark (PP2) doesn't show a
+ * difference, so I leave this enabled. */
+
+#if 1 || defined SAVE_MEMORY
+#define SAVE_MEMORY_BANKS
+#endif
+
+#ifndef REGPARAM
+#define REGPARAM
+#endif
+
+typedef uae_u32 (*mem_get_func)(uaecptr) REGPARAM;
+typedef void (*mem_put_func)(uaecptr, uae_u32) REGPARAM;
+typedef uae_u8 *(*xlate_func)(uaecptr) REGPARAM;
+typedef int (*check_func)(uaecptr, uae_u32) REGPARAM;
+
+extern char *address_space, *good_address_map;
+extern uae_u8 *chipmemory;
+
+extern uae_u32 allocated_chipmem;
+extern uae_u32 allocated_fastmem;
+extern uae_u32 allocated_bogomem;
+extern uae_u32 allocated_gfxmem;
+extern uae_u32 allocated_z3fastmem;
+extern uae_u32 allocated_a3000mem;
+
+#undef DIRECT_MEMFUNCS_SUCCESSFUL
+#include "machdep/maccess.h"
+
+#ifndef CAN_MAP_MEMORY
+#undef USE_COMPILER
+#endif
+
+#if defined(USE_COMPILER) && !defined(USE_MAPPED_MEMORY)
+#define USE_MAPPED_MEMORY
+#endif
+
+#define kickmem_size 0x080000
+
+#define chipmem_start 0x00000000
+#define bogomem_start 0x00C00000
+#define a3000mem_start 0x07000000
+#define kickmem_start 0x00F80000
+
+extern int ersatzkickfile;
+
+typedef struct {
+ /* These ones should be self-explanatory... */
+ mem_get_func lget, wget, bget;
+ mem_put_func lput, wput, bput;
+ /* Use xlateaddr to translate an Amiga address to a uae_u8 * that can
+ * be used to address memory without calling the wget/wput functions.
+ * This doesn't work for all memory banks, so this function may call
+ * abort(). */
+ xlate_func xlateaddr;
+ /* To prevent calls to abort(), use check before calling xlateaddr.
+ * It checks not only that the memory bank can do xlateaddr, but also
+ * that the pointer points to an area of at least the specified size.
+ * This is used for example to translate bitplane pointers in custom.c */
+ check_func check;
+} addrbank;
+
+extern uae_u8 filesysory[65536];
+
+extern addrbank chipmem_bank;
+extern addrbank kickmem_bank;
+extern addrbank custom_bank;
+extern addrbank clock_bank;
+extern addrbank cia_bank;
+extern addrbank rtarea_bank;
+extern addrbank expamem_bank;
+extern addrbank fastmem_bank;
+extern addrbank gfxmem_bank;
+
+extern void rtarea_init (void);
+extern void rtarea_setup (void);
+extern void expamem_init (void);
+extern void expamem_reset (void);
+
+extern uae_u32 gfxmem_start;
+extern uae_u8 *gfxmemory;
+extern uae_u32 gfxmem_mask;
+extern int address_space_24;
+
+/* Default memory access functions */
+
+extern int default_check(uaecptr addr, uae_u32 size) REGPARAM;
+extern uae_u8 *default_xlate(uaecptr addr) REGPARAM;
+
+#define bankindex(addr) (((uaecptr)(addr)) >> 16)
+
+#ifdef SAVE_MEMORY_BANKS
+extern addrbank *mem_banks[65536];
+#define get_mem_bank(addr) (*mem_banks[bankindex(addr)])
+#define put_mem_bank(addr, b) (mem_banks[bankindex(addr)] = (b))
+#else
+extern addrbank mem_banks[65536];
+#define get_mem_bank(addr) (mem_banks[bankindex(addr)])
+#define put_mem_bank(addr, b) (mem_banks[bankindex(addr)] = *(b))
+#endif
+
+extern void memory_init(void);
+extern void map_banks(addrbank *bank, int first, int count);
+
+#ifndef NO_INLINE_MEMORY_ACCESS
+
+#define longget(addr) (call_mem_get_func(get_mem_bank(addr).lget, addr))
+#define wordget(addr) (call_mem_get_func(get_mem_bank(addr).wget, addr))
+#define byteget(addr) (call_mem_get_func(get_mem_bank(addr).bget, addr))
+#define longput(addr,l) (call_mem_put_func(get_mem_bank(addr).lput, addr, l))
+#define wordput(addr,w) (call_mem_put_func(get_mem_bank(addr).wput, addr, w))
+#define byteput(addr,b) (call_mem_put_func(get_mem_bank(addr).bput, addr, b))
+
+#else
+
+extern uae_u32 alongget(uaecptr addr);
+extern uae_u32 awordget(uaecptr addr);
+extern uae_u32 longget(uaecptr addr);
+extern uae_u32 wordget(uaecptr addr);
+extern uae_u32 byteget(uaecptr addr);
+extern void longput(uaecptr addr, uae_u32 l);
+extern void wordput(uaecptr addr, uae_u32 w);
+extern void byteput(uaecptr addr, uae_u32 b);
+
+#endif
+
+#ifndef MD_HAVE_MEM_1_FUNCS
+
+#define longget_1 longget
+#define wordget_1 wordget
+#define byteget_1 byteget
+#define longput_1 longput
+#define wordput_1 wordput
+#define byteput_1 byteput
+
+#endif
+
+static inline uae_u32 get_long(uaecptr addr)
+{
+ return longget_1(addr);
+}
+static inline uae_u32 get_word(uaecptr addr)
+{
+ return wordget_1(addr);
+}
+static inline uae_u32 get_byte(uaecptr addr)
+{
+ return byteget_1(addr);
+}
+static inline void put_long(uaecptr addr, uae_u32 l)
+{
+ longput_1(addr, l);
+}
+static inline void put_word(uaecptr addr, uae_u32 w)
+{
+ wordput_1(addr, w);
+}
+static inline void put_byte(uaecptr addr, uae_u32 b)
+{
+ byteput_1(addr, b);
+}
+
+static inline uae_u8 *get_real_address(uaecptr addr)
+{
+ return get_mem_bank(addr).xlateaddr(addr);
+}
+
+static inline int valid_address(uaecptr addr, uae_u32 size)
+{
+ return get_mem_bank(addr).check(addr, size);
+}
diff --git a/plugins/uade2/uade-2.13/src/include/newcpu.h b/plugins/uade2/uade-2.13/src/include/newcpu.h
new file mode 100644
index 00000000..84732f10
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/newcpu.h
@@ -0,0 +1,275 @@
+ /*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * MC68000 emulation
+ *
+ * Copyright 1995 Bernd Schmidt
+ */
+
+#include <machdep/m68k.h>
+
+void m68k_run_1 (void);
+
+#ifndef SET_CFLG
+
+#define SET_CFLG(x) (CFLG = (x))
+#define SET_NFLG(x) (NFLG = (x))
+#define SET_VFLG(x) (VFLG = (x))
+#define SET_ZFLG(x) (ZFLG = (x))
+#define SET_XFLG(x) (XFLG = (x))
+
+#define GET_CFLG CFLG
+#define GET_NFLG NFLG
+#define GET_VFLG VFLG
+#define GET_ZFLG ZFLG
+#define GET_XFLG XFLG
+
+#define CLEAR_CZNV do { \
+ SET_CFLG (0); \
+ SET_ZFLG (0); \
+ SET_NFLG (0); \
+ SET_VFLG (0); \
+while (0)
+
+#define COPY_CARRY (SET_XFLG (GET_CFLG))
+#endif
+
+extern int areg_byteinc[];
+extern int imm8_table[];
+
+extern int movem_index1[256];
+extern int movem_index2[256];
+extern int movem_next[256];
+
+extern int fpp_movem_index1[256];
+extern int fpp_movem_index2[256];
+extern int fpp_movem_next[256];
+
+extern int broken_in;
+
+typedef unsigned long cpuop_func (uae_u32) REGPARAM;
+
+struct cputbl {
+ cpuop_func *handler;
+ int specific;
+ uae_u16 opcode;
+};
+
+extern unsigned long op_illg (uae_u32) REGPARAM;
+
+typedef char flagtype;
+
+extern struct regstruct
+{
+ uae_u32 regs[16];
+ uaecptr usp,isp,msp;
+ uae_u16 sr;
+ flagtype t1;
+ flagtype t0;
+ flagtype s;
+ flagtype m;
+ flagtype x;
+ flagtype stopped;
+ int intmask;
+
+ uae_u32 pc;
+ uae_u8 *pc_p;
+ uae_u8 *pc_oldp;
+
+ uae_u32 vbr,sfc,dfc;
+
+ double fp[8];
+ uae_u32 fpcr,fpsr,fpiar;
+
+ uae_u32 spcflags;
+ uae_u32 kick_mask;
+
+ /* Fellow sources say this is 4 longwords. That's impossible. It needs
+ * to be at least a longword. The HRM has some cryptic comment about two
+ * instructions being on the same longword boundary.
+ * The way this is implemented now seems like a good compromise.
+ */
+ uae_u32 prefetch;
+} regs, lastint_regs;
+
+#define m68k_dreg(r,num) ((r).regs[(num)])
+#define m68k_areg(r,num) (((r).regs + 8)[(num)])
+
+#define get_ibyte(o) do_get_mem_byte((uae_u8 *)(regs.pc_p + (o) + 1))
+#define get_iword(o) do_get_mem_word((uae_u16 *)(regs.pc_p + (o)))
+#define get_ilong(o) do_get_mem_long((uae_u32 *)(regs.pc_p + (o)))
+
+#ifdef HAVE_GET_WORD_UNSWAPPED
+#define GET_OPCODE (do_get_mem_word_unswapped (regs.pc_p))
+#else
+#define GET_OPCODE (get_iword (0))
+#endif
+
+static inline uae_u32 get_ibyte_prefetch (uae_s32 o)
+{
+ if (o > 3 || o < 0)
+ return do_get_mem_byte((uae_u8 *)(regs.pc_p + o + 1));
+
+ return do_get_mem_byte((uae_u8 *)(((uae_u8 *)&regs.prefetch) + o + 1));
+}
+static inline uae_u32 get_iword_prefetch (uae_s32 o)
+{
+ if (o > 3 || o < 0)
+ return do_get_mem_word((uae_u16 *)(regs.pc_p + o));
+
+ return do_get_mem_word((uae_u16 *)(((uae_u8 *)&regs.prefetch) + o));
+}
+static inline uae_u32 get_ilong_prefetch (uae_s32 o)
+{
+ union {
+ uae_u32 *u32;
+ uae_u16 *u16;
+ } prefetch_u;
+
+ if (o > 3 || o < 0)
+ return do_get_mem_long((uae_u32 *)(regs.pc_p + o));
+ if (o == 0)
+ return do_get_mem_long(&regs.prefetch);
+
+ prefetch_u.u32 = &regs.prefetch;
+
+ return (do_get_mem_word (prefetch_u.u16 + 1) << 16) | do_get_mem_word ((uae_u16 *)(regs.pc_p + 4));
+}
+
+#define m68k_incpc(o) (regs.pc_p += (o))
+
+static inline void fill_prefetch_0 (void)
+{
+ uae_u32 r;
+#ifdef UNALIGNED_PROFITABLE
+ r = *(uae_u32 *)regs.pc_p;
+ regs.prefetch = r;
+#else
+ r = do_get_mem_long ((uae_u32 *)regs.pc_p);
+ do_put_mem_long (&regs.prefetch, r);
+#endif
+}
+
+#if 0
+static inline void fill_prefetch_2 (void)
+{
+ uae_u32 r = do_get_mem_long (&regs.prefetch) << 16;
+ uae_u32 r2 = do_get_mem_word (((uae_u16 *)regs.pc_p) + 1);
+ r |= r2;
+ do_put_mem_long (&regs.prefetch, r);
+}
+#else
+#define fill_prefetch_2 fill_prefetch_0
+#endif
+
+/* These are only used by the 68020/68881 code, and therefore don't
+ * need to handle prefetch. */
+static inline uae_u32 next_ibyte (void)
+{
+ uae_u32 r = get_ibyte (0);
+ m68k_incpc (2);
+ return r;
+}
+
+static inline uae_u32 next_iword (void)
+{
+ uae_u32 r = get_iword (0);
+ m68k_incpc (2);
+ return r;
+}
+
+static inline uae_u32 next_ilong (void)
+{
+ uae_u32 r = get_ilong (0);
+ m68k_incpc (4);
+ return r;
+}
+
+#if !defined USE_COMPILER
+static inline void m68k_setpc (uaecptr newpc)
+{
+ regs.pc_p = regs.pc_oldp = get_real_address(newpc);
+ regs.pc = newpc;
+}
+#else
+extern void m68k_setpc (uaecptr newpc);
+#endif
+
+static inline uaecptr m68k_getpc (void)
+{
+ return regs.pc + ((char *)regs.pc_p - (char *)regs.pc_oldp);
+}
+
+static inline uaecptr m68k_getpc_p (uae_u8 *p)
+{
+ return regs.pc + ((char *)p - (char *)regs.pc_oldp);
+}
+
+#ifdef USE_COMPILER
+extern void m68k_setpc_fast (uaecptr newpc);
+extern void m68k_setpc_bcc (uaecptr newpc);
+extern void m68k_setpc_rte (uaecptr newpc);
+#else
+#define m68k_setpc_fast m68k_setpc
+#define m68k_setpc_bcc m68k_setpc
+#define m68k_setpc_rte m68k_setpc
+#endif
+
+static inline void m68k_setstopped (int stop)
+{
+ regs.stopped = stop;
+ if (stop)
+ regs.spcflags |= SPCFLAG_STOP;
+}
+
+extern uae_u32 get_disp_ea_020 (uae_u32 base, uae_u32 dp);
+extern uae_u32 get_disp_ea_000 (uae_u32 base, uae_u32 dp);
+
+extern uae_s32 ShowEA (int reg, amodes mode, wordsizes size, char *buf);
+
+extern void MakeSR (void);
+extern void MakeFromSR (void);
+extern void Exception (int, uaecptr);
+extern void dump_counts (void);
+extern void m68k_move2c (int, uae_u32 *);
+extern void m68k_movec2 (int, uae_u32 *);
+extern void m68k_divl (uae_u32, uae_u32, uae_u16, uaecptr);
+extern void m68k_mull (uae_u32, uae_u32, uae_u16);
+extern void init_m68k (void);
+extern void m68k_go (void);
+extern void m68k_dumpstate (uaecptr *);
+extern void m68k_disasm (uaecptr, uaecptr *, int);
+extern void m68k_reset (void);
+
+extern void mmu_op (uae_u32, uae_u16);
+
+extern void fpp_opp (uae_u32, uae_u16);
+extern void fdbcc_opp (uae_u32, uae_u16);
+extern void fscc_opp (uae_u32, uae_u16);
+extern void ftrapcc_opp (uae_u32,uaecptr);
+extern void fbcc_opp (uae_u32, uaecptr, uae_u32);
+extern void fsave_opp (uae_u32);
+extern void frestore_opp (uae_u32);
+
+/* Opcode of faulting instruction */
+extern uae_u16 last_op_for_exception_3;
+/* PC at fault time */
+extern uaecptr last_addr_for_exception_3;
+/* Address that generated the exception */
+extern uaecptr last_fault_for_exception_3;
+
+#define CPU_OP_NAME(a) op ## a
+
+/* 68020 + 68881 */
+extern struct cputbl op_smalltbl_0[];
+/* 68020 */
+extern struct cputbl op_smalltbl_1[];
+/* 68010 */
+extern struct cputbl op_smalltbl_2[];
+/* 68000 */
+extern struct cputbl op_smalltbl_3[];
+/* 68000 slow but compatible. */
+extern struct cputbl op_smalltbl_4[];
+
+extern cpuop_func *cpufunctbl[65536];
+
diff --git a/plugins/uade2/uade-2.13/src/include/options.h b/plugins/uade2/uade-2.13/src/include/options.h
new file mode 100644
index 00000000..2ec4befc
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/options.h
@@ -0,0 +1,262 @@
+ /*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * Stuff
+ *
+ * Copyright 1995, 1996 Ed Hanway
+ * Copyright 1995-98 Bernd Schmidt
+ */
+
+#define UAEMAJOR 0
+#define UAEMINOR 8
+#define UAESUBREV 9
+
+typedef enum { KBD_LANG_US, KBD_LANG_DE, KBD_LANG_SE, KBD_LANG_FR, KBD_LANG_IT, KBD_LANG_ES } KbdLang;
+
+extern long int version;
+
+struct uaedev_mount_info;
+
+struct strlist {
+ struct strlist *next;
+ char *str;
+};
+
+struct uae_prefs {
+ struct strlist *unknown_lines;
+
+ char description[256];
+
+ int illegal_mem;
+ int no_xhair;
+ int use_serial;
+ int serial_demand;
+ int parallel_demand;
+ int automount_uaedev;
+ int use_gfxlib;
+ int socket_emu;
+
+ int start_debugger;
+ int start_gui;
+
+ int jport0;
+ int jport1;
+ KbdLang keyboard_lang;
+ int allow_save;
+ int emul_accuracy;
+ int test_drawing_speed;
+
+ int produce_sound;
+ int stereo;
+ int sound_bits;
+ int sound_freq;
+ int sound_minbsiz;
+ int sound_maxbsiz;
+ int sound_pri_time;
+ int sound_pri_cutoff;
+ int sound_interpol;
+
+ int gfx_framerate;
+ int gfx_width;
+ int gfx_height;
+ int gfx_lores;
+ int gfx_linedbl;
+ int gfx_correct_aspect;
+ int gfx_afullscreen;
+ int gfx_pfullscreen;
+ int gfx_xcenter;
+ int gfx_ycenter;
+ int color_mode;
+
+ int blits_32bit_enabled;
+ int immediate_blits;
+ unsigned int chipset_mask;
+ int ntscmode;
+
+ char df[4][256];
+ char romfile[256];
+ char keyfile[256];
+ char prtname[256];
+
+ char path_floppy[256];
+ char path_hardfile[256];
+ char path_rom[256];
+
+ int m68k_speed;
+ int cpu_level;
+ int cpu_compatible;
+ int address_space_24;
+
+ uae_u32 z3fastmem_size;
+ uae_u32 fastmem_size;
+ uae_u32 chipmem_size;
+ uae_u32 bogomem_size;
+ uae_u32 a3000mem_size;
+ uae_u32 gfxmem_size;
+
+ struct uaedev_mount_info *mountinfo;
+
+ /* Target specific options */
+ int x11_use_low_bandwidth;
+ int x11_use_mitshm;
+ int x11_use_dgamode;
+ int x11_hide_cursor;
+ int svga_no_linear;
+ int win32_middle_mouse;
+ int win32_sound_style;
+ int win32_sound_tweak;
+ int win32_logfile;
+ int win32_iconified_nospeed;
+ int win32_iconified_nosound;
+};
+
+extern void save_options (FILE *, struct uae_prefs *);
+
+extern void default_prefs (struct uae_prefs *);
+extern void discard_prefs (struct uae_prefs *);
+
+extern int cfgfile_yesno (char *option, char *value, char *name, int *location);
+extern int cfgfile_intval (char *option, char *value, char *name, int *location, int scale);
+extern int cfgfile_strval (char *option, char *value, char *name, int *location, const char *table[], int more);
+extern int cfgfile_string (char *option, char *value, char *name, char *location, int maxsz);
+extern char *cfgfile_subst_path (const char *path, const char *subst, const char *file);
+
+extern int target_parse_option (struct uae_prefs *, char *option, char *value);
+extern void target_save_options (FILE *, struct uae_prefs *);
+
+extern int cfgfile_load (struct uae_prefs *, const char *filename);
+extern int cfgfile_save (struct uae_prefs *, const char *filename);
+extern void cfgfile_parse_line (struct uae_prefs *p, char *);
+extern int cfgfile_parse_option (struct uae_prefs *p, char *option, char *value);
+extern int cfgfile_get_description (const char *filename, char *description);
+extern void cfgfile_show_usage (void);
+
+extern void fixup_prefs_dimensions (struct uae_prefs *prefs);
+
+extern void check_prefs_changed_custom (void);
+extern void check_prefs_changed_cpu (void);
+extern int check_prefs_changed_gfx (void);
+
+#define JSEM_DECODEVAL(n,v) ((n) == 0 ? (v)->jport0 : (v)->jport1)
+/* Determine how port n is configured */
+#define JSEM_ISJOY0(n,v) (JSEM_DECODEVAL(n,v) == 0)
+#define JSEM_ISJOY1(n,v) (JSEM_DECODEVAL(n,v) == 1)
+#define JSEM_ISMOUSE(n,v) (JSEM_DECODEVAL(n,v) == 2)
+#define JSEM_ISNUMPAD(n,v) (JSEM_DECODEVAL(n,v) == 3)
+#define JSEM_ISCURSOR(n,v) (JSEM_DECODEVAL(n,v) == 4)
+#define JSEM_ISSOMEWHEREELSE(n,v) (JSEM_DECODEVAL(n,v) == 5)
+extern const char *gameport_state (int n);
+
+extern struct uae_prefs currprefs, changed_prefs;
+
+#if __GNUC__ - 1 > 1 || __GNUC_MINOR__ - 1 > 6
+extern void write_log (const char *, ...) __attribute__ ((format (printf, 1, 2)));
+#else
+extern void write_log (const char *, ...);
+#endif
+
+extern void machdep_init (void);
+
+/* AIX doesn't think it is Unix. Neither do I. */
+#if defined(_ALL_SOURCE) || defined(_AIX)
+#undef __unix
+#define __unix
+#endif
+
+extern char romfile[], keyfile[], prtname[], sername[];
+
+extern int cloanto_rom;
+
+#define MAX_COLOR_MODES 5
+
+extern int fast_memcmp(const void *foo, const void *bar, int len);
+extern int memcmpy(void *foo, const void *bar, int len);
+
+/*
+ * You can specify numbers from 0 to 5 here. It is possible that higher
+ * numbers will make the CPU emulation slightly faster, but if the setting
+ * is too high, you will run out of memory while compiling.
+ * Best to leave this as it is.
+ */
+#define CPU_EMU_SIZE 0
+
+/* #define NEED_TO_DEBUG_BADLY */
+
+#if !defined(USER_PROGRAMS_BEHAVE)
+#define USER_PROGRAMS_BEHAVE 0
+#endif
+
+/* Some memsets which know that they can safely overwrite some more memory
+ * at both ends and use that knowledge to align the pointers. */
+
+#define QUADRUPLIFY(c) (((c) | ((c) << 8)) | (((c) | ((c) << 8)) << 16))
+
+/* When you call this routine, bear in mind that it rounds the bounds and
+ * may need some padding for the array. */
+
+#define fuzzy_memset(p, c, o, l) fuzzy_memset_1 ((p), QUADRUPLIFY (c), (o) & ~3, ((l) + 4) >> 2)
+static inline void fuzzy_memset_1 (void *p, uae_u32 c, int offset, int len)
+{
+ uae_u32 *p2 = (uae_u32 *)((char *)p + offset);
+ int a = len & 7;
+ len >>= 3;
+ switch (a) {
+ case 7: p2--; goto l1;
+ case 6: p2-=2; goto l2;
+ case 5: p2-=3; goto l3;
+ case 4: p2-=4; goto l4;
+ case 3: p2-=5; goto l5;
+ case 2: p2-=6; goto l6;
+ case 1: p2-=7; goto l7;
+ case 0: if (!--len) return; break;
+ }
+
+ for (;;) {
+ p2[0] = c;
+ l1:
+ p2[1] = c;
+ l2:
+ p2[2] = c;
+ l3:
+ p2[3] = c;
+ l4:
+ p2[4] = c;
+ l5:
+ p2[5] = c;
+ l6:
+ p2[6] = c;
+ l7:
+ p2[7] = c;
+
+ if (!len)
+ break;
+ len--;
+ p2 += 8;
+ }
+}
+
+/* This one knows it will never be asked to clear more than 32 bytes. Make sure you call this with a
+ constant for the length. */
+#define fuzzy_memset_le32(p, c, o, l) fuzzy_memset_le32_1 ((p), QUADRUPLIFY (c), (o) & ~3, ((l) + 7) >> 2)
+static inline void fuzzy_memset_le32_1 (void *p, uae_u32 c, int offset, int len)
+{
+ uae_u32 *p2 = (uae_u32 *)((char *)p + offset);
+
+ switch (len) {
+ case 9: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; p2[5] = c; p2[6] = c; p2[7] = c; p2[8] = c; break;
+ case 8: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; p2[5] = c; p2[6] = c; p2[7] = c; break;
+ case 7: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; p2[5] = c; p2[6] = c; break;
+ case 6: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; p2[5] = c; break;
+ case 5: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; break;
+ case 4: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; break;
+ case 3: p2[0] = c; p2[1] = c; p2[2] = c; break;
+ case 2: p2[0] = c; p2[1] = c; break;
+ case 1: p2[0] = c; break;
+ case 0: break;
+ default: printf("Hit the programmer.\n"); break;
+ }
+}
+
+#if defined(AMIGA) && defined(__GNUC__)
+/* #include "od-amiga/amiga-kludges.h" */
+#endif
diff --git a/plugins/uade2/uade-2.13/src/include/osemu.h b/plugins/uade2/uade-2.13/src/include/osemu.h
new file mode 100644
index 00000000..817c5c9b
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/osemu.h
@@ -0,0 +1,19 @@
+ /*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * OS emulation prototypes
+ *
+ * Copyright 1996 Bernd Schmidt
+ */
+
+static inline char *raddr(uaecptr p)
+{
+ return p == 0 ? NULL : (char *)get_real_address(p);
+}
+
+extern void gfxlib_install(void);
+
+/* graphics.library */
+
+extern int GFX_WritePixel(uaecptr rp, int x, int y);
+
diff --git a/plugins/uade2/uade-2.13/src/include/readcpu.h b/plugins/uade2/uade-2.13/src/include/readcpu.h
new file mode 100644
index 00000000..62a81c6a
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/readcpu.h
@@ -0,0 +1,99 @@
+ENUMDECL {
+ Dreg, Areg, Aind, Aipi, Apdi, Ad16, Ad8r,
+ absw, absl, PC16, PC8r, imm, imm0, imm1, imm2, immi, am_unknown, am_illg
+} ENUMNAME (amodes);
+
+ENUMDECL {
+ i_ILLG,
+
+ i_OR, i_AND, i_EOR, i_ORSR, i_ANDSR, i_EORSR,
+ i_SUB, i_SUBA, i_SUBX, i_SBCD,
+ i_ADD, i_ADDA, i_ADDX, i_ABCD,
+ i_NEG, i_NEGX, i_NBCD, i_CLR, i_NOT, i_TST,
+ i_BTST, i_BCHG, i_BCLR, i_BSET,
+ i_CMP, i_CMPM, i_CMPA,
+ i_MVPRM, i_MVPMR, i_MOVE, i_MOVEA, i_MVSR2, i_MV2SR,
+ i_SWAP, i_EXG, i_EXT, i_MVMEL, i_MVMLE,
+ i_TRAP, i_MVR2USP, i_MVUSP2R, i_RESET, i_NOP, i_STOP, i_RTE, i_RTD,
+ i_LINK, i_UNLK,
+ i_RTS, i_TRAPV, i_RTR,
+ i_JSR, i_JMP, i_BSR, i_Bcc,
+ i_LEA, i_PEA, i_DBcc, i_Scc,
+ i_DIVU, i_DIVS, i_MULU, i_MULS,
+ i_ASR, i_ASL, i_LSR, i_LSL, i_ROL, i_ROR, i_ROXL, i_ROXR,
+ i_ASRW, i_ASLW, i_LSRW, i_LSLW, i_ROLW, i_RORW, i_ROXLW, i_ROXRW,
+ i_CHK,i_CHK2,
+ i_MOVEC2, i_MOVE2C, i_CAS, i_CAS2, i_DIVL, i_MULL,
+ i_BFTST,i_BFEXTU,i_BFCHG,i_BFEXTS,i_BFCLR,i_BFFFO,i_BFSET,i_BFINS,
+ i_PACK, i_UNPK, i_TAS, i_BKPT, i_CALLM, i_RTM, i_TRAPcc, i_MOVES,
+ i_FPP, i_FDBcc, i_FScc, i_FTRAPcc, i_FBcc, i_FSAVE, i_FRESTORE,
+ i_MMUOP
+} ENUMNAME (instrmnem);
+
+extern struct mnemolookup {
+ instrmnem mnemo;
+ const char *name;
+} lookuptab[];
+
+ENUMDECL {
+ sz_byte, sz_word, sz_long
+} ENUMNAME (wordsizes);
+
+ENUMDECL {
+ fa_set, fa_unset, fa_zero, fa_one, fa_dontcare, fa_unknown, fa_isjmp
+} ENUMNAME (flagaffect);
+
+ENUMDECL {
+ fu_used, fu_unused, fu_maybecc, fu_unknown, fu_isjmp
+} ENUMNAME (flaguse);
+
+ENUMDECL {
+ bit0, bit1, bitc, bitC, bitf, biti, bitI, bitj, bitJ, bitk, bitK,
+ bits, bitS, bitd, bitD, bitr, bitR, bitz, lastbit
+} ENUMNAME (bitvals);
+
+struct instr_def {
+ unsigned int bits;
+ int n_variable;
+ char bitpos[16];
+ unsigned int mask;
+ int cpulevel;
+ int plevel;
+ struct {
+ unsigned int flaguse:3;
+ unsigned int flagset:3;
+ } flaginfo[5];
+ unsigned char sduse;
+ const char *opcstr;
+};
+
+extern struct instr_def defs68k[];
+extern int n_defs68k;
+
+extern struct instr {
+ long int handler;
+ unsigned char dreg;
+ unsigned char sreg;
+ signed char dpos;
+ signed char spos;
+ unsigned char sduse;
+ int flagdead:8, flaglive:8;
+ unsigned int mnemo:8;
+ unsigned int cc:4;
+ unsigned int plev:2;
+ unsigned int size:2;
+ unsigned int smode:5;
+ unsigned int stype:3;
+ unsigned int dmode:5;
+ unsigned int suse:1;
+ unsigned int duse:1;
+ unsigned int unused1:1;
+ unsigned int clev:3;
+ unsigned int unused2:5;
+} *table68k;
+
+extern void read_table68k (void);
+extern void do_merges (void);
+extern int get_no_mismatches (void);
+extern int nr_cpuop_funcs;
+
diff --git a/plugins/uade2/uade-2.13/src/include/sinctable.h b/plugins/uade2/uade-2.13/src/include/sinctable.h
new file mode 100644
index 00000000..56fb62d7
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/sinctable.h
@@ -0,0 +1,7 @@
+#ifndef _SINCTABLE_H_
+#define _SINCTABLE_H_
+
+#define SINC_QUEUE_MAX_AGE 2048
+extern const int winsinc_integral[5][SINC_QUEUE_MAX_AGE];
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/include/sysdeps.h b/plugins/uade2/uade-2.13/src/include/sysdeps.h
new file mode 100644
index 00000000..5d407b2d
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/sysdeps.h
@@ -0,0 +1,347 @@
+ /*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * Try to include the right system headers and get other system-specific
+ * stuff right & other collected kludges.
+ *
+ * If you think about modifying this, think twice. Some systems rely on
+ * the exact order of the #include statements. That's also the reason
+ * why everything gets included unconditionally regardless of whether
+ * it's actually needed by the .c file.
+ *
+ * Copyright 1996, 1997 Bernd Schmidt
+ */
+
+/* MODIF PMO */
+#ifndef _H_SYSDEPS
+#define _H_SYSDEPS
+/* ENDOF MODIF PMO */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <limits.h>
+
+#ifndef __STDC__
+#error "Your compiler is not ANSI. Get a real one."
+#endif
+
+#include <stdarg.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_VALUES_H
+#include <values.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+#else
+# define dirent direct
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#ifdef HAVE_SYS_UTIME_H
+# include <sys/utime.h>
+#endif
+
+#include <errno.h>
+#include <assert.h>
+
+#if EEXIST == ENOTEMPTY
+#define BROKEN_OS_PROBABLY_AIX
+#endif
+
+#ifdef __NeXT__
+#define S_IRUSR S_IREAD
+#define S_IWUSR S_IWRITE
+#define S_IXUSR S_IEXEC
+#define S_ISDIR(val) (S_IFDIR & val)
+struct utimbuf
+{
+ time_t actime;
+ time_t modtime;
+};
+#endif
+
+#define REGPARAM2
+
+#ifdef __DOS__
+#include <pc.h>
+#include <io.h>
+#endif
+
+/* MODIF PMO */
+/* WIN32/UNIX compatibility */
+#ifdef WINDOWS_VCPP
+ #define COMP_SEPARATOR '\\'
+ #define COMP_S_SEPARATOR "\\"
+#else
+ #define COMP_SEPARATOR '/'
+ #define COMP_S_SEPARATOR "/"
+#endif
+/* ENDOF MODIF PMO */
+
+/* Acorn specific stuff */
+#ifdef ACORN
+
+#define S_IRUSR S_IREAD
+#define S_IWUSR S_IWRITE
+#define S_IXUSR S_IEXEC
+
+#define strcasecmp stricmp
+
+#endif
+
+#ifndef L_tmpnam
+#define L_tmpnam 128 /* ought to be safe */
+#endif
+
+/* If char has more then 8 bits, good night. */
+typedef unsigned char uae_u8;
+typedef signed char uae_s8;
+
+typedef struct { uae_u8 RGB[3]; } RGB;
+
+#if SIZEOF_SHORT == 2
+typedef unsigned short uae_u16;
+typedef short uae_s16;
+#elif SIZEOF_INT == 2
+typedef unsigned int uae_u16;
+typedef int uae_s16;
+#else
+#error No 2 byte type, you lose.
+#endif
+
+#if SIZEOF_INT == 4
+typedef unsigned int uae_u32;
+typedef int uae_s32;
+#elif SIZEOF_LONG == 4
+typedef unsigned long uae_u32;
+typedef long uae_s32;
+#else
+#error No 4 byte type, you lose.
+#endif
+
+typedef uae_u32 uaecptr;
+
+#undef uae_s64
+#undef uae_u64
+
+#if SIZEOF_LONG_LONG == 8
+#define uae_s64 long long
+#define uae_u64 long long
+#define VAL64(a) (a ## LL)
+#define UVAL64(a) (a ## uLL)
+#elif SIZEOF___INT64 == 8
+#define uae_s64 __int64
+#define uae_u64 unsigned __int64
+#define VAL64(a) (a)
+#define UVAL64(a) (a)
+#elif SIZEOF_LONG == 8
+#define uae_s64 long;
+#define uae_u64 unsigned long;
+#define VAL64(a) (a ## l)
+#define UVAL64(a) (a ## ul)
+#endif
+
+#ifdef HAVE_STRDUP
+#define my_strdup strdup
+#else
+extern char *my_strdup (const char*s);
+#endif
+extern void *xmalloc(size_t);
+
+/* We can only rely on GNU C getting enums right. Mickeysoft VSC++ is known
+ * to have problems, and it's likely that other compilers choke too. */
+#ifdef __GNUC__
+#define ENUMDECL typedef enum
+#define ENUMNAME(name) name
+#else
+#define ENUMDECL enum
+#define ENUMNAME(name) ; typedef int name
+#endif
+
+/*
+ * Porters to weird systems, look! This is the preferred way to get
+ * filesys.c (and other stuff) running on your system. Define the
+ * appropriate macros and implement wrappers in a machine-specific file.
+ *
+ * I guess the Mac port could use this (Ernesto?)
+ */
+
+#undef DONT_HAVE_POSIX
+#undef DONT_HAVE_REAL_POSIX /* define if open+delete doesn't do what it should */
+#undef DONT_HAVE_STDIO
+#undef DONT_HAVE_MALLOC
+
+#if defined _WIN32
+
+#if defined __WATCOMC__
+
+#define O_NDELAY 0
+#include <direct.h>
+#define dirent direct
+#define mkdir(a,b) mkdir(a)
+#define strcasecmp stricmp
+
+#elif defined __MINGW32__
+
+#define O_NDELAY 0
+#define mkdir(a,b) mkdir(a)
+
+#endif
+
+#endif /* _WIN32 */
+
+#ifdef DONT_HAVE_POSIX
+
+#define access posixemu_access
+extern int posixemu_access (const char *, int);
+#define open posixemu_open
+extern int posixemu_open (const char *, int, int);
+#define close posixemu_close
+extern void posixemu_close (int);
+#define read posixemu_read
+extern int posixemu_read (int, char *, int);
+#define write posixemu_write
+extern int posixemu_write (int, const char *, int);
+#undef lseek
+#define lseek posixemu_seek
+extern int posixemu_seek (int, int, int);
+#define stat(a,b) posixemu_stat ((a), (b))
+extern int posixemu_stat (const char *, STAT *);
+#define mkdir posixemu_mkdir
+extern int mkdir (const char *, int);
+#define rmdir posixemu_rmdir
+extern int posixemu_rmdir (const char *);
+#define unlink posixemu_unlink
+extern int posixemu_unlink (const char *);
+#define truncate posixemu_truncate
+extern int posixemu_truncate (const char *, long int);
+#define rename posixemu_rename
+extern int posixemu_rename (const char *, const char *);
+#define chmod posixemu_chmod
+extern int posixemu_chmod (const char *, int);
+#define tmpnam posixemu_tmpnam
+extern void posixemu_tmpnam (char *);
+#define utime posixemu_utime
+extern int posixemu_utime (const char *, struct utimbuf *);
+#define opendir posixemu_opendir
+extern DIR * posixemu_opendir (const char *);
+#define readdir posixemu_readdir
+extern struct dirent* readdir (DIR *);
+#define closedir posixemu_closedir
+extern void closedir (DIR *);
+
+/* This isn't the best place for this, but it fits reasonably well. The logic
+ * is that you probably don't have POSIX errnos if you don't have the above
+ * functions. */
+extern long dos_errno (void);
+
+#endif
+
+#ifdef DONT_HAVE_STDIO
+
+extern FILE *stdioemu_fopen (const char *, const char *);
+#define fopen(a,b) stdioemu_fopen(a, b)
+extern int stdioemu_fseek (FILE *, int, int);
+#define fseek(a,b,c) stdioemu_fseek(a, b, c)
+extern int stdioemu_fread (char *, int, int, FILE *);
+#define fread(a,b,c,d) stdioemu_fread(a, b, c, d)
+extern int stdioemu_fwrite (const char *, int, int, FILE *);
+#define fwrite(a,b,c,d) stdioemu_fwrite(a, b, c, d)
+extern int stdioemu_ftell (FILE *);
+#define ftell(a) stdioemu_ftell(a)
+extern int stdioemu_fclose (FILE *);
+#define fclose(a) stdioemu_fclose(a)
+
+#endif
+
+#ifdef DONT_HAVE_MALLOC
+
+#define malloc(a) mallocemu_malloc(a)
+extern void *mallocemu_malloc (int size);
+#define free(a) mallocemu_free(a)
+extern void mallocemu_free (void *ptr);
+
+#endif
+
+#ifdef X86_ASSEMBLY
+#define ASM_SYM_FOR_FUNC(a) __asm__(a)
+#else
+#define ASM_SYM_FOR_FUNC(a)
+#endif
+
+#if defined USE_COMPILER
+#undef NO_PREFETCH_BUFFER
+#undef NO_EXCEPTION_3
+#define NO_EXCEPTION_3
+#define NO_PREFETCH_BUFFER
+#endif
+
+#include "target.h"
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/* Every Amiga hardware clock cycle takes this many "virtual" cycles. This
+ used to be hardcoded as 1, but using higher values allows us to time some
+ stuff more precisely.
+ 512 is the official value from now on - it can't change, unless we want
+ _another_ config option "finegrain2_m68k_speed".
+
+ We define this value here rather than in events.h so that gencpu.c sees
+ it. */
+#define CYCLE_UNIT 512
+
+/* MODIF PMO */
+#endif
+
+/* ENDOF MODIF PMO */
+
diff --git a/plugins/uade2/uade-2.13/src/include/text_scope.h b/plugins/uade2/uade-2.13/src/include/text_scope.h
new file mode 100644
index 00000000..7bc9d206
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/text_scope.h
@@ -0,0 +1,21 @@
+#ifndef _TEXT_SCOPE_H_
+#define _TEXT_SCOPE_H_
+
+#include "uadeconfig.h"
+
+#ifdef UADE_CONFIG_TEXT_SCOPE
+#define TEXT_SCOPE(cycles, voice, e, value) \
+ do { \
+ if (use_text_scope) \
+ text_scope(cycles, voice, e, value); \
+ } while (0)
+#else
+#define TEXT_SCOPE(cycles, voice, e, value) do {} while (0)
+#endif
+
+enum PaulaEventType {PET_VOL, PET_PER, PET_DAT, PET_LEN, PET_LCH, PET_LCL};
+
+void text_scope(unsigned long cycles, int voice, enum PaulaEventType e,
+ int value);
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/include/uade.h b/plugins/uade2/uade-2.13/src/include/uade.h
new file mode 100644
index 00000000..91f590fe
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/uade.h
@@ -0,0 +1,43 @@
+#ifndef _UADE_MAIN_H_
+#define _UADE_MAIN_H_
+
+#include <limits.h>
+#include <stdlib.h>
+
+#include "uadeipc.h"
+
+struct uade_song {
+ char playername[PATH_MAX]; /* filename of eagleplayer */
+ char modulename[PATH_MAX]; /* filename of song */
+ char scorename[PATH_MAX]; /* filename of score file */
+
+ int min_subsong;
+ int max_subsong;
+ int cur_subsong;
+};
+
+
+void uade_change_subsong(int subs);
+void uade_check_sound_buffers(int bytes);
+void uade_send_debug(const char *fmt, ...);
+void uade_get_amiga_message(void);
+void uade_handle_r_state(void);
+void uade_option(int, char**); /* handles command line parameters */
+void uade_reset(void);
+void uade_send_amiga_message(int msgtype);
+void uade_set_automatic_song_end(int song_end_possible);
+void uade_set_ntsc(int usentsc);
+void uade_song_end(char *reason, int kill_it);
+void uade_swap_buffer_bytes(void *data, int bytes);
+
+extern int uade_audio_output;
+extern int uade_audio_skip;
+extern int uade_debug;
+extern int uade_local_sound;
+extern int uade_read_size;
+extern int uade_reboot;
+extern int uade_time_critical;
+
+extern struct uade_ipc uadeipc;
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/include/uadeconstants.h b/plugins/uade2/uade-2.13/src/include/uadeconstants.h
new file mode 100644
index 00000000..5a69953a
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/uadeconstants.h
@@ -0,0 +1,10 @@
+#ifndef _UADE_CONSTANTS_H_
+#define _UADE_CONSTANTS_H_
+
+/* You must not change anything */
+#define UADE_CHANNELS (2)
+#define UADE_DEFAULT_FREQUENCY (44100)
+#define UADE_BYTES_PER_SAMPLE (2)
+#define UADE_BYTES_PER_FRAME (UADE_CHANNELS * UADE_BYTES_PER_SAMPLE)
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/include/uadeipc.h b/plugins/uade2/uade-2.13/src/include/uadeipc.h
new file mode 100644
index 00000000..3bad980b
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/uadeipc.h
@@ -0,0 +1,77 @@
+#ifndef _UADEIPC_H_
+#define _UADEIPC_H_
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "uadeutils.h"
+
+#define UADE_MAX_MESSAGE_SIZE (4096)
+
+enum uade_msgtype {
+ UADE_MSG_FIRST = 0,
+ UADE_COMMAND_ACTIVATE_DEBUGGER,
+ UADE_COMMAND_CHANGE_SUBSONG,
+ UADE_COMMAND_CONFIG,
+ UADE_COMMAND_SCORE,
+ UADE_COMMAND_PLAYER,
+ UADE_COMMAND_MODULE,
+ UADE_COMMAND_READ,
+ UADE_COMMAND_REBOOT,
+ UADE_COMMAND_SET_SUBSONG,
+ UADE_COMMAND_IGNORE_CHECK,
+ UADE_COMMAND_SONG_END_NOT_POSSIBLE,
+ UADE_COMMAND_SET_NTSC,
+ UADE_COMMAND_FILTER,
+ UADE_COMMAND_SET_FREQUENCY,
+ UADE_COMMAND_SET_PLAYER_OPTION,
+ UADE_COMMAND_SET_RESAMPLING_MODE,
+ UADE_COMMAND_SPEED_HACK,
+ UADE_COMMAND_TOKEN,
+ UADE_COMMAND_USE_TEXT_SCOPE,
+ UADE_REPLY_MSG,
+ UADE_REPLY_CANT_PLAY,
+ UADE_REPLY_CAN_PLAY,
+ UADE_REPLY_SONG_END,
+ UADE_REPLY_SUBSONG_INFO,
+ UADE_REPLY_PLAYERNAME,
+ UADE_REPLY_MODULENAME,
+ UADE_REPLY_FORMATNAME,
+ UADE_REPLY_DATA,
+ UADE_MSG_LAST
+};
+
+struct uade_msg {
+ uint32_t msgtype;
+ uint32_t size;
+ uint8_t data[0];
+} __attribute__((packed));
+
+enum uade_control_state {
+ UADE_INITIAL_STATE = 0,
+ UADE_R_STATE,
+ UADE_S_STATE
+};
+
+struct uade_ipc {
+ void *input;
+ void *output;
+ unsigned int inputbytes;
+ char inputbuffer[UADE_MAX_MESSAGE_SIZE];
+ enum uade_control_state state;
+};
+
+void uade_check_fix_string(struct uade_msg *um, size_t maxlen);
+int uade_parse_u32_message(uint32_t *u1, struct uade_msg *um);
+int uade_parse_two_u32s_message(uint32_t *u1, uint32_t *u2, struct uade_msg *um);
+int uade_receive_message(struct uade_msg *um, size_t maxbytes, struct uade_ipc *ipc);
+int uade_receive_short_message(enum uade_msgtype msgtype, struct uade_ipc *ipc);
+int uade_receive_string(char *s, enum uade_msgtype msgtype, size_t maxlen, struct uade_ipc *ipc);
+int uade_send_message(struct uade_msg *um, struct uade_ipc *ipc);
+int uade_send_short_message(enum uade_msgtype msgtype, struct uade_ipc *ipc);
+int uade_send_string(enum uade_msgtype msgtype, const char *str, struct uade_ipc *ipc);
+int uade_send_u32(enum uade_msgtype com, uint32_t u, struct uade_ipc *ipc);
+int uade_send_two_u32s(enum uade_msgtype com, uint32_t u1, uint32_t u2, struct uade_ipc *ipc);
+void uade_set_peer(struct uade_ipc *ipc, int peer_is_client, const char *input, const char *output);
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/include/uadeutils.h b/plugins/uade2/uade-2.13/src/include/uadeutils.h
new file mode 100644
index 00000000..fcd24233
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/uadeutils.h
@@ -0,0 +1,27 @@
+#ifndef _UADE_UTILS_H_
+#define _UADE_UTILS_H_
+
+#include <stdint.h>
+
+#define uade_error(fmt, args...) do { \
+ fprintf(stderr, "%s:%d: %s: " fmt, __FILE__, __LINE__, __func__, ## args); \
+ abort(); \
+ } while (0)
+
+static inline uint16_t read_be_u16(void *s)
+{
+ uint16_t x;
+ uint8_t *ptr = (uint8_t *) s;
+ x = ptr[1] + (ptr[0] << 8);
+ return x;
+}
+
+static inline uint32_t read_be_u32(void *s)
+{
+ uint32_t x;
+ uint8_t *ptr = (uint8_t *) s;
+ x = (ptr[0] << 24) + (ptr[1] << 16) + (ptr[2] << 8) + ptr[3];
+ return x;
+}
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/include/uae.h b/plugins/uade2/uade-2.13/src/include/uae.h
new file mode 100644
index 00000000..1ab9d75f
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/uae.h
@@ -0,0 +1,30 @@
+ /*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * Prototypes for main.c
+ *
+ * Copyright 1996 Bernd Schmidt
+ */
+
+extern int uade_main (int argc, char **argv);
+extern void uae_quit (void);
+
+extern int quit_program;
+
+extern char warning_buffer[256];
+
+/* This structure is used to define menus. The val field can hold key
+ * shortcuts, or one of these special codes:
+ * -4: deleted entry, not displayed, not selectable, but does count in
+ * select value
+ * -3: end of table
+ * -2: line that is displayed, but not selectable
+ * -1: line that is selectable, but has no keyboard shortcut
+ * 0: Menu title
+ */
+struct bstring {
+ const char *data;
+ int val;
+};
+
+extern char *colormodes[];
diff --git a/plugins/uade2/uade-2.13/src/include/unixatomic.h b/plugins/uade2/uade-2.13/src/include/unixatomic.h
new file mode 100644
index 00000000..565cf864
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/unixatomic.h
@@ -0,0 +1,15 @@
+#ifndef _UNIXATOMIC_H_
+#define _UNIXATOMIC_H_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int atomic_close(int fd);
+int atomic_dup2(int oldfd, int newfd);
+size_t atomic_fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
+ssize_t atomic_read(int fd, const void *buf, size_t count);
+void *atomic_read_file(size_t *fs, const char *filename);
+ssize_t atomic_write(int fd, const void *buf, size_t count);
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/include/unixsupport.h b/plugins/uade2/uade-2.13/src/include/unixsupport.h
new file mode 100644
index 00000000..dc7d545e
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/include/unixsupport.h
@@ -0,0 +1,32 @@
+#ifndef _UADE_UNIXSUPPORT_H_
+#define _UADE_UNIXSUPPORT_H_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <string.h>
+#include <errno.h>
+
+#include "uadeipc.h"
+
+
+#define die(fmt, args...) do { fprintf(stderr, "uade: " fmt, ## args); exit(1); } while(0)
+
+#define dieerror(fmt, args...) do { fprintf(stderr, "uade: " fmt ": %s\n", ## args, strerror(errno)); exit(1); } while(0)
+
+
+char *uade_dirname(char *dst, char *src, size_t maxlen);
+FILE *uade_open_amiga_file(char *aname, const char *playerdir);
+void uade_portable_initializations(void);
+void uade_arch_spawn(struct uade_ipc *ipc, pid_t *uadepid, const char *uadename);
+
+/* These read and write functions MUST read and write the full size_t amount
+ if they are able to. */
+ssize_t uade_ipc_read(void *f, const void *buf, size_t count);
+ssize_t uade_ipc_write(void *f, const void *buf, size_t count);
+void *uade_ipc_set_input(const char *input);
+void *uade_ipc_set_output(const char *output);
+
+char *windows_to_cygwin_path(const char *path);
+
+#endif
diff --git a/plugins/uade2/uade-2.13/src/ossupport.c b/plugins/uade2/uade-2.13/src/ossupport.c
new file mode 100644
index 00000000..6ecfb53e
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/ossupport.c
@@ -0,0 +1,48 @@
+#include "ossupport.h"
+
+#include "unixsupport.c"
+/* This module was written by Heikki Orsila <heikki.orsila@iki.fi> 2000-2005.
+ * No copyrights claimed, so this module is in Public Domain (only this
+ * code module). See OpenBSD man pages for strlcat and strlcpy
+ */
+
+#include <string.h>
+
+size_t strlcpy(char *dst, const char *src, size_t size)
+{
+ size_t slen = strlen(src);
+ if(slen < size)
+ strcpy(dst, src);
+ else if (size > 0) {
+ strncpy(dst, src, size-1);
+ dst[size-1] = 0;
+ }
+ return slen;
+}
+
+
+size_t strlcat(char *dst, const char *src, size_t size)
+{
+ size_t slen = strlen(src);
+ size_t dlen = 0;
+ while(dlen < size) {
+ if(dst[dlen] == 0)
+ break;
+ dlen++;
+ }
+
+ if(dlen == size) {
+ return slen + dlen;
+ }
+
+ if((dlen + slen) < size)
+ strcat(dst, src);
+ else {
+ int left = size - dlen - 1;
+ if(left > 0) {
+ strncat(dst, src, left);
+ }
+ dst[size-1] = 0;
+ }
+ return slen + dlen;
+}
diff --git a/plugins/uade2/uade-2.13/src/uadeipc.c b/plugins/uade2/uade-2.13/src/uadeipc.c
new file mode 100644
index 00000000..cba45ce0
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/uadeipc.c
@@ -0,0 +1,291 @@
+/* UADE
+ *
+ * Copyright 2005 Heikki Orsila <heikki.orsila@iki.fi>
+ *
+ * This source code module is dual licensed under GPL and Public Domain.
+ * Hence you may use _this_ module (not another code module) in any way you
+ * want in your projects.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+
+#include "uadeipc.h"
+#include "ossupport.h"
+#include "sysincludes.h"
+
+
+static int valid_message(struct uade_msg *uc);
+
+
+void uade_check_fix_string(struct uade_msg *um, size_t maxlen)
+{
+ uint8_t *s = (uint8_t *) um->data;
+ size_t safelen;
+ if (um->size == 0) {
+ s[0] = 0;
+ fprintf(stderr, "zero string detected\n");
+ }
+ safelen = 0;
+ while (s[safelen] != 0 && safelen < maxlen)
+ safelen++;
+ if (safelen == maxlen) {
+ safelen--;
+ fprintf(stderr, "too long a string\n");
+ s[safelen] = 0;
+ }
+ if (um->size != (safelen + 1)) {
+ fprintf(stderr, "string size does not match\n");
+ um->size = safelen + 1;
+ s[safelen] = 0;
+ }
+}
+
+
+static ssize_t get_more(size_t bytes, struct uade_ipc *ipc)
+{
+ if (ipc->inputbytes < bytes) {
+ ssize_t s = uade_ipc_read(ipc->input, &ipc->inputbuffer[ipc->inputbytes], bytes - ipc->inputbytes);
+ if (s <= 0)
+ return -1;
+ ipc->inputbytes += s;
+ }
+ return 0;
+}
+
+
+static void copy_from_inputbuffer(void *dst, int bytes, struct uade_ipc *ipc)
+{
+ if (ipc->inputbytes < bytes) {
+ fprintf(stderr, "not enough bytes in input buffer\n");
+ exit(-1);
+ }
+ memcpy(dst, ipc->inputbuffer, bytes);
+ memmove(ipc->inputbuffer, &ipc->inputbuffer[bytes], ipc->inputbytes - bytes);
+ ipc->inputbytes -= bytes;
+}
+
+
+int uade_parse_u32_message(uint32_t *u1, struct uade_msg *um)
+{
+ if (um->size != 4)
+ return -1;
+ *u1 = ntohl(* (uint32_t *) um->data);
+ return 0;
+}
+
+
+int uade_parse_two_u32s_message(uint32_t *u1, uint32_t *u2,
+ struct uade_msg *um)
+{
+ if (um->size != 8)
+ return -1;
+ *u1 = ntohl(((uint32_t *) um->data)[0]);
+ *u2 = ntohl(((uint32_t *) um->data)[1]);
+ return 0;
+}
+
+
+int uade_receive_message(struct uade_msg *um, size_t maxbytes,
+ struct uade_ipc *ipc)
+{
+ size_t fullsize;
+
+ if (ipc->state == UADE_INITIAL_STATE) {
+ ipc->state = UADE_R_STATE;
+ } else if (ipc->state == UADE_S_STATE) {
+ fprintf(stderr, "protocol error: receiving in S state is forbidden\n");
+ return -1;
+ }
+
+ if (ipc->inputbytes < sizeof(*um)) {
+ if (get_more(sizeof(*um), ipc))
+ return 0;
+ }
+
+ copy_from_inputbuffer(um, sizeof(*um), ipc);
+
+ um->msgtype = ntohl(um->msgtype);
+ um->size = ntohl(um->size);
+
+ if (!valid_message(um))
+ return -1;
+
+ fullsize = um->size + sizeof(*um);
+ if (fullsize > maxbytes) {
+ fprintf(stderr, "too big a command: %zu\n", fullsize);
+ return -1;
+ }
+ if (ipc->inputbytes < um->size) {
+ if (get_more(um->size, ipc))
+ return -1;
+ }
+ copy_from_inputbuffer(&um->data, um->size, ipc);
+
+ if (um->msgtype == UADE_COMMAND_TOKEN)
+ ipc->state = UADE_S_STATE;
+
+ return 1;
+}
+
+
+int uade_receive_short_message(enum uade_msgtype msgtype, struct uade_ipc *ipc)
+{
+ struct uade_msg um;
+
+ if (ipc->state == UADE_INITIAL_STATE) {
+ ipc->state = UADE_R_STATE;
+ } else if (ipc->state == UADE_S_STATE) {
+ fprintf(stderr, "protocol error: receiving (%d) in S state is forbidden\n", msgtype);
+ return -1;
+ }
+
+ if (uade_receive_message(&um, sizeof(um), ipc) <= 0) {
+ fprintf(stderr, "can not receive short message: %d\n", msgtype);
+ return -1;
+ }
+ return (um.msgtype == msgtype) ? 0 : -1;
+}
+
+
+int uade_receive_string(char *s, enum uade_msgtype com,
+ size_t maxlen, struct uade_ipc *ipc)
+{
+ uint8_t commandbuf[UADE_MAX_MESSAGE_SIZE];
+ struct uade_msg *um = (struct uade_msg *) commandbuf;
+ int ret;
+
+ if (ipc->state == UADE_INITIAL_STATE) {
+ ipc->state = UADE_R_STATE;
+ } else if (ipc->state == UADE_S_STATE) {
+ fprintf(stderr, "protocol error: receiving in S state is forbidden\n");
+ return -1;
+ }
+
+ ret = uade_receive_message(um, UADE_MAX_MESSAGE_SIZE, ipc);
+ if (ret <= 0)
+ return ret;
+ if (um->msgtype != com)
+ return -1;
+ if (um->size == 0)
+ return -1;
+ if (um->size != (strlen((char *) um->data) + 1))
+ return -1;
+ strlcpy(s, (char *) um->data, maxlen);
+ return 1;
+}
+
+
+int uade_send_message(struct uade_msg *um, struct uade_ipc *ipc)
+{
+ uint32_t size = um->size;
+
+ if (ipc->state == UADE_INITIAL_STATE) {
+ ipc->state = UADE_S_STATE;
+ } else if (ipc->state == UADE_R_STATE) {
+ fprintf(stderr, "protocol error: sending in R state is forbidden\n");
+ return -1;
+ }
+
+ if (!valid_message(um))
+ return -1;
+ if (um->msgtype == UADE_COMMAND_TOKEN)
+ ipc->state = UADE_R_STATE;
+ um->msgtype = htonl(um->msgtype);
+ um->size = htonl(um->size);
+ if (uade_ipc_write(ipc->output, um, sizeof(*um) + size) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+int uade_send_short_message(enum uade_msgtype msgtype, struct uade_ipc *ipc)
+{
+ struct uade_msg msg = {.msgtype = msgtype};
+
+ if (uade_send_message(&msg, ipc)) {
+ fprintf(stderr, "can not send short message: %d\n", msgtype);
+ return -1;
+ }
+ return 0;
+}
+
+
+int uade_send_string(enum uade_msgtype com, const char *str, struct uade_ipc *ipc)
+{
+ uint32_t size = strlen(str) + 1;
+ struct uade_msg um = {.msgtype = ntohl(com), .size = ntohl(size)};
+
+ if (ipc->state == UADE_INITIAL_STATE) {
+ ipc->state = UADE_S_STATE;
+ } else if (ipc->state == UADE_R_STATE) {
+ fprintf(stderr, "protocol error: sending in R state is forbidden\n");
+ return -1;
+ }
+
+ if ((sizeof(um) + size) > UADE_MAX_MESSAGE_SIZE)
+ return -1;
+ if (uade_ipc_write(ipc->output, &um, sizeof(um)) < 0)
+ return -1;
+ if (uade_ipc_write(ipc->output, str, size) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+int uade_send_u32(enum uade_msgtype com, uint32_t u, struct uade_ipc *ipc)
+{
+ uint8_t space[UADE_MAX_MESSAGE_SIZE];
+ struct uade_msg *um = (struct uade_msg *) space;
+ um->msgtype = com;
+ um->size = 4;
+ * (uint32_t *) um->data = htonl(u);
+ return uade_send_message(um, ipc);
+}
+
+
+int uade_send_two_u32s(enum uade_msgtype com, uint32_t u1, uint32_t u2,
+ struct uade_ipc *ipc)
+{
+ uint8_t space[UADE_MAX_MESSAGE_SIZE];
+ struct uade_msg *um = (struct uade_msg *) space;
+ um->msgtype = com;
+ um->size = 8;
+ ((uint32_t *) um->data)[0] = htonl(u1);
+ ((uint32_t *) um->data)[1] = htonl(u2);
+ return uade_send_message(um, ipc);
+}
+
+
+void uade_set_peer(struct uade_ipc *ipc, int peer_is_client, const char *input, const char *output)
+{
+ assert(peer_is_client == 0 || peer_is_client == 1);
+ assert(input != NULL);
+ assert(output != NULL);
+
+ *ipc = (struct uade_ipc) {.state = UADE_INITIAL_STATE,
+ .input= uade_ipc_set_input(input),
+ .output = uade_ipc_set_output(output)};
+}
+
+
+static int valid_message(struct uade_msg *um)
+{
+ size_t len;
+ if (um->msgtype <= UADE_MSG_FIRST || um->msgtype >= UADE_MSG_LAST) {
+ fprintf(stderr, "unknown command: %u\n", (unsigned int) um->msgtype);
+ return 0;
+ }
+ len = sizeof(*um) + um->size;
+ if (len > UADE_MAX_MESSAGE_SIZE) {
+ fprintf(stderr, "too long a message: %zu\n", len);
+ return 0;
+ }
+ return 1;
+}
diff --git a/plugins/uade2/uade-2.13/src/unixatomic.c b/plugins/uade2/uade-2.13/src/unixatomic.c
new file mode 100644
index 00000000..1adbe27a
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/unixatomic.c
@@ -0,0 +1,149 @@
+#include <errno.h>
+#include <stdint.h>
+#include <assert.h>
+
+#include "unixatomic.h"
+#include "sysincludes.h"
+
+int atomic_close(int fd)
+{
+ while (1) {
+ if (close(fd) < 0) {
+ if (errno == EINTR)
+ continue;
+ return -1;
+ }
+ break;
+ }
+ return 0;
+}
+
+
+int atomic_dup2(int oldfd, int newfd)
+{
+ while (1) {
+ if (dup2(oldfd, newfd) < 0) {
+ if (errno == EINTR)
+ continue;
+ return -1;
+ }
+ break;
+ }
+ return newfd;
+}
+
+
+size_t atomic_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+ uint8_t *dest = ptr;
+ size_t readmembers = 0;
+ size_t ret;
+
+ while (readmembers < nmemb) {
+ ret = fread(dest + size * readmembers, size, nmemb - readmembers, stream);
+ if (ret == 0)
+ break;
+ readmembers += ret;
+ }
+
+ assert(readmembers <= nmemb);
+
+ return readmembers;
+}
+
+
+ssize_t atomic_read(int fd, const void *buf, size_t count)
+{
+ char *b = (char *) buf;
+ ssize_t bytes_read = 0;
+ ssize_t ret;
+ while (bytes_read < count) {
+ ret = read(fd, &b[bytes_read], count - bytes_read);
+ if (ret < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EAGAIN) {
+ fd_set s;
+ FD_ZERO(&s);
+ FD_SET(fd, &s);
+ if (select(fd + 1, &s, NULL, NULL, NULL) == 0)
+ fprintf(stderr, "atomic_read: very strange. infinite select() returned 0. report this!\n");
+ continue;
+ }
+ return -1;
+ } else if (ret == 0) {
+ return 0;
+ }
+ bytes_read += ret;
+ }
+ return bytes_read;
+}
+
+
+void *atomic_read_file(size_t *fs, const char *filename)
+{
+ FILE *f;
+ size_t off;
+ void *mem = NULL;
+ size_t msize;
+ long pos;
+
+ if ((f = fopen(filename, "rb")) == NULL)
+ goto error;
+
+ if (fseek(f, 0, SEEK_END))
+ goto error;
+ pos = ftell(f);
+ if (pos < 0)
+ goto error;
+ if (fseek(f, 0, SEEK_SET))
+ goto error;
+
+ *fs = pos;
+ msize = (pos > 0) ? pos : 1;
+
+ if ((mem = malloc(msize)) == NULL)
+ goto error;
+
+ off = atomic_fread(mem, 1, *fs, f);
+ if (off < *fs) {
+ fprintf(stderr, "Not able to read the whole file %s\n", filename);
+ goto error;
+ }
+
+ fclose(f);
+ return mem;
+
+ error:
+ if (f)
+ fclose(f);
+ free(mem);
+ *fs = 0;
+ return NULL;
+}
+
+
+ssize_t atomic_write(int fd, const void *buf, size_t count)
+{
+ char *b = (char *) buf;
+ ssize_t bytes_written = 0;
+ ssize_t ret;
+ while (bytes_written < count) {
+ ret = write(fd, &b[bytes_written], count - bytes_written);
+ if (ret < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EAGAIN) {
+ fd_set s;
+ FD_ZERO(&s);
+ FD_SET(fd, &s);
+ if (select(fd + 1, NULL, &s, NULL, NULL) == 0)
+ fprintf(stderr, "atomic_write: very strange. infinite select() returned 0. report this!\n");
+ continue;
+ }
+ return -1;
+ }
+ bytes_written += ret;
+ }
+ return bytes_written;
+}
diff --git a/plugins/uade2/uade-2.13/src/unixsupport.c b/plugins/uade2/uade-2.13/src/unixsupport.c
new file mode 100644
index 00000000..d6131bc2
--- /dev/null
+++ b/plugins/uade2/uade-2.13/src/unixsupport.c
@@ -0,0 +1,350 @@
+/* UNIX support tools for uadecore.
+
+ Copyright 2000 - 2005 (C) Heikki Orsila <heikki.orsila@iki.fi>
+
+ This module is licensed under the GNU GPL.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <libgen.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <limits.h>
+#include <ctype.h>
+
+#include "uade.h"
+#include "unixatomic.h"
+
+
+static int url_to_fd(const char *url, int flags, mode_t mode)
+{
+ int fd;
+ if (strncmp(url, "fd://", 5) == 0) {
+ char *endptr;
+ if (url[5] == 0)
+ return -1;
+ fd = strtol(&url[5], &endptr, 10);
+ if (*endptr != 0)
+ return -1;
+ } else {
+ if (flags & O_WRONLY) {
+ fd = open(url, flags, mode);
+ } else {
+ fd = open(url, flags);
+ }
+ }
+ if (fd < 0)
+ fd = -1;
+ return fd;
+}
+
+
+/* This must read the full size_t count if it can, and therefore we use
+ atomic_read() */
+ssize_t uade_ipc_read(void *f, const void *buf, size_t count)
+{
+ int fd = (intptr_t) f;
+ return atomic_read(fd, buf, count);
+}
+
+
+/* This must write the full size_t count if it can, and therefore we use
+ atomic_write() */
+ssize_t uade_ipc_write(void *f, const void *buf, size_t count)
+{
+ int fd = (intptr_t) f;
+ return atomic_write(fd, buf, count);
+}
+
+
+void *uade_ipc_set_input(const char *input)
+{
+ int fd;
+ if ((fd = url_to_fd(input, O_RDONLY, 0)) < 0) {
+ fprintf(stderr, "can not open input file %s: %s\n", input, strerror(errno));
+ exit(-1);
+ }
+ return (void *) ((intptr_t) fd);
+}
+
+
+void *uade_ipc_set_output(const char *output)
+{
+ int fd;
+ if ((fd = url_to_fd(output, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
+ fprintf(stderr, "can not open output file %s: %s\n", output, strerror(errno));
+ exit(-1);
+ }
+ return (void *) ((intptr_t) fd);
+}
+
+
+static int uade_amiga_scandir(char *real, char *dirname, char *fake, int ml)
+{
+ DIR *dir;
+ struct dirent *direntry;
+ if (!(dir = opendir(dirname))) {
+ fprintf(stderr, "uade: can't open dir (%s) (amiga scandir)\n", dirname);
+ return 0;
+ }
+ while ((direntry = readdir(dir))) {
+ if (!strcmp(fake, direntry->d_name)) {
+ if (((int) strlcpy(real, direntry->d_name, ml)) >= ml) {
+ fprintf(stderr, "uade: %s does not fit real", direntry->d_name);
+ closedir(dir);
+ return 0;
+ }
+ break;
+ }
+ }
+ if (direntry) {
+ closedir(dir);
+ return 1;
+ }
+ rewinddir(dir);
+ while ((direntry = readdir(dir))) {
+ if (!strcasecmp(fake, direntry->d_name)) {
+ if (((int) strlcpy(real, direntry->d_name, ml)) >= ml) {
+ fprintf(stderr, "uade: %s does not fit real", direntry->d_name);
+ closedir(dir);
+ return 0;
+ }
+ break;
+ }
+ }
+ closedir(dir);
+ return direntry ? 1 : 0;
+}
+
+
+char *uade_dirname(char *dst, char *src, size_t maxlen)
+{
+ char *srctemp = strdup(src);
+ if (srctemp == NULL)
+ return NULL;
+ strlcpy(dst, dirname(srctemp), maxlen);
+ free(srctemp);
+ return dst;
+}
+
+
+/* opens file in amiga namespace */
+FILE *uade_open_amiga_file(char *aname, const char *playerdir)
+{
+ char *separator;
+ char *ptr;
+ char copy[PATH_MAX];
+ char dirname[PATH_MAX];
+ char fake[PATH_MAX];
+ char real[PATH_MAX];
+ int len;
+ DIR *dir;
+ FILE *file;
+
+ if (strlcpy(copy, aname, sizeof(copy)) >= sizeof(copy)) {
+ fprintf(stderr, "uade: error: amiga tried to open a very long filename\nplease REPORT THIS!\n");
+ return NULL;
+ }
+ ptr = copy;
+ /* fprintf(stderr, "uade: opening %s\n", ptr); */
+ if ((separator = strchr(ptr, (int) ':'))) {
+ len = (int) (separator - ptr);
+ memcpy(dirname, ptr, len);
+ dirname[len] = 0;
+ if (!strcasecmp(dirname, "ENV")) {
+ snprintf(dirname, sizeof(dirname), "%s/ENV/", playerdir);
+ } else if (!strcasecmp(dirname, "S")) {
+ snprintf(dirname, sizeof(dirname), "%s/S/", playerdir);
+ } else {
+ fprintf(stderr, "uade: open_amiga_file: unknown amiga volume (%s)\n", aname);
+ return NULL;
+ }
+ if (!(dir = opendir(dirname))) {
+ fprintf(stderr, "uade: can't open dir (%s) (volume parsing)\n", dirname);
+ return NULL;
+ }
+ closedir(dir);
+ /* fprintf(stderr, "uade: opening from dir %s\n", dirname); */
+ ptr = separator + 1;
+ } else {
+ if (*ptr == '/') {
+ /* absolute path */
+ strlcpy(dirname, "/", sizeof(dirname));
+ ptr++;
+ } else {
+ /* relative path */
+ strlcpy(dirname, "./", sizeof(dirname));
+ }
+ }
+
+ while ((separator = strchr(ptr, (int) '/'))) {
+ len = (int) (separator - ptr);
+ if (!len) {
+ ptr++;
+ continue;
+ }
+ memcpy(fake, ptr, len);
+ fake[len] = 0;
+ if (uade_amiga_scandir(real, dirname, fake, sizeof(real))) {
+ /* found matching entry */
+ if (strlcat(dirname, real, sizeof(dirname)) >= sizeof(dirname)) {
+ fprintf(stderr, "uade: too long dir path (%s + %s)\n", dirname, real);
+ return NULL;
+ }
+ if (strlcat(dirname, "/", sizeof(dirname)) >= sizeof(dirname)) {
+ fprintf(stderr, "uade: too long dir path (%s + %s)\n", dirname, "/");
+ return NULL;
+ }
+ } else {
+ /* didn't find entry */
+ /* fprintf (stderr, "uade: %s not found from (%s) (dir scanning)\n", fake, dirname); */
+ return NULL;
+ }
+ ptr = separator + 1;
+ }
+ /* fprintf(stderr, "uade: pass 3: (%s) (%s)\n", dirname, ptr); */
+
+ if (!(dir = opendir(dirname))) {
+ fprintf(stderr, "can't open dir (%s) (after dir scanning)\n", dirname);
+ return NULL;
+ }
+ closedir(dir);
+
+ if (uade_amiga_scandir(real, dirname, ptr, sizeof(real))) {
+ /* found matching entry */
+ if (strlcat(dirname, real, sizeof(dirname)) >= sizeof(dirname)) {
+ fprintf(stderr, "uade: too long dir path (%s + %s)\n", dirname, real);
+ return NULL;
+ }
+ } else {
+ /* didn't find entry */
+ /* fprintf (stderr, "uade: %s not found from %s\n", ptr, dirname); */
+ return NULL;
+ }
+ if (!(file = fopen(dirname, "r"))) {
+ fprintf (stderr, "uade: couldn't open file (%s) induced by (%s)\n", dirname, aname);
+ }
+ return file;
+}
+
+
+void uade_portable_initializations(void)
+{
+ int signals[] = {SIGINT, -1};
+ int *signum = signals;
+ struct sigaction act;
+ memset(&act, 0, sizeof act);
+ act.sa_handler = SIG_IGN;
+
+ while (*signum != -1) {
+ while (1) {
+ if ((sigaction(*signum, &act, NULL)) < 0) {
+ if (errno == EINTR)
+ continue;
+ fprintf(stderr, "can not ignore signal %d: %s\n", *signum, strerror(errno));
+ exit(-1);
+ }
+ break;
+ }
+ signum++;
+ }
+}
+
+
+void uade_arch_spawn(struct uade_ipc *ipc, pid_t *uadepid,
+ const char *uadename)
+{
+ int fds[2];
+ char input[32], output[32];
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) {
+ fprintf(stderr, "Can not create socketpair: %s\n", strerror(errno));
+ abort();
+ }
+
+ *uadepid = fork();
+ if (*uadepid < 0) {
+ fprintf(stderr, "Fork failed: %s\n", strerror(errno));
+ abort();
+ }
+
+ /* The child (*uadepid == 0) will execute uadecore */
+ if (*uadepid == 0) {
+ int fd;
+ int maxfds;
+
+ if ((maxfds = sysconf(_SC_OPEN_MAX)) < 0) {
+ maxfds = 1024;
+ fprintf(stderr, "Getting max fds failed. Using %d.\n", maxfds);
+ }
+
+ /* close everything else but stdin, stdout, stderr, and in/out fds */
+ for (fd = 3; fd < maxfds; fd++) {
+ if (fd != fds[1])
+ atomic_close(fd);
+ }
+
+ /* give in/out fds as command line parameters to the uade process */
+ snprintf(input, sizeof(input), "fd://%d", fds[1]);
+ snprintf(output, sizeof(output), "fd://%d", fds[1]);
+
+ execlp(uadename, uadename, "-i", input, "-o", output, (char *) NULL);
+ fprintf(stderr, "uade execlp failed: %s\n", strerror(errno));
+ abort();
+ }
+
+ /* Close fds that the uadecore uses */
+ if (atomic_close(fds[1]) < 0) {
+ fprintf(stderr, "Could not close uadecore fds: %s\n", strerror(errno));
+ kill (*uadepid, SIGTERM);
+ abort();
+ }
+
+ do {
+ snprintf(output, sizeof output, "fd://%d", fds[0]);
+ snprintf(input, sizeof input, "fd://%d", fds[0]);
+ uade_set_peer(ipc, 1, input, output);
+ } while (0);
+}
+
+/*
+ * A hack that converts X:\something style windows names into cygwin style name
+ * /cygdrive/X/something. All '\\' characters are converted into '/'
+ * characters.
+ */
+char *windows_to_cygwin_path(const char *path)
+{
+ size_t i;
+ char *s;
+ size_t len = strlen(path);
+
+ if (len == 0)
+ return calloc(1, 1);
+
+ if (len >= 2 && isalpha(path[0]) && path[1] == ':') {
+ /* uses windows drive names */
+ size_t newlen = len + 32;
+ s = malloc(newlen);
+ if (s != NULL)
+ snprintf(s, newlen, "/cygdrive/%c/%s", path[0], &path[2]);
+ } else {
+ s = strdup(path);
+ }
+ if (s == NULL)
+ return NULL;
+
+ for (i = 0; s[i] != 0; i++) {
+ if (s[i] == '\\')
+ s[i] = '/';
+ }
+
+ return s;
+}
diff --git a/plugins/vfs_curl/Makefile.am b/plugins/vfs_curl/Makefile.am
index 95794831..4c69c51f 100644
--- a/plugins/vfs_curl/Makefile.am
+++ b/plugins/vfs_curl/Makefile.am
@@ -4,6 +4,6 @@ pkglib_LTLIBRARIES = vfs_curl.la
vfs_curl_la_SOURCES = vfs_curl.c
vfs_curl_la_LDFLAGS = -module
-vfs_curl_la_LIBADD = $(LDADD) $(CURL_LIBS)
+vfs_curl_la_LIBADD = $(LDADD) $(VFS_CURL_LIBS)
AM_CFLAGS = $(CFLAGS) -std=c99
endif
diff --git a/plugins/vfs_curl/vfs_curl.c b/plugins/vfs_curl/vfs_curl.c
index 048f964e..528b3809 100644
--- a/plugins/vfs_curl/vfs_curl.c
+++ b/plugins/vfs_curl/vfs_curl.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -46,6 +46,7 @@ enum {
STATUS_FINISHED = 2,
STATUS_ABORTED = 3,
STATUS_SEEK = 4,
+ STATUS_DESTROY = 5,
};
typedef struct {
@@ -72,6 +73,8 @@ typedef struct {
int metadata_size; // size of metadata in stream
int metadata_have_size; // amount which is already in metadata buffer
+ char http_err[CURL_ERROR_SIZE];
+
// flags (bitfields to save some space)
unsigned seektoend : 1; // indicates that next tell must return length
unsigned gotheader : 1; // tells that all headers (including ICY) were processed (to start reading body)
@@ -81,13 +84,34 @@ typedef struct {
static DB_vfs_t plugin;
-static char http_err[CURL_ERROR_SIZE];
-
static int allow_new_streams;
static size_t
http_content_header_handler (void *ptr, size_t size, size_t nmemb, void *stream);
+static int64_t biglock;
+
+#define MAX_ABORT_FILES 100
+static DB_FILE *open_files[MAX_ABORT_FILES];
+static int num_open_files = 0;
+static DB_FILE *abort_files[MAX_ABORT_FILES];
+static int num_abort_files = 0;
+
+static int
+http_need_abort (DB_FILE *fp);
+
+static void
+http_cancel_abort (DB_FILE *fp);
+
+static void
+http_abort (DB_FILE *fp);
+
+static void
+http_reg_open_file (DB_FILE *fp);
+
+static void
+http_unreg_open_file (DB_FILE *fp);
+
static size_t
http_curl_write_wrapper (HTTP_FILE *fp, void *ptr, size_t size) {
size_t avail = size;
@@ -98,7 +122,8 @@ http_curl_write_wrapper (HTTP_FILE *fp, void *ptr, size_t size) {
deadbeef->mutex_unlock (fp->mutex);
return 0;
}
- if (fp->status == STATUS_ABORTED) {
+ if (http_need_abort ((DB_FILE*)fp)) {
+ fp->status = STATUS_ABORTED;
trace ("vfs_curl STATUS_ABORTED in the middle of packet\n");
deadbeef->mutex_unlock (fp->mutex);
break;
@@ -217,13 +242,14 @@ http_curl_write (void *ptr, size_t size, size_t nmemb, void *stream) {
// trace ("http_curl_write %d bytes, wait_meta=%d\n", size * nmemb, fp->wait_meta);
gettimeofday (&fp->last_read_time, NULL);
- if (fp->status == STATUS_ABORTED) {
+ if (http_need_abort (stream)) {
+ fp->status = STATUS_ABORTED;
trace ("vfs_curl STATUS_ABORTED at start of packet\n");
return 0;
}
- if (fp->gotsomeheader) {
- fp->gotheader = 1;
- }
+// if (fp->gotsomeheader) {
+// fp->gotheader = 1;
+// }
if (!fp->gotheader) {
// check if that's ICY
if (!fp->icyheader && avail >= 10 && !memcmp (ptr, "ICY 200 OK", 10)) {
@@ -467,7 +493,8 @@ http_curl_control (void *stream, double dltotal, double dlnow, double ultotal, d
deadbeef->mutex_unlock (fp->mutex);
return -1;
}
- if (fp->status == STATUS_ABORTED) {
+ if (http_need_abort ((DB_FILE *)fp)) {
+ fp->status = STATUS_ABORTED;
trace ("vfs_curl STATUS_ABORTED in progress callback\n");
deadbeef->mutex_unlock (fp->mutex);
return -1;
@@ -477,6 +504,23 @@ http_curl_control (void *stream, double dltotal, double dlnow, double ultotal, d
}
static void
+http_destroy (HTTP_FILE *fp) {
+ if (fp->content_type) {
+ free (fp->content_type);
+ }
+ if (fp->track) {
+ deadbeef->pl_item_unref (fp->track);
+ }
+ if (fp->url) {
+ free (fp->url);
+ }
+ if (fp->mutex) {
+ deadbeef->mutex_free (fp->mutex);
+ }
+ free (fp);
+}
+
+static void
http_thread_func (void *ctx) {
HTTP_FILE *fp = (HTTP_FILE *)ctx;
CURL *curl;
@@ -492,10 +536,11 @@ http_thread_func (void *ctx) {
struct curl_slist *headers = NULL;
curl_easy_reset (curl);
curl_easy_setopt (curl, CURLOPT_URL, fp->url);
+ curl_easy_setopt (curl, CURLOPT_USERAGENT, "deadbeef");
curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1);
curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, http_curl_write);
curl_easy_setopt (curl, CURLOPT_WRITEDATA, ctx);
- curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, http_err);
+ curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, fp->http_err);
curl_easy_setopt (curl, CURLOPT_BUFFERSIZE, BUFFER_SIZE/2);
curl_easy_setopt (curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, http_content_header_handler);
@@ -513,9 +558,10 @@ http_thread_func (void *ctx) {
curl_easy_setopt (curl, CURLOPT_RESUME_FROM, fp->pos);
}
if (deadbeef->conf_get_int ("network.proxy", 0)) {
- curl_easy_setopt (curl, CURLOPT_PROXY, deadbeef->conf_get_str ("network.proxy.address", ""));
+ deadbeef->conf_lock ();
+ curl_easy_setopt (curl, CURLOPT_PROXY, deadbeef->conf_get_str_fast ("network.proxy.address", ""));
curl_easy_setopt (curl, CURLOPT_PROXYPORT, deadbeef->conf_get_int ("network.proxy.port", 8080));
- const char *type = deadbeef->conf_get_str ("network.proxy.type", "HTTP");
+ const char *type = deadbeef->conf_get_str_fast ("network.proxy.type", "HTTP");
int curlproxytype = CURLPROXY_HTTP;
if (!strcasecmp (type, "HTTP")) {
curlproxytype = CURLPROXY_HTTP;
@@ -543,8 +589,8 @@ http_thread_func (void *ctx) {
#endif
curl_easy_setopt (curl, CURLOPT_PROXYTYPE, curlproxytype);
- const char *proxyuser = deadbeef->conf_get_str ("network.proxy.username", "");
- const char *proxypass = deadbeef->conf_get_str ("network.proxy.password", "");
+ const char *proxyuser = deadbeef->conf_get_str_fast ("network.proxy.username", "");
+ const char *proxypass = deadbeef->conf_get_str_fast ("network.proxy.password", "");
if (*proxyuser || *proxypass) {
#if LIBCURL_VERSION_MINOR >= 19 && LIBCURL_VERSION_PATCH >= 1
curl_easy_setopt (curl, CURLOPT_PROXYUSERNAME, proxyuser);
@@ -555,6 +601,7 @@ http_thread_func (void *ctx) {
curl_easy_setopt (curl, CURLOPT_PROXYUSERPWD, pwd);
#endif
}
+ deadbeef->conf_unlock ();
}
// fp->status = STATUS_INITIAL;
trace ("vfs_curl: calling curl_easy_perform (status=%d)...\n", fp->status);
@@ -562,7 +609,7 @@ http_thread_func (void *ctx) {
status = curl_easy_perform (curl);
trace ("vfs_curl: curl_easy_perform retval=%d\n", status);
if (status != 0) {
- trace ("curl error:\n%s\n", http_err);
+ trace ("curl error:\n%s\n", fp->http_err);
}
deadbeef->mutex_lock (fp->mutex);
if (status == 0 && fp->length < 0 && fp->status != STATUS_ABORTED && fp->status != STATUS_SEEK) {
@@ -583,10 +630,12 @@ http_thread_func (void *ctx) {
continue;
}
if (fp->status != STATUS_SEEK) {
+ trace ("vfs_curl: break loop\n");
deadbeef->mutex_unlock (fp->mutex);
break;
}
else {
+ trace ("vfs_curl: restart loop\n");
fp->skipbytes = 0;
fp->status = STATUS_INITIAL;
trace ("seeking to %d\n", fp->pos);
@@ -612,15 +661,22 @@ http_thread_func (void *ctx) {
curl_easy_cleanup (curl);
deadbeef->mutex_lock (fp->mutex);
+
+ if (fp->status == STATUS_ABORTED) {
+ trace ("vfs_curl: thread ended due to abort signal\n");
+ }
+ else {
+ trace ("vfs_curl: thread ended normally\n");
+ }
fp->status = STATUS_FINISHED;
deadbeef->mutex_unlock (fp->mutex);
- fp->tid = 0;
}
static void
http_start_streamer (HTTP_FILE *fp) {
fp->mutex = deadbeef->mutex_create ();
fp->tid = deadbeef->thread_start (http_thread_func, fp);
+// deadbeef->thread_detach (fp->tid);
}
static DB_FILE *
@@ -630,6 +686,7 @@ http_open (const char *fname) {
}
trace ("http_open\n");
HTTP_FILE *fp = malloc (sizeof (HTTP_FILE));
+ http_reg_open_file ((DB_FILE *)fp);
memset (fp, 0, sizeof (HTTP_FILE));
fp->vfs = &plugin;
fp->url = strdup (fname);
@@ -651,24 +708,13 @@ http_close (DB_FILE *stream) {
assert (stream);
HTTP_FILE *fp = (HTTP_FILE *)stream;
- deadbeef->mutex_lock (fp->mutex);
+ http_abort (stream);
if (fp->tid) {
- fp->status = STATUS_ABORTED;
- trace ("http_close thread_join\n");
- deadbeef->mutex_unlock (fp->mutex);
deadbeef->thread_join (fp->tid);
}
- if (fp->content_type) {
- free (fp->content_type);
- }
- if (fp->track) {
- deadbeef->pl_item_unref (fp->track);
- }
- if (fp->url) {
- free (fp->url);
- }
- deadbeef->mutex_free (fp->mutex);
- free (stream);
+ http_cancel_abort ((DB_FILE *)fp);
+ http_destroy (fp);
+ http_unreg_open_file ((DB_FILE *)fp);
trace ("http_close done\n");
}
@@ -690,7 +736,7 @@ http_read (void *ptr, size_t size, size_t nmemb, DB_FILE *stream) {
{
// wait until data is available
while ((fp->remaining == 0 || fp->skipbytes > 0) && fp->status != STATUS_FINISHED) {
-// trace ("vfs_curl: readwait..\n");
+ trace ("vfs_curl: readwait, status: %d..\n", fp->status);
deadbeef->mutex_lock (fp->mutex);
if (fp->status == STATUS_READING) {
struct timeval tm;
@@ -867,43 +913,163 @@ http_get_content_type (DB_FILE *stream) {
return fp->content_type;
}
-void
+static void
http_abort (DB_FILE *fp) {
- trace ("http_abort %p\n", fp);
- HTTP_FILE *f = (HTTP_FILE *)fp;
- if (f->tid) {
- deadbeef->mutex_lock (f->mutex);
- f->status = STATUS_ABORTED;
- deadbeef->mutex_unlock (f->mutex);
- }
- trace ("http_abort done\n");
+ trace ("abort file: %p\n", fp);
+ deadbeef->mutex_lock (biglock);
+ int i;
+ for (i = 0; i < num_abort_files; i++) {
+ if (abort_files[i] == fp) {
+ break;
+ }
+ }
+ if (i == num_abort_files) {
+ if (num_abort_files == MAX_ABORT_FILES) {
+ trace ("vfs_curl: abort_files list overflow\n");
+ }
+ else {
+ trace ("added file to abort list: %p\n", fp);
+ abort_files[num_abort_files++] = fp;
+ }
+ }
+ deadbeef->mutex_unlock (biglock);
+}
+
+static int
+http_need_abort (DB_FILE *fp) {
+ deadbeef->mutex_lock (biglock);
+ for (int i = 0; i < num_abort_files; i++) {
+ if (abort_files[i] == fp) {
+ trace ("need to abort: %p\n", fp);
+ deadbeef->mutex_unlock (biglock);
+ return 1;
+ }
+ }
+ deadbeef->mutex_unlock (biglock);
+ return 0;
+}
+
+static void
+http_cancel_abort (DB_FILE *fp) {
+ deadbeef->mutex_lock (biglock);
+ for (int i = 0; i < num_abort_files; i++) {
+ if (abort_files[i] == fp) {
+ if (i != num_abort_files-1) {
+ abort_files[i] = abort_files[num_abort_files-1];
+ }
+ num_abort_files--;
+ break;
+ }
+ }
+ deadbeef->mutex_unlock (biglock);
+}
+
+static void
+http_reg_open_file (DB_FILE *fp) {
+ deadbeef->mutex_lock (biglock);
+ for (int i = 0; i < num_open_files; i++) {
+ if (open_files[i] == fp) {
+ deadbeef->mutex_unlock (biglock);
+ return;
+ }
+ }
+ if (num_open_files == MAX_ABORT_FILES) {
+ fprintf (stderr, "vfs_curl: open files overflow\n");
+ deadbeef->mutex_unlock (biglock);
+ return;
+ }
+ open_files[num_open_files++] = fp;
+ deadbeef->mutex_unlock (biglock);
+}
+
+static void
+http_unreg_open_file (DB_FILE *fp) {
+ deadbeef->mutex_lock (biglock);
+ int i;
+ for (i = 0; i < num_open_files; i++) {
+ if (open_files[i] == fp) {
+ if (i != num_open_files-1) {
+ open_files[i] = open_files[num_open_files-1];
+ }
+ num_open_files--;
+ trace ("remove from open list: %p\n", fp);
+ break;
+ }
+ }
+
+ // gc abort_files
+ int j = 0;
+ while (j < num_abort_files) {
+ for (i = 0; i < num_open_files; i++) {
+ if (abort_files[j] == open_files[i]) {
+ break;
+ }
+ }
+ if (i == num_open_files) {
+ // remove abort
+ http_cancel_abort (abort_files[j]);
+ continue;
+ }
+ j++;
+ }
+ deadbeef->mutex_unlock (biglock);
}
static int
vfs_curl_start (void) {
allow_new_streams = 1;
+ biglock = deadbeef->mutex_create ();
return 0;
}
static int
vfs_curl_stop (void) {
allow_new_streams = 0;
+ if (biglock) {
+ deadbeef->mutex_free (biglock);
+ biglock = 0;
+ }
return 0;
}
static const char *scheme_names[] = { "http://", "ftp://", NULL };
+const char **
+http_get_schemes (void) {
+ return scheme_names;
+}
+
+int
+http_is_streaming (void) {
+ return 1;
+}
+
// standard stdio vfs
static DB_vfs_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_VFS,
.plugin.id = "vfs_curl",
.plugin.name = "cURL vfs",
.plugin.descr = "http and ftp streaming module using libcurl, with ICY protocol support",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = vfs_curl_start,
.plugin.stop = vfs_curl_stop,
@@ -917,8 +1083,8 @@ static DB_vfs_t plugin = {
.rewind = http_rewind,
.getlength = http_getlength,
.get_content_type = http_get_content_type,
- .scheme_names = scheme_names,
- .streaming = 1
+ .get_schemes = http_get_schemes,
+ .is_streaming = http_is_streaming,
};
DB_plugin_t *
diff --git a/plugins/vfs_zip/Makefile.am b/plugins/vfs_zip/Makefile.am
new file mode 100644
index 00000000..8a03b68d
--- /dev/null
+++ b/plugins/vfs_zip/Makefile.am
@@ -0,0 +1,9 @@
+if HAVE_VFS_ZIP
+pkglib_LTLIBRARIES = vfs_zip.la
+vfs_zip_la_SOURCES = vfs_zip.c
+
+vfs_zip_la_LDFLAGS = -module
+
+vfs_zip_la_LIBADD = $(LDADD) $(ZLIB_LIBS) $(ZIP_LIBS)
+AM_CFLAGS = $(CFLAGS) -std=c99
+endif
diff --git a/plugins/vfs_zip/vfs_zip.c b/plugins/vfs_zip/vfs_zip.c
new file mode 100644
index 00000000..5e77b740
--- /dev/null
+++ b/plugins/vfs_zip/vfs_zip.c
@@ -0,0 +1,255 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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 <string.h>
+#include <zip.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "../../deadbeef.h"
+
+#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+//#define trace(fmt,...)
+
+#define min(x,y) ((x)<(y)?(x):(y))
+
+static DB_functions_t *deadbeef;
+static DB_vfs_t plugin;
+
+typedef struct {
+ DB_FILE file;
+ struct zip* z;
+ struct zip_file *zf;
+ int64_t offset;
+ int index;
+ int64_t size;
+} zip_file_t;
+
+static const char *scheme_names[] = { "zip://", NULL };
+
+const char **
+vfs_zip_get_schemes (void) {
+ return scheme_names;
+}
+
+int
+vfs_zip_is_streaming (void) {
+ return 0;
+}
+
+// fname must have form of zip://full_filepath.zip:full_filepath_in_zip
+DB_FILE*
+vfs_zip_open (const char *fname) {
+ if (strncasecmp (fname, "zip://", 6)) {
+ return NULL;
+ }
+
+ fname += 6;
+ const char *colon = strchr (fname, ':');
+ if (!colon) {
+ return NULL;
+ }
+
+
+ char zipname[colon-fname+1];
+ memcpy (zipname, fname, colon-fname);
+ zipname[colon-fname] = 0;
+
+ fname = colon+1;
+
+ struct zip *z = zip_open (zipname, 0, NULL);
+ if (!z) {
+ return NULL;
+ }
+ struct zip_stat st;
+ memset (&st, 0, sizeof (st));
+
+ int res = zip_stat(z, fname, 0, &st);
+ if (res != 0) {
+ zip_close (z);
+ return NULL;
+ }
+
+ struct zip_file *zf = zip_fopen_index (z, st.index, 0);
+ if (!zf) {
+ zip_close (z);
+ return NULL;
+ }
+
+ zip_file_t *f = malloc (sizeof (zip_file_t));
+ memset (f, 0, sizeof (zip_file_t));
+ f->file.vfs = &plugin;
+ f->z = z;
+ f->zf = zf;
+ f->index = st.index;
+ f->size = st.size;
+ return (DB_FILE*)f;
+}
+
+void
+vfs_zip_close (DB_FILE *f) {
+ zip_file_t *zf = (zip_file_t *)f;
+ if (zf->zf) {
+ zip_fclose (zf->zf);
+ }
+ if (zf->z) {
+ zip_close (zf->z);
+ }
+ free (zf);
+}
+
+size_t
+vfs_zip_read (void *ptr, size_t size, size_t nmemb, DB_FILE *f) {
+ zip_file_t *zf = (zip_file_t *)f;
+ ssize_t rb = zip_fread (zf->zf, ptr, size * nmemb);
+ zf->offset += rb;
+ return rb / size;
+}
+
+int
+vfs_zip_seek (DB_FILE *f, int64_t offset, int whence) {
+ zip_file_t *zf = (zip_file_t *)f;
+
+ if (whence == SEEK_CUR) {
+ offset = zf->offset + offset;
+ }
+ else if (whence == SEEK_END) {
+ offset = zf->size + offset;
+ }
+
+ if (offset < zf->offset) {
+ // reopen
+ zip_fclose (zf->zf);
+ zf->zf = zip_fopen_index (zf->z, zf->index, 0);
+ if (!zf->zf) {
+ return -1;
+ }
+ zf->offset = 0;
+ }
+ char buf[4096];
+ int64_t n = offset - zf->offset;
+ while (n > 0) {
+ int sz = min (n, sizeof (buf));
+ ssize_t rb = zip_fread (zf->zf, buf, sz);
+ n -= rb;
+ assert (n >= 0);
+ zf->offset += rb;
+ if (rb != sz) {
+ break;
+ }
+ }
+ if (n > 0) {
+ return -1;
+ }
+ return 0;
+}
+
+int64_t
+vfs_zip_tell (DB_FILE *f) {
+ zip_file_t *zf = (zip_file_t *)f;
+ return zf->offset;
+}
+
+void
+vfs_zip_rewind (DB_FILE *f) {
+ zip_file_t *zf = (zip_file_t *)f;
+ zip_fclose (zf->zf);
+ zf->zf = zip_fopen_index (zf->z, zf->index, 0);
+ assert (zf->zf); // FIXME: better error handling?
+ zf->offset = 0;
+}
+
+int64_t
+vfs_zip_getlength (DB_FILE *f) {
+ zip_file_t *zf = (zip_file_t *)f;
+ return zf->size;
+}
+
+int
+vfs_zip_scandir (const char *dir, struct dirent ***namelist, int (*selector) (const struct dirent *), int (*cmp) (const struct dirent **, const struct dirent **)) {
+ struct zip *z = zip_open (dir, ZIP_CHECKCONS, NULL);
+ if (!z) {
+ return -1;
+ }
+
+ int n = zip_get_num_files (z);
+ *namelist = malloc (sizeof (void *) * n);
+ for (int i = 0; i < n; i++) {
+ (*namelist)[i] = malloc (sizeof (struct dirent));
+ memset ((*namelist)[i], 0, sizeof (struct dirent));
+ const char *nm = zip_get_name (z, i, 0);
+ snprintf ((*namelist)[i]->d_name, sizeof ((*namelist)[i]->d_name), "zip://%s:%s", dir, nm);
+ }
+
+ zip_close (z);
+ return n;
+}
+
+int
+vfs_zip_is_container (const char *fname) {
+ const char *ext = strrchr (fname, '.');
+ if (ext && !strcasecmp (ext, ".zip")) {
+ return 1;
+ }
+ return 0;
+}
+
+static DB_vfs_t plugin = {
+ DB_PLUGIN_SET_API_VERSION
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
+ .plugin.type = DB_PLUGIN_VFS,
+ .plugin.id = "vfs_zip",
+ .plugin.name = "ZIP vfs",
+ .plugin.descr = "play files directly from zip files",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
+ .plugin.website = "http://deadbeef.sf.net",
+ .open = vfs_zip_open,
+ .close = vfs_zip_close,
+ .read = vfs_zip_read,
+ .seek = vfs_zip_seek,
+ .tell = vfs_zip_tell,
+ .rewind = vfs_zip_rewind,
+ .getlength = vfs_zip_getlength,
+ .get_schemes = vfs_zip_get_schemes,
+ .is_streaming = vfs_zip_is_streaming,
+ .is_container = vfs_zip_is_container,
+ .scandir = vfs_zip_scandir,
+};
+
+DB_plugin_t *
+vfs_zip_load (DB_functions_t *api) {
+ deadbeef = api;
+ return DB_PLUGIN (&plugin);
+}
diff --git a/plugins/vorbis/vorbis.c b/plugins/vorbis/vorbis.c
index fc0afe9e..691e40f3 100644
--- a/plugins/vorbis/vorbis.c
+++ b/plugins/vorbis/vorbis.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -22,6 +22,7 @@
#include <assert.h>
#include <limits.h>
#include <unistd.h>
+#include <math.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
@@ -88,6 +89,7 @@ static const char *metainfo[] = {
"DISCNUMBER", "disc",
"COPYRIGHT", "copyright",
"TOTALTRACKS", "numtracks",
+ "TRACKTOTAL", "numtracks",
"ALBUM ARTIST", "band",
NULL
};
@@ -112,7 +114,6 @@ update_vorbis_comments (DB_playItem_t *it, vorbis_comment *vc, int refresh_playl
for (m = 0; metainfo[m]; m += 2) {
int l = strlen (metainfo[m]);
if (vc->comment_lengths[i] > l && !strncasecmp (metainfo[m], s, l) && s[l] == '=') {
- trace ("ogg adding %s\n", s);
if (refresh_playlist == 2) {
const char *val = deadbeef->pl_find_meta (it, metainfo[m+1]);
if (!val || strcmp (val, s+l+1)) {
@@ -121,6 +122,7 @@ update_vorbis_comments (DB_playItem_t *it, vorbis_comment *vc, int refresh_playl
}
else {
deadbeef->pl_append_meta (it, metainfo[m+1], s + l + 1);
+ break;
}
}
}
@@ -129,16 +131,28 @@ update_vorbis_comments (DB_playItem_t *it, vorbis_comment *vc, int refresh_playl
deadbeef->pl_add_meta (it, "cuesheet", s + 9);
}
else if (!strncasecmp (s, "replaygain_album_gain=", 22)) {
- it->replaygain_album_gain = atof (s + 22);
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMGAIN, atof (s+22));
}
else if (!strncasecmp (s, "replaygain_album_peak=", 22)) {
- it->replaygain_album_peak = atof (s + 22);
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMPEAK, atof (s+22));
}
else if (!strncasecmp (s, "replaygain_track_gain=", 22)) {
- it->replaygain_track_gain = atof (s + 22);
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKGAIN, atof (s+22));
}
else if (!strncasecmp (s, "replaygain_track_peak=", 22)) {
- it->replaygain_track_peak = atof (s + 22);
+ deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKPEAK, atof (s+22));
+ }
+ else {
+ const char *p = s;
+ while (*p && *p != '=') {
+ p++;
+ }
+ if (*p == '=') {
+ char key[p-s+1];
+ memcpy (key, s, p-s);
+ key[p-s] = 0;
+ deadbeef->pl_add_meta (it, key, p+1);
+ }
}
}
}
@@ -154,10 +168,11 @@ update_vorbis_comments (DB_playItem_t *it, vorbis_comment *vc, int refresh_playl
if (refresh_playlist) {
deadbeef->plug_trigger_event_playlistchanged ();
}
+ return 0;
}
static DB_fileinfo_t *
-cvorbis_open (void) {
+cvorbis_open (uint32_t hints) {
DB_fileinfo_t *_info = malloc (sizeof (ogg_info_t));
ogg_info_t *info = (ogg_info_t *)_info;
memset (info, 0, sizeof (ogg_info_t));
@@ -173,18 +188,19 @@ cvorbis_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
info->cur_bit_stream = -1;
}
else {
- info->cur_bit_stream = it->tracknum;
+ int tracknum = deadbeef->pl_find_meta_int (it, ":TRACKNUM", -1);
+ info->cur_bit_stream = tracknum;
}
info->ptrack = it;
deadbeef->pl_item_ref (it);
- info->info.file = deadbeef->fopen (it->fname);
+ info->info.file = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!info->info.file) {
trace ("ogg: failed to open file %s\n", it->fname);
return -1;
}
int ln = deadbeef->fgetlength (info->info.file);
- if (info->info.file->vfs->streaming && ln == -1) {
+ if (info->info.file->vfs->is_streaming () && ln == -1) {
ov_callbacks ovcb = {
.read_func = cvorbis_fread,
.seek_func = NULL,
@@ -227,13 +243,18 @@ cvorbis_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
return -1;
}
_info->plugin = &plugin;
- _info->bps = 16;
+ _info->fmt.bps = 16;
//_info->dataSize = ov_pcm_total (&vorbis_file, -1) * vi->channels * 2;
- _info->channels = info->vi->channels;
- _info->samplerate = info->vi->rate;
+ _info->fmt.channels = info->vi->channels;
+ _info->fmt.samplerate = info->vi->rate;
+
+ for (int i = 0; i < _info->fmt.channels; i++) {
+ _info->fmt.channelmask |= 1 << i;
+ }
+
_info->readpos = 0;
info->currentsample = 0;
- if (!info->info.file->vfs->streaming) {
+ if (!info->info.file->vfs->is_streaming ()) {
if (it->endsample > 0) {
info->startsample = it->startsample;
info->endsample = it->endsample;
@@ -266,8 +287,12 @@ cvorbis_free (DB_fileinfo_t *_info) {
deadbeef->pl_item_unref (info->ptrack);
}
if (info->info.file) {
- ov_clear (&info->vorbis_file);
- //fclose (file); //-- ov_clear closes it
+ if (info->vorbis_file.datasource) {
+ ov_clear (&info->vorbis_file);
+ }
+ else {
+ deadbeef->fclose (info->info.file);
+ }
}
free (info);
}
@@ -277,10 +302,12 @@ static int
cvorbis_read (DB_fileinfo_t *_info, char *bytes, int size) {
ogg_info_t *info = (ogg_info_t *)_info;
// trace ("cvorbis_read %d bytes\n", size);
- int out_ch = min (_info->channels, 2);
- if (!info->info.file->vfs->streaming) {
- if (info->currentsample + size / (2 * out_ch) > info->endsample) {
- size = (info->endsample - info->currentsample + 1) * 2 * out_ch;
+
+ int samplesize = _info->fmt.channels * _info->fmt.bps / 8;
+
+ if (!info->info.file->vfs->is_streaming ()) {
+ if (info->currentsample + size / samplesize > info->endsample) {
+ size = (info->endsample - info->currentsample + 1) * samplesize;
trace ("size truncated to %d bytes, cursample=%d, info->endsample=%d, totalsamples=%d\n", size, info->currentsample, info->endsample, ov_pcm_total (&info->vorbis_file, -1));
if (size <= 0) {
return 0;
@@ -288,7 +315,7 @@ cvorbis_read (DB_fileinfo_t *_info, char *bytes, int size) {
}
}
else {
- if (info->ptrack && info->currentsample - info->last_comment_update > 5 * _info->samplerate) {
+ if (info->ptrack && info->currentsample - info->last_comment_update > 5 * _info->fmt.samplerate) {
if (info->ptrack) {
info->last_comment_update = info->currentsample;
vorbis_comment *vc = ov_comment (&info->vorbis_file, -1);
@@ -311,23 +338,33 @@ cvorbis_read (DB_fileinfo_t *_info, char *bytes, int size) {
endianess = 1;
#endif
- if (out_ch != _info->channels) {
- int nframes = size / out_ch / 2;
- int16_t buf[nframes * _info->channels];
- ret=ov_read (&info->vorbis_file, (char*)buf, sizeof(buf), endianess, 2, 1, &info->cur_bit_stream);
+ if (_info->fmt.channels <= 2 || _info->fmt.channels == 4) {
+ ret=ov_read (&info->vorbis_file, bytes, size, endianess, 2, 1, &info->cur_bit_stream);
+ }
+ else {
+ int16_t temp[size/2];
+ ret=ov_read (&info->vorbis_file, (char *)temp, size, endianess, 2, 1, &info->cur_bit_stream);
if (ret > 0) {
- int n = ret / _info->channels / 2;
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < out_ch; j++) {
- ((int16_t *)bytes)[i * out_ch + j] = buf[i * _info->channels + j];
+ // remap channels to wav format
+ int idx = _info->fmt.channels - 3;
+ static int remap[4][6] = {
+ {0,2,1},
+ {0,1,2,3}, // should not be used
+ {0,2,1,3,4},
+ {0,2,1,4,5,3}
+ };
+
+ int i, j;
+ int16_t *src = temp;
+ int n = ret / samplesize;
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < _info->fmt.channels; j++) {
+ ((int16_t *)(bytes + samplesize * i))[remap[idx][j]] = src[j];
}
+ src += _info->fmt.channels;
}
- ret = n * out_ch * 2;
}
}
- else {
- ret=ov_read (&info->vorbis_file, bytes, size, endianess, 2, 1, &info->cur_bit_stream);
- }
if (ret <= 0)
{
if (ret < 0) {
@@ -352,12 +389,12 @@ cvorbis_read (DB_fileinfo_t *_info, char *bytes, int size) {
}
else if (ret < size)
{
- info->currentsample += ret / (out_ch * 2);
+ info->currentsample += ret / samplesize;
size -= ret;
bytes += ret;
}
else {
- info->currentsample += ret / (out_ch * 2);
+ info->currentsample += ret / samplesize;
size = 0;
break;
}
@@ -410,10 +447,10 @@ cvorbis_insert (DB_playItem_t *after, const char *fname) {
trace ("vorbis: failed to fopen %s\n", fname);
return NULL;
}
- if (fp->vfs->streaming) {
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->fname = strdup (fname);
- it->filetype = "OggVorbis";
+ int64_t fsize = deadbeef->fgetlength (fp);
+ if (fp->vfs->is_streaming ()) {
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
+ deadbeef->pl_add_meta (it, ":FILETYPE", "OggVorbis");
deadbeef->pl_set_item_duration (it, -1);
deadbeef->pl_add_meta (it, "title", NULL);
after = deadbeef->pl_insert_item (after, it);
@@ -448,11 +485,9 @@ cvorbis_insert (DB_playItem_t *after, const char *fname) {
float duration = ov_time_total (&vorbis_file, stream);
int totalsamples = ov_pcm_total (&vorbis_file, stream);
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (fname);
- it->filetype = "OggVorbis";
- it->tracknum = stream;
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
+ deadbeef->pl_add_meta (it, ":FILETYPE", "OggVorbis");
+ deadbeef->pl_set_meta_int (it, ":TRACKNUM", stream);
deadbeef->pl_set_item_duration (it, duration);
if (nstreams > 1) {
it->startsample = currentsample;
@@ -465,6 +500,19 @@ cvorbis_insert (DB_playItem_t *after, const char *fname) {
update_vorbis_comments (it, vc, 0);
int samplerate = vi->rate;
+ char s[100];
+ snprintf (s, sizeof (s), "%lld", fsize);
+ deadbeef->pl_add_meta (it, ":FILE_SIZE", s);
+ deadbeef->pl_add_meta (it, ":BPS", "16");
+ snprintf (s, sizeof (s), "%d", vi->channels);
+ deadbeef->pl_add_meta (it, ":CHANNELS", s);
+ snprintf (s, sizeof (s), "%d", samplerate);
+ deadbeef->pl_add_meta (it, ":SAMPLERATE", s);
+ int br = (int)roundf(fsize / duration * 8 / 1000);
+ snprintf (s, sizeof (s), "%d", br);
+ deadbeef->pl_add_meta (it, ":BITRATE", s);
+
+
if (nstreams == 1) {
DB_playItem_t *cue = deadbeef->pl_insert_cue (after, it, totalsamples, samplerate);
if (cue) {
@@ -513,12 +561,12 @@ cvorbis_read_metadata (DB_playItem_t *it) {
OggVorbis_File vorbis_file;
vorbis_info *vi = NULL;
- fp = deadbeef->fopen (it->fname);
+ fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!fp) {
trace ("cvorbis_read_metadata: failed to fopen %s\n", it->fname);
return -1;
}
- if (fp->vfs->streaming) {
+ if (fp->vfs->is_streaming ()) {
trace ("cvorbis_read_metadata: failed to fopen %s\n", it->fname);
goto error;
}
@@ -533,14 +581,15 @@ cvorbis_read_metadata (DB_playItem_t *it) {
trace ("cvorbis_read_metadata: ov_open_callbacks returned %d\n", res);
goto error;
}
- vi = ov_info (&vorbis_file, it->tracknum);
+ int tracknum = deadbeef->pl_find_meta_int (it, ":TRACKNUM", -1);
+ vi = ov_info (&vorbis_file, tracknum);
if (!vi) { // not a vorbis stream
trace ("cvorbis_read_metadata: failed to ov_open %s\n", it->fname);
goto error;
}
// metainfo
- vorbis_comment *vc = ov_comment (&vorbis_file, it->tracknum);
+ vorbis_comment *vc = ov_comment (&vorbis_file, tracknum);
if (vc) {
update_vorbis_comments (it, vc, 0);
}
@@ -576,7 +625,7 @@ cvorbis_write_metadata (DB_playItem_t *it) {
trace ("cvorbis_write_metadata: vcedit_new_state failed\n");
return -1;
}
- fp = fopen (it->fname, "rb");
+ fp = fopen (deadbeef->pl_find_meta (it, ":URI"), "rb");
if (!fp) {
trace ("cvorbis_write_metadata: failed to read metadata from %s\n", it->fname);
goto error;
@@ -592,6 +641,7 @@ cvorbis_write_metadata (DB_playItem_t *it) {
goto error;
}
+#if 0
// copy all unknown fields to separate buffer
for (int i = 0; i < vc->comments; i++) {
int m;
@@ -612,42 +662,55 @@ cvorbis_write_metadata (DB_playItem_t *it) {
preserved_fields = f;
}
}
+#endif
vorbis_comment_clear(vc);
vorbis_comment_init(vc);
- // add known fields
- for (int m = 0; metainfo[m]; m += 2) {
- const char *val = deadbeef->pl_find_meta (it, metainfo[m+1]);
- if (val && *val) {
- while (val) {
- const char *next = strchr (val, '\n');
- int l;
- if (next) {
- l = next - val;
- next++;
- }
- else {
- l = strlen (val);
+ // add unknown/custom fields
+ deadbeef->pl_lock ();
+ DB_metaInfo_t *m = deadbeef->pl_get_metadata_head (it);
+ while (m) {
+ if (m->key[0] != ':') {
+ int i;
+ for (i = 0; metainfo[i]; i += 2) {
+ if (!strcasecmp (metainfo[i+1], m->key)) {
+ break;
}
- if (l > 0) {
- char s[100+l+1];
- int n = snprintf (s, sizeof (s), "%s=", metainfo[m]);
- strncpy (s+n, val, l);
- *(s+n+l) = 0;
- vorbis_comment_add (vc, s);
+ }
+ const char *val = m->value;
+ if (val && *val) {
+ while (val) {
+ const char *next = strchr (val, '\n');
+ int l;
+ if (next) {
+ l = next - val;
+ next++;
+ }
+ else {
+ l = strlen (val);
+ }
+ if (l > 0) {
+ char s[100+l+1];
+ int n = snprintf (s, sizeof (s), "%s=", metainfo[i] ? metainfo[i] : m->key);
+ strncpy (s+n, val, l);
+ *(s+n+l) = 0;
+ vorbis_comment_add (vc, s);
+ }
+ val = next;
}
- val = next;
}
}
+ m = m->next;
}
+ deadbeef->pl_unlock ();
// add preserved fields
for (struct field *f = preserved_fields; f; f = f->next) {
vorbis_comment_add (vc, f->data);
}
- snprintf (outname, sizeof (outname), "%s.temp.ogg", it->fname);
+ snprintf (outname, sizeof (outname), "%s.temp.ogg", deadbeef->pl_find_meta (it, ":URI"));
out = fopen (outname, "w+b");
if (!out) {
@@ -678,7 +741,7 @@ error:
}
if (!err) {
- rename (outname, it->fname);
+ rename (outname, deadbeef->pl_find_meta (it, ":URI"));
}
else if (out) {
unlink (outname);
@@ -694,21 +757,36 @@ static const char *filetypes[] = { "OggVorbis", NULL };
// define plugin interface
static DB_decoder_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.id = "stdogg",
.plugin.name = "OggVorbis decoder",
.plugin.descr = "OggVorbis decoder using standard xiph.org libraries",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = vorbis_start,
.plugin.stop = vorbis_stop,
.open = cvorbis_open,
.init = cvorbis_init,
.free = cvorbis_free,
- .read_int16 = cvorbis_read,
+ .read = cvorbis_read,
// vorbisfile can't output float32
// .read_float32 = cvorbis_read_float32,
.seek = cvorbis_seek,
diff --git a/plugins/vtx/vtx.c b/plugins/vtx/vtx.c
index 3e4ed6b9..aa62422e 100644
--- a/plugins/vtx/vtx.c
+++ b/plugins/vtx/vtx.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -47,7 +47,7 @@ typedef struct {
} vtx_info_t;
static DB_fileinfo_t *
-vtx_open (void) {
+vtx_open (uint32_t hints) {
DB_fileinfo_t *_info = malloc (sizeof (vtx_info_t));
memset (_info, 0, sizeof (vtx_info_t));
return _info;
@@ -62,9 +62,9 @@ vtx_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
size_t sz = 0;
char *buf = NULL;
- DB_FILE *fp = deadbeef->fopen (it->fname);
+ DB_FILE *fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!fp) {
- trace ("vtx: failed to open file %s\n", it->fname);
+ trace ("vtx: failed to open file %s\n", deadbeef->pl_find_meta (it, ":URI"));
return -1;
}
@@ -102,16 +102,21 @@ vtx_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
int samplerate = deadbeef->conf_get_int ("synth.samplerate", 44100);
- ayemu_set_sound_format (&info->ay, samplerate, deadbeef->get_output ()->channels (), deadbeef->get_output ()->bitspersample ());
-
info->left = 0;
- info->rate = deadbeef->get_output ()->channels () * deadbeef->get_output ()->bitspersample () / 8;
info->vtx_pos = 0;
_info->plugin = &plugin;
- _info->bps = deadbeef->get_output ()->bitspersample ();
- _info->channels = deadbeef->get_output ()->channels ();
- _info->samplerate = samplerate;
+ _info->fmt.bps = deadbeef->conf_get_int ("vtx.bps", 16);;
+ if (_info->fmt.bps != 16 && _info->fmt.bps != 8) {
+ _info->fmt.bps = 16;
+ }
+ _info->fmt.channels = 2;
+ _info->fmt.samplerate = samplerate;
+ _info->fmt.channelmask = _info->fmt.channels == 1 ? DDB_SPEAKER_FRONT_LEFT : (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT);
_info->readpos = 0;
+
+ ayemu_set_sound_format (&info->ay, samplerate, _info->fmt.channels, _info->fmt.bps);
+
+ info->rate = _info->fmt.channels * _info->fmt.bps / 8;
return 0;
}
@@ -149,7 +154,7 @@ ayemu_vtx_get_next_frame (vtx_info_t *info)
}
static int
-vtx_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
+vtx_read (DB_fileinfo_t *_info, char *bytes, int size) {
// try decode `size' bytes
// return number of decoded bytes
// return 0 on EOF
@@ -170,7 +175,7 @@ vtx_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
}
else {
// number of samples it current frame
- info->left = _info->samplerate / info->decoder->playerFreq;
+ info->left = _info->fmt.samplerate / info->decoder->playerFreq;
// mul by rate to get number of bytes;
info->left *= info->rate;
ayemu_set_regs (&info->ay, info->regs);
@@ -179,7 +184,7 @@ vtx_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
}
}
info->currentsample += (initsize - size) / 4;
- _info->readpos = (float)info->currentsample / _info->samplerate;
+ _info->readpos = (float)info->currentsample / _info->fmt.samplerate;
return initsize - size;
}
@@ -192,7 +197,7 @@ vtx_seek_sample (DB_fileinfo_t *_info, int sample) {
// get frame
int num_frames = info->decoder->regdata_size / AY_FRAME_SIZE;
- int samples_per_frame = _info->samplerate / info->decoder->playerFreq;
+ int samples_per_frame = _info->fmt.samplerate / info->decoder->playerFreq;
// start of frame
info->vtx_pos = sample / samples_per_frame;
@@ -206,11 +211,11 @@ vtx_seek_sample (DB_fileinfo_t *_info, int sample) {
info->regs[n] = *p;
}
// set number of bytes left in frame
- info->left = _info->samplerate / info->decoder->playerFreq - (sample % samples_per_frame);
+ info->left = _info->fmt.samplerate / info->decoder->playerFreq - (sample % samples_per_frame);
// mul by rate to get number of bytes
info->left *= info->rate;
info->currentsample = sample;
- _info->readpos = (float)info->currentsample / _info->samplerate;
+ _info->readpos = (float)info->currentsample / _info->fmt.samplerate;
return 0;
}
@@ -220,7 +225,7 @@ vtx_seek (DB_fileinfo_t *_info, float time) {
// seek to specified time in seconds
// return 0 on success
// return -1 on failure
- return vtx_seek_sample (_info, time * _info->samplerate);
+ return vtx_seek_sample (_info, time * _info->fmt.samplerate);
}
static DB_playItem_t *
@@ -253,11 +258,8 @@ vtx_insert (DB_playItem_t *after, const char *fname) {
}
trace ("vtx: datasize: %d\n", hdr->regdata_size);
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
-
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (fname);
- it->filetype = filetypes[0];
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
+ deadbeef->pl_add_meta (it, ":FILETYPE", filetypes[0]);
int numframes = hdr->regdata_size / AY_FRAME_SIZE;
// int totalsamples = numframes * hdr->playerFreq;
@@ -290,25 +292,48 @@ vtx_stop (void) {
// return -1 on failure
return 0;
}
+
+static const char settings_dlg[] =
+ "property \"Bits Per Sample (8 or 16)\" entry vtx.bps 16;\n"
+;
+
// define plugin interface
static DB_decoder_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.id = "vtx",
.plugin.name = "VTX decoder",
.plugin.descr = "AY8910/12 chip emulator and vtx file player",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "Uses libayemu - AY/YM sound chip emulator and music file loader\n"
+ "Copyright (C) 2003-2004 Sashnov Alexander\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = vtx_start,
.plugin.stop = vtx_stop,
+ .plugin.configdialog = settings_dlg,
.open = vtx_open,
.init = vtx_init,
.free = vtx_free,
- .read_int16 = vtx_read_int16,
-// .read_float32 = vtx_read_float32,
+ .read = vtx_read,
.seek = vtx_seek,
.seek_sample = vtx_seek_sample,
.insert = vtx_insert,
diff --git a/plugins/wavpack/COPYING b/plugins/wavpack/COPYING
new file mode 100644
index 00000000..f1cf0011
--- /dev/null
+++ b/plugins/wavpack/COPYING
@@ -0,0 +1,26 @@
+WavPack plugin for DeaDBeeF Player
+Copyright (C) 2009-2011, Alexey Yakovenko <waker@users.sourceforge.net>
+With contributions from David Bryant <david@wavpack.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/plugins/wavpack/wavpack.c b/plugins/wavpack/wavpack.c
index e1eb4787..15973421 100644
--- a/plugins/wavpack/wavpack.c
+++ b/plugins/wavpack/wavpack.c
@@ -1,20 +1,30 @@
/*
- DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@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.
+WavPack plugin for DeaDBeeF Player
+Copyright (C) 2009-2011, Alexey Yakovenko <waker@users.sourceforge.net>
+Copyright (C) 2010-2011, David Bryant <david@wavpack.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
@@ -106,7 +116,7 @@ static WavpackStreamReader wsr = {
#endif
static DB_fileinfo_t *
-wv_open (void) {
+wv_open (uint32_t hints) {
DB_fileinfo_t *_info = malloc (sizeof (wvctx_t));
memset (_info, 0, sizeof (wvctx_t));
return _info;
@@ -115,15 +125,15 @@ wv_open (void) {
static int
wv_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
wvctx_t *info = (wvctx_t *)_info;
- info->file = deadbeef->fopen (it->fname);
+ info->file = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!info->file) {
return -1;
}
#ifndef TINYWV
- char *c_fname = alloca (strlen (it->fname) + 2);
+ char *c_fname = alloca (strlen (deadbeef->pl_find_meta (it, ":URI")) + 2);
if (c_fname) {
- strcpy (c_fname, it->fname);
+ strcpy (c_fname, deadbeef->pl_find_meta (it, ":URI"));
strcat (c_fname, "c");
info->c_file = deadbeef->fopen (c_fname);
}
@@ -136,16 +146,18 @@ wv_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
#ifdef TINYWV
info->ctx = WavpackOpenFileInput (wv_read_stream, info->file, error);
#else
- info->ctx = WavpackOpenFileInputEx (&wsr, info->file, info->c_file, error, OPEN_2CH_MAX | OPEN_NORMALIZE, 0);
+ info->ctx = WavpackOpenFileInputEx (&wsr, info->file, info->c_file, error, OPEN_NORMALIZE, 0);
#endif
if (!info->ctx) {
fprintf (stderr, "wavpack error: %s\n", error);
return -1;
}
_info->plugin = &plugin;
- _info->bps = WavpackGetBytesPerSample (info->ctx) * 8;
- _info->channels = WavpackGetNumChannels (info->ctx);
- _info->samplerate = WavpackGetSampleRate (info->ctx);
+ _info->fmt.bps = WavpackGetBytesPerSample (info->ctx) * 8;
+ _info->fmt.channels = WavpackGetNumChannels (info->ctx);
+ _info->fmt.samplerate = WavpackGetSampleRate (info->ctx);
+ _info->fmt.is_float = (WavpackGetMode (info->ctx) & MODE_FLOAT) ? 1 : 0;
+ _info->fmt.channelmask = WavpackGetChannelMask (info->ctx);
_info->readpos = 0;
if (it->endsample > 0) {
info->startsample = it->startsample;
@@ -184,49 +196,57 @@ wv_free (DB_fileinfo_t *_info) {
}
static int
-wv_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
+wv_read (DB_fileinfo_t *_info, char *bytes, int size) {
wvctx_t *info = (wvctx_t *)_info;
int currentsample = WavpackGetSampleIndex (info->ctx);
- int nchannels = WavpackGetReducedChannels (info->ctx);
- if (size / (2 * nchannels) + currentsample > info->endsample) {
- size = (info->endsample - currentsample + 1) * 2 * nchannels;
- trace ("wv: size truncated to %d bytes, cursample=%d, endsample=%d\n", size, currentsample, info->endsample);
+ int samplesize = _info->fmt.channels * _info->fmt.bps / 8;
+ if (size / samplesize + currentsample > info->endsample) {
+ size = (info->endsample - currentsample + 1) * samplesize;
+ trace ("wv: size truncated to %d bytes (%d samples), cursample=%d, endsample=%d\n", size, info->endsample - currentsample + 1, currentsample, info->endsample);
if (size <= 0) {
return 0;
}
}
- int32_t buffer[size/2];
- int n = WavpackUnpackSamples (info->ctx, buffer, size/(2*nchannels));
- size = n * 2 * nchannels;
- // convert to int16
- int32_t *p = buffer;
- n *= nchannels;
-
+ int initsize = size;
+ int n;
if (WavpackGetMode (info->ctx) & MODE_FLOAT) {
- while (n > 0) {
- float val = *(float*)p;
- if (val >= 1.0)
- *((int16_t *)bytes) = 32767;
- else if (val <= -1.0)
- *((int16_t *)bytes) = -32768;
- else
- *((int16_t *)bytes) = floor (val * 32768.f);
- bytes += sizeof (int16_t);
- p++;
- n--;
- }
+ _info->fmt.is_float = 1;
+ }
+ if (_info->fmt.is_float || _info->fmt.bps == 32) {
+ n = WavpackUnpackSamples (info->ctx, (int32_t *)bytes, size / samplesize);
+ size -= n * samplesize;
}
else {
- while (n > 0) {
- if (_info->bps >= 16) {
- *((int16_t *)bytes) = (int16_t)((*p) >> (_info->bps-16));
+ int32_t buffer[size/(_info->fmt.bps / 8)];
+ n = WavpackUnpackSamples (info->ctx, (int32_t *)buffer, size / samplesize);
+ size -= n * samplesize;
+ n *= _info->fmt.channels;
+
+ // convert from int32 to input (what???)
+ int32_t *p = buffer;
+ if (_info->fmt.bps == 16) {
+ while (n > 0) {
+ *((int16_t *)bytes) = (int16_t)(*p);
+ bytes += sizeof (int16_t);
+ p++;
+ n--;
}
- else {
- *((int16_t *)bytes) = (int16_t)((*p) << (16-_info->bps));
+ }
+ else if (_info->fmt.bps == 8) {
+ while (n > 0) {
+ *bytes++ = (char)(*p);
+ p++;
+ n--;
+ }
+ }
+ else if (_info->fmt.bps == 24) {
+ while (n > 0) {
+ *bytes++ = (*p)&0xff;
+ *bytes++ = ((*p)&0xff00)>>8;
+ *bytes++ = ((*p)&0xff0000)>>16;
+ p++;
+ n--;
}
- bytes += sizeof (int16_t);
- p++;
- n--;
}
}
_info->readpos = (float)(WavpackGetSampleIndex (info->ctx)-info->startsample)/WavpackGetSampleRate (info->ctx);
@@ -235,45 +255,7 @@ wv_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) {
deadbeef->streamer_set_bitrate (WavpackGetInstantBitrate (info->ctx) / 1000);
#endif
- return size;
-}
-
-static int
-wv_read_float32 (DB_fileinfo_t *_info, char *bytes, int size) {
- wvctx_t *info = (wvctx_t *)_info;
- int nchannels = WavpackGetReducedChannels (info->ctx);
- int currentsample = WavpackGetSampleIndex (info->ctx);
- if (size / (4 * nchannels) + currentsample > info->endsample) {
- size = (info->endsample - currentsample + 1) * 4 * nchannels;
- trace ("wv: size truncated to %d bytes, cursample=%d, endsample=%d\n", size, currentsample, info->endsample);
- if (size <= 0) {
- return 0;
- }
- }
- int32_t buffer[size/4];
- int n = WavpackUnpackSamples (info->ctx, buffer, size/(4*nchannels));
- size = n * 4 * nchannels;
- // convert to float32
- n *= nchannels;
-
- if (WavpackGetMode (info->ctx) & MODE_FLOAT) {
- memcpy (bytes, buffer, size);
- }
- else {
- float mul = 1.f/ (1UL << (_info->bps-1));
- int32_t *p = buffer;
- while (n > 0) {
- *((float *)bytes) = (*p) * mul;
- bytes += sizeof (float);
- p++;
- n--;
- }
- }
- _info->readpos = (float)(WavpackGetSampleIndex (info->ctx)-info->startsample)/WavpackGetSampleRate (info->ctx);
-#ifndef TINYWV
- deadbeef->streamer_set_bitrate (WavpackGetInstantBitrate (info->ctx) / 1000);
-#endif
- return size;
+ return initsize-size;
}
static int
@@ -294,7 +276,6 @@ wv_seek (DB_fileinfo_t *_info, float sec) {
static DB_playItem_t *
wv_insert (DB_playItem_t *after, const char *fname) {
-
DB_FILE *fp = deadbeef->fopen (fname);
if (!fp) {
return NULL;
@@ -314,10 +295,8 @@ wv_insert (DB_playItem_t *after, const char *fname) {
int samplerate = WavpackGetSampleRate (ctx);
float duration = (float)totalsamples / samplerate;
- DB_playItem_t *it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id);
- it->fname = strdup (fname);
- it->filetype = "wv";
+ DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
+ deadbeef->pl_add_meta (it, ":FILETYPE", "wv");
deadbeef->pl_set_item_duration (it, duration);
trace ("wv: totalsamples=%d, samplerate=%d, duration=%f\n", totalsamples, samplerate, duration);
@@ -340,28 +319,21 @@ wv_insert (DB_playItem_t *after, const char *fname) {
if (!v1err) {
trace ("wv: id3v1 tag found\n");
}
-
-#if 0
- // embedded cue
- char *emb_cuesheet;
- int len = WavpackGetTagItem (ctx, "cuesheet", NULL, 0);
- if (len) {
- emb_cuesheet = malloc (len);
- if (emb_cuesheet) {
- WavpackGetTagItem (ctx, "Cuesheet", emb_cuesheet, len);
- trace ("got cuesheet\n%s\n", emb_cuesheet);
- DB_playItem_t *last = deadbeef->pl_insert_cue_from_buffer (after, it, emb_cuesheet, strlen (emb_cuesheet), totalsamples, samplerate);
- free (emb_cuesheet);
- if (last) {
- deadbeef->pl_item_unref (it);
- deadbeef->fclose (fp);
- WavpackCloseFile (ctx);
- return last;
- }
- trace ("pl_insert_cue_from_buffer failed!\n");
- }
- }
-#endif
+ deadbeef->pl_add_meta (it, "title", NULL);
+
+ char s[100];
+ snprintf (s, sizeof (s), "%lld", deadbeef->fgetlength (fp));
+ deadbeef->pl_add_meta (it, ":FILE_SIZE", s);
+ snprintf (s, sizeof (s), "%d", WavpackGetBytesPerSample (ctx) * 8);
+ deadbeef->pl_add_meta (it, ":BPS", s);
+ snprintf (s, sizeof (s), "%d", WavpackGetNumChannels (ctx));
+ deadbeef->pl_add_meta (it, ":CHANNELS", s);
+ snprintf (s, sizeof (s), "%d", WavpackGetSampleRate (ctx));
+ deadbeef->pl_add_meta (it, ":SAMPLERATE", s);
+ snprintf (s, sizeof (s), "%d", (int)(WavpackGetAverageBitrate (ctx, 1) / 1000));
+ deadbeef->pl_add_meta (it, ":BITRATE", s);
+ snprintf (s, sizeof (s), "%s", (WavpackGetMode (ctx) & MODE_FLOAT) ? "FLOAT" : "INTEGER");
+ deadbeef->pl_add_meta (it, ":WAVPACK_MODE", s);
// embedded cue
const char *cuesheet = deadbeef->pl_find_meta (it, "cuesheet");
@@ -396,7 +368,7 @@ wv_insert (DB_playItem_t *after, const char *fname) {
int
wv_read_metadata (DB_playItem_t *it) {
- DB_FILE *fp = deadbeef->fopen (it->fname);
+ DB_FILE *fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
if (!fp) {
return -1;
}
@@ -442,20 +414,45 @@ static const char *filetypes[] = { "wv", NULL };
// define plugin interface
static DB_decoder_t plugin = {
DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.id = "wv",
.plugin.name = "WavPack decoder",
- .plugin.descr = ".wv player using libwavpack",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.descr = "WavPack (.wv, .iso.wv) player",
+ .plugin.copyright =
+ "WavPack plugin for DeaDBeeF Player\n"
+ "Copyright (C) 2009-2011, Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "Copyright (C) 2010-2011, David Bryant <david@wavpack.com>\n"
+ "All rights reserved.\n"
+ "\n"
+ "Redistribution and use in source and binary forms, with or without\n"
+ "modification, are permitted provided that the following conditions are met:\n"
+ " * Redistributions of source code must retain the above copyright\n"
+ " notice, this list of conditions and the following disclaimer.\n"
+ " * Redistributions in binary form must reproduce the above copyright\n"
+ " notice, this list of conditions and the following disclaimer in the\n"
+ " documentation and/or other materials provided with the distribution.\n"
+ " * Neither the name of the <organization> nor the\n"
+ " names of its contributors may be used to endorse or promote products\n"
+ " derived from this software without specific prior written permission.\n"
+ "\n"
+ "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n"
+ "ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"
+ "WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n"
+ "DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\n"
+ "DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n"
+ "(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n"
+ "LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n"
+ "ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
+ "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n"
+ "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.open = wv_open,
.init = wv_init,
.free = wv_free,
- .read_int16 = wv_read_int16,
- .read_float32 = wv_read_float32,
+ .read = wv_read,
.seek = wv_seek,
.seek_sample = wv_seek_sample,
.insert = wv_insert,
diff --git a/plugins/wildmidi/wildmidiplug.c b/plugins/wildmidi/wildmidiplug.c
index e9c976b3..87aee260 100644
--- a/plugins/wildmidi/wildmidiplug.c
+++ b/plugins/wildmidi/wildmidiplug.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@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
@@ -42,7 +42,7 @@ typedef struct {
} wmidi_info_t;
DB_fileinfo_t *
-wmidi_open (void) {
+wmidi_open (uint32_t hints) {
DB_fileinfo_t *_info = (DB_fileinfo_t *)malloc (sizeof (wmidi_info_t));
memset (_info, 0, sizeof (wmidi_info_t));
return _info;
@@ -52,16 +52,17 @@ int
wmidi_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
wmidi_info_t *info = (wmidi_info_t *)_info;
- info->m = WildMidi_Open (it->fname);
+ info->m = WildMidi_Open (deadbeef->pl_find_meta (it, ":URI"));
if (!info->m) {
- trace ("wmidi: failed to open %s\n", it->fname);
+ trace ("wmidi: failed to open %s\n", deadbeef->pl_find_meta (it, ":URI"));
return -1;
}
_info->plugin = &wmidi_plugin;
- _info->channels = 2;
- _info->bps = 16;
- _info->samplerate = 44100;
+ _info->fmt.channels = 2;
+ _info->fmt.bps = 16;
+ _info->fmt.samplerate = 44100;
+ _info->fmt.channelmask = _info->fmt.channels == 1 ? DDB_SPEAKER_FRONT_LEFT : (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT);
_info->readpos = 0;
return 0;
@@ -96,13 +97,13 @@ wmidi_seek_sample (DB_fileinfo_t *_info, int sample) {
wmidi_info_t *info = (wmidi_info_t *)_info;
unsigned long int s = sample;
WildMidi_SampledSeek (info->m, &s);
- _info->readpos = s/44100.0f;
+ _info->readpos = s/(float)_info->fmt.samplerate;
return 0;
}
int
wmidi_seek (DB_fileinfo_t *_info, float time) {
- return wmidi_seek_sample (_info, time * 44100);
+ return wmidi_seek_sample (_info, time * _info->fmt.samplerate);
}
DB_playItem_t *
@@ -116,12 +117,10 @@ wmidi_insert (DB_playItem_t *after, const char *fname) {
}
struct _WM_Info *inf = WildMidi_GetInfo (m);
- it = deadbeef->pl_item_alloc ();
- it->decoder_id = deadbeef->plug_get_decoder_id (wmidi_plugin.plugin.id);
- it->fname = strdup (fname);
+ it = deadbeef->pl_item_alloc_init (fname, wmidi_plugin.plugin.id);
deadbeef->pl_add_meta (it, "title", NULL);
deadbeef->pl_set_item_duration (it, inf->approx_total_samples / 44100.f);
- it->filetype = "MID";
+ deadbeef->pl_add_meta (it, ":FILETYPE", "MID");
after = deadbeef->pl_insert_item (after, it);
deadbeef->pl_item_unref (it);
WildMidi_Close (m);
@@ -132,7 +131,8 @@ wmidi_insert (DB_playItem_t *after, const char *fname) {
int
wmidi_start (void) {
- const char *config_files = deadbeef->conf_get_str ("wildmidi.config", DEFAULT_TIMIDITY_CONFIG);
+ char config_files[1000];
+ deadbeef->conf_get_str ("wildmidi.config", DEFAULT_TIMIDITY_CONFIG, config_files, sizeof (config_files));
char config[1024] = "";
const char *p = config_files;
while (p) {
@@ -186,12 +186,30 @@ static const char settings_dlg[] =
DB_decoder_t wmidi_plugin = {
DB_PLUGIN_SET_API_VERSION
.plugin.type = DB_PLUGIN_DECODER,
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
.plugin.name = "WildMidi player",
- .plugin.descr = "MIDI player based on WildMidi library",
- .plugin.author = "Alexey Yakovenko",
- .plugin.email = "waker@users.sourceforge.net",
+ .plugin.descr = "MIDI player based on WildMidi library\n\nRequires freepats package to be installed\nSee http://freepats.zenvoid.org/\nMake sure to set correct freepats.cfg path in plugin settings.",
+ .plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "Uses modified WildMidi v0.2.2\n"
+ "(C) 2001-2004 Chris Ison\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = wmidi_start,
.plugin.stop = wmidi_stop,
@@ -200,7 +218,7 @@ DB_decoder_t wmidi_plugin = {
.open = wmidi_open,
.init = wmidi_init,
.free = wmidi_free,
- .read_int16 = wmidi_read,
+ .read = wmidi_read,
.seek = wmidi_seek,
.seek_sample = wmidi_seek_sample,
.insert = wmidi_insert,