aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/images/advanced.pngbin757 -> 0 bytes
-rw-r--r--src/images/interface.pngbin779 -> 0 bytes
-rw-r--r--src/images/pause.pngbin315 -> 0 bytes
-rw-r--r--src/images/play.pngbin364 -> 0 bytes
-rw-r--r--src/images/playlist.pngbin383 -> 0 bytes
-rw-r--r--src/images/plugins.pngbin471 -> 0 bytes
-rw-r--r--src/images/stop.pngbin323 -> 0 bytes
-rw-r--r--src/plugins/CMakeLists.txt4
-rw-r--r--src/plugins/Effect/CMakeLists.txt8
-rw-r--r--src/plugins/Effect/Effect.pro4
-rw-r--r--src/plugins/Effect/srconverter/CMakeLists.txt76
-rw-r--r--src/plugins/Effect/srconverter/effectsrconverterfactory.cpp57
-rw-r--r--src/plugins/Effect/srconverter/effectsrconverterfactory.h46
-rw-r--r--src/plugins/Effect/srconverter/settingsdialog.cpp48
-rw-r--r--src/plugins/Effect/srconverter/settingsdialog.h46
-rw-r--r--src/plugins/Effect/srconverter/settingsdialog.ui124
-rw-r--r--src/plugins/Effect/srconverter/srconverter.cpp125
-rw-r--r--src/plugins/Effect/srconverter/srconverter.h59
-rw-r--r--src/plugins/Effect/srconverter/srconverter.pro34
-rw-r--r--src/plugins/General/General.pro4
-rw-r--r--src/plugins/General/dbuscontrol/dbusadaptor.cpp62
-rw-r--r--src/plugins/General/dbuscontrol/dbusadaptor.h47
-rw-r--r--src/plugins/General/dbuscontrol/dbuscontrol.cpp61
-rw-r--r--src/plugins/General/dbuscontrol/dbuscontrol.h43
-rw-r--r--src/plugins/General/dbuscontrol/dbuscontrol.pro39
-rw-r--r--src/plugins/General/dbuscontrol/dbuscontrolfactory.cpp55
-rw-r--r--src/plugins/General/dbuscontrol/dbuscontrolfactory.h45
-rw-r--r--src/plugins/General/scrobbler/scrobbler.cpp259
-rw-r--r--src/plugins/General/scrobbler/scrobbler.h75
-rw-r--r--src/plugins/General/scrobbler/scrobbler.pro41
-rw-r--r--src/plugins/General/scrobbler/scrobblerfactory.cpp59
-rw-r--r--src/plugins/General/scrobbler/scrobblerfactory.h45
-rw-r--r--src/plugins/General/scrobbler/settingsdialog.cpp51
-rw-r--r--src/plugins/General/scrobbler/settingsdialog.h48
-rw-r--r--src/plugins/General/scrobbler/settingsdialog.ui92
-rw-r--r--src/plugins/General/statusicon/images/images.qrc8
-rw-r--r--src/plugins/General/statusicon/images/tray_pause.pngbin0 -> 569 bytes
-rw-r--r--src/plugins/General/statusicon/images/tray_play.pngbin0 -> 706 bytes
-rw-r--r--src/plugins/General/statusicon/images/tray_stop.pngbin0 -> 503 bytes
-rw-r--r--src/plugins/General/statusicon/settingsdialog.cpp55
-rw-r--r--src/plugins/General/statusicon/settingsdialog.h48
-rw-r--r--src/plugins/General/statusicon/settingsdialog.ui173
-rw-r--r--src/plugins/General/statusicon/statusicon.cpp109
-rw-r--r--src/plugins/General/statusicon/statusicon.h58
-rw-r--r--src/plugins/General/statusicon/statusicon.pro36
-rw-r--r--src/plugins/General/statusicon/statusiconfactory.cpp59
-rw-r--r--src/plugins/General/statusicon/statusiconfactory.h45
-rw-r--r--src/plugins/Input/CMakeLists.txt49
-rw-r--r--src/plugins/Input/Input.pro26
-rw-r--r--src/plugins/Input/ffmpeg/CMakeLists.txt94
-rw-r--r--src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp342
-rw-r--r--src/plugins/Input/ffmpeg/decoder_ffmpeg.h78
-rw-r--r--src/plugins/Input/ffmpeg/decoderffmpegfactory.cpp93
-rw-r--r--src/plugins/Input/ffmpeg/decoderffmpegfactory.h54
-rw-r--r--src/plugins/Input/ffmpeg/detailsdialog.cpp103
-rw-r--r--src/plugins/Input/ffmpeg/detailsdialog.h45
-rw-r--r--src/plugins/Input/ffmpeg/detailsdialog.ui332
-rw-r--r--src/plugins/Input/ffmpeg/ffmpeg.pro35
-rw-r--r--src/plugins/Input/ffmpeg/translations/ffmpeg_plugin_cs.ts150
-rw-r--r--src/plugins/Input/ffmpeg/translations/ffmpeg_plugin_ru.qmbin0 -> 2221 bytes
-rw-r--r--src/plugins/Input/ffmpeg/translations/ffmpeg_plugin_ru.ts149
-rw-r--r--src/plugins/Input/ffmpeg/translations/translations.qrc6
-rw-r--r--src/plugins/Input/flac/CMakeLists.txt86
-rw-r--r--src/plugins/Input/flac/decoder_flac.cpp567
-rw-r--r--src/plugins/Input/flac/decoder_flac.h124
-rw-r--r--src/plugins/Input/flac/decoderflacfactory.cpp95
-rw-r--r--src/plugins/Input/flac/decoderflacfactory.h54
-rw-r--r--src/plugins/Input/flac/detailsdialog.cpp118
-rw-r--r--src/plugins/Input/flac/detailsdialog.h49
-rw-r--r--src/plugins/Input/flac/detailsdialog.ui349
-rw-r--r--src/plugins/Input/flac/flac.pro36
-rw-r--r--src/plugins/Input/flac/translations/flac_plugin_ru.qmbin0 -> 2218 bytes
-rw-r--r--src/plugins/Input/flac/translations/flac_plugin_ru.ts154
-rw-r--r--src/plugins/Input/flac/translations/translations.qrc6
-rw-r--r--src/plugins/Input/mad/CMakeLists.txt90
-rw-r--r--src/plugins/Input/mad/decoder_mad.cpp572
-rw-r--r--src/plugins/Input/mad/decoder_mad.h95
-rw-r--r--src/plugins/Input/mad/decodermadfactory.cpp188
-rw-r--r--src/plugins/Input/mad/decodermadfactory.h53
-rw-r--r--src/plugins/Input/mad/detailsdialog.cpp294
-rw-r--r--src/plugins/Input/mad/detailsdialog.h63
-rw-r--r--src/plugins/Input/mad/detailsdialog.ui392
-rw-r--r--src/plugins/Input/mad/mad.pro39
-rw-r--r--src/plugins/Input/mad/settingsdialog.cpp107
-rw-r--r--src/plugins/Input/mad/settingsdialog.h52
-rw-r--r--src/plugins/Input/mad/settingsdialog.ui306
-rw-r--r--src/plugins/Input/mad/translations/mad_plugin_ru.qmbin0 -> 3625 bytes
-rw-r--r--src/plugins/Input/mad/translations/mad_plugin_ru.ts242
-rw-r--r--src/plugins/Input/mad/translations/translations.qrc6
-rw-r--r--src/plugins/Input/mad/ui_detailsdialog.h400
-rw-r--r--src/plugins/Input/mad/ui_settingsdialog.h245
-rw-r--r--src/plugins/Input/mpc/CMakeLists.txt86
-rw-r--r--src/plugins/Input/mpc/Makefile254
-rw-r--r--src/plugins/Input/mpc/decoder_mpc.cpp386
-rw-r--r--src/plugins/Input/mpc/decoder_mpc.h80
-rw-r--r--src/plugins/Input/mpc/decodermpcfactory.cpp95
-rw-r--r--src/plugins/Input/mpc/decodermpcfactory.h54
-rw-r--r--src/plugins/Input/mpc/detailsdialog.cpp115
-rw-r--r--src/plugins/Input/mpc/detailsdialog.h49
-rw-r--r--src/plugins/Input/mpc/detailsdialog.ui349
-rw-r--r--src/plugins/Input/mpc/mpc.pro32
-rw-r--r--src/plugins/Input/mpc/translations/mpc_plugin_ru.qmbin0 -> 2230 bytes
-rw-r--r--src/plugins/Input/mpc/translations/mpc_plugin_ru.ts149
-rw-r--r--src/plugins/Input/mpc/translations/translations.qrc6
-rw-r--r--src/plugins/Input/sndfile/CMakeLists.txt74
-rw-r--r--src/plugins/Input/sndfile/decoder_sndfile.cpp282
-rw-r--r--src/plugins/Input/sndfile/decoder_sndfile.h66
-rw-r--r--src/plugins/Input/sndfile/decodersndfilefactory.cpp126
-rw-r--r--src/plugins/Input/sndfile/decodersndfilefactory.h54
-rw-r--r--src/plugins/Input/sndfile/sndfile.pro28
-rw-r--r--src/plugins/Input/vorbis/CMakeLists.txt96
-rw-r--r--src/plugins/Input/vorbis/decoder_vorbis.cpp425
-rw-r--r--src/plugins/Input/vorbis/decoder_vorbis.h63
-rw-r--r--src/plugins/Input/vorbis/decodervorbisfactory.cpp105
-rw-r--r--src/plugins/Input/vorbis/decodervorbisfactory.h54
-rw-r--r--src/plugins/Input/vorbis/detailsdialog.cpp120
-rw-r--r--src/plugins/Input/vorbis/detailsdialog.h49
-rw-r--r--src/plugins/Input/vorbis/detailsdialog.ui384
-rw-r--r--src/plugins/Input/vorbis/translations/translations.qrc6
-rw-r--r--src/plugins/Input/vorbis/translations/vorbis_plugin_ru.qmbin0 -> 2569 bytes
-rw-r--r--src/plugins/Input/vorbis/translations/vorbis_plugin_ru.ts164
-rw-r--r--src/plugins/Input/vorbis/vorbis.pro35
-rw-r--r--src/plugins/Misc/CommandLineOptions/IncDecVolumeOption.pro2
-rw-r--r--src/plugins/Misc/CommandLineOptions/IncDecVolumeOption/IncDecVolumeOption.pro26
-rw-r--r--src/plugins/Misc/CommandLineOptions/IncDecVolumeOption/Makefile301
-rw-r--r--src/plugins/Misc/CommandLineOptions/IncDecVolumeOption/incdecvolumeoption.cpp53
-rw-r--r--src/plugins/Misc/CommandLineOptions/IncDecVolumeOption/incdecvolumeoption.h23
-rw-r--r--src/plugins/Misc/FileDialogs/FileDialogs.pro3
-rw-r--r--src/plugins/Misc/FileDialogs/Makefile134
-rw-r--r--src/plugins/Misc/FileDialogs/QmmpFileDialog/QmmpFileDialog.pro28
-rw-r--r--src/plugins/Misc/FileDialogs/QmmpFileDialog/images/cdup.pngbin0 -> 736 bytes
-rw-r--r--src/plugins/Misc/FileDialogs/QmmpFileDialog/images/detail.pngbin0 -> 551 bytes
-rw-r--r--src/plugins/Misc/FileDialogs/QmmpFileDialog/images/images.qrc8
-rw-r--r--src/plugins/Misc/FileDialogs/QmmpFileDialog/images/list.pngbin0 -> 547 bytes
-rw-r--r--src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialog.cpp44
-rw-r--r--src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialog.h40
-rw-r--r--src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialog.ui216
-rw-r--r--src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialogimpl.cpp109
-rw-r--r--src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialogimpl.h33
-rw-r--r--src/plugins/Misc/FileDialogs/Qt3FileDialog/Qt3FileDialog.pro28
-rw-r--r--src/plugins/Misc/FileDialogs/Qt3FileDialog/qt3filedialog.cpp35
-rw-r--r--src/plugins/Misc/FileDialogs/Qt3FileDialog/qt3filedialog.h23
-rw-r--r--src/plugins/Misc/FileDialogs/Qt3FileDialog/qt3filedialogfactory.cpp20
-rw-r--r--src/plugins/Misc/FileDialogs/Qt3FileDialog/qt3filedialogfactory.h19
-rw-r--r--src/plugins/Misc/FileDialogs/Qt3FileDialog/readme14
-rwxr-xr-xsrc/plugins/Misc/FileDialogs/libQmmpFileDialog.sobin0 -> 137806 bytes
-rwxr-xr-xsrc/plugins/Misc/FileDialogs/libQt3FileDialog.sobin0 -> 104681 bytes
-rw-r--r--src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/CSVPlaylistFormat.pro20
-rw-r--r--src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/Makefile213
-rw-r--r--src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/csvplaylistformat.cpp72
-rw-r--r--src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/csvplaylistformat.h33
-rw-r--r--src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/moc_csvplaylistformat.cpp64
-rw-r--r--src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/readme12
-rw-r--r--src/plugins/Misc/PlaylistFormats/Makefile112
-rw-r--r--src/plugins/Misc/PlaylistFormats/PlaylistFormats.pro2
-rwxr-xr-xsrc/plugins/Misc/PlaylistFormats/libCSVPlaylistFormat.sobin0 -> 38452 bytes
-rw-r--r--src/plugins/Output/CMakeLists.txt24
-rw-r--r--src/plugins/Output/Output.pro26
-rw-r--r--src/plugins/Output/alsa/CMakeLists.txt65
-rw-r--r--src/plugins/Output/alsa/alsa.pro37
-rw-r--r--src/plugins/Output/alsa/outputalsa.cpp539
-rw-r--r--src/plugins/Output/alsa/outputalsa.h85
-rw-r--r--src/plugins/Output/alsa/outputalsafactory.cpp63
-rw-r--r--src/plugins/Output/alsa/outputalsafactory.h48
-rw-r--r--src/plugins/Output/alsa/settingsdialog.cpp237
-rw-r--r--src/plugins/Output/alsa/settingsdialog.h59
-rw-r--r--src/plugins/Output/alsa/settingsdialog.ui261
-rw-r--r--src/plugins/Output/alsa/translations/alsa_plugin_cs.ts90
-rw-r--r--src/plugins/Output/alsa/translations/alsa_plugin_ru.qmbin0 -> 1580 bytes
-rw-r--r--src/plugins/Output/alsa/translations/alsa_plugin_ru.ts89
-rw-r--r--src/plugins/Output/alsa/translations/translations.qrc6
-rw-r--r--src/plugins/Output/jack/CMakeLists.txt74
-rw-r--r--src/plugins/Output/jack/bio2jack.c2635
-rw-r--r--src/plugins/Output/jack/bio2jack.h145
-rw-r--r--src/plugins/Output/jack/jack.pro33
-rw-r--r--src/plugins/Output/jack/outputjack.cpp208
-rw-r--r--src/plugins/Output/jack/outputjack.h49
-rw-r--r--src/plugins/Output/jack/outputjackfactory.cpp60
-rw-r--r--src/plugins/Output/jack/outputjackfactory.h48
-rw-r--r--src/plugins/Output/jack/translations/jack_plugin_ru.qmbin0 -> 540 bytes
-rw-r--r--src/plugins/Output/jack/translations/jack_plugin_ru.ts26
-rw-r--r--src/plugins/Output/jack/translations/translations.qrc6
-rw-r--r--src/plugins/Output/oss/CMakeLists.txt67
-rw-r--r--src/plugins/Output/oss/oss.pro36
-rw-r--r--src/plugins/Output/oss/outputoss.cpp505
-rw-r--r--src/plugins/Output/oss/outputoss.h76
-rw-r--r--src/plugins/Output/oss/outputossfactory.cpp70
-rw-r--r--src/plugins/Output/oss/outputossfactory.h48
-rw-r--r--src/plugins/Output/oss/settingsdialog.cpp60
-rw-r--r--src/plugins/Output/oss/settingsdialog.h47
-rw-r--r--src/plugins/Output/oss/settingsdialog.ui309
-rw-r--r--src/plugins/Output/oss/translations/oss_plugin_cs.ts90
-rw-r--r--src/plugins/Visual/CMakeLists.txt8
-rw-r--r--src/plugins/Visual/Visual.pro3
-rw-r--r--src/plugins/Visual/analyzer/CMakeLists.txt70
-rw-r--r--src/plugins/Visual/analyzer/analyzer.cpp308
-rw-r--r--src/plugins/Visual/analyzer/analyzer.h102
-rw-r--r--src/plugins/Visual/analyzer/analyzer.pro35
-rw-r--r--src/plugins/Visual/analyzer/colorwidget.cpp56
-rw-r--r--src/plugins/Visual/analyzer/colorwidget.h50
-rw-r--r--src/plugins/Visual/analyzer/fft.c (renamed from src/fft.c)0
-rw-r--r--src/plugins/Visual/analyzer/fft.h (renamed from src/fft.h)0
-rw-r--r--src/plugins/Visual/analyzer/inlines.h (renamed from src/inlines.h)0
-rw-r--r--src/plugins/Visual/analyzer/settingsdialog.cpp62
-rw-r--r--src/plugins/Visual/analyzer/settingsdialog.h46
-rw-r--r--src/plugins/Visual/analyzer/settingsdialog.ui403
-rw-r--r--src/plugins/Visual/analyzer/visualanalyzerfactory.cpp57
-rw-r--r--src/plugins/Visual/analyzer/visualanalyzerfactory.h46
-rw-r--r--src/plugins/plugins.pri2
-rw-r--r--src/plugins/plugins.pro7
-rw-r--r--src/qmmp/CMakeLists.txt68
-rw-r--r--src/qmmp/buffer.h44
-rw-r--r--src/qmmp/constants.h19
-rw-r--r--src/qmmp/decoder.cpp409
-rw-r--r--src/qmmp/decoder.h197
-rw-r--r--src/qmmp/decoderfactory.h64
-rw-r--r--src/qmmp/downloader.cpp344
-rw-r--r--src/qmmp/downloader.h86
-rw-r--r--src/qmmp/effect.cpp148
-rw-r--r--src/qmmp/effect.h87
-rw-r--r--src/qmmp/effectfactory.h53
-rw-r--r--src/qmmp/equ/iir.c85
-rw-r--r--src/qmmp/equ/iir.h84
-rw-r--r--src/qmmp/equ/iir_cfs.c237
-rw-r--r--src/qmmp/equ/iir_cfs.h39
-rw-r--r--src/qmmp/equ/iir_fpu.c210
-rw-r--r--src/qmmp/equ/iir_fpu.h39
-rw-r--r--src/qmmp/filetag.cpp100
-rw-r--r--src/qmmp/filetag.h67
-rw-r--r--src/qmmp/output.cpp269
-rw-r--r--src/qmmp/output.h208
-rw-r--r--src/qmmp/outputfactory.h53
-rw-r--r--src/qmmp/qmmp.pro66
-rw-r--r--src/qmmp/recycler.cpp120
-rw-r--r--src/qmmp/recycler.h49
-rw-r--r--src/qmmp/soundcore.cpp440
-rw-r--r--src/qmmp/soundcore.h208
-rw-r--r--src/qmmp/streamreader.cpp139
-rw-r--r--src/qmmp/streamreader.h85
-rw-r--r--src/qmmp/visual.cpp151
-rw-r--r--src/qmmp/visual.h69
-rw-r--r--src/qmmp/visualfactory.h50
-rw-r--r--src/qmmpui/general.cpp157
-rw-r--r--src/qmmpui/general.h86
-rw-r--r--src/qmmpui/generalfactory.h52
-rw-r--r--src/qmmpui/generalhandler.cpp143
-rw-r--r--src/qmmpui/generalhandler.h69
-rw-r--r--src/qmmpui/qmmpui.pro38
-rw-r--r--src/qmmpui/songinfo.cpp137
-rw-r--r--src/qmmpui/songinfo.h76
-rw-r--r--src/ui/aboutdialog.cpp (renamed from src/aboutdialog.cpp)0
-rw-r--r--src/ui/aboutdialog.h (renamed from src/aboutdialog.h)0
-rw-r--r--src/ui/addurldialog.cpp (renamed from src/addurldialog.cpp)0
-rw-r--r--src/ui/addurldialog.h (renamed from src/addurldialog.h)0
-rw-r--r--src/ui/balancebar.cpp (renamed from src/balancebar.cpp)0
-rw-r--r--src/ui/balancebar.h (renamed from src/balancebar.h)0
-rw-r--r--src/ui/button.cpp (renamed from src/button.cpp)0
-rw-r--r--src/ui/button.h (renamed from src/button.h)0
-rw-r--r--src/ui/commandlineoption.cpp216
-rw-r--r--src/ui/commandlineoption.h94
-rw-r--r--src/ui/configdialog.cpp (renamed from src/configdialog.cpp)86
-rw-r--r--src/ui/configdialog.h (renamed from src/configdialog.h)2
-rw-r--r--src/ui/default/balance.png (renamed from src/default/balance.png)bin1464 -> 1464 bytes
-rw-r--r--src/ui/default/cbuttons.png (renamed from src/default/cbuttons.png)bin3148 -> 3148 bytes
-rw-r--r--src/ui/default/eq_ex.png (renamed from src/default/eq_ex.png)bin4423 -> 4423 bytes
-rw-r--r--src/ui/default/eqmain.png (renamed from src/default/eqmain.png)bin34985 -> 34985 bytes
-rw-r--r--src/ui/default/main.png (renamed from src/default/main.png)bin25055 -> 25055 bytes
-rw-r--r--src/ui/default/monoster.png (renamed from src/default/monoster.png)bin1060 -> 1060 bytes
-rw-r--r--src/ui/default/numbers.png (renamed from src/default/numbers.png)bin210 -> 210 bytes
-rw-r--r--src/ui/default/playpaus.png (renamed from src/default/playpaus.png)bin179 -> 179 bytes
-rw-r--r--src/ui/default/pledit.png (renamed from src/default/pledit.png)bin19730 -> 19730 bytes
-rw-r--r--src/ui/default/pledit.txt (renamed from src/default/pledit.txt)2
-rw-r--r--src/ui/default/posbar.png (renamed from src/default/posbar.png)bin3279 -> 3279 bytes
-rw-r--r--src/ui/default/shufrep.png (renamed from src/default/shufrep.png)bin2560 -> 2560 bytes
-rw-r--r--src/ui/default/text.png (renamed from src/default/text.png)bin525 -> 525 bytes
-rw-r--r--src/ui/default/titlebar.png (renamed from src/default/titlebar.png)bin11329 -> 11329 bytes
-rw-r--r--src/ui/default/viscolor.txt (renamed from src/default/viscolor.txt)2
-rw-r--r--src/ui/default/volume.png (renamed from src/default/volume.png)bin1727 -> 1727 bytes
-rw-r--r--src/ui/display.cpp (renamed from src/display.cpp)0
-rw-r--r--src/ui/display.h (renamed from src/display.h)0
-rw-r--r--src/ui/dock.cpp (renamed from src/dock.cpp)0
-rw-r--r--src/ui/dock.h (renamed from src/dock.h)0
-rw-r--r--src/ui/eqgraph.cpp (renamed from src/eqgraph.cpp)0
-rw-r--r--src/ui/eqgraph.h (renamed from src/eqgraph.h)0
-rw-r--r--src/ui/eqpreset.cpp (renamed from src/eqpreset.cpp)0
-rw-r--r--src/ui/eqpreset.h (renamed from src/eqpreset.h)0
-rw-r--r--src/ui/eqslider.cpp (renamed from src/eqslider.cpp)0
-rw-r--r--src/ui/eqslider.h (renamed from src/eqslider.h)0
-rw-r--r--src/ui/eqtitlebar.cpp (renamed from src/eqtitlebar.cpp)0
-rw-r--r--src/ui/eqtitlebar.h (renamed from src/eqtitlebar.h)0
-rw-r--r--src/ui/eqwidget.cpp (renamed from src/eqwidget.cpp)0
-rw-r--r--src/ui/eqwidget.h (renamed from src/eqwidget.h)0
-rw-r--r--src/ui/fft.c296
-rw-r--r--src/ui/fft.h45
-rw-r--r--src/ui/filedialog.cpp (renamed from src/filedialog.cpp)13
-rw-r--r--src/ui/filedialog.h (renamed from src/filedialog.h)4
-rw-r--r--src/ui/fileloader.cpp (renamed from src/fileloader.cpp)0
-rw-r--r--src/ui/fileloader.h (renamed from src/fileloader.h)0
-rw-r--r--src/ui/forms/aboutdialog.ui (renamed from src/aboutdialog.ui)0
-rw-r--r--src/ui/forms/addurldialog.ui (renamed from src/addurldialog.ui)0
-rw-r--r--src/ui/forms/configdialog.ui (renamed from src/configdialog.ui)228
-rw-r--r--src/ui/forms/jumptotrackdialog.ui (renamed from src/jumptotrackdialog.ui)0
-rw-r--r--src/ui/forms/preseteditor.ui (renamed from src/preseteditor.ui)0
-rw-r--r--src/ui/html/about_cs.html (renamed from src/html/about_cs.html)0
-rw-r--r--src/ui/html/about_en.html (renamed from src/html/about_en.html)0
-rw-r--r--src/ui/html/about_ru.html (renamed from src/html/about_ru.html)0
-rw-r--r--src/ui/html/about_zh_CN.html (renamed from src/html/about_zh_CN.html)0
-rw-r--r--src/ui/html/authors_cs.txt (renamed from src/html/authors_cs.txt)0
-rw-r--r--src/ui/html/authors_en.txt (renamed from src/html/authors_en.txt)0
-rw-r--r--src/ui/html/authors_ru.txt (renamed from src/html/authors_ru.txt)0
-rw-r--r--src/ui/html/authors_zh_CN.txt (renamed from src/html/authors_zh_CN.txt)0
-rw-r--r--src/ui/html/thanks_cs.txt (renamed from src/html/thanks_cs.txt)0
-rw-r--r--src/ui/html/thanks_en.txt (renamed from src/html/thanks_en.txt)0
-rw-r--r--src/ui/html/thanks_ru.txt (renamed from src/html/thanks_ru.txt)0
-rw-r--r--src/ui/html/thanks_zh_CN.txt (renamed from src/html/thanks_zh_CN.txt)0
-rw-r--r--src/ui/images/advanced.pngbin0 -> 1420 bytes
-rw-r--r--src/ui/images/images.qrc (renamed from src/images/images.qrc)4
-rw-r--r--src/ui/images/interface.pngbin0 -> 1439 bytes
-rw-r--r--src/ui/images/logo-qmmp.png (renamed from src/images/logo-qmmp.png)bin61213 -> 61213 bytes
-rw-r--r--src/ui/images/network.pngbin0 -> 1953 bytes
-rw-r--r--src/ui/images/playlist.pngbin0 -> 1085 bytes
-rw-r--r--src/ui/images/plugins.pngbin0 -> 2237 bytes
-rw-r--r--src/ui/images/qmmp.xpm (renamed from src/images/qmmp.xpm)0
-rw-r--r--src/ui/inlines.h505
-rw-r--r--src/ui/jumptotrackdialog.cpp (renamed from src/jumptotrackdialog.cpp)0
-rw-r--r--src/ui/jumptotrackdialog.h (renamed from src/jumptotrackdialog.h)0
-rw-r--r--src/ui/keyboardmanager.cpp (renamed from src/keyboardmanager.cpp)0
-rw-r--r--src/ui/keyboardmanager.h (renamed from src/keyboardmanager.h)0
-rw-r--r--src/ui/listwidget.cpp (renamed from src/listwidget.cpp)0
-rw-r--r--src/ui/listwidget.h (renamed from src/listwidget.h)0
-rw-r--r--src/ui/logscale.cpp (renamed from src/logscale.cpp)0
-rw-r--r--src/ui/logscale.h (renamed from src/logscale.h)0
-rw-r--r--src/ui/mainvisual.cpp (renamed from src/mainvisual.cpp)0
-rw-r--r--src/ui/mainvisual.h (renamed from src/mainvisual.h)0
-rw-r--r--src/ui/mainwindow.cpp (renamed from src/mainwindow.cpp)151
-rw-r--r--src/ui/mainwindow.h (renamed from src/mainwindow.h)35
-rw-r--r--src/ui/mediafile.cpp (renamed from src/mediafile.cpp)7
-rw-r--r--src/ui/mediafile.h (renamed from src/mediafile.h)1
-rw-r--r--src/ui/monostereo.cpp (renamed from src/monostereo.cpp)0
-rw-r--r--src/ui/monostereo.h (renamed from src/monostereo.h)0
-rw-r--r--src/ui/mp3player.cpp (renamed from src/mp3player.cpp)0
-rw-r--r--src/ui/number.cpp (renamed from src/number.cpp)0
-rw-r--r--src/ui/number.h (renamed from src/number.h)0
-rw-r--r--src/ui/pixmapwidget.cpp (renamed from src/pixmapwidget.cpp)0
-rw-r--r--src/ui/pixmapwidget.h (renamed from src/pixmapwidget.h)0
-rw-r--r--src/ui/playlist.cpp (renamed from src/playlist.cpp)0
-rw-r--r--src/ui/playlist.h (renamed from src/playlist.h)0
-rw-r--r--src/ui/playlistcontrol.cpp (renamed from src/playlistcontrol.cpp)0
-rw-r--r--src/ui/playlistcontrol.h (renamed from src/playlistcontrol.h)0
-rw-r--r--src/ui/playlistformat.cpp (renamed from src/playlistformat.cpp)2
-rw-r--r--src/ui/playlistformat.h (renamed from src/playlistformat.h)4
-rw-r--r--src/ui/playlistmodel.cpp (renamed from src/playlistmodel.cpp)0
-rw-r--r--src/ui/playlistmodel.h (renamed from src/playlistmodel.h)0
-rw-r--r--src/ui/playlistslider.cpp (renamed from src/playlistslider.cpp)0
-rw-r--r--src/ui/playlistslider.h (renamed from src/playlistslider.h)0
-rw-r--r--src/ui/playlisttitlebar.cpp (renamed from src/playlisttitlebar.cpp)0
-rw-r--r--src/ui/playlisttitlebar.h (renamed from src/playlisttitlebar.h)0
-rw-r--r--src/ui/playstate.cpp (renamed from src/playstate.cpp)0
-rw-r--r--src/ui/playstate.h (renamed from src/playstate.h)0
-rw-r--r--src/ui/playstatus.cpp (renamed from src/playstatus.cpp)0
-rw-r--r--src/ui/playstatus.h (renamed from src/playstatus.h)0
-rw-r--r--src/ui/pluginitem.cpp (renamed from src/pluginitem.cpp)30
-rw-r--r--src/ui/pluginitem.h (renamed from src/pluginitem.h)20
-rw-r--r--src/ui/positionbar.cpp (renamed from src/positionbar.cpp)0
-rw-r--r--src/ui/positionbar.h (renamed from src/positionbar.h)0
-rw-r--r--src/ui/preseteditor.cpp (renamed from src/preseteditor.cpp)0
-rw-r--r--src/ui/preseteditor.h (renamed from src/preseteditor.h)0
-rw-r--r--src/ui/qmmpstarter.cpp (renamed from src/qmmpstarter.cpp)28
-rw-r--r--src/ui/qmmpstarter.h (renamed from src/qmmpstarter.h)3
-rw-r--r--src/ui/shadedbar.cpp (renamed from src/shadedbar.cpp)0
-rw-r--r--src/ui/shadedbar.h (renamed from src/shadedbar.h)0
-rw-r--r--src/ui/shadedvisual.cpp (renamed from src/shadedvisual.cpp)0
-rw-r--r--src/ui/shadedvisual.h (renamed from src/shadedvisual.h)0
-rw-r--r--src/ui/skin.cpp (renamed from src/skin.cpp)2
-rw-r--r--src/ui/skin.h (renamed from src/skin.h)0
-rw-r--r--src/ui/skinreader.cpp (renamed from src/skinreader.cpp)6
-rw-r--r--src/ui/skinreader.h (renamed from src/skinreader.h)2
-rw-r--r--src/ui/stuff.qrc (renamed from src/stuff.qrc)2
-rw-r--r--src/ui/symboldisplay.cpp (renamed from src/symboldisplay.cpp)0
-rw-r--r--src/ui/symboldisplay.h (renamed from src/symboldisplay.h)0
-rw-r--r--src/ui/textscroller.cpp (renamed from src/textscroller.cpp)0
-rw-r--r--src/ui/textscroller.h (renamed from src/textscroller.h)0
-rw-r--r--src/ui/timeindicator.cpp (renamed from src/timeindicator.cpp)0
-rw-r--r--src/ui/timeindicator.h (renamed from src/timeindicator.h)0
-rw-r--r--src/ui/titlebar.cpp (renamed from src/titlebar.cpp)0
-rw-r--r--src/ui/titlebar.h (renamed from src/titlebar.h)0
-rw-r--r--src/ui/titlebarcontrol.cpp (renamed from src/titlebarcontrol.cpp)0
-rw-r--r--src/ui/titlebarcontrol.h (renamed from src/titlebarcontrol.h)0
-rw-r--r--src/ui/togglebutton.cpp (renamed from src/togglebutton.cpp)0
-rw-r--r--src/ui/togglebutton.h (renamed from src/togglebutton.h)0
-rw-r--r--src/ui/translations/qmmp_cs.ts (renamed from src/translations/qmmp_cs.ts)0
-rw-r--r--src/ui/translations/qmmp_locales.qrc (renamed from src/translations/qmmp_locales.qrc)0
-rw-r--r--src/ui/translations/qmmp_ru.qm (renamed from src/translations/qmmp_ru.qm)bin8812 -> 8812 bytes
-rw-r--r--src/ui/translations/qmmp_ru.ts (renamed from src/translations/qmmp_ru.ts)0
-rw-r--r--src/ui/translations/qmmp_tr.qm (renamed from src/translations/qmmp_tr.qm)bin8960 -> 8960 bytes
-rw-r--r--src/ui/translations/qmmp_tr.ts (renamed from src/translations/qmmp_tr.ts)0
-rw-r--r--src/ui/translations/qmmp_zh_CN.qm (renamed from src/translations/qmmp_zh_CN.qm)bin7081 -> 7081 bytes
-rw-r--r--src/ui/translations/qmmp_zh_CN.ts (renamed from src/translations/qmmp_zh_CN.ts)0
-rw-r--r--src/ui/ui.pro (renamed from src/src.pro)101
-rw-r--r--src/ui/unixdomainsocket.cpp (renamed from src/unixdomainsocket.cpp)8
-rw-r--r--src/ui/unixdomainsocket.h (renamed from src/unixdomainsocket.h)2
-rw-r--r--src/ui/version.h (renamed from src/version.h)0
-rw-r--r--src/ui/visualmenu.cpp (renamed from src/visualmenu.cpp)0
-rw-r--r--src/ui/visualmenu.h (renamed from src/visualmenu.h)0
-rw-r--r--src/ui/volumebar.cpp (renamed from src/volumebar.cpp)0
-rw-r--r--src/ui/volumebar.h (renamed from src/volumebar.h)0
407 files changed, 28082 insertions, 401 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e0ec01195..be0d02e78 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -79,6 +79,7 @@ SET(libsrc_SRCS
shadedvisual.cpp
titlebarcontrol.cpp
shadedbar.cpp
+ commandlineoption.cpp
)
SET(libsrc_MOC_HDRS
@@ -134,6 +135,7 @@ SET(libsrc_MOC_HDRS
shadedvisual.h
titlebarcontrol.h
shadedbar.h
+ commandlineoption.h
)
SET(libsrc_RCCS images/images.qrc stuff.qrc translations/qmmp_locales.qrc)
diff --git a/src/images/advanced.png b/src/images/advanced.png
deleted file mode 100644
index beb0071b4..000000000
--- a/src/images/advanced.png
+++ /dev/null
Binary files differ
diff --git a/src/images/interface.png b/src/images/interface.png
deleted file mode 100644
index 0277801c1..000000000
--- a/src/images/interface.png
+++ /dev/null
Binary files differ
diff --git a/src/images/pause.png b/src/images/pause.png
deleted file mode 100644
index 096371d82..000000000
--- a/src/images/pause.png
+++ /dev/null
Binary files differ
diff --git a/src/images/play.png b/src/images/play.png
deleted file mode 100644
index 5a4aee976..000000000
--- a/src/images/play.png
+++ /dev/null
Binary files differ
diff --git a/src/images/playlist.png b/src/images/playlist.png
deleted file mode 100644
index 0cff0ddcb..000000000
--- a/src/images/playlist.png
+++ /dev/null
Binary files differ
diff --git a/src/images/plugins.png b/src/images/plugins.png
deleted file mode 100644
index b08dcac3f..000000000
--- a/src/images/plugins.png
+++ /dev/null
Binary files differ
diff --git a/src/images/stop.png b/src/images/stop.png
deleted file mode 100644
index 637137f59..000000000
--- a/src/images/stop.png
+++ /dev/null
Binary files differ
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt
new file mode 100644
index 000000000..42382b5cd
--- /dev/null
+++ b/src/plugins/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_subdirectory(Input)
+add_subdirectory(Output)
+add_subdirectory(Visual)
+add_subdirectory(Effect) \ No newline at end of file
diff --git a/src/plugins/Effect/CMakeLists.txt b/src/plugins/Effect/CMakeLists.txt
new file mode 100644
index 000000000..a777010b9
--- /dev/null
+++ b/src/plugins/Effect/CMakeLists.txt
@@ -0,0 +1,8 @@
+SET(USE_SRC TRUE CACHE BOOL "enable/disable SRC plugin")
+
+IF(USE_SRC)
+MESSAGE( STATUS "SRC ON")
+add_subdirectory(srconverter)
+ELSE(USE_SRC)
+MESSAGE( STATUS "SRC OFF")
+ENDIF(USE_SRC)
diff --git a/src/plugins/Effect/Effect.pro b/src/plugins/Effect/Effect.pro
new file mode 100644
index 000000000..b03c8a598
--- /dev/null
+++ b/src/plugins/Effect/Effect.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+
+SUBDIRS += srconverter
+
diff --git a/src/plugins/Effect/srconverter/CMakeLists.txt b/src/plugins/Effect/srconverter/CMakeLists.txt
new file mode 100644
index 000000000..ef95abf79
--- /dev/null
+++ b/src/plugins/Effect/srconverter/CMakeLists.txt
@@ -0,0 +1,76 @@
+project(libsrconverter)
+
+cmake_minimum_required(VERSION 2.4.0)
+
+
+INCLUDE(UsePkgConfig)
+INCLUDE(FindQt4)
+
+find_package(Qt4 REQUIRED) # find and setup Qt4 for this project
+include(${QT_USE_FILE})
+
+# qt plugin
+ADD_DEFINITIONS( -Wall )
+ADD_DEFINITIONS(${QT_DEFINITIONS})
+ADD_DEFINITIONS(-DQT_PLUGIN)
+ADD_DEFINITIONS(-DQT_NO_DEBUG)
+ADD_DEFINITIONS(-DQT_SHARED)
+ADD_DEFINITIONS(-DQT_THREAD)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+SET(QT_INCLUDES
+ ${QT_INCLUDES}
+ ${CMAKE_CURRENT_BINARY_DIR}/../../../
+)
+
+# libqmmp
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+link_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+
+PKGCONFIG(samplerate SAMPLERATE_INCLUDE_DIR SAMPLERATE_LINK_DIR SAMPLERATE_LINK_FLAGS SAMPLERATE_CFLAGS)
+
+IF(NOT SAMPLERATE_LINK_FLAGS)
+ SET(SAMPLERATE_LINK_FLAGS -lsamplerate)
+ENDIF(NOT SAMPLERATE_LINK_FLAGS)
+
+include_directories(${SAMPLERATE_INCLUDE_DIR})
+link_directories(${SAMPLERATE_LINK_DIR})
+
+ADD_DEFINITIONS(${SAMPLERATE_CFLAGS})
+
+SET(libsrconverter_SRCS
+ srconverter.cpp
+ settingsdialog.cpp
+ effectsrconverterfactory.cpp
+)
+
+SET(libsrconverter_MOC_HDRS
+ srconverter.h
+ settingsdialog.h
+ effectsrconverterfactory.h
+)
+
+#SET(libsrconverter_RCCS translations/translations.qrc)
+
+#QT4_ADD_RESOURCES(libsrconverter_RCC_SRCS ${libsrconverter_RCCS})
+
+QT4_WRAP_CPP(libsrconverter_MOC_SRCS ${libsrconverter_MOC_HDRS})
+
+# user interface
+
+
+SET(libsrconverter_UIS
+ settingsdialog.ui
+)
+
+QT4_WRAP_UI(libsrconverter_UIS_H ${libsrconverter_UIS})
+# Don't forget to include output directory, otherwise
+# the UI file won't be wrapped!
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+ADD_LIBRARY(srconverter SHARED ${libsrconverter_SRCS} ${libsrconverter_MOC_SRCS} ${libsrconverter_UIS_H}
+ ${libsrconverter_RCC_SRCS})
+target_link_libraries(srconverter ${QT_LIBRARIES} -lqmmp ${SAMPLERATE_LINK_FLAGS})
+install(TARGETS srconverter DESTINATION ${LIB_DIR}/qmmp/Effect)
+
diff --git a/src/plugins/Effect/srconverter/effectsrconverterfactory.cpp b/src/plugins/Effect/srconverter/effectsrconverterfactory.cpp
new file mode 100644
index 000000000..bd4f93c1b
--- /dev/null
+++ b/src/plugins/Effect/srconverter/effectsrconverterfactory.cpp
@@ -0,0 +1,57 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QtGui>
+
+#include "settingsdialog.h"
+#include "effectsrconverterfactory.h"
+#include "srconverter.h"
+
+const EffectProperties EffectSRConverterFactory::properties() const
+{
+ EffectProperties properties;
+ properties.name = tr("SRC Plugin");
+ return properties;
+};
+
+Effect *EffectSRConverterFactory::create(QObject *parent)
+{
+ return new SRConverter(parent);
+};
+
+void EffectSRConverterFactory::showSettings(QWidget *parent)
+{
+ SettingsDialog *s = new SettingsDialog(parent);
+ s ->show();
+};
+
+void EffectSRConverterFactory::showAbout(QWidget *parent)
+{
+ QMessageBox::about (parent, tr("About Sample Rate Converter Plugin"),
+ tr("Qmmp Sample Rate Converter Plugin")+"\n"+
+ tr("Writen by: Ilya Kotov <forkotov02@hotmail.ru>"));
+};
+
+QTranslator *EffectSRConverterFactory::createTranslator(QObject *parent)
+{
+ return 0;
+};
+
+Q_EXPORT_PLUGIN(EffectSRConverterFactory)
diff --git a/src/plugins/Effect/srconverter/effectsrconverterfactory.h b/src/plugins/Effect/srconverter/effectsrconverterfactory.h
new file mode 100644
index 000000000..4112a3af5
--- /dev/null
+++ b/src/plugins/Effect/srconverter/effectsrconverterfactory.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef EFFECTSRCONVERTERFACTORY_H
+#define EFFECTSRCONVERTERFACTORY_H
+
+
+#include <QObject>
+
+#include <effectfactory.h>
+#include <effect.h>
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class EffectSRConverterFactory : public QObject, public EffectFactory
+{
+Q_OBJECT
+Q_INTERFACES(EffectFactory);
+
+public:
+ const EffectProperties properties() const;
+ Effect *create(QObject *parent);
+ void showSettings(QWidget *parent);
+ void showAbout(QWidget *parent);
+ QTranslator *createTranslator(QObject *parent);
+};
+
+
+#endif
diff --git a/src/plugins/Effect/srconverter/settingsdialog.cpp b/src/plugins/Effect/srconverter/settingsdialog.cpp
new file mode 100644
index 000000000..d4e017bba
--- /dev/null
+++ b/src/plugins/Effect/srconverter/settingsdialog.cpp
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QSettings>
+#include <QDir>
+
+#include "settingsdialog.h"
+
+SettingsDialog::SettingsDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ ui.setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose, TRUE);
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ ui.srSpinBox->setValue(settings.value("SRC/sample_rate",48000).toInt());
+ ui.engineComboBox->setCurrentIndex(settings.value("SRC/engine", 0).toInt());
+ connect (ui.okButton, SIGNAL(clicked()),SLOT(writeSettings()));
+}
+
+
+SettingsDialog::~SettingsDialog()
+{
+}
+
+void SettingsDialog::writeSettings()
+{
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.setValue("SRC/sample_rate",ui.srSpinBox->value());
+ settings.setValue("SRC/engine", ui.engineComboBox->currentIndex());
+ accept();
+}
diff --git a/src/plugins/Effect/srconverter/settingsdialog.h b/src/plugins/Effect/srconverter/settingsdialog.h
new file mode 100644
index 000000000..b7c466477
--- /dev/null
+++ b/src/plugins/Effect/srconverter/settingsdialog.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef SETTINGSDIALOG_H
+#define SETTINGSDIALOG_H
+
+#include <QDialog>
+
+#include "ui_settingsdialog.h"
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class SettingsDialog : public QDialog
+{
+Q_OBJECT
+public:
+ SettingsDialog(QWidget *parent = 0);
+
+ ~SettingsDialog();
+
+private slots:
+ void writeSettings();
+
+private:
+ Ui::SettingsDialog ui;
+
+};
+
+#endif
diff --git a/src/plugins/Effect/srconverter/settingsdialog.ui b/src/plugins/Effect/srconverter/settingsdialog.ui
new file mode 100644
index 000000000..e837c9cf0
--- /dev/null
+++ b/src/plugins/Effect/srconverter/settingsdialog.ui
@@ -0,0 +1,124 @@
+<ui version="4.0" >
+ <class>SettingsDialog</class>
+ <widget class="QDialog" name="SettingsDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>357</width>
+ <height>107</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Sample Rate Converter Plugin Settings</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Sample Rate (Hz):</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QSpinBox" name="srSpinBox" >
+ <property name="maximum" >
+ <number>96000</number>
+ </property>
+ <property name="singleStep" >
+ <number>100</number>
+ </property>
+ <property name="value" >
+ <number>48000</number>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Interpolation Engine:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QComboBox" name="engineComboBox" >
+ <item>
+ <property name="text" >
+ <string>Best Sinc Interpolation</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Medium Sinc Interpolation</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Fastest Sinc Interpolation</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>ZOH Interpolation</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Linear Interpolation</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QPushButton" name="okButton" >
+ <property name="text" >
+ <string>&amp;OK</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelButton" >
+ <property name="text" >
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>cancelButton</sender>
+ <signal>clicked()</signal>
+ <receiver>SettingsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>302</x>
+ <y>88</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>42</x>
+ <y>69</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/Effect/srconverter/srconverter.cpp b/src/plugins/Effect/srconverter/srconverter.cpp
new file mode 100644
index 000000000..0e733c8c4
--- /dev/null
+++ b/src/plugins/Effect/srconverter/srconverter.cpp
@@ -0,0 +1,125 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QSettings>
+#include <QDir>
+#include <math.h>
+
+#include "srconverter.h"
+
+SRConverter::SRConverter(QObject* parent) : Effect(parent)
+{
+ m_isSrcAlloc = FALSE;
+ int converter_type_array[] = {SRC_SINC_BEST_QUALITY, SRC_SINC_MEDIUM_QUALITY, SRC_SINC_FASTEST,
+ SRC_ZERO_ORDER_HOLD, SRC_LINEAR};
+ m_srcIn = 0;
+ m_srcOut = 0;
+ m_src_state = 0;
+ m_srcError = 0;
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ m_overSamplingFs = settings.value("SRC/sample_rate",48000).toInt();
+ m_converter_type = converter_type_array[settings.value("SRC/engine", 0).toInt()];
+}
+
+SRConverter::~SRConverter()
+{
+ src_reset (m_src_state) ;
+ freeSRC();
+ m_src_data.data_in = 0;
+ m_src_data.data_out = 0;
+ m_src_data.end_of_input = 0;
+ m_src_data.input_frames = 0;
+ m_src_data.output_frames = 0;
+ if (m_isSrcAlloc)
+ {
+ free(m_srcIn);
+ free(m_srcOut);
+ free(m_wOut);
+ m_isSrcAlloc = FALSE;
+ }
+}
+
+const ulong SRConverter::process(char *in_data, const ulong size, char **out_data)
+{
+ if (m_isSrcAlloc)
+ {
+ free(m_srcIn);
+ free(m_srcOut);
+ free(m_wOut);
+ m_isSrcAlloc = FALSE;
+ }
+ ulong wbytes = 0;
+
+ if (m_src_state && size > 0)
+ {
+ int lrLength = size/2;
+ int overLrLength= (int)floor(lrLength*(m_src_data.src_ratio+1));
+ m_srcIn = (float*) malloc(sizeof(float)*lrLength);
+ m_srcOut = (float*) malloc(sizeof(float)*overLrLength);
+ m_wOut = (short int*) malloc(sizeof(short int)*overLrLength);
+ src_short_to_float_array((short int*)in_data, m_srcIn, lrLength);
+ m_isSrcAlloc = TRUE;
+ m_src_data.data_in = m_srcIn;
+ m_src_data.data_out = m_srcOut;
+ m_src_data.end_of_input = 0;
+ m_src_data.input_frames = lrLength/2;
+ m_src_data.output_frames = overLrLength/2;
+ if ((m_srcError = src_process(m_src_state, &m_src_data)) > 0)
+ {
+ qWarning("SRConverter: src_process(): %s\n", src_strerror(m_srcError));
+ }
+ else
+ {
+ src_float_to_short_array(m_srcOut, m_wOut, m_src_data.output_frames_gen*2);
+ wbytes = m_src_data.output_frames_gen*4;
+ *out_data = new char[wbytes];
+ memcpy(*out_data, (char*) m_wOut, wbytes);
+ }
+ }
+ return wbytes;
+}
+
+void SRConverter::configure(ulong freq, int chan, int res)
+{
+ Effect::configure(freq, chan, res);
+ freeSRC();
+ uint rate = freq;
+ {
+ m_src_state = src_new(m_converter_type, 2, &m_srcError);
+ if (m_src_state)
+ {
+ m_src_data.src_ratio = (float)m_overSamplingFs/(float)rate;
+ rate = m_overSamplingFs;
+ }
+ else
+ qDebug("SRConverter: src_new(): %s", src_strerror(m_srcError));
+ }
+}
+
+const ulong SRConverter::frequency()
+{
+ return m_overSamplingFs;
+}
+
+void SRConverter::freeSRC()
+{
+ if (m_src_state != NULL)
+ m_src_state = src_delete(m_src_state);
+}
diff --git a/src/plugins/Effect/srconverter/srconverter.h b/src/plugins/Effect/srconverter/srconverter.h
new file mode 100644
index 000000000..8c6dcb6d3
--- /dev/null
+++ b/src/plugins/Effect/srconverter/srconverter.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef SRCONVERTER_H
+#define SRCONVERTER_H
+
+#include <effect.h>
+
+extern "C"
+{
+#include <samplerate.h>
+}
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+
+class SRConverter : public Effect
+{
+ Q_OBJECT
+public:
+ SRConverter(QObject *parent = 0);
+
+ virtual ~SRConverter();
+
+ const ulong process(char *in_data, const ulong size, char **out_data);
+ void configure(ulong freq, int chan, int res);
+ const ulong frequency();
+
+private:
+ void freeSRC();
+ SRC_STATE *m_src_state;
+ SRC_DATA m_src_data;
+ int m_overSamplingFs;
+ int m_srcError;
+ int m_converter_type;
+ bool m_isSrcAlloc;
+ float *m_srcIn, *m_srcOut;
+ short *m_wOut;
+ ulong m_freq;
+};
+
+#endif
diff --git a/src/plugins/Effect/srconverter/srconverter.pro b/src/plugins/Effect/srconverter/srconverter.pro
new file mode 100644
index 000000000..af20c1e92
--- /dev/null
+++ b/src/plugins/Effect/srconverter/srconverter.pro
@@ -0,0 +1,34 @@
+include(../../plugins.pri)
+
+HEADERS += srconverter.h \
+ effectsrconverterfactory.h \
+ settingsdialog.h
+
+SOURCES += srconverter.cpp \
+ effectsrconverterfactory.cpp \
+ settingsdialog.cpp
+
+TARGET=$$PLUGINS_PREFIX/Effect/srconverter
+QMAKE_CLEAN =$$PLUGINS_PREFIX/Effect/libsrconverter.so
+INCLUDEPATH += ../../../qmmp
+CONFIG += release \
+warn_on \
+plugin \
+link_pkgconfig
+
+PKGCONFIG += samplerate
+TEMPLATE = lib
+QMAKE_LIBDIR += ../../../../lib
+LIBS += -lqmmp -L/usr/lib -I/usr/include
+
+#TRANSLATIONS = translations/ffmpeg_plugin_ru.ts
+#RESOURCES = translations/translations.qrc
+
+isEmpty(LIB_DIR){
+ LIB_DIR = /lib
+}
+target.path = $$LIB_DIR/qmmp/Effect
+INSTALLS += target
+
+FORMS += settingsdialog.ui
+
diff --git a/src/plugins/General/General.pro b/src/plugins/General/General.pro
new file mode 100644
index 000000000..11f567452
--- /dev/null
+++ b/src/plugins/General/General.pro
@@ -0,0 +1,4 @@
+SUBDIRS += statusicon \
+ scrobbler \
+ dbuscontrol
+TEMPLATE = subdirs
diff --git a/src/plugins/General/dbuscontrol/dbusadaptor.cpp b/src/plugins/General/dbuscontrol/dbusadaptor.cpp
new file mode 100644
index 000000000..77ace9208
--- /dev/null
+++ b/src/plugins/General/dbuscontrol/dbusadaptor.cpp
@@ -0,0 +1,62 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include "dbusadaptor.h"
+
+DBUSAdaptor::DBUSAdaptor(QObject *parent)
+ : QDBusAbstractAdaptor(parent)
+{
+ setAutoRelaySignals(TRUE);
+}
+
+DBUSAdaptor::~DBUSAdaptor()
+{
+}
+
+void DBUSAdaptor::play()
+{
+ QMetaObject::invokeMethod(parent(), "play");
+}
+
+void DBUSAdaptor::stop()
+{
+ QMetaObject::invokeMethod(parent(), "stop");
+}
+
+void DBUSAdaptor::next()
+{
+ QMetaObject::invokeMethod(parent(), "next");
+}
+
+void DBUSAdaptor::previous()
+{
+ QMetaObject::invokeMethod(parent(), "previous");
+}
+
+void DBUSAdaptor::pause()
+{
+ QMetaObject::invokeMethod(parent(), "pause");
+}
+
+void DBUSAdaptor::exit()
+{
+ QMetaObject::invokeMethod(parent(), "exit");
+}
+
+
diff --git a/src/plugins/General/dbuscontrol/dbusadaptor.h b/src/plugins/General/dbuscontrol/dbusadaptor.h
new file mode 100644
index 000000000..43294e753
--- /dev/null
+++ b/src/plugins/General/dbuscontrol/dbusadaptor.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef DBUSADAPTOR_H
+#define DBUSADAPTOR_H
+
+#include <QtDBus>
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class DBUSAdaptor : public QDBusAbstractAdaptor
+{
+Q_OBJECT
+Q_CLASSINFO("D-Bus Interface", "org.qmmp.dbus")
+public:
+ DBUSAdaptor(QObject *parent = 0);
+
+ ~DBUSAdaptor();
+
+public slots:
+ void play();
+ void stop();
+ void next();
+ void previous();
+ void pause();
+ void exit();
+
+};
+
+#endif
diff --git a/src/plugins/General/dbuscontrol/dbuscontrol.cpp b/src/plugins/General/dbuscontrol/dbuscontrol.cpp
new file mode 100644
index 000000000..1133cec7a
--- /dev/null
+++ b/src/plugins/General/dbuscontrol/dbuscontrol.cpp
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include "dbusadaptor.h"
+#include "dbuscontrol.h"
+
+DBUSControl::DBUSControl(QObject *parent)
+ : General(parent)
+{
+ new DBUSAdaptor(this);
+ QDBusConnection connection = QDBusConnection::sessionBus();
+ connection.registerObject("/Qmmp", this);
+ connection.registerService("org.qmmp.dbus");
+}
+
+
+DBUSControl::~DBUSControl()
+{}
+
+void DBUSControl::setState(const uint &state)
+{
+ switch ((uint) state)
+ {
+ case General::Playing:
+ {
+ //m_tray->setIcon(QIcon(":/tray_play.png"));
+ break;
+ }
+ case General::Paused:
+ {
+ //m_tray->setIcon(QIcon(":/tray_pause.png"));
+ break;
+ }
+ case General::Stopped:
+ {
+ //m_tray->setIcon(QIcon(":/tray_stop.png"));
+ break;
+ }
+ }
+}
+
+void DBUSControl::setSongInfo(const SongInfo &song)
+{
+}
diff --git a/src/plugins/General/dbuscontrol/dbuscontrol.h b/src/plugins/General/dbuscontrol/dbuscontrol.h
new file mode 100644
index 000000000..2d5f3c91a
--- /dev/null
+++ b/src/plugins/General/dbuscontrol/dbuscontrol.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef STATUSICON_H
+#define STATUSICON_H
+
+
+#include <qmmpui/general.h>
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+
+class DBUSControl : public General
+{
+Q_OBJECT
+public:
+ DBUSControl(QObject *parent = 0);
+
+ ~DBUSControl();
+
+ void setState(const uint& state);
+ void setSongInfo(const SongInfo &song);
+
+};
+
+#endif
diff --git a/src/plugins/General/dbuscontrol/dbuscontrol.pro b/src/plugins/General/dbuscontrol/dbuscontrol.pro
new file mode 100644
index 000000000..4ad8e047b
--- /dev/null
+++ b/src/plugins/General/dbuscontrol/dbuscontrol.pro
@@ -0,0 +1,39 @@
+include(../../plugins.pri)
+
+CONFIG += release \
+warn_on \
+plugin \
+ lib \
+ qdbus
+
+TARGET=$$PLUGINS_PREFIX/General/dbuscontrol
+QMAKE_CLEAN =$$PLUGINS_PREFIX/General/libdbuscontrol.so
+
+TEMPLATE = lib
+QMAKE_LIBDIR += ../../../../lib
+
+#TRANSLATIONS = translations/ffmpeg_plugin_ru.ts
+#RESOURCES = translations/translations.qrc
+
+isEmpty(LIB_DIR){
+ LIB_DIR = /lib
+}
+target.path = $$LIB_DIR/qmmp/General
+INSTALLS += target
+#FORMS += settingsdialog.ui
+
+#RESOURCES += images/images.qrc
+
+
+HEADERS += dbuscontrolfactory.h \
+ dbuscontrol.h \
+ dbusadaptor.h
+
+SOURCES += dbuscontrolfactory.cpp \
+ dbuscontrol.cpp \
+ dbusadaptor.cpp
+
+INCLUDEPATH += ../../../../src
+
+LIBS += -lqmmpui
+
diff --git a/src/plugins/General/dbuscontrol/dbuscontrolfactory.cpp b/src/plugins/General/dbuscontrol/dbuscontrolfactory.cpp
new file mode 100644
index 000000000..922962c67
--- /dev/null
+++ b/src/plugins/General/dbuscontrol/dbuscontrolfactory.cpp
@@ -0,0 +1,55 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QtGui>
+
+#include "dbuscontrol.h"
+#include "dbuscontrolfactory.h"
+
+const GeneralProperties DBUSControlFactory::properties() const
+{
+ GeneralProperties properties;
+ properties.name = tr("D-Bus Plugin");
+ properties.hasAbout = TRUE;
+ properties.hasSettings = FALSE;
+ return properties;
+}
+
+General *DBUSControlFactory::create(QObject *parent)
+{
+ return new DBUSControl(parent);
+}
+
+void DBUSControlFactory::showSettings(QWidget *)
+{}
+
+void DBUSControlFactory::showAbout(QWidget *parent)
+{
+ QMessageBox::about (parent, tr("About D-Bus Plugin"),
+ tr("Qmmp D-Bus Plugin")+"\n"+
+ tr("Writen by: Ilya Kotov <forkotov02@hotmail.ru>"));
+}
+
+QTranslator *DBUSControlFactory::createTranslator(QObject *parent)
+{
+ return 0;
+}
+
+Q_EXPORT_PLUGIN(DBUSControlFactory)
diff --git a/src/plugins/General/dbuscontrol/dbuscontrolfactory.h b/src/plugins/General/dbuscontrol/dbuscontrolfactory.h
new file mode 100644
index 000000000..98121edec
--- /dev/null
+++ b/src/plugins/General/dbuscontrol/dbuscontrolfactory.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef STATUSICONFACTORY_H
+#define STATUSICONFACTORY_H
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+#include <QObject>
+#include <QTranslator>
+
+#include <qmmpui/general.h>
+#include <qmmpui/generalfactory.h>
+
+class DBUSControlFactory : public QObject, public GeneralFactory
+{
+Q_OBJECT
+Q_INTERFACES(GeneralFactory);
+public:
+ const GeneralProperties properties() const;
+ General *create(QObject *parent);
+ void showSettings(QWidget *parent);
+ void showAbout(QWidget *parent);
+ QTranslator *createTranslator(QObject *parent);
+
+};
+
+#endif
diff --git a/src/plugins/General/scrobbler/scrobbler.cpp b/src/plugins/General/scrobbler/scrobbler.cpp
new file mode 100644
index 000000000..7713161b7
--- /dev/null
+++ b/src/plugins/General/scrobbler/scrobbler.cpp
@@ -0,0 +1,259 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QMenu>
+#include <QHttp>
+#include <QByteArray>
+#include <QCryptographicHash>
+#include <QUrl>
+#include <QTime>
+#include <QSettings>
+#include <QDir>
+
+#include "scrobbler.h"
+
+#define SCROBBLER_HS_URL "post.audioscrobbler.com"
+#define PROTOCOL_VER "1.2"
+#define CLIENT_ID "qmm"
+#define CLIENT_VER "0.1"
+
+Scrobbler::Scrobbler(QObject *parent)
+ : General(parent)
+{
+ m_http = new QHttp(this);
+ m_http->setHost(SCROBBLER_HS_URL, 80);
+ m_state = General::Stopped;
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.beginGroup("Scrobbler");
+ m_login = settings.value("login").toString();
+ m_passw = settings.value("password").toString();
+ settings.endGroup();
+ m_disabled = m_login.isEmpty() || m_passw.isEmpty();
+ m_passw = QString(QCryptographicHash::hash(m_passw.toAscii(), QCryptographicHash::Md5).toHex());
+ connect(m_http, SIGNAL(requestFinished (int, bool)), SLOT(processResponse(int, bool)));
+ connect(m_http, SIGNAL(readyRead (const QHttpResponseHeader&)),
+ SLOT(readResponse(const QHttpResponseHeader&)));
+ m_time = new QTime();
+ m_submitedSongs = 0;
+ m_handshakeid = 0;
+ m_submitid = 0;
+ if (!m_disabled)
+ handshake();
+ //TODO proxy support
+}
+
+
+Scrobbler::~Scrobbler()
+{
+ delete m_time;
+}
+
+void Scrobbler::setState(const uint &state)
+{
+ m_state = state;
+ if (m_disabled)
+ return;
+ switch ((uint) state)
+ {
+ case General::Playing:
+ {
+ m_start_ts = time(NULL);
+ m_time->restart();
+ if (!isReady() && m_handshakeid == 0)
+ handshake();
+ break;
+ }
+ case General::Paused:
+ {
+ break;
+ }
+ case General::Stopped:
+ {
+ if (!m_song.isEmpty()
+ && ((m_time->elapsed ()/1000 > 240)
+ || (m_time->elapsed ()/1000 > int(m_song.length()/2)))
+ && (m_time->elapsed ()/1000 > 60))
+ {
+ m_songCache << m_song;
+ m_timeStamps << m_start_ts;
+ }
+
+ m_song.clear();
+ if (m_songCache.isEmpty())
+ break;
+
+ if (m_http->error() != QHttp::NoError)
+ m_http->clearPendingRequests ();
+
+ if (isReady() && m_submitid == 0)
+ {
+ submit();
+ }
+ break;
+ }
+ }
+}
+
+void Scrobbler::setSongInfo(const SongInfo &song)
+{
+ if (m_state == General::Playing
+ && !song.title().isEmpty() //skip empty tags
+ && !song.artist().isEmpty()
+ && !song.isStream() //skip stream
+ && !song.artist().contains("&") //skip tags with special symbols
+ && !song.title().contains("&")
+ && !song.album().contains("&")
+ && !song.artist().contains("=")
+ && !song.title().contains("=")
+ && !song.album().contains("="))
+ {
+ m_song = song;
+ }
+}
+
+void Scrobbler::processResponse(int id, bool error)
+{
+ if (error)
+ {
+ qWarning("Scrobbler: %s", qPrintable(m_http->errorString ()));
+ //TODO hard failure handling
+
+ if (id == m_submitid)
+ m_submitid = 0;
+ else if (id == m_handshakeid)
+ m_handshakeid = 0;
+ return;
+ }
+ QString str(m_array);
+ QStringList strlist = str.split("\n");
+
+ if (id == m_handshakeid)
+ {
+ m_handshakeid = 0;
+ if (!strlist[0].contains("OK") || strlist.size() < 4)
+ {
+ qWarning("Scrobbler: handshake phase error: %s", qPrintable(strlist[0]));
+ //TODO badtime handling
+ return;
+ }
+ if (strlist.size() > 3) //process handshake response
+ {
+ qDebug("Scrobbler: reading handshake response");
+ qDebug("Scrobbler: Session ID: %s",qPrintable(strlist[1]));
+ qDebug("Scrobbler: Now-Playing URL: %s",qPrintable(strlist[2]));
+ qDebug("Scrobbler: Submission URL: %s",qPrintable(strlist[3]));
+ m_submitUrl = strlist[3];
+ m_session = strlist[1];
+ return;
+ }
+ }
+ else if (id == m_submitid)
+ {
+ m_submitid = 0;
+ if (!strlist[0].contains("OK"))
+ {
+ qWarning("Scrobbler: submit error: %s", qPrintable(strlist[0]));
+ //TODO badsession handling
+ return;
+ }
+ qWarning("Scrobbler: submited %d song(s)", m_submitedSongs);
+ while (m_submitedSongs)
+ {
+ m_submitedSongs--;
+ m_timeStamps.removeFirst ();
+ m_songCache.removeFirst ();
+ }
+ }
+ m_array.clear();
+}
+
+void Scrobbler::readResponse(const QHttpResponseHeader &header)
+{
+ if (header.statusCode () != 200)
+ {
+ qWarning("Scrobbler: error: %s",qPrintable(header.reasonPhrase ()));
+ //TODO Failure Handling
+ return;
+ }
+ m_array = m_http->readAll();
+}
+
+void Scrobbler::handshake()
+{
+ qDebug("Scrobbler::handshake()");
+ time_t ts = time(NULL);
+ qDebug("Scrobbler: current time stamp %ld",ts);
+ QString auth_tmp = QString("%1%2").arg(m_passw).arg(ts);
+ QByteArray auth = QCryptographicHash::hash(auth_tmp.toAscii (), QCryptographicHash::Md5);
+ auth = auth.toHex();
+
+ QString url = QString("%1?hs=true&p=%2&c=%3&v=%4&u=%5&t=%6&a=%7")
+ .arg("/")
+ .arg(PROTOCOL_VER)
+ .arg(CLIENT_ID)
+ .arg(CLIENT_VER)
+ .arg(m_login)
+ .arg(ts)
+ .arg(QString(auth));
+
+ qDebug("Scrobbler: request url: %s",qPrintable(url));
+ m_http->setHost(SCROBBLER_HS_URL, 80);
+ m_handshakeid = m_http->get(url);
+}
+
+void Scrobbler::submit()
+{
+ qDebug("Scrobbler::submit()");
+ if (m_songCache.isEmpty())
+ return;
+ m_submitedSongs = m_songCache.size();
+ QString body = QString("s=%1").arg(m_session);
+ for (int i = 0; i < qMin(m_songCache.size(), 25); ++i)
+ {
+ SongInfo info = m_songCache[i];
+ body += QString("&a[%9]=%1&t[%9]=%2&i[%9]=%3&o[%9]=%4&r[%9]=%5&l[%9]=%6&b[%9]=%7&n[%9]=%8&m[%9]=")
+ .arg(info.artist())
+ .arg(info.title())
+ .arg( m_timeStamps[i])
+ .arg("P")
+ .arg("")
+ .arg(info.length())
+ .arg(info.album())
+ .arg(info.track())
+ .arg(i);
+ }
+ QUrl url(m_submitUrl);
+ m_http->setHost(url.host(), url.port());
+ QHttpRequestHeader header("POST", url.path());
+ header.setContentType("application/x-www-form-urlencoded");
+ header.setValue("User-Agent","iScrobbler/1.5.1qmmp-plugins/0.2");
+ header.setValue("Host",url.host());
+ header.setValue("Accept", "*/*");
+ header.setContentLength(QUrl::toPercentEncoding(body,":/[]&=").size());
+ qDebug("Scrobbler: submit request header");
+ qDebug(qPrintable(header.toString()));
+ qDebug("*****************************");
+ m_submitid = m_http->request(header, QUrl::toPercentEncoding(body,":/[]&="));
+}
+
+bool Scrobbler::isReady()
+{
+ return !m_submitUrl.isEmpty() && !m_session.isEmpty();
+}
diff --git a/src/plugins/General/scrobbler/scrobbler.h b/src/plugins/General/scrobbler/scrobbler.h
new file mode 100644
index 000000000..25faa13fd
--- /dev/null
+++ b/src/plugins/General/scrobbler/scrobbler.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef SCROBBLER_H
+#define SCROBBLER_H
+
+#include <QHttpResponseHeader>
+#include <qmmpui/general.h>
+#include <time.h>
+
+class QHttp;
+class QTime;
+
+
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+
+class Scrobbler : public General
+{
+Q_OBJECT
+public:
+ Scrobbler(QObject *parent = 0);
+
+ ~Scrobbler();
+
+ void setState(const uint& state);
+ void setSongInfo(const SongInfo &song);
+
+private slots:
+ void processResponse(int, bool);
+ void processResponseHeader(const QHttpResponseHeader &);
+ void readResponse(const QHttpResponseHeader&);
+
+private:
+ void handshake();
+ void submit();
+ bool isReady();
+ time_t m_start_ts;
+ SongInfo m_song;
+ QHttp *m_http;
+ uint m_state;
+ QString m_login;
+ QString m_passw;
+ QString m_submitUrl;
+ QString m_session;
+ QList <time_t> m_timeStamps;
+ QList <SongInfo> m_songCache;
+ QTime* m_time;
+ int m_submitedSongs;
+ int m_handshakeid;
+ int m_submitid;
+ QByteArray m_array;
+ bool m_disabled;
+
+};
+
+#endif
diff --git a/src/plugins/General/scrobbler/scrobbler.pro b/src/plugins/General/scrobbler/scrobbler.pro
new file mode 100644
index 000000000..787cb9f37
--- /dev/null
+++ b/src/plugins/General/scrobbler/scrobbler.pro
@@ -0,0 +1,41 @@
+include(../../plugins.pri)
+
+CONFIG += release \
+ warn_on \
+ plugin
+
+TEMPLATE = lib
+QMAKE_LIBDIR += ../../../../lib
+
+TARGET=$$PLUGINS_PREFIX/General/scrobbler
+QMAKE_CLEAN =$$PLUGINS_PREFIX/General/libscrobbler.so
+
+
+#TRANSLATIONS = translations/ffmpeg_plugin_ru.ts
+#RESOURCES = translations/translations.qrc
+
+isEmpty(LIB_DIR){
+ LIB_DIR = /lib
+}
+target.path = $$LIB_DIR/qmmp/General
+INSTALLS += target
+#FORMS += settingsdialog.ui
+
+#RESOURCES += images/images.qrc
+
+
+HEADERS += scrobblerfactory.h \
+ scrobbler.h \
+ settingsdialog.h
+SOURCES += scrobblerfactory.cpp \
+ scrobbler.cpp \
+ settingsdialog.cpp
+QT += network
+
+
+INCLUDEPATH += ../../../
+
+LIBS += -lqmmpui
+
+FORMS += settingsdialog.ui
+
diff --git a/src/plugins/General/scrobbler/scrobblerfactory.cpp b/src/plugins/General/scrobbler/scrobblerfactory.cpp
new file mode 100644
index 000000000..77bbb0f2b
--- /dev/null
+++ b/src/plugins/General/scrobbler/scrobblerfactory.cpp
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QtGui>
+
+#include "scrobbler.h"
+#include "settingsdialog.h"
+#include "scrobblerfactory.h"
+
+const GeneralProperties ScrobblerFactory::properties() const
+{
+ GeneralProperties properties;
+ properties.name = tr("Scrobbler Plugin");
+ properties.hasAbout = TRUE;
+ properties.hasSettings = TRUE;
+ return properties;
+}
+
+General *ScrobblerFactory::create(QObject *parent)
+{
+ return new Scrobbler(parent);
+}
+
+void ScrobblerFactory::showSettings(QWidget *parent)
+{
+ SettingsDialog *dialog = new SettingsDialog(parent);
+ dialog->show();
+}
+
+void ScrobblerFactory::showAbout(QWidget *parent)
+{
+ QMessageBox::about (parent, tr("About Scrobbler Plugin"),
+ tr("Qmmp AudioScrobbler Plugin")+"\n"+
+ tr("Writen by: Ilya Kotov <forkotov02@hotmail.ru>"));
+}
+
+QTranslator *ScrobblerFactory::createTranslator(QObject *parent)
+{
+ return 0;
+}
+
+Q_EXPORT_PLUGIN(ScrobblerFactory)
diff --git a/src/plugins/General/scrobbler/scrobblerfactory.h b/src/plugins/General/scrobbler/scrobblerfactory.h
new file mode 100644
index 000000000..240749714
--- /dev/null
+++ b/src/plugins/General/scrobbler/scrobblerfactory.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef SCROBBLERFACTORY_H
+#define SCROBBLERFACTORY_H
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+#include <QObject>
+#include <QTranslator>
+
+#include <qmmpui/general.h>
+#include <qmmpui/generalfactory.h>
+
+class ScrobblerFactory : public QObject, public GeneralFactory
+{
+Q_OBJECT
+Q_INTERFACES(GeneralFactory);
+public:
+ const GeneralProperties properties() const;
+ General *create(QObject *parent);
+ void showSettings(QWidget *parent);
+ void showAbout(QWidget *parent);
+ QTranslator *createTranslator(QObject *parent);
+
+};
+
+#endif
diff --git a/src/plugins/General/scrobbler/settingsdialog.cpp b/src/plugins/General/scrobbler/settingsdialog.cpp
new file mode 100644
index 000000000..8dc2dfe22
--- /dev/null
+++ b/src/plugins/General/scrobbler/settingsdialog.cpp
@@ -0,0 +1,51 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QSettings>
+#include <QDir>
+
+#include "settingsdialog.h"
+
+SettingsDialog::SettingsDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ ui.setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose);
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.beginGroup("Scrobbler");
+ ui.userLineEdit->setText(settings.value("login").toString());
+ ui.passwordLineEdit->setText(settings.value("password").toString());
+ settings.endGroup();
+ connect(ui.okButton, SIGNAL(clicked()), SLOT(writeSettings()));
+}
+
+
+SettingsDialog::~SettingsDialog()
+{}
+
+void SettingsDialog::writeSettings()
+{
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.beginGroup("Scrobbler");
+ settings.setValue("login",ui.userLineEdit->text());
+ settings.setValue("password",ui.passwordLineEdit->text());
+ settings.endGroup();
+ accept();
+}
diff --git a/src/plugins/General/scrobbler/settingsdialog.h b/src/plugins/General/scrobbler/settingsdialog.h
new file mode 100644
index 000000000..0d5b21d52
--- /dev/null
+++ b/src/plugins/General/scrobbler/settingsdialog.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef SETTINGSDIALOG_H
+#define SETTINGSDIALOG_H
+
+#include <QDialog>
+
+
+#include "ui_settingsdialog.h"
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class SettingsDialog : public QDialog
+{
+Q_OBJECT
+public:
+ SettingsDialog(QWidget *parent = 0);
+
+ ~SettingsDialog();
+
+
+private slots:
+ void writeSettings();
+
+private:
+ Ui::SettingsDialog ui;
+
+};
+
+#endif
diff --git a/src/plugins/General/scrobbler/settingsdialog.ui b/src/plugins/General/scrobbler/settingsdialog.ui
new file mode 100644
index 000000000..ec446bba2
--- /dev/null
+++ b/src/plugins/General/scrobbler/settingsdialog.ui
@@ -0,0 +1,92 @@
+<ui version="4.0" >
+ <class>SettingsDialog</class>
+ <widget class="QDialog" name="SettingsDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>250</width>
+ <height>123</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Scrobbler Plugin Settings</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>User name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="userLineEdit" />
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Password:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="passwordLineEdit" >
+ <property name="echoMode" >
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="2" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>61</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="okButton" >
+ <property name="text" >
+ <string>OK</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="canselButton" >
+ <property name="text" >
+ <string>Cansel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>canselButton</sender>
+ <signal>clicked()</signal>
+ <receiver>SettingsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>204</x>
+ <y>90</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>26</x>
+ <y>102</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/General/statusicon/images/images.qrc b/src/plugins/General/statusicon/images/images.qrc
new file mode 100644
index 000000000..b072b1d73
--- /dev/null
+++ b/src/plugins/General/statusicon/images/images.qrc
@@ -0,0 +1,8 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+ <qresource>
+ <file>tray_play.png</file>
+ <file>tray_pause.png</file>
+ <file>tray_stop.png</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/General/statusicon/images/tray_pause.png b/src/plugins/General/statusicon/images/tray_pause.png
new file mode 100644
index 000000000..dfed3deb1
--- /dev/null
+++ b/src/plugins/General/statusicon/images/tray_pause.png
Binary files differ
diff --git a/src/plugins/General/statusicon/images/tray_play.png b/src/plugins/General/statusicon/images/tray_play.png
new file mode 100644
index 000000000..4d0f9099c
--- /dev/null
+++ b/src/plugins/General/statusicon/images/tray_play.png
Binary files differ
diff --git a/src/plugins/General/statusicon/images/tray_stop.png b/src/plugins/General/statusicon/images/tray_stop.png
new file mode 100644
index 000000000..9e894d9eb
--- /dev/null
+++ b/src/plugins/General/statusicon/images/tray_stop.png
Binary files differ
diff --git a/src/plugins/General/statusicon/settingsdialog.cpp b/src/plugins/General/statusicon/settingsdialog.cpp
new file mode 100644
index 000000000..7cb6bb1e5
--- /dev/null
+++ b/src/plugins/General/statusicon/settingsdialog.cpp
@@ -0,0 +1,55 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QSettings>
+#include <QDir>
+
+#include "settingsdialog.h"
+
+SettingsDialog::SettingsDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ ui.setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose);
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.beginGroup("Tray");
+ ui.messageCheckBox->setChecked(settings.value("show_message",TRUE).toBool());
+ ui.messageDelaySpinBox->setValue(settings.value("message_delay", 2000).toInt());
+ ui.toolTipCheckBox->setChecked(settings.value("show_tooltip",FALSE).toBool());
+ ui.hideToTrayRadioButton->setChecked(settings.value("hide_on_close", FALSE).toBool());
+ settings.endGroup();
+ connect(ui.okButton, SIGNAL(clicked()), SLOT(writeSettings()));
+}
+
+
+SettingsDialog::~SettingsDialog()
+{}
+
+void SettingsDialog::writeSettings()
+{
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.beginGroup("Tray");
+ settings.setValue ("show_message", ui.messageCheckBox->isChecked());
+ settings.setValue ("message_delay", ui.messageDelaySpinBox->value());
+ settings.setValue ("show_tooltip", ui.toolTipCheckBox->isChecked());
+ settings.setValue ("hide_on_close", ui.hideToTrayRadioButton->isChecked());
+ settings.endGroup();
+ accept();
+}
diff --git a/src/plugins/General/statusicon/settingsdialog.h b/src/plugins/General/statusicon/settingsdialog.h
new file mode 100644
index 000000000..0d5b21d52
--- /dev/null
+++ b/src/plugins/General/statusicon/settingsdialog.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef SETTINGSDIALOG_H
+#define SETTINGSDIALOG_H
+
+#include <QDialog>
+
+
+#include "ui_settingsdialog.h"
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class SettingsDialog : public QDialog
+{
+Q_OBJECT
+public:
+ SettingsDialog(QWidget *parent = 0);
+
+ ~SettingsDialog();
+
+
+private slots:
+ void writeSettings();
+
+private:
+ Ui::SettingsDialog ui;
+
+};
+
+#endif
diff --git a/src/plugins/General/statusicon/settingsdialog.ui b/src/plugins/General/statusicon/settingsdialog.ui
new file mode 100644
index 000000000..126fcce7a
--- /dev/null
+++ b/src/plugins/General/statusicon/settingsdialog.ui
@@ -0,0 +1,173 @@
+<ui version="4.0" >
+ <class>SettingsDialog</class>
+ <widget class="QDialog" name="SettingsDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>267</width>
+ <height>285</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Status Icon Plugin Settings</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QGroupBox" name="groupBox_4" >
+ <property name="title" >
+ <string>Tray Icon</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QCheckBox" name="messageCheckBox" >
+ <property name="text" >
+ <string>Show message</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QCheckBox" name="toolTipCheckBox" >
+ <property name="text" >
+ <string>Show tooltip</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Message delay, ms:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QSpinBox" name="messageDelaySpinBox" >
+ <property name="minimum" >
+ <number>100</number>
+ </property>
+ <property name="maximum" >
+ <number>10000</number>
+ </property>
+ <property name="singleStep" >
+ <number>100</number>
+ </property>
+ <property name="value" >
+ <number>1000</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="closeGroupBox" >
+ <property name="title" >
+ <string>Action On Close</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <property name="leftMargin" >
+ <number>9</number>
+ </property>
+ <property name="topMargin" >
+ <number>9</number>
+ </property>
+ <property name="rightMargin" >
+ <number>9</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QRadioButton" name="hideToTrayRadioButton" >
+ <property name="text" >
+ <string>Hide to tray</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="quitRadioButton" >
+ <property name="text" >
+ <string>Quit</string>
+ </property>
+ <property name="checked" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <property name="leftMargin" >
+ <number>0</number>
+ </property>
+ <property name="topMargin" >
+ <number>0</number>
+ </property>
+ <property name="rightMargin" >
+ <number>0</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>0</number>
+ </property>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>131</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="okButton" >
+ <property name="text" >
+ <string>OK</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelButton" >
+ <property name="text" >
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>cancelButton</sender>
+ <signal>clicked()</signal>
+ <receiver>SettingsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>336</x>
+ <y>210</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>179</x>
+ <y>224</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/General/statusicon/statusicon.cpp b/src/plugins/General/statusicon/statusicon.cpp
new file mode 100644
index 000000000..59225d028
--- /dev/null
+++ b/src/plugins/General/statusicon/statusicon.cpp
@@ -0,0 +1,109 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QMenu>
+#include <QSettings>
+#include <QDir>
+#include <QTimer>
+#include <QCoreApplication>
+
+#include "statusicon.h"
+
+StatusIcon::StatusIcon(QObject *parent)
+ : General(parent)
+{
+ m_tray = new QSystemTrayIcon(this);
+ connect(m_tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
+ m_tray->setIcon ( QIcon(":/tray_stop.png"));
+ m_tray->show();
+ QMenu *menu = new QMenu(qobject_cast<QWidget *>(parent));
+ menu->addAction(tr("Play"), this, SLOT(play()));
+ menu->addAction(tr("Pause"), this, SLOT(pause()));
+ menu->addAction(tr("Stop"), this, SLOT(stop()));
+ menu->addAction(tr("Next"), this, SLOT(next()));
+ menu->addAction(tr("Previous"), this, SLOT(previous()));
+ menu->addSeparator();
+ menu->addAction(tr("Exit"), this, SLOT(exit()));
+ m_tray->setContextMenu(menu);
+
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.beginGroup("Tray");
+ m_showMessage = settings.value("show_message",TRUE).toBool();
+ m_messageDelay = settings.value("message_delay", 2000).toInt();
+ m_showTooltip = settings.value("show_tooltip",FALSE).toBool();
+ m_hideToTray = settings.value("hide_on_close", FALSE).toBool();
+ settings.endGroup();
+ m_enabled = FALSE;
+ QTimer::singleShot(200, this, SLOT(enable()));
+
+}
+
+
+StatusIcon::~StatusIcon()
+{}
+
+void StatusIcon::setState(const uint &state)
+{
+ switch ((uint) state)
+ {
+ case General::Playing:
+ {
+ m_tray->setIcon(QIcon(":/tray_play.png"));
+ break;
+ }
+ case General::Paused:
+ {
+ m_tray->setIcon(QIcon(":/tray_pause.png"));
+ break;
+ }
+ case General::Stopped:
+ {
+ m_tray->setIcon(QIcon(":/tray_stop.png"));
+ break;
+ }
+ }
+}
+
+void StatusIcon::setSongInfo(const SongInfo &song)
+{
+ if(!m_enabled)
+ return;
+ QString message = song.artist() + " - " +song.title();
+ if (song.artist().isEmpty())
+ message = song.title();
+ if (song.title().isEmpty())
+ message = song.artist();
+ if (m_showMessage)
+ m_tray->showMessage (tr("Now Playing"), message,
+ QSystemTrayIcon::Information, m_messageDelay);
+ if (m_showTooltip)
+ m_tray->setToolTip(message);
+}
+
+void StatusIcon::trayActivated(QSystemTrayIcon::ActivationReason reason)
+{
+ if (reason == QSystemTrayIcon::Trigger)
+ toggleVisibility();
+}
+
+void StatusIcon::enable()
+{
+ m_enabled = TRUE;
+}
diff --git a/src/plugins/General/statusicon/statusicon.h b/src/plugins/General/statusicon/statusicon.h
new file mode 100644
index 000000000..fae20422d
--- /dev/null
+++ b/src/plugins/General/statusicon/statusicon.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef STATUSICON_H
+#define STATUSICON_H
+
+#include <QSystemTrayIcon>
+
+#include <qmmpui/general.h>
+
+
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+
+class StatusIcon : public General
+{
+Q_OBJECT
+public:
+ StatusIcon(QObject *parent = 0);
+
+ ~StatusIcon();
+
+ void setState(const uint& state);
+ void setSongInfo(const SongInfo &song);
+
+private slots:
+ void trayActivated(QSystemTrayIcon::ActivationReason);
+ void enable();
+
+private:
+ QSystemTrayIcon *m_tray;
+ bool m_showMessage;
+ bool m_showTooltip;
+ bool m_hideToTray;
+ bool m_enabled;
+ int m_messageDelay;
+
+};
+
+#endif
diff --git a/src/plugins/General/statusicon/statusicon.pro b/src/plugins/General/statusicon/statusicon.pro
new file mode 100644
index 000000000..01408d1c8
--- /dev/null
+++ b/src/plugins/General/statusicon/statusicon.pro
@@ -0,0 +1,36 @@
+include(../../plugins.pri)
+
+INCLUDEPATH += ../../../../src
+CONFIG += release \
+warn_on \
+plugin
+
+TARGET=$$PLUGINS_PREFIX/General/statusicon
+QMAKE_CLEAN =$$PLUGINS_PREFIX/General/libstatusicon.so
+
+
+TEMPLATE = lib
+QMAKE_LIBDIR += ../../../../lib
+LIBS += -lqmmpui
+
+#TRANSLATIONS = translations/ffmpeg_plugin_ru.ts
+#RESOURCES = translations/translations.qrc
+
+isEmpty(LIB_DIR){
+ LIB_DIR = /lib
+}
+target.path = $$LIB_DIR/qmmp/General
+INSTALLS += target
+#FORMS += settingsdialog.ui
+
+RESOURCES += images/images.qrc
+
+
+HEADERS += statusiconfactory.h \
+statusicon.h \
+ settingsdialog.h
+SOURCES += statusiconfactory.cpp \
+statusicon.cpp \
+ settingsdialog.cpp
+FORMS += settingsdialog.ui
+
diff --git a/src/plugins/General/statusicon/statusiconfactory.cpp b/src/plugins/General/statusicon/statusiconfactory.cpp
new file mode 100644
index 000000000..1d3beaa0b
--- /dev/null
+++ b/src/plugins/General/statusicon/statusiconfactory.cpp
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QtGui>
+
+#include "statusicon.h"
+#include "settingsdialog.h"
+#include "statusiconfactory.h"
+
+const GeneralProperties StatusIconFactory::properties() const
+{
+ GeneralProperties properties;
+ properties.name = tr("Status Icon Plugin");
+ properties.hasAbout = TRUE;
+ properties.hasSettings = TRUE;
+ return properties;
+}
+
+General *StatusIconFactory::create(QObject *parent)
+{
+ return new StatusIcon(parent);
+}
+
+void StatusIconFactory::showSettings(QWidget *parent)
+{
+ SettingsDialog *s = new SettingsDialog(parent);
+ s->show();
+}
+
+void StatusIconFactory::showAbout(QWidget *parent)
+{
+ QMessageBox::about (parent, tr("About Scrobbler Plugin"),
+ tr("Qmmp Status Icon Plugin")+"\n"+
+ tr("Writen by: Ilya Kotov <forkotov02@hotmail.ru>"));
+}
+
+QTranslator *StatusIconFactory::createTranslator(QObject *parent)
+{
+ return 0;
+}
+
+Q_EXPORT_PLUGIN(StatusIconFactory)
diff --git a/src/plugins/General/statusicon/statusiconfactory.h b/src/plugins/General/statusicon/statusiconfactory.h
new file mode 100644
index 000000000..b09fb1ef1
--- /dev/null
+++ b/src/plugins/General/statusicon/statusiconfactory.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef STATUSICONFACTORY_H
+#define STATUSICONFACTORY_H
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+#include <QObject>
+#include <QTranslator>
+
+#include <qmmpui/general.h>
+#include <qmmpui/generalfactory.h>
+
+class StatusIconFactory : public QObject, public GeneralFactory
+{
+Q_OBJECT
+Q_INTERFACES(GeneralFactory);
+public:
+ const GeneralProperties properties() const;
+ General *create(QObject *parent);
+ void showSettings(QWidget *parent);
+ void showAbout(QWidget *parent);
+ QTranslator *createTranslator(QObject *parent);
+
+};
+
+#endif
diff --git a/src/plugins/Input/CMakeLists.txt b/src/plugins/Input/CMakeLists.txt
new file mode 100644
index 000000000..8114bc092
--- /dev/null
+++ b/src/plugins/Input/CMakeLists.txt
@@ -0,0 +1,49 @@
+
+SET(USE_MAD TRUE CACHE BOOL "enable/disable mad plugin")
+SET(USE_FLAC TRUE CACHE BOOL "enable/disable flac plugin")
+SET(USE_VORBIS TRUE CACHE BOOL "enable/disable ogg vorbis plugin")
+SET(USE_FFMPEG TRUE CACHE BOOL "enable/disable ffmpeg plugin")
+SET(USE_MPC TRUE CACHE BOOL "enable/disable mpc plugin")
+SET(USE_SNDFILE TRUE CACHE BOOL "enable/disable sndfile plugin")
+
+IF(USE_MAD)
+MESSAGE( STATUS "MAD ON")
+add_subdirectory(mad)
+ELSE(USE_MAD)
+MESSAGE( STATUS "MAD OFF")
+ENDIF(USE_MAD)
+
+IF(USE_FLAC)
+MESSAGE( STATUS "FLAC ON")
+add_subdirectory(flac)
+ELSE(USE_FLAC)
+MESSAGE( STATUS "FLAC OFF")
+ENDIF(USE_FLAC)
+
+IF(USE_VORBIS)
+MESSAGE( STATUS "VORBIS ON")
+add_subdirectory(vorbis)
+ELSE(USE_VORBIS)
+MESSAGE( STATUS "VORBIS OFF")
+ENDIF(USE_VORBIS)
+
+IF(USE_FFMPEG)
+MESSAGE( STATUS "FFMPEG ON")
+add_subdirectory(ffmpeg)
+ELSE(USE_FFMPEG)
+MESSAGE( STATUS "FFMPEG OFF")
+ENDIF(USE_FFMPEG)
+
+IF(USE_MPC)
+MESSAGE( STATUS "MPC ON")
+add_subdirectory(mpc)
+ELSE(USE_MPC)
+MESSAGE( STATUS "MPC OFF")
+ENDIF(USE_MPC)
+
+IF(USE_SNDFILE)
+MESSAGE( STATUS "SNDFILE ON")
+add_subdirectory(sndfile)
+ELSE(USE_SNDFILE)
+MESSAGE( STATUS "SNDFILE OFF")
+ENDIF(USE_SNDFILE)
diff --git a/src/plugins/Input/Input.pro b/src/plugins/Input/Input.pro
new file mode 100644
index 000000000..e180229cc
--- /dev/null
+++ b/src/plugins/Input/Input.pro
@@ -0,0 +1,26 @@
+include(../../../qmmp.pri)
+
+SUBDIRS += mad vorbis sndfile
+TEMPLATE = subdirs
+
+contains(CONFIG, MUSEPACK_PLUGIN){
+ SUBDIRS += mpc
+ message(***************************)
+ message(* Musepack plugin enabled *)
+ message(***************************)
+}
+
+contains(CONFIG, FLAC_PLUGIN){
+ SUBDIRS += flac
+ message(***********************)
+ message(* FLAC plugin enabled *)
+ message(***********************)
+}
+
+contains(CONFIG, FFMPEG_PLUGIN){
+ SUBDIRS += ffmpeg
+ message(*************************)
+ message(* FFMPEG plugin enabled *)
+ message(*************************)
+}
+
diff --git a/src/plugins/Input/ffmpeg/CMakeLists.txt b/src/plugins/Input/ffmpeg/CMakeLists.txt
new file mode 100644
index 000000000..1ca0d4b7a
--- /dev/null
+++ b/src/plugins/Input/ffmpeg/CMakeLists.txt
@@ -0,0 +1,94 @@
+project(libffmpeg)
+
+cmake_minimum_required(VERSION 2.4.0)
+
+
+INCLUDE(UsePkgConfig)
+INCLUDE(FindQt4)
+
+find_package(Qt4 REQUIRED) # find and setup Qt4 for this project
+include(${QT_USE_FILE})
+
+# qt plugin
+ADD_DEFINITIONS( -Wall )
+ADD_DEFINITIONS(${QT_DEFINITIONS})
+ADD_DEFINITIONS(-DQT_PLUGIN)
+ADD_DEFINITIONS(-DQT_NO_DEBUG)
+ADD_DEFINITIONS(-DQT_SHARED)
+ADD_DEFINITIONS(-DQT_THREAD)
+# fixes ffmpeg defines
+ADD_DEFINITIONS(-D__STDC_CONSTANT_MACROS)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+SET(QT_INCLUDES
+ ${QT_INCLUDES}
+ ${CMAKE_CURRENT_BINARY_DIR}/../../../
+)
+
+# libqmmp
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+link_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+
+# libffmpeg and taglib
+PKGCONFIG(libavcodec LIBAVCODEC_INCLUDE_DIR LIBAVCODEC_LINK_DIR LIBAVCODEC_LINK_FLAGS LIBAVCODEC_CFLAGS)
+PKGCONFIG(libavformat LIBAVFORMAT_INCLUDE_DIR LIBAVFORMAT_LINK_DIR LIBAVFORMAT_LINK_FLAGS LIBAVFORMAT_CFLAGS)
+PKGCONFIG(taglib TAGLIB_INCLUDE_DIR TAGLIB_LINK_DIR TAGLIB_LINK_FLAGS TAGLIB_CFLAGS)
+
+IF(NOT LIBAVCODEC_LINK_FLAGS)
+ SET(LIBAVCODEC_LINK_FLAGS -lavcodec)
+ENDIF(NOT LIBAVCODEC_LINK_FLAGS)
+
+IF(NOT LIBAVFORMAT_LINK_FLAGS)
+ SET(LIBAVFORMAT_LINK_FLAGS -lavformat)
+ENDIF(NOT LIBAVFORMAT_LINK_FLAGS)
+
+IF(NOT TAGLIB_LINK_FLAGS)
+ SET(TAGLIB_LINK_FLAGS -ltag)
+ SET(TAGLIB_INCLUDE_DIR /usr/include/taglib)
+ SET(TAGLIB_CFLAGS -I/usr/include/taglib)
+ENDIF(NOT TAGLIB_LINK_FLAGS)
+
+include_directories(${FLAC_INCLUDE_DIR} ${TAGLIB_INCLUDE_DIR})
+link_directories(${FLAC_LINK_DIR} ${TAGLIB_LINK_DIR})
+
+ADD_DEFINITIONS(${LIBAVCODEC_CFLAGS})
+ADD_DEFINITIONS(${LIBAVFORMAT_CFLAGS})
+ADD_DEFINITIONS(${TAGLIB_CFLAGS})
+
+
+SET(libffmpeg_SRCS
+ decoder_ffmpeg.cpp
+ decoderffmpegfactory.cpp
+ detailsdialog.cpp
+)
+
+SET(libffmpeg_MOC_HDRS
+ decoderffmpegfactory.h
+ decoder_ffmpeg.h
+ detailsdialog.h
+)
+
+SET(libffmpeg_RCCS translations/translations.qrc)
+
+QT4_ADD_RESOURCES(libffmpeg_RCC_SRCS ${libffmpeg_RCCS})
+
+QT4_WRAP_CPP(libffmpeg_MOC_SRCS ${libffmpeg_MOC_HDRS})
+
+# user interface
+
+
+SET(libffmpeg_UIS
+ detailsdialog.ui
+)
+
+QT4_WRAP_UI(libffmpeg_UIS_H ${libffmpeg_UIS})
+# Don't forget to include output directory, otherwise
+# the UI file won't be wrapped!
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+ADD_LIBRARY(ffmpeg SHARED ${libffmpeg_SRCS} ${libffmpeg_MOC_SRCS} ${libffmpeg_UIS_H}
+ ${libffmpeg_RCC_SRCS})
+target_link_libraries(ffmpeg ${QT_LIBRARIES} -lqmmp ${LIBAVCODEC_LINK_FLAGS} ${LIBAVFORMAT_LINK_FLAGS} ${TAGLIB_LINK_FLAGS} ${TAGLIB_CFLAGS})
+install(TARGETS ffmpeg DESTINATION ${LIB_DIR}/qmmp/Input PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ)
+
diff --git a/src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp b/src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp
new file mode 100644
index 000000000..095f818e7
--- /dev/null
+++ b/src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp
@@ -0,0 +1,342 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QObject>
+#include <QFile>
+
+#include "constants.h"
+#include "buffer.h"
+#include "output.h"
+#include "recycler.h"
+
+#include "decoder_ffmpeg.h"
+
+// Decoder class
+
+DecoderFFmpeg::DecoderFFmpeg(QObject *parent, DecoderFactory *d, QIODevice *i, Output *o)
+ : Decoder(parent, d, i, o)
+{
+ inited = FALSE;
+ user_stop = FALSE;
+ stat = 0;
+ output_buf = 0;
+ output_bytes = 0;
+ output_at = 0;
+ bks = 0;
+ done = FALSE;
+ finish = FALSE;
+ freq = 0;
+ bitrate = 0;
+ seekTime = -1.0;
+ totalTime = 0.0;
+ chan = 0;
+ output_size = 0;
+ ic = 0;
+ wma_outbuf = 0;
+}
+
+
+DecoderFFmpeg::~DecoderFFmpeg()
+{
+ deinit();
+ if (wma_outbuf)
+ {
+ delete [] wma_outbuf;
+ wma_outbuf = 0;
+ }
+ if (output_buf)
+ delete [] output_buf;
+ output_buf = 0;
+
+ if (ic)
+ av_close_input_file(ic);
+}
+
+
+void DecoderFFmpeg::stop()
+{
+ user_stop = TRUE;
+}
+
+
+void DecoderFFmpeg::flush(bool final)
+{
+ ulong min = final ? 0 : bks;
+
+ while ((! done && ! finish) && output_bytes > min)
+ {
+ output()->recycler()->mutex()->lock ();
+
+ while ((! done && ! finish) && output()->recycler()->full())
+ {
+ mutex()->unlock();
+
+ output()->recycler()->cond()->wait(output()->recycler()->mutex());
+
+ mutex()->lock ();
+ done = user_stop;
+ }
+
+ if (user_stop || finish)
+ {
+ inited = FALSE;
+ done = TRUE;
+ }
+ else
+ {
+ output_bytes -= produceSound(output_buf, output_bytes, bitrate, chan);
+ output_size += bks;
+ output_at = output_bytes;
+ }
+
+ if (output()->recycler()->full())
+ {
+ output()->recycler()->cond()->wakeOne();
+ }
+
+ output()->recycler()->mutex()->unlock();
+ }
+}
+
+
+bool DecoderFFmpeg::initialize()
+{
+ bks = blockSize();
+ inited = user_stop = done = finish = FALSE;
+ freq = bitrate = 0;
+ stat = chan = 0;
+ output_size = 0;
+ seekTime = -1.0;
+ totalTime = 0.0;
+
+
+ if (! input())
+ {
+ error("DecoderFFmpeg: cannot initialize. No input.");
+
+ return FALSE;
+ }
+
+ if (! output_buf)
+ output_buf = new char[globalBufferSize];
+ output_at = 0;
+ output_bytes = 0;
+
+ if (! input())
+ {
+ error("DecoderFFmpeg: cannot initialize. No input.");
+
+ return FALSE;
+ }
+
+ if (! output_buf)
+ output_buf = new char[globalBufferSize];
+ output_at = 0;
+ output_bytes = 0;
+
+ QString filename = qobject_cast<QFile*>(input())->fileName ();
+ input()->close();
+ avcodec_init();
+ avcodec_register_all();
+ av_register_all();
+
+ AVCodec *codec;
+ if (av_open_input_file(&ic, filename.toLocal8Bit(), NULL,0, NULL) < 0)
+ {
+ qDebug("DecoderFFmpeg: cannot open input file");
+ return FALSE;
+ }
+ for (wma_idx = 0; wma_idx < ic->nb_streams; wma_idx++)
+ {
+ c = ic->streams[wma_idx]->codec;
+ if (c->codec_type == CODEC_TYPE_AUDIO) break;
+ }
+
+ av_find_stream_info(ic);
+
+ codec = avcodec_find_decoder(c->codec_id);
+
+ if (!codec) return FALSE;
+ if (avcodec_open(c, codec) < 0)
+ return FALSE;
+
+ totalTime = ic->duration/AV_TIME_BASE;
+
+ configure(c->sample_rate, c->channels, 16, c->bit_rate);
+
+ bitrate = c->bit_rate;
+ chan = c->channels;
+ wma_outbuf = new uint8_t[AVCODEC_MAX_AUDIO_FRAME_SIZE*sizeof(int16_t)];
+ inited = TRUE;
+ qDebug("DecoderFFmpeg: initialize succes");
+ return TRUE;
+}
+
+
+double DecoderFFmpeg::lengthInSeconds()
+{
+ if (! inited)
+ return 0;
+
+ return totalTime;
+}
+
+
+void DecoderFFmpeg::seek(double pos)
+{
+ seekTime = pos;
+}
+
+
+void DecoderFFmpeg::deinit()
+{
+ inited = user_stop = done = finish = FALSE;
+ freq = bitrate = 0;
+ stat = chan = 0;
+ output_size = 0;
+}
+
+void DecoderFFmpeg::run()
+{
+// mpc_uint32_t vbrAcc = 0;
+// mpc_uint32_t vbrUpd = 0;
+ uint8_t *inbuf_ptr;
+ int out_size, size;
+ AVPacket pkt;
+
+ mutex()->lock ();
+
+ if (! inited)
+ {
+ mutex()->unlock();
+
+ return;
+ }
+ stat = DecoderState::Decoding;
+ mutex()->unlock();
+ {
+ dispatch(DecoderState ((DecoderState::Type) stat));
+ }
+
+ while (! done && ! finish)
+ {
+ mutex()->lock ();
+ // decode
+
+ if (seekTime >= 0.0)
+ {
+ int64_t timestamp;
+ timestamp = int64_t(seekTime)*AV_TIME_BASE;
+ if (ic->start_time != AV_NOPTS_VALUE)
+ timestamp += ic->start_time;
+ av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
+ avcodec_flush_buffers(c);
+ seekTime = -1.0;
+ }
+
+ int l = 0;
+ if (av_read_frame(ic, &pkt) < 0)
+ {
+ finish = TRUE;
+ goto end;
+ }
+ size = pkt.size;
+ inbuf_ptr = pkt.data;
+
+ out_size = 0;
+
+ while (size > 0)
+ {
+ out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE*sizeof(int16_t);
+ l = avcodec_decode_audio2(c, (int16_t *)(wma_outbuf), &out_size, inbuf_ptr, size);
+
+ if(l < 0)
+ goto end;
+ ffmpeg_out(out_size);
+ size -= l;
+ inbuf_ptr += l;
+ if (pkt.data)
+ av_free_packet(&pkt);
+ }
+ bitrate = c->bit_rate/1024;
+end:
+ if (finish)
+ {
+ flush(TRUE);
+
+ if (output())
+ {
+ output()->recycler()->mutex()->lock ();
+ // end of stream
+ while (! output()->recycler()->empty() && ! user_stop)
+ {
+ output()->recycler()->cond()->wakeOne();
+ mutex()->unlock();
+ output()->recycler()->cond()->wait(output()->recycler()->mutex());
+ mutex()->lock ();
+ }
+ output()->recycler()->mutex()->unlock();
+ }
+
+ done = TRUE;
+ if (! user_stop)
+ {
+ finish = TRUE;
+ }
+ }
+
+ mutex()->unlock();
+
+ }
+
+ mutex()->lock ();
+
+ if (finish)
+ stat = DecoderState::Finished;
+ else if (user_stop)
+ stat = DecoderState::Stopped;
+
+ mutex()->unlock();
+
+ {
+ dispatch(DecoderState ((DecoderState::Type) stat));
+ }
+
+ deinit();
+}
+
+void DecoderFFmpeg::ffmpeg_out(int size)
+{
+ if (size == 0)
+ return;
+ int at = 0;
+ int to_copy = 0;
+ while (size > 0 && !user_stop)
+ {
+ to_copy = qMin(int(globalBufferSize - output_at), int(size) );
+ memmove ( (char *) (output_buf + output_at), wma_outbuf + at, to_copy);
+ at += to_copy;
+ size -= to_copy;
+ output_at += to_copy;
+ output_bytes += to_copy;
+ if (output())
+ flush();
+ }
+}
diff --git a/src/plugins/Input/ffmpeg/decoder_ffmpeg.h b/src/plugins/Input/ffmpeg/decoder_ffmpeg.h
new file mode 100644
index 000000000..956e5f32b
--- /dev/null
+++ b/src/plugins/Input/ffmpeg/decoder_ffmpeg.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef __decoder_ffmeg_h
+#define __decoder_ffmeg_h
+
+extern "C"{
+#include <ffmpeg/avformat.h>
+#include <ffmpeg/avcodec.h>
+}
+#include "decoder.h"
+
+class DecoderFFmpeg : public Decoder
+{
+public:
+ DecoderFFmpeg(QObject *, DecoderFactory *, QIODevice *, Output *);
+ virtual ~DecoderFFmpeg();
+
+ // Standard Decoder API
+ bool initialize();
+ double lengthInSeconds();
+ void seek(double);
+ void stop();
+
+ // Equalizer
+ bool isEQSupported() const { return FALSE; }
+ void setEQEnabled(bool) { ; }
+ void setEQGain(int) { ; }
+ void setEQBands(int[10]) { ; }
+
+
+private:
+ // thread run function
+ void run();
+ // helper functions
+ void flush(bool = FALSE);
+ void deinit();
+ void ffmpeg_out(int size);
+
+ bool inited, user_stop;
+ int stat;
+
+ // output buffer
+ char *output_buf;
+ ulong output_bytes, output_at;
+
+ AVFormatContext *ic;
+ AVCodecContext *c;
+ uint wma_st_buff, wma_idx, wma_idx2;
+ uint8_t *wma_outbuf;
+
+ unsigned int bks;
+ bool done, finish;
+ long freq, bitrate;
+ int chan;
+ unsigned long output_size;
+ double totalTime, seekTime;
+};
+
+
+#endif // __decoder_ffmpeg_h
diff --git a/src/plugins/Input/ffmpeg/decoderffmpegfactory.cpp b/src/plugins/Input/ffmpeg/decoderffmpegfactory.cpp
new file mode 100644
index 000000000..789635a15
--- /dev/null
+++ b/src/plugins/Input/ffmpeg/decoderffmpegfactory.cpp
@@ -0,0 +1,93 @@
+#include <QtGui>
+
+extern "C"{
+#include <ffmpeg/avformat.h>
+#include <ffmpeg/avcodec.h>
+}
+
+#include "detailsdialog.h"
+#include "decoder_ffmpeg.h"
+#include "decoderffmpegfactory.h"
+
+
+// DecoderFFmpegFactory
+
+bool DecoderFFmpegFactory::supports(const QString &source) const
+{
+
+ return (source.right(4).toLower() == ".wma" || source.right(4).toLower() == ".wav");
+}
+
+bool DecoderFFmpegFactory::canDecode(QIODevice *) const
+{
+ return FALSE;
+}
+
+const DecoderProperties DecoderFFmpegFactory::properties() const
+{
+ DecoderProperties properties;
+ properties.name = tr("WMA Files");
+ properties.filter = "*.wma *.wav";
+ properties.description = tr("WMA Files");
+ //properties.contentType = "";
+ properties.hasAbout = TRUE;
+ properties.hasSettings = FALSE;
+ return properties;
+}
+
+Decoder *DecoderFFmpegFactory::create(QObject *parent, QIODevice *input,
+ Output *output)
+{
+ return new DecoderFFmpeg(parent, this, input, output);
+}
+
+FileTag *DecoderFFmpegFactory::createTag(const QString &source)
+{
+ FileTag *ftag = new FileTag();
+ avcodec_init();
+ avcodec_register_all();
+ av_register_all();
+ AVFormatContext *in;
+
+ if (av_open_input_file(&in, source.toLocal8Bit(), NULL,0, NULL) < 0)
+ return ftag;
+ av_find_stream_info(in);
+ ftag->setValue(FileTag::ALBUM, QString::fromUtf8(in->album).trimmed());
+ ftag->setValue(FileTag::ARTIST, QString::fromUtf8(in->author).trimmed());
+ ftag->setValue(FileTag::COMMENT, QString::fromUtf8(in->comment).trimmed());
+ ftag->setValue(FileTag::GENRE, QString::fromUtf8(in->genre).trimmed());
+ ftag->setValue(FileTag::TITLE, QString::fromUtf8(in->title).trimmed());
+ ftag->setValue(FileTag::YEAR, in->year);
+ ftag->setValue(FileTag::TRACK, in->track);
+ ftag->setValue(FileTag::LENGTH ,int(in->duration/AV_TIME_BASE));
+ av_close_input_file(in);
+ return ftag;
+}
+
+QObject* DecoderFFmpegFactory::showDetails(QWidget *parent, const QString &path)
+{
+ DetailsDialog *d = new DetailsDialog(parent, path);
+ d -> show();
+ return d;
+}
+
+void DecoderFFmpegFactory::showSettings(QWidget *)
+{}
+
+void DecoderFFmpegFactory::showAbout(QWidget *parent)
+{
+ QMessageBox::about (parent, tr("About FFmpeg Audio Plugin"),
+ tr("Qmmp FFmpeg Audio Plugin")+"\n"+
+ tr("Suppored formats: WMA")+"\n"+
+ tr("Writen by: Ilya Kotov <forkotov02@hotmail.ru>"));
+}
+
+QTranslator *DecoderFFmpegFactory::createTranslator(QObject *parent)
+{
+ QTranslator *translator = new QTranslator(parent);
+ QString locale = QLocale::system().name();
+ translator->load(QString(":/ffmpeg_plugin_") + locale);
+ return translator;
+}
+
+Q_EXPORT_PLUGIN(DecoderFFmpegFactory)
diff --git a/src/plugins/Input/ffmpeg/decoderffmpegfactory.h b/src/plugins/Input/ffmpeg/decoderffmpegfactory.h
new file mode 100644
index 000000000..16b6de1dd
--- /dev/null
+++ b/src/plugins/Input/ffmpeg/decoderffmpegfactory.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef DECODERFFMPEGFACTORY_H
+#define DECODERFFMPEGFACTORY_H
+
+#include <QObject>
+#include <QString>
+#include <QIODevice>
+#include <QWidget>
+
+#include <decoder.h>
+#include <output.h>
+#include <decoderfactory.h>
+#include <filetag.h>
+
+
+
+
+class DecoderFFmpegFactory : public QObject,
+ DecoderFactory
+{
+Q_OBJECT
+Q_INTERFACES(DecoderFactory);
+
+public:
+ bool supports(const QString &source) const;
+ bool canDecode(QIODevice *input) const;
+ const DecoderProperties properties() const;
+ Decoder *create(QObject *, QIODevice *, Output *);
+ FileTag *createTag(const QString &source);
+ QObject* showDetails(QWidget *parent, const QString &path);
+ void showSettings(QWidget *parent);
+ void showAbout(QWidget *parent);
+ QTranslator *createTranslator(QObject *parent);
+};
+
+#endif
diff --git a/src/plugins/Input/ffmpeg/detailsdialog.cpp b/src/plugins/Input/ffmpeg/detailsdialog.cpp
new file mode 100644
index 000000000..076cd6872
--- /dev/null
+++ b/src/plugins/Input/ffmpeg/detailsdialog.cpp
@@ -0,0 +1,103 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+extern "C"
+{
+#include <ffmpeg/avformat.h>
+#include <ffmpeg/avcodec.h>
+}
+#include <QFile>
+
+#include "detailsdialog.h"
+
+DetailsDialog::DetailsDialog(QWidget *parent, const QString &path)
+ : QDialog(parent)
+{
+ ui.setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose);
+ m_path = path;
+ setWindowTitle (path.section('/',-1));
+ path.section('/',-1);
+
+ ui.pathLineEdit->setText(m_path);
+ if(QFile::exists(m_path))
+ loadInfo();
+}
+
+
+DetailsDialog::~DetailsDialog()
+{}
+
+void DetailsDialog::loadInfo()
+{
+ AVFormatContext *in;
+ avcodec_init();
+ avcodec_register_all();
+ av_register_all();
+ if (av_open_input_file(&in, m_path.toLocal8Bit(), NULL,0, NULL) < 0)
+ return;
+ av_find_stream_info(in);
+ QString string = QString::fromUtf8(in->title).trimmed();
+ ui.titleLineEdit->setText(string);
+ string = QString::fromUtf8(in->author).trimmed();
+ ui.artistLineEdit->setText(string);
+ string = QString::fromUtf8(in->album).trimmed();
+ ui.albumLineEdit->setText(string);
+ string = QString::fromUtf8(in->comment).trimmed();
+ ui.commentLineEdit->setText(string);
+ string = QString("%1").arg(in->year);
+ ui.yearLineEdit->setText(string);
+ string = QString("%1").arg(in->track);
+ ui.trackLineEdit->setText(string);
+ string = QString::fromUtf8(in->genre).trimmed();
+ ui.genreLineEdit->setText(string);
+
+ QString text;
+ text = QString("%1").arg(int(in->duration/AV_TIME_BASE)/60);
+ text +=":"+QString("%1").arg(int(in->duration/AV_TIME_BASE)%60,2,10,QChar('0'));
+ ui.lengthLabel->setText(text);
+
+
+ text = QString("%1").arg(in->file_size/1024)+" "+tr("KB");
+ ui.fileSizeLabel->setText(text);
+ text = QString("%1").arg(in->bit_rate/1000);
+ ui.bitrateLabel->setText(text+" "+tr("kbps"));
+
+ AVCodecContext *c = 0;
+ uint wma_idx;
+
+ for (wma_idx = 0; wma_idx < in->nb_streams; wma_idx++)
+ {
+ c = in->streams[wma_idx]->codec;
+ if (c->codec_type == CODEC_TYPE_AUDIO) break;
+ }
+
+ if (c)
+ {
+ text = QString("%1").arg(c->sample_rate);
+ ui.sampleRateLabel->setText(text+" "+tr("Hz"));
+ text = QString("%1").arg(c->channels);
+ ui.channelsLabel->setText(text);
+ }
+
+ av_close_input_file(in);
+}
+
+
diff --git a/src/plugins/Input/ffmpeg/detailsdialog.h b/src/plugins/Input/ffmpeg/detailsdialog.h
new file mode 100644
index 000000000..258a1bd21
--- /dev/null
+++ b/src/plugins/Input/ffmpeg/detailsdialog.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef DETAILSDIALOG_H
+#define DETAILSDIALOG_H
+
+#include <QDialog>
+
+#include "ui_detailsdialog.h"
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class DetailsDialog : public QDialog
+{
+Q_OBJECT
+public:
+ DetailsDialog(QWidget *parent = 0, const QString &path = 0);
+
+ ~DetailsDialog();
+
+private:
+ void loadInfo();
+ Ui::DetailsDialog ui;
+ QString m_path;
+
+};
+
+#endif
diff --git a/src/plugins/Input/ffmpeg/detailsdialog.ui b/src/plugins/Input/ffmpeg/detailsdialog.ui
new file mode 100644
index 000000000..70ed57052
--- /dev/null
+++ b/src/plugins/Input/ffmpeg/detailsdialog.ui
@@ -0,0 +1,332 @@
+<ui version="4.0" >
+ <class>DetailsDialog</class>
+ <widget class="QDialog" name="DetailsDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>449</width>
+ <height>375</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Details</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item rowspan="2" row="1" column="0" colspan="2" >
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="minimumSize" >
+ <size>
+ <width>175</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="title" >
+ <string>ASF Info</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="4" column="1" >
+ <widget class="QLabel" name="bitrateLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QLabel" name="channelsLabel" >
+ <property name="layoutDirection" >
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Bitrate:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_5" >
+ <property name="text" >
+ <string>File size:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_10" >
+ <property name="layoutDirection" >
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text" >
+ <string>Channels:</string>
+ </property>
+ <property name="textFormat" >
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLabel" name="sampleRateLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Sample rate:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLabel" name="lengthLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Length:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QLabel" name="fileSizeLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>74</width>
+ <height>151</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="2" colspan="2" >
+ <widget class="QGroupBox" name="groupBox_2" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title" >
+ <string>WMA Tag</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="6" column="1" colspan="2" >
+ <widget class="QPushButton" name="pushButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Save</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="3" >
+ <widget class="QLineEdit" name="trackLineEdit" />
+ </item>
+ <item row="4" column="2" >
+ <widget class="QLabel" name="label_26" >
+ <property name="text" >
+ <string>Track number:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" >
+ <widget class="QLineEdit" name="yearLineEdit" />
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="label_25" >
+ <property name="text" >
+ <string>Year:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" >
+ <widget class="QLabel" name="label_27" >
+ <property name="text" >
+ <string>Genre:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_24" >
+ <property name="text" >
+ <string>Comment:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_23" >
+ <property name="text" >
+ <string>Album:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_22" >
+ <property name="text" >
+ <string>Artist:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_21" >
+ <property name="text" >
+ <string>Title:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="3" >
+ <widget class="QLineEdit" name="titleLineEdit" />
+ </item>
+ <item row="1" column="1" colspan="3" >
+ <widget class="QLineEdit" name="artistLineEdit" />
+ </item>
+ <item row="2" column="1" colspan="3" >
+ <widget class="QLineEdit" name="albumLineEdit" />
+ </item>
+ <item row="3" column="1" colspan="3" >
+ <widget class="QLineEdit" name="commentLineEdit" />
+ </item>
+ <item row="5" column="1" colspan="2" >
+ <widget class="QLineEdit" name="genreLineEdit" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="2" column="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>111</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="3" >
+ <widget class="QPushButton" name="pushButton_3" >
+ <property name="text" >
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_28" >
+ <property name="text" >
+ <string>File path:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="3" >
+ <widget class="QLineEdit" name="pathLineEdit" >
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>pushButton_3</sender>
+ <signal>clicked()</signal>
+ <receiver>DetailsDialog</receiver>
+ <slot>close()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>623</x>
+ <y>353</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>539</x>
+ <y>352</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/Input/ffmpeg/ffmpeg.pro b/src/plugins/Input/ffmpeg/ffmpeg.pro
new file mode 100644
index 000000000..7de7c7d5b
--- /dev/null
+++ b/src/plugins/Input/ffmpeg/ffmpeg.pro
@@ -0,0 +1,35 @@
+include(../../plugins.pri)
+
+FORMS += detailsdialog.ui
+HEADERS += decoderffmpegfactory.h \
+ detailsdialog.h \
+ decoder_ffmpeg.h
+SOURCES += detailsdialog.cpp \
+ decoder_ffmpeg.cpp \
+ decoderffmpegfactory.cpp
+
+
+QMAKE_CLEAN = ../libffmpeg.so
+
+TARGET=$$PLUGINS_PREFIX/Input/ffmpeg
+QMAKE_CLEAN =$$PLUGINS_PREFIX/Input/libffmpeg.so
+
+
+INCLUDEPATH += ../../../qmmp
+CONFIG += release \
+warn_on \
+plugin \
+link_pkgconfig
+TEMPLATE = lib
+QMAKE_LIBDIR += ../../../../lib
+LIBS += -lqmmp -L/usr/lib -I/usr/include
+DEFINES += __STDC_CONSTANT_MACROS
+PKGCONFIG += libavcodec libavformat
+#TRANSLATIONS = translations/ffmpeg_plugin_ru.ts
+#RESOURCES = translations/translations.qrc
+
+isEmpty (LIB_DIR){
+LIB_DIR = /lib
+}
+target.path = $$LIB_DIR/qmmp/Input
+INSTALLS += target
diff --git a/src/plugins/Input/ffmpeg/translations/ffmpeg_plugin_cs.ts b/src/plugins/Input/ffmpeg/translations/ffmpeg_plugin_cs.ts
new file mode 100644
index 000000000..8f686a145
--- /dev/null
+++ b/src/plugins/Input/ffmpeg/translations/ffmpeg_plugin_cs.ts
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS><TS version="1.1" language="pl">
+<defaultcodec></defaultcodec>
+<context>
+ <name>DecoderFFmpegFactory</name>
+ <message>
+ <location filename="../decoderffmpegfactory.cpp" line="33"/>
+ <source>WMA Files</source>
+ <translation>Soubory WMA</translation>
+ </message>
+ <message>
+ <location filename="../decoderffmpegfactory.cpp" line="61"/>
+ <source>About FFmpeg Audio Plugin</source>
+ <translation>O pluginu FFmpeg</translation>
+ </message>
+ <message>
+ <location filename="../decoderffmpegfactory.cpp" line="62"/>
+ <source>Qmmp FFmpeg Audio Plugin</source>
+ <translation>Vstupní plugin Qmmp FFmpeg</translation>
+ </message>
+ <message>
+ <location filename="../decoderffmpegfactory.cpp" line="63"/>
+ <source>Suppored formats: WMA</source>
+ <translation>Podporované formáty: WMA</translation>
+ </message>
+ <message>
+ <location filename="../decoderffmpegfactory.cpp" line="64"/>
+ <source>Writen by: Ilya Kotov &lt;forkotov02@hotmail.ru&gt;</source>
+ <translation>Autor: Ilja Kotov &lt;forkotov02@hotmail.ru&gt;</translation>
+ </message>
+ <message>
+ <location filename="../decoderffmpegfactory.cpp" line="19"/>
+ <source>FFmpeg Plugin</source>
+ <translation>Plugin FFmpeg</translation>
+ </message>
+</context>
+<context>
+ <name>DetailsDialog</name>
+ <message>
+ <location filename="../detailsdialog.cpp" line="81"/>
+ <source>kbps</source>
+ <translation>kbps</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.cpp" line="95"/>
+ <source>Hz</source>
+ <translation>Hz</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.cpp" line="78"/>
+ <source>KB</source>
+ <translation>KB</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="13"/>
+ <source>Details</source>
+ <translation>Podrobnosti</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="70"/>
+ <source>File size:</source>
+ <translation>Velikost souboru:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="130"/>
+ <source>-</source>
+ <translation>-</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="103"/>
+ <source>Sample rate:</source>
+ <translation>Vzorkovací frakvence:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="176"/>
+ <source>Save</source>
+ <translation>Uložit</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="186"/>
+ <source>Track number:</source>
+ <translation>Číslo stopy:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="199"/>
+ <source>Year:</source>
+ <translation>Rok:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="209"/>
+ <source>Genre:</source>
+ <translation>Žánr:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="219"/>
+ <source>Comment:</source>
+ <translation>Komentář:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="229"/>
+ <source>Album:</source>
+ <translation>Album:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="239"/>
+ <source>Artist:</source>
+ <translation>Umělec:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="249"/>
+ <source>Title:</source>
+ <translation>Název:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="290"/>
+ <source>Close</source>
+ <translation>Zavřít</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="297"/>
+ <source>File path:</source>
+ <translation>Cesta k souboru:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="120"/>
+ <source>Length:</source>
+ <translation>Délka:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="83"/>
+ <source>Channels:</source>
+ <translation>Počet kanálů:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="60"/>
+ <source>Bitrate:</source>
+ <translation>Datový tok:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="31"/>
+ <source>ASF Info</source>
+ <translation>Informace ASF</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="161"/>
+ <source>WMA Tag</source>
+ <translation>WMA tag</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/plugins/Input/ffmpeg/translations/ffmpeg_plugin_ru.qm b/src/plugins/Input/ffmpeg/translations/ffmpeg_plugin_ru.qm
new file mode 100644
index 000000000..68ceb6f8b
--- /dev/null
+++ b/src/plugins/Input/ffmpeg/translations/ffmpeg_plugin_ru.qm
Binary files differ
diff --git a/src/plugins/Input/ffmpeg/translations/ffmpeg_plugin_ru.ts b/src/plugins/Input/ffmpeg/translations/ffmpeg_plugin_ru.ts
new file mode 100644
index 000000000..a65f434f2
--- /dev/null
+++ b/src/plugins/Input/ffmpeg/translations/ffmpeg_plugin_ru.ts
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS><TS version="1.1" language="ru">
+<context>
+ <name>DecoderFFmpegFactory</name>
+ <message>
+ <location filename="../decoderffmegfactory.cpp" line="19"/>
+ <source>FFmpeg Plugin</source>
+ <translation>Модуль FFmpeg</translation>
+ </message>
+ <message>
+ <location filename="../decoderffmegfactory.cpp" line="33"/>
+ <source>WMA Files</source>
+ <translation>Файлы WMA</translation>
+ </message>
+ <message>
+ <location filename="../decoderffmegfactory.cpp" line="61"/>
+ <source>About FFmpeg Audio Plugin</source>
+ <translation>Об аудио-модуле FFmpeg</translation>
+ </message>
+ <message>
+ <location filename="../decoderffmegfactory.cpp" line="62"/>
+ <source>Qmmp FFmpeg Audio Plugin</source>
+ <translation>Аудио-модуль FFmpeg для Qmmp</translation>
+ </message>
+ <message>
+ <location filename="../decoderffmegfactory.cpp" line="63"/>
+ <source>Suppored formats: WMA</source>
+ <translation>Поддерживаемые форматы: WMA</translation>
+ </message>
+ <message>
+ <location filename="../decoderffmegfactory.cpp" line="64"/>
+ <source>Writen by: Ilya Kotov &lt;forkotov02@hotmail.ru&gt;</source>
+ <translation>Разработчик: Илья Котов &lt;forkotov02@hotmail.ru&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>DetailsDialog</name>
+ <message>
+ <location filename="../detailsdialog.cpp" line="78"/>
+ <source>KB</source>
+ <translation>Кб</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.cpp" line="95"/>
+ <source>Hz</source>
+ <translation>Гц</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="31"/>
+ <source>ASF Info</source>
+ <translation>Информация ASF</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="130"/>
+ <source>-</source>
+ <translation></translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="60"/>
+ <source>Bitrate:</source>
+ <translation>Битовая частота:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="70"/>
+ <source>File size:</source>
+ <translation>Размер файла:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="83"/>
+ <source>Channels:</source>
+ <translation>Каналов:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="103"/>
+ <source>Sample rate:</source>
+ <translation>Дискретизация:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="120"/>
+ <source>Length:</source>
+ <translation>Длительность:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="161"/>
+ <source>WMA Tag</source>
+ <translation>WMA-тег</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="176"/>
+ <source>Save</source>
+ <translation>Сохранить</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="186"/>
+ <source>Track number:</source>
+ <translation>Номер трека:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="199"/>
+ <source>Year:</source>
+ <translation>Год:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="209"/>
+ <source>Genre:</source>
+ <translation>Жанр:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="219"/>
+ <source>Comment:</source>
+ <translation>Комментарий:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="229"/>
+ <source>Album:</source>
+ <translation>Альбом:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="239"/>
+ <source>Artist:</source>
+ <translation>Исполнитель:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="249"/>
+ <source>Title:</source>
+ <translation>Название:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="290"/>
+ <source>Close</source>
+ <translation>Закрыть</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="297"/>
+ <source>File path:</source>
+ <translation>Путь к файлу:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.cpp" line="81"/>
+ <source>kbps</source>
+ <translation>Кб/с</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="13"/>
+ <source>Details</source>
+ <translation>Информация</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/plugins/Input/ffmpeg/translations/translations.qrc b/src/plugins/Input/ffmpeg/translations/translations.qrc
new file mode 100644
index 000000000..5e15f321d
--- /dev/null
+++ b/src/plugins/Input/ffmpeg/translations/translations.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+ <qresource>
+ <file>ffmpeg_plugin_ru.qm</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/Input/flac/CMakeLists.txt b/src/plugins/Input/flac/CMakeLists.txt
new file mode 100644
index 000000000..24041608c
--- /dev/null
+++ b/src/plugins/Input/flac/CMakeLists.txt
@@ -0,0 +1,86 @@
+project(libflac)
+
+cmake_minimum_required(VERSION 2.4.0)
+
+
+INCLUDE(UsePkgConfig)
+INCLUDE(FindQt4)
+
+find_package(Qt4 REQUIRED) # find and setup Qt4 for this project
+include(${QT_USE_FILE})
+
+# qt plugin
+ADD_DEFINITIONS( -Wall )
+ADD_DEFINITIONS(${QT_DEFINITIONS})
+ADD_DEFINITIONS(-DQT_PLUGIN)
+ADD_DEFINITIONS(-DQT_NO_DEBUG)
+ADD_DEFINITIONS(-DQT_SHARED)
+ADD_DEFINITIONS(-DQT_THREAD)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+SET(QT_INCLUDES
+ ${QT_INCLUDES}
+ ${CMAKE_CURRENT_BINARY_DIR}/../../../
+)
+
+# libqmmp
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+link_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+
+# libflac and taglib
+PKGCONFIG(flac FLAC_INCLUDE_DIR FLAC_LINK_DIR FLAC_LINK_FLAGS FLAC_CFLAGS)
+PKGCONFIG(taglib TAGLIB_INCLUDE_DIR TAGLIB_LINK_DIR TAGLIB_LINK_FLAGS TAGLIB_CFLAGS)
+
+IF(NOT FLAC_LINK_FLAGS)
+ SET(FLAC_LINK_FLAGS -lFLAC)
+ENDIF(NOT FLAC_LINK_FLAGS)
+
+IF(NOT TAGLIB_LINK_FLAGS)
+ SET(TAGLIB_LINK_FLAGS -ltag)
+ SET(TAGLIB_INCLUDE_DIR /usr/include/taglib)
+ SET(TAGLIB_CFLAGS -I/usr/include/taglib)
+ENDIF(NOT TAGLIB_LINK_FLAGS)
+
+include_directories(${FLAC_INCLUDE_DIR} ${TAGLIB_INCLUDE_DIR})
+link_directories(${FLAC_LINK_DIR} ${TAGLIB_LINK_DIR})
+
+ADD_DEFINITIONS(${FLAC_CFLAGS})
+ADD_DEFINITIONS(${TAGLIB_CFLAGS})
+
+
+SET(libflac_SRCS
+ decoder_flac.cpp
+ decoderflacfactory.cpp
+ detailsdialog.cpp
+)
+
+SET(libflac_MOC_HDRS
+ decoderflacfactory.h
+ decoder_flac.h
+ detailsdialog.h
+)
+
+SET(libflac_RCCS translations/translations.qrc)
+
+QT4_ADD_RESOURCES(libflac_RCC_SRCS ${libflac_RCCS})
+
+QT4_WRAP_CPP(libflac_MOC_SRCS ${libflac_MOC_HDRS})
+
+# user interface
+
+
+SET(libflac_UIS
+ detailsdialog.ui
+)
+
+QT4_WRAP_UI(libflac_UIS_H ${libflac_UIS})
+# Don't forget to include output directory, otherwise
+# the UI file won't be wrapped!
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+ADD_LIBRARY(flac SHARED ${libflac_SRCS} ${libflac_MOC_SRCS} ${libflac_UIS_H}
+ ${libflac_RCC_SRCS})
+target_link_libraries(flac ${QT_LIBRARIES} -lqmmp ${FLAC_LINK_FLAGS} ${FLAC_CFLAGS} ${TAGLIB_LINK_FLAGS} ${TAGLIB_CFLAGS})
+install(TARGETS flac DESTINATION ${LIB_DIR}/qmmp/Input PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ)
+
diff --git a/src/plugins/Input/flac/decoder_flac.cpp b/src/plugins/Input/flac/decoder_flac.cpp
new file mode 100644
index 000000000..b2a895bca
--- /dev/null
+++ b/src/plugins/Input/flac/decoder_flac.cpp
@@ -0,0 +1,567 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+
+#include "constants.h"
+#include "buffer.h"
+#include "output.h"
+#include "recycler.h"
+
+#include <QObject>
+#include <QIODevice>
+#include <FLAC/all.h>
+#include "decoder_flac.h"
+
+
+
+static size_t pack_pcm_signed (FLAC__byte *data,
+ const FLAC__int32 * const input[],
+ unsigned wide_samples,
+ unsigned channels, unsigned bps)
+{
+ FLAC__byte * const start = data;
+ FLAC__int32 sample;
+ const FLAC__int32 *input_;
+ unsigned samples, channel;
+ unsigned bytes_per_sample;
+ unsigned incr;
+
+ if (bps == 24)
+ bps = 32; /* we encode to 32-bit words */
+ bytes_per_sample = bps / 8;
+ incr = bytes_per_sample * channels;
+
+ for (channel = 0; channel < channels; channel++)
+ {
+ samples = wide_samples;
+ data = start + bytes_per_sample * channel;
+ input_ = input[channel];
+
+ while (samples--)
+ {
+ sample = *input_++;
+
+ switch (bps)
+ {
+ case 8:
+ data[0] = sample;
+ break;
+ case 16:
+ data[1] = (FLAC__byte)(sample >> 8);
+ data[0] = (FLAC__byte)sample;
+ break;
+ case 32:
+ data[3] = (FLAC__byte)(sample >> 16);
+ data[2] = (FLAC__byte)(sample >> 8);
+ data[1] = (FLAC__byte)sample;
+ data[0] = 0;
+ break;
+ }
+
+ data += incr;
+ }
+ }
+
+ return wide_samples * channels * bytes_per_sample;
+}
+
+static int flac_decode (void *void_data, char *buf, int buf_len) /*,
+ struct sound_params *sound_params)*/
+{
+ //struct flac_data *data = (struct flac_data *)void_data;
+ DecoderFLAC *dflac = (DecoderFLAC *) void_data;
+ unsigned to_copy;
+ int bytes_per_sample;
+ FLAC__uint64 decode_position;
+
+ bytes_per_sample = dflac->data()->bits_per_sample / 8;
+
+ /*switch (bytes_per_sample) {
+ case 1:
+ sound_params->fmt = SFMT_S8;
+ break;
+ case 2:
+ sound_params->fmt = SFMT_S16 | SFMT_LE;
+ break;
+ case 3:
+ sound_params->fmt = SFMT_S32 | SFMT_LE;
+ break;
+ }
+
+ sound_params->rate = data->sample_rate;
+ sound_params->channels = data->channels;*/
+
+ //decoder_error_clear (&data->error);
+
+ if (!dflac->data()->sample_buffer_fill)
+ {
+
+ if (FLAC__stream_decoder_get_state(dflac->data()->decoder)
+ == FLAC__STREAM_DECODER_END_OF_STREAM)
+ {
+ return 0;
+ }
+
+ if (!FLAC__stream_decoder_process_single(
+ dflac->data()->decoder))
+ {
+ return 0;
+ }
+
+ /* Count the bitrate */
+ if (!FLAC__stream_decoder_get_decode_position(
+ dflac->data()->decoder, &decode_position))
+ decode_position = 0;
+ if (decode_position > dflac->data()->last_decode_position)
+ {
+ int bytes_per_sec = bytes_per_sample * dflac->data()->sample_rate
+ * dflac->data()->channels;
+
+ dflac->data()->bitrate = int(((float)decode_position -
+ dflac->data()->last_decode_position) * 8.0 *
+ bytes_per_sec /
+ dflac->data()->sample_buffer_fill / 1000);
+ }
+
+ dflac->data()->last_decode_position = decode_position;
+ }
+
+ to_copy = qMin((unsigned)buf_len, dflac->data()->sample_buffer_fill);
+ memcpy (buf, dflac->data()->sample_buffer, to_copy);
+ memmove (dflac->data()->sample_buffer,
+ dflac->data()->sample_buffer + to_copy,
+ dflac->data()->sample_buffer_fill - to_copy);
+ dflac->data()->sample_buffer_fill -= to_copy;
+ return to_copy;
+}
+
+
+static FLAC__StreamDecoderReadStatus
+flac_callback_read (const FLAC__StreamDecoder *, FLAC__byte buffer[],
+ size_t *bytes, void *client_data)
+{
+ DecoderFLAC *dflac = (DecoderFLAC *) client_data;
+ qint64 res;
+
+ res = dflac->input()->read((char *)buffer, *bytes);
+
+ if (res > 0)
+ {
+ *bytes = res;
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ }
+ if (res == 0)
+ {
+ *bytes = res;
+ return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ }
+
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+
+}
+
+static FLAC__StreamDecoderWriteStatus
+flac_callback_write (const FLAC__StreamDecoder *, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+ DecoderFLAC *dflac = (DecoderFLAC *) client_data;
+ const unsigned wide_samples = frame->header.blocksize;
+
+ if (dflac->data()->abort)
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+
+
+ dflac->data()->sample_buffer_fill = pack_pcm_signed (
+ dflac->data()->sample_buffer,
+ buffer, wide_samples,
+ dflac->data()->channels,
+ dflac->data()->bits_per_sample);
+
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+static FLAC__StreamDecoderTellStatus
+flac_callback_tell (const FLAC__StreamDecoder *, FLAC__uint64 *offset, void *client_data)
+{
+ DecoderFLAC *dflac = (DecoderFLAC *) client_data;
+ *offset = dflac->input()->pos ();
+ return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+}
+
+static FLAC__StreamDecoderSeekStatus
+flac_callback_seek (const FLAC__StreamDecoder *, FLAC__uint64 offset, void *client_data)
+{
+ DecoderFLAC *dflac = (DecoderFLAC *) client_data;
+
+ return dflac->input()->seek(offset)
+ ? FLAC__STREAM_DECODER_SEEK_STATUS_OK
+ : FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+}
+
+static FLAC__StreamDecoderLengthStatus
+flac_callback_length (const FLAC__StreamDecoder *, FLAC__uint64 *stream_length, void *client_data)
+{
+ DecoderFLAC *dflac = (DecoderFLAC *) client_data;
+ *stream_length = dflac->input()->size();
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+}
+
+static void
+flac_callback_metadata (const FLAC__StreamDecoder *, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+ DecoderFLAC *dflac = (DecoderFLAC *) client_data;
+
+ if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
+ {
+ qDebug ("DecoderFLAC: getting metadata info");
+
+ dflac->data()->total_samples =
+ (unsigned)(metadata->data.stream_info.total_samples
+ & 0xffffffff);
+ dflac->data()->bits_per_sample =
+ metadata->data.stream_info.bits_per_sample;
+ dflac->data()->channels = metadata->data.stream_info.channels;
+ dflac->data()->sample_rate = metadata->data.stream_info.sample_rate;
+ dflac->data()->length = dflac->data()->total_samples / dflac->data()->sample_rate;
+ }
+}
+
+static FLAC__bool
+flac_callback_eof (const FLAC__StreamDecoder *, void *)
+{
+ return FALSE;
+}
+
+static void
+flac_callback_error (const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{}
+
+// Decoder class
+
+DecoderFLAC::DecoderFLAC(QObject *parent, DecoderFactory *d, QIODevice *i, Output *o)
+ : Decoder(parent, d, i, o)
+{
+ inited = FALSE;
+ user_stop = FALSE;
+ stat = 0;
+ output_buf = 0;
+ output_bytes = 0;
+ output_at = 0;
+ bks = 0;
+ done = FALSE;
+ finish = FALSE;
+ len = 0;
+ freq = 0;
+ bitrate = 0;
+ seekTime = -1.0;
+ totalTime = 0.0;
+ chan = 0;
+ output_size = 0;
+ m_data = 0;
+
+
+
+
+}
+
+
+DecoderFLAC::~DecoderFLAC()
+{
+ deinit();
+ if (data())
+ {
+ if (data()->decoder)
+ FLAC__stream_decoder_delete (data()->decoder);
+ delete data();
+ m_data = 0;
+ }
+
+ if (output_buf)
+ delete [] output_buf;
+ output_buf = 0;
+}
+
+
+void DecoderFLAC::stop()
+{
+ user_stop = TRUE;
+}
+
+
+void DecoderFLAC::flush(bool final)
+{
+ //qDebug("DecoderFLAC: flush()");
+ ulong min = final ? 0 : bks;
+
+ while ((! done && ! finish) && output_bytes > min)
+ {
+ output()->recycler()->mutex()->lock();
+
+ while ((! done && ! finish) && output()->recycler()->full())
+ {
+ mutex()->unlock();
+
+ output()->recycler()->cond()->wait(output()->recycler()->mutex());
+
+ mutex()->lock();
+ done = user_stop;
+ }
+
+ if (user_stop || finish)
+ {
+ inited = FALSE;
+ done = TRUE;
+ }
+ else
+ {
+ output_bytes -= produceSound(output_buf, output_bytes, bitrate, chan);
+ output_size += bks;
+ output_at = output_bytes;
+ }
+
+ if (output()->recycler()->full())
+ {
+ output()->recycler()->cond()->wakeOne();
+ }
+
+ output()->recycler()->mutex()->unlock();
+ }
+}
+
+
+bool DecoderFLAC::initialize()
+{
+ bks = blockSize();
+ inited = user_stop = done = finish = FALSE;
+ len = freq = bitrate = 0;
+ stat = chan = 0;
+ output_size = 0;
+ seekTime = -1.0;
+ totalTime = 0.0;
+
+
+ if (! input())
+ {
+ error("DecoderFLAC: cannot initialize. No input.");
+
+ return FALSE;
+ }
+
+ if (! output_buf)
+ output_buf = new char[globalBufferSize];
+ output_at = 0;
+ output_bytes = 0;
+
+ if (! input()->isOpen())
+ {
+ if (! input()->open(QIODevice::ReadOnly))
+ {
+
+ return FALSE;
+ }
+ }
+
+
+ if (! input())
+ {
+ error("DecoderFLAC: cannot initialize. No input.");
+
+ return FALSE;
+ }
+
+ if (! output_buf)
+ output_buf = new char[globalBufferSize];
+ output_at = 0;
+ output_bytes = 0;
+
+ if (! input()->isOpen())
+ {
+ if (! input()->open(QIODevice::ReadOnly))
+ {
+ return FALSE;
+ }
+ }
+ if (!m_data)
+ {
+ m_data = new flac_data;
+ m_data->decoder = NULL;
+ }
+
+ m_data->bitrate = -1;
+ m_data->abort = 0;
+ m_data->sample_buffer_fill = 0;
+ m_data->last_decode_position = 0;
+ if (!m_data->decoder)
+ {
+ qDebug("DecoderFLAC: creating FLAC__StreamDecoder");
+ m_data->decoder = FLAC__stream_decoder_new ();
+ }
+ qDebug("DecoderFLAC: setting callbacks");
+ if (FLAC__stream_decoder_init_stream(
+ m_data->decoder,
+ flac_callback_read,
+ flac_callback_seek,
+ flac_callback_tell,
+ flac_callback_length,
+ flac_callback_eof,
+ flac_callback_write,
+ flac_callback_metadata,
+ flac_callback_error,
+ this) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+ {
+ data()->ok = 0;
+ return FALSE;
+ }
+
+ if (!FLAC__stream_decoder_process_until_end_of_metadata(
+ data()->decoder))
+ {
+ data()->ok = 0;
+ return FALSE;
+ }
+ chan = data()->channels;
+ configure(data()->sample_rate, data()->channels, 16, bitrate);
+ totalTime = data()->length;
+
+ inited = TRUE;
+ qDebug("DecoderFLAC: initialize succes");
+ return TRUE;
+}
+
+
+double DecoderFLAC::lengthInSeconds()
+{
+ if (! inited)
+ return 0;
+
+ return totalTime;
+}
+
+
+void DecoderFLAC::seek(double pos)
+{
+ seekTime = pos;
+}
+
+
+void DecoderFLAC::deinit()
+{
+ if(data())
+ FLAC__stream_decoder_finish (data()->decoder);
+ inited = user_stop = done = finish = FALSE;
+ len = freq = bitrate = 0;
+ stat = chan = 0;
+ output_size = 0;
+}
+
+void DecoderFLAC::run()
+{
+ mutex()->lock ();
+
+ if (! inited)
+ {
+ mutex()->unlock();
+
+ return;
+ }
+ stat = DecoderState::Decoding;
+ mutex()->unlock();
+ {
+ dispatch(DecoderState ((DecoderState::Type) stat));
+ }
+
+ while (! done && ! finish)
+ {
+ mutex()->lock ();
+ // decode
+
+ if (seekTime >= 0.0)
+ {
+ FLAC__uint64 target_sample;
+
+ target_sample = (FLAC__uint64)((seekTime/(double)data()->length) *
+ (double)data()->total_samples);
+
+ FLAC__stream_decoder_seek_absolute(data()->decoder,
+ target_sample);
+ seekTime = -1.0;
+ }
+ len = flac_decode (this, (char *) (output_buf + output_at), bks);
+
+ if (len > 0)
+ {
+ bitrate = data()->bitrate;
+ output_at += len;
+ output_bytes += len;
+
+ if (output())
+ flush();
+
+ }
+ else if (len == 0)
+ {
+ flush(TRUE);
+
+ if (output())
+ {
+ output()->recycler()->mutex()->lock ();
+ // end of stream
+ while (! output()->recycler()->empty() && ! user_stop)
+ {
+ output()->recycler()->cond()->wakeOne();
+ mutex()->unlock();
+ output()->recycler()->cond()->wait(output()->recycler()->mutex());
+ mutex()->lock ();
+ }
+ output()->recycler()->mutex()->unlock();
+ }
+
+ done = TRUE;
+ if (! user_stop)
+ {
+ finish = TRUE;
+ }
+ }
+ else
+ {
+ // error in read
+ error("DecoderFLAC: Error while decoding stream, File appears to be "
+ "corrupted");
+
+ finish = TRUE;
+ }
+
+ mutex()->unlock();
+ }
+
+ mutex()->lock ();
+
+ if (finish)
+ stat = DecoderState::Finished;
+ else if (user_stop)
+ stat = DecoderState::Stopped;
+
+ mutex()->unlock();
+
+ {
+ dispatch(DecoderState ((DecoderState::Type) stat));
+ }
+
+ deinit();
+}
diff --git a/src/plugins/Input/flac/decoder_flac.h b/src/plugins/Input/flac/decoder_flac.h
new file mode 100644
index 000000000..4c85176ed
--- /dev/null
+++ b/src/plugins/Input/flac/decoder_flac.h
@@ -0,0 +1,124 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef __decoder_flac_h
+#define __decoder_flac_h
+
+class DecoderOgg;
+
+#include "decoder.h"
+
+#include <FLAC/all.h>
+
+#define MAX_SUPPORTED_CHANNELS 2
+
+#define SAMPLES_PER_WRITE 512
+#define SAMPLE_BUFFER_SIZE ((FLAC__MAX_BLOCK_SIZE + SAMPLES_PER_WRITE) * MAX_SUPPORTED_CHANNELS * (32/8))
+
+struct flac_data
+{
+ //FLAC__SeekableStreamDecoder *decoder;
+ FLAC__StreamDecoder *decoder;
+ struct io_stream *stream;
+ int bitrate;
+ int abort; /* abort playing (due to an error) */
+
+ unsigned length;
+ unsigned total_samples;
+
+ FLAC__byte sample_buffer[SAMPLE_BUFFER_SIZE];
+ unsigned sample_buffer_fill;
+
+ /* sound parameters */
+ unsigned bits_per_sample;
+ unsigned sample_rate;
+ unsigned channels;
+
+ FLAC__uint64 last_decode_position;
+
+ int ok; /* was this stream successfully opened? */
+ //struct decoder_error error;
+};
+
+class DecoderFLAC : public Decoder
+{
+public:
+ DecoderFLAC(QObject *, DecoderFactory *, QIODevice *, Output *);
+ virtual ~DecoderFLAC();
+
+ // Standard Decoder API
+ bool initialize();
+ double lengthInSeconds();
+ void seek(double);
+ void stop();
+
+ // Equalizer
+ bool isEQSupported() const
+ {
+ return FALSE;
+ }
+ void setEQEnabled(bool)
+ {
+ ;
+ }
+ void setEQGain(int)
+ {
+ ;
+ }
+ void setEQBands(int[10])
+ {
+ ;
+ }
+
+ struct flac_data *data()
+ {
+ return m_data;
+ }
+
+
+private:
+ // thread run function
+ void run();
+ struct flac_data *m_data;
+ // helper functions
+ void flush(bool = FALSE);
+ void deinit();
+
+ bool inited, user_stop;
+ int stat;
+
+ // output buffer
+ char *output_buf;
+ ulong output_bytes, output_at;
+
+ // FLAC Decoder
+ //FLAC__SeekableStreamDecoder *m_flacDecoder;
+ FLAC__StreamDecoder *m_flacDecoder;
+
+ unsigned int bks;
+ bool done, finish;
+ long len, freq, bitrate;
+ int chan;
+ unsigned long output_size;
+ double totalTime, seekTime;
+};
+
+
+#endif // __decoder_flac_h
diff --git a/src/plugins/Input/flac/decoderflacfactory.cpp b/src/plugins/Input/flac/decoderflacfactory.cpp
new file mode 100644
index 000000000..5abb60b39
--- /dev/null
+++ b/src/plugins/Input/flac/decoderflacfactory.cpp
@@ -0,0 +1,95 @@
+#include <QtGui>
+#include <taglib/tag.h>
+#include <taglib/fileref.h>
+
+#include "detailsdialog.h"
+#include "decoder_flac.h"
+#include "decoderflacfactory.h"
+
+
+// DecoderFLACFactory
+
+bool DecoderFLACFactory::supports(const QString &source) const
+{
+
+ return (source.right(5).toLower() == ".flac");
+}
+
+bool DecoderFLACFactory::canDecode(QIODevice *input) const
+{
+ return FALSE;
+}
+
+const DecoderProperties DecoderFLACFactory::properties() const
+{
+ DecoderProperties properties;
+ properties.name = tr("FLAC Plugin");
+ properties.filter = "*.flac";
+ properties.description = tr("FLAC Files");
+ //properties.contentType = ;
+ properties.hasAbout = TRUE;
+ properties.hasSettings = FALSE;
+ return properties;
+}
+
+Decoder *DecoderFLACFactory::create(QObject *parent, QIODevice *input,
+ Output *output)
+{
+ return new DecoderFLAC(parent, this, input, output);
+}
+
+FileTag *DecoderFLACFactory::createTag(const QString &source)
+{
+ FileTag *ftag = new FileTag();
+
+ TagLib::FileRef fileRef(source.toLocal8Bit ());
+ TagLib::Tag *tag = fileRef.tag();
+
+ if (tag && !tag->isEmpty())
+ {
+ ftag->setValue(FileTag::ALBUM,
+ QString::fromUtf8(tag->album().toCString(TRUE)).trimmed());
+ ftag->setValue(FileTag::ARTIST,
+ QString::fromUtf8(tag->artist().toCString(TRUE)).trimmed());
+ ftag->setValue(FileTag::COMMENT,
+ QString::fromUtf8(tag->comment().toCString(TRUE)).trimmed());
+ ftag->setValue(FileTag::GENRE,
+ QString::fromUtf8(tag->genre().toCString(TRUE)).trimmed());
+ ftag->setValue(FileTag::TITLE,
+ QString::fromUtf8(tag->title().toCString(TRUE)).trimmed());
+ ftag->setValue(FileTag::YEAR, tag->year());
+ ftag->setValue(FileTag::TRACK, tag->track());
+ }
+
+ if (fileRef.audioProperties())
+ ftag->setValue(FileTag::LENGTH, fileRef.audioProperties()->length());
+
+ return ftag;
+}
+
+QObject* DecoderFLACFactory::showDetails(QWidget *parent, const QString &path)
+{
+ DetailsDialog *d = new DetailsDialog(parent, path);
+ d -> show();
+ return d;
+}
+
+void DecoderFLACFactory::showSettings(QWidget *)
+{}
+
+void DecoderFLACFactory::showAbout(QWidget *parent)
+{
+ QMessageBox::about (parent, tr("About FLAC Audio Plugin"),
+ tr("Qmmp FLAC Audio Plugin")+"\n"+
+ tr("Writen by: Ilya Kotov <forkotov02@hotmail.ru>"));
+}
+
+QTranslator *DecoderFLACFactory::createTranslator(QObject *parent)
+{
+ QTranslator *translator = new QTranslator(parent);
+ QString locale = QLocale::system().name();
+ translator->load(QString(":/flac_plugin_") + locale);
+ return translator;
+}
+
+Q_EXPORT_PLUGIN(DecoderFLACFactory)
diff --git a/src/plugins/Input/flac/decoderflacfactory.h b/src/plugins/Input/flac/decoderflacfactory.h
new file mode 100644
index 000000000..586bc3b33
--- /dev/null
+++ b/src/plugins/Input/flac/decoderflacfactory.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef DECODERFLACFACTORY_H
+#define DECODERFLACFACTORY_H
+
+#include <QObject>
+#include <QString>
+#include <QIODevice>
+#include <QWidget>
+
+#include <decoder.h>
+#include <output.h>
+#include <decoderfactory.h>
+#include <filetag.h>
+
+
+
+
+class DecoderFLACFactory : public QObject,
+ DecoderFactory
+{
+Q_OBJECT
+Q_INTERFACES(DecoderFactory);
+
+public:
+ bool supports(const QString &source) const;
+ bool canDecode(QIODevice *input) const;
+ const DecoderProperties properties() const;
+ Decoder *create(QObject *, QIODevice *, Output *);
+ FileTag *createTag(const QString &source);
+ QObject* showDetails(QWidget *parent, const QString &path);
+ void showSettings(QWidget *parent);
+ void showAbout(QWidget *parent);
+ QTranslator *createTranslator(QObject *parent);
+};
+
+#endif
diff --git a/src/plugins/Input/flac/detailsdialog.cpp b/src/plugins/Input/flac/detailsdialog.cpp
new file mode 100644
index 000000000..2826b6cdb
--- /dev/null
+++ b/src/plugins/Input/flac/detailsdialog.cpp
@@ -0,0 +1,118 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include <taglib/tag.h>
+#include <taglib/fileref.h>
+#include <taglib/flacfile.h>
+
+#include <QFile>
+#include <QFileInfo>
+
+#include "detailsdialog.h"
+
+#define QStringToTString_qt4(s) TagLib::String(s.toUtf8().constData(), TagLib::String::UTF8)
+
+DetailsDialog::DetailsDialog(QWidget *parent, const QString &path)
+ : QDialog(parent)
+{
+ ui.setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose);
+ m_path = path;
+ setWindowTitle (path.section('/',-1));
+ path.section('/',-1);
+ ui.pathLineEdit->setText(m_path);
+ if (QFile::exists(m_path))
+ {
+ loadFLACInfo();
+ loadTag();
+ }
+}
+
+
+DetailsDialog::~DetailsDialog()
+{}
+
+void DetailsDialog::loadFLACInfo()
+{
+ TagLib::FLAC::File f (m_path.toLocal8Bit());
+ //l.label
+ //ui. f.audioProperties()->level();
+ QString text;
+ text = QString("%1").arg(f.audioProperties()->length()/60);
+ text +=":"+QString("%1").arg(f.audioProperties()->length()%60,2,10,QChar('0'));
+ ui.lengthLabel->setText(text);
+ text = QString("%1").arg(f.audioProperties()->sampleRate());
+ ui.sampleRateLabel->setText(text+" "+tr("Hz"));
+ text = QString("%1").arg(f.audioProperties()->channels());
+ ui.channelsLabel->setText(text);
+ text = QString("%1").arg(f.audioProperties()->bitrate());
+ ui.bitrateLabel->setText(text+" "+tr("kbps"));
+ text = QString("%1").arg(f.audioProperties()->sampleWidth());
+ ui.sampleWidthLabel->setText(text+" "+tr("bits"));
+ text = QString("%1 "+tr("KB")).arg(f.length()/1024);
+ ui.fileSizeLabel->setText(text);
+
+}
+
+void DetailsDialog::loadTag()
+{
+ TagLib::FileRef f (m_path.toLocal8Bit());
+
+ if (f.tag())
+ { //TODO: load codec name from config
+
+ TagLib::String title = f.tag()->title();
+ TagLib::String artist = f.tag()->artist();
+ TagLib::String album = f.tag()->album();
+ TagLib::String comment = f.tag()->comment();
+ TagLib::String genre = f.tag()->genre();
+ QString string = QString::fromUtf8(title.toCString(TRUE)).trimmed();
+ ui.titleLineEdit->setText(string);
+ string = QString::fromUtf8(artist.toCString(TRUE)).trimmed();
+ ui.artistLineEdit->setText(string);
+ string = QString::fromUtf8(album.toCString(TRUE)).trimmed();
+ ui.albumLineEdit->setText(string);
+ string = QString::fromUtf8(comment.toCString(TRUE)).trimmed();
+ ui.commentLineEdit->setText(string);
+ string = QString("%1").arg(f.tag()->year());
+ ui.yearLineEdit->setText(string);
+ string = QString("%1").arg(f.tag()->track());
+ ui.trackLineEdit->setText(string);
+ string = QString::fromUtf8(genre.toCString(TRUE)).trimmed();
+ ui.genreLineEdit->setText(string);
+ }
+ QFileInfo info(m_path);
+ ui.saveButton->setEnabled(info.isWritable());
+ connect(ui.saveButton, SIGNAL(clicked()), SLOT(saveTag()));
+}
+
+void DetailsDialog::saveTag()
+{
+ TagLib::FileRef f (m_path.toLocal8Bit());
+
+ f.tag()->setTitle(QStringToTString_qt4(ui.titleLineEdit->text()));
+ f.tag()->setArtist(QStringToTString_qt4(ui.artistLineEdit->text()));
+ f.tag()->setAlbum(QStringToTString_qt4(ui.albumLineEdit->text()));
+ f.tag()->setComment(QStringToTString_qt4(ui.commentLineEdit->text()));
+ f.tag()->setGenre(QStringToTString_qt4(ui.genreLineEdit->text()));
+ f.tag()->setYear(ui.yearLineEdit->text().toUInt());
+ f.tag()->setTrack(ui.trackLineEdit->text().toUInt());
+
+ f.save();
+}
diff --git a/src/plugins/Input/flac/detailsdialog.h b/src/plugins/Input/flac/detailsdialog.h
new file mode 100644
index 000000000..80c17544c
--- /dev/null
+++ b/src/plugins/Input/flac/detailsdialog.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef DETAILSDIALOG_H
+#define DETAILSDIALOG_H
+
+#include <QDialog>
+
+#include "ui_detailsdialog.h"
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class DetailsDialog : public QDialog
+{
+Q_OBJECT
+public:
+ DetailsDialog(QWidget *parent = 0, const QString &path = 0);
+
+ ~DetailsDialog();
+
+private slots:
+ void saveTag();
+
+private:
+ void loadFLACInfo();
+ void loadTag();
+ Ui::DetailsDialog ui;
+ QString m_path;
+
+};
+
+#endif
diff --git a/src/plugins/Input/flac/detailsdialog.ui b/src/plugins/Input/flac/detailsdialog.ui
new file mode 100644
index 000000000..5ea739953
--- /dev/null
+++ b/src/plugins/Input/flac/detailsdialog.ui
@@ -0,0 +1,349 @@
+<ui version="4.0" >
+ <class>DetailsDialog</class>
+ <widget class="QDialog" name="DetailsDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>449</width>
+ <height>375</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Details</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item rowspan="2" row="1" column="0" colspan="2" >
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="minimumSize" >
+ <size>
+ <width>175</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="title" >
+ <string>FLAC Info</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="6" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>74</width>
+ <height>151</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1" colspan="2" >
+ <widget class="QLabel" name="fileSizeLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Length:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="2" >
+ <widget class="QLabel" name="lengthLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Sample rate:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" colspan="2" >
+ <widget class="QLabel" name="sampleRateLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_10" >
+ <property name="layoutDirection" >
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text" >
+ <string>Channels:</string>
+ </property>
+ <property name="textFormat" >
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_5" >
+ <property name="text" >
+ <string>File size:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Bitrate:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" colspan="2" >
+ <widget class="QLabel" name="channelsLabel" >
+ <property name="layoutDirection" >
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" colspan="2" >
+ <widget class="QLabel" name="bitrateLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" >
+ <widget class="QLabel" name="label_4" >
+ <property name="text" >
+ <string>Sample width:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1" colspan="2" >
+ <widget class="QLabel" name="sampleWidthLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="3" >
+ <widget class="QLineEdit" name="pathLineEdit" >
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_28" >
+ <property name="text" >
+ <string>File path:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="3" >
+ <widget class="QPushButton" name="pushButton_3" >
+ <property name="text" >
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>111</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="2" colspan="2" >
+ <widget class="QGroupBox" name="groupBox_2" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title" >
+ <string>FLAC Tag</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="6" column="1" colspan="2" >
+ <widget class="QPushButton" name="saveButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Save</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="3" >
+ <widget class="QLineEdit" name="trackLineEdit" />
+ </item>
+ <item row="4" column="2" >
+ <widget class="QLabel" name="label_26" >
+ <property name="text" >
+ <string>Track number:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" >
+ <widget class="QLineEdit" name="yearLineEdit" />
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="label_25" >
+ <property name="text" >
+ <string>Year:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" >
+ <widget class="QLabel" name="label_27" >
+ <property name="text" >
+ <string>Genre:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_24" >
+ <property name="text" >
+ <string>Comment:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_23" >
+ <property name="text" >
+ <string>Album:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_22" >
+ <property name="text" >
+ <string>Artist:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_21" >
+ <property name="text" >
+ <string>Title:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="3" >
+ <widget class="QLineEdit" name="titleLineEdit" />
+ </item>
+ <item row="1" column="1" colspan="3" >
+ <widget class="QLineEdit" name="artistLineEdit" />
+ </item>
+ <item row="2" column="1" colspan="3" >
+ <widget class="QLineEdit" name="albumLineEdit" />
+ </item>
+ <item row="3" column="1" colspan="3" >
+ <widget class="QLineEdit" name="commentLineEdit" />
+ </item>
+ <item row="5" column="1" colspan="2" >
+ <widget class="QLineEdit" name="genreLineEdit" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>pushButton_3</sender>
+ <signal>clicked()</signal>
+ <receiver>DetailsDialog</receiver>
+ <slot>close()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>623</x>
+ <y>353</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>539</x>
+ <y>352</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/Input/flac/flac.pro b/src/plugins/Input/flac/flac.pro
new file mode 100644
index 000000000..4ab46c296
--- /dev/null
+++ b/src/plugins/Input/flac/flac.pro
@@ -0,0 +1,36 @@
+# ???? ?????? ? KDevelop ?????????? qmake.
+# -------------------------------------------
+# ?????????? ???????????? ???????? ???????? ???????: ./Plugins/Input/flac
+# ???? - ??????????:
+
+include(../../plugins.pri)
+
+FORMS += detailsdialog.ui
+HEADERS += decoderflacfactory.h \
+ decoder_flac.h \
+ detailsdialog.h
+SOURCES += decoder_flac.cpp \
+ decoderflacfactory.cpp \
+ detailsdialog.cpp
+
+TARGET=$$PLUGINS_PREFIX/Input/flac
+QMAKE_CLEAN =$$PLUGINS_PREFIX/Input/libflac.so
+
+INCLUDEPATH += ../../../qmmp
+CONFIG += release \
+warn_on \
+plugin \
+link_pkgconfig
+TEMPLATE = lib
+QMAKE_LIBDIR += ../../../../lib
+LIBS += -lqmmp -L/usr/lib -I/usr/include
+PKGCONFIG += taglib flac
+#TRANSLATIONS = translations/flac_plugin_ru.ts
+#RESOURCES = translations/translations.qrc
+
+isEmpty (LIB_DIR){
+LIB_DIR = /lib
+}
+target.path = $$LIB_DIR/qmmp/Input
+INSTALLS += target
+
diff --git a/src/plugins/Input/flac/translations/flac_plugin_ru.qm b/src/plugins/Input/flac/translations/flac_plugin_ru.qm
new file mode 100644
index 000000000..fbd97d091
--- /dev/null
+++ b/src/plugins/Input/flac/translations/flac_plugin_ru.qm
Binary files differ
diff --git a/src/plugins/Input/flac/translations/flac_plugin_ru.ts b/src/plugins/Input/flac/translations/flac_plugin_ru.ts
new file mode 100644
index 000000000..a1e9b98b7
--- /dev/null
+++ b/src/plugins/Input/flac/translations/flac_plugin_ru.ts
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS><TS version="1.1" language="ru">
+<context>
+ <name>DecoderFLACFactory</name>
+ <message>
+ <location filename="../decoderflacfactory.cpp" line="21"/>
+ <source>FLAC Plugin</source>
+ <translation>Модуль FLAC</translation>
+ </message>
+ <message>
+ <location filename="../decoderflacfactory.cpp" line="35"/>
+ <source>FLAC Files</source>
+ <translation>Файлы FLAC</translation>
+ </message>
+ <message>
+ <location filename="../decoderflacfactory.cpp" line="63"/>
+ <source>About FLAC Audio Plugin</source>
+ <translation>Об аудио-модуле FLAC</translation>
+ </message>
+ <message>
+ <location filename="../decoderflacfactory.cpp" line="64"/>
+ <source>Qmmp FLAC Audio Plugin</source>
+ <translation>Аудио-модуль FLAC для Qmmp</translation>
+ </message>
+ <message>
+ <location filename="../decoderflacfactory.cpp" line="65"/>
+ <source>Writen by: Ilya Kotov &lt;forkotov02@hotmail.ru&gt;</source>
+ <translation>Разработчик: Илья Котов &lt;forkotov02@hotmail.ru&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>DetailsDialog</name>
+ <message>
+ <location filename="../detailsdialog.cpp" line="54"/>
+ <source>Hz</source>
+ <translation>Гц</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.cpp" line="60"/>
+ <source>bits</source>
+ <translation>бит</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="31"/>
+ <source>FLAC Info</source>
+ <translation>Информация FLAC</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="160"/>
+ <source>-</source>
+ <translation></translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="63"/>
+ <source>Length:</source>
+ <translation>Длительность:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="80"/>
+ <source>Sample rate:</source>
+ <translation>Частота сэмплов:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="100"/>
+ <source>Channels:</source>
+ <translation>Каналов:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="113"/>
+ <source>File size:</source>
+ <translation>Размер файла:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="123"/>
+ <source>Bitrate:</source>
+ <translation>Битовая частота:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="150"/>
+ <source>Sample width:</source>
+ <translation>Ширина кадра:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="177"/>
+ <source>File path:</source>
+ <translation>Путь к файлу:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="187"/>
+ <source>Close</source>
+ <translation>Закрыть</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="215"/>
+ <source>FLAC Tag</source>
+ <translation>FLAC-тег</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="230"/>
+ <source>Save</source>
+ <translation>Сохранить</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="240"/>
+ <source>Track number:</source>
+ <translation>Номер трека:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="253"/>
+ <source>Year:</source>
+ <translation>Год:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="263"/>
+ <source>Genre:</source>
+ <translation>Жанр:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="273"/>
+ <source>Comment:</source>
+ <translation>Комментарий:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="283"/>
+ <source>Album:</source>
+ <translation>Альбом:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="293"/>
+ <source>Artist:</source>
+ <translation>Исполнитель:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="303"/>
+ <source>Title:</source>
+ <translation>Название:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.cpp" line="58"/>
+ <source>kbps</source>
+ <translation>Кб/с</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.cpp" line="61"/>
+ <source>KB</source>
+ <translation>Кб</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="13"/>
+ <source>Details</source>
+ <translation>Информация</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/plugins/Input/flac/translations/translations.qrc b/src/plugins/Input/flac/translations/translations.qrc
new file mode 100644
index 000000000..cd630dfce
--- /dev/null
+++ b/src/plugins/Input/flac/translations/translations.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+ <qresource>
+ <file>flac_plugin_ru.qm</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/Input/mad/CMakeLists.txt b/src/plugins/Input/mad/CMakeLists.txt
new file mode 100644
index 000000000..3e4dfa9d0
--- /dev/null
+++ b/src/plugins/Input/mad/CMakeLists.txt
@@ -0,0 +1,90 @@
+project(libmad)
+
+cmake_minimum_required(VERSION 2.4.0)
+
+
+INCLUDE(UsePkgConfig)
+INCLUDE(FindQt4)
+
+find_package(Qt4 REQUIRED) # find and setup Qt4 for this project
+include(${QT_USE_FILE})
+
+# qt plugin
+ADD_DEFINITIONS( -Wall )
+ADD_DEFINITIONS(${QT_DEFINITIONS})
+ADD_DEFINITIONS(-DQT_PLUGIN)
+ADD_DEFINITIONS(-DQT_NO_DEBUG)
+ADD_DEFINITIONS(-DQT_SHARED)
+ADD_DEFINITIONS(-DQT_THREAD)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+SET(QT_INCLUDES
+ ${QT_INCLUDES}
+ ${CMAKE_CURRENT_BINARY_DIR}/../../../
+)
+
+# libqmmp
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+link_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+
+# libmad and taglib
+PKGCONFIG(mad MAD_INCLUDE_DIR MAD_LINK_DIR MAD_LINK_FLAGS MAD_CFLAGS)
+PKGCONFIG(taglib TAGLIB_INCLUDE_DIR TAGLIB_LINK_DIR TAGLIB_LINK_FLAGS TAGLIB_CFLAGS)
+
+IF(NOT MAD_LINK_FLAGS)
+ MESSAGE("Can not find mad.pc")
+ SET(MAD_LINK_FLAGS -lmad)
+ENDIF(NOT MAD_LINK_FLAGS)
+
+IF(NOT TAGLIB_LINK_FLAGS)
+ SET(TAGLIB_LINK_FLAGS -ltag)
+ SET(TAGLIB_INCLUDE_DIR /usr/include/taglib)
+ SET(TAGLIB_CFLAGS -I/usr/include/taglib)
+ENDIF(NOT TAGLIB_LINK_FLAGS)
+
+include_directories(${MAD_INCLUDE_DIR} ${TAGLIB_INCLUDE_DIR})
+link_directories(${MAD_LINK_DIR} ${TAGLIB_LINK_DIR})
+
+#ADD_DEFINITIONS(${MAD_CFLAGS})
+ADD_DEFINITIONS(${TAGLIB_CFLAGS})
+
+
+SET(libmad_SRCS
+ decoder_mad.cpp
+ decodermadfactory.cpp
+ detailsdialog.cpp
+ settingsdialog.cpp
+)
+
+SET(libmad_MOC_HDRS
+ settingsdialog.h
+ decodermadfactory.h
+ decoder_mad.h
+ detailsdialog.h
+)
+
+SET(libmad_RCCS translations/translations.qrc)
+
+QT4_ADD_RESOURCES(libmad_RCC_SRCS ${libmad_RCCS})
+
+QT4_WRAP_CPP(libmad_MOC_SRCS ${libmad_MOC_HDRS})
+
+# user interface
+
+
+SET(libmad_UIS
+ detailsdialog.ui
+ settingsdialog.ui
+)
+
+QT4_WRAP_UI(libmad_UIS_H ${libmad_UIS})
+# Don't forget to include output directory, otherwise
+# the UI file won't be wrapped!
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+ADD_LIBRARY(mad SHARED ${libmad_SRCS} ${libmad_MOC_SRCS} ${libmad_UIS_H}
+ ${libmad_RCC_SRCS})
+
+target_link_libraries(mad ${QT_LIBRARIES} -lqmmp ${MAD_LINK_FLAGS} ${TAGLIB_LINK_FLAGS} ${TAGLIB_CFLAGS})
+install(TARGETS mad DESTINATION ${LIB_DIR}/qmmp/Input PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ)
diff --git a/src/plugins/Input/mad/decoder_mad.cpp b/src/plugins/Input/mad/decoder_mad.cpp
new file mode 100644
index 000000000..6b4c2569a
--- /dev/null
+++ b/src/plugins/Input/mad/decoder_mad.cpp
@@ -0,0 +1,572 @@
+#include <QtGui>
+
+#include "decoder_mad.h"
+#include "constants.h"
+#include "buffer.h"
+#include "output.h"
+
+#include <math.h>
+#include <stdio.h>
+
+# define XING_MAGIC (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g')
+
+
+DecoderMAD::DecoderMAD(QObject *parent, DecoderFactory *d, QIODevice *i, Output *o)
+ : Decoder(parent, d, i, o)
+{
+ inited = false;
+ user_stop = false;
+ done = false;
+ finish = false;
+ derror = false;
+ eof = false;
+ useeq = false;
+ totalTime = 0.;
+ seekTime = -1.;
+ channels = 0;
+ bks = 0;
+ bitrate = 0;
+ freq = 0;
+ len = 0;
+ input_buf = 0;
+ input_bytes = 0;
+ output_buf = 0;
+ output_bytes = 0;
+ output_at = 0;
+ output_size = 0;
+}
+
+DecoderMAD::~DecoderMAD()
+{
+ wait();
+ deinit();
+ mutex()->lock();
+ if (input_buf)
+ {
+ qDebug("DecoderMAD: deleting input_buf");
+ delete [] input_buf;
+ }
+ input_buf = 0;
+
+ if (output_buf)
+ {
+ qDebug("DecoderMAD: deleting output_buf");
+ delete [] output_buf;
+ }
+ output_buf = 0;
+ mutex()->unlock();
+}
+
+bool DecoderMAD::initialize()
+{
+ bks = blockSize();
+
+ inited = false;
+ user_stop = false;
+ done = false;
+ finish = false;
+ derror = false;
+ eof = false;
+ totalTime = 0.;
+ seekTime = -1.;
+ channels = 0;
+ bitrate = 0;
+ freq = 0;
+ len = 0;
+ input_bytes = 0;
+ output_bytes = 0;
+ output_at = 0;
+ output_size = 0;
+
+ if (! input())
+ {
+ error("DecoderMAD: cannot initialize. No input.");
+ return FALSE;
+ }
+
+ if (! input_buf)
+ input_buf = new char[globalBufferSize];
+
+ if (! output_buf)
+ output_buf = new char[globalBufferSize];
+
+ if (! input()->isOpen())
+ {
+ if (! input()->open(QIODevice::ReadOnly))
+ {
+ error("DecoderMAD: Failed to open input. Error " +
+ QString::number(input()->isOpen()) + ".");
+ return FALSE;
+ }
+ }
+
+ mad_stream_init(&stream);
+ mad_frame_init(&frame);
+ mad_synth_init(&synth);
+
+ if (! findHeader())
+ {
+ qDebug("DecoderMAD: Cannot find a valid MPEG header.");
+ return FALSE;
+ }
+ configure(freq, channels, 16, bitrate);
+
+ inited = TRUE;
+ return TRUE;
+}
+
+
+void DecoderMAD::deinit()
+{
+ if(!inited)
+ return;
+
+ mad_synth_finish(&synth);
+ mad_frame_finish(&frame);
+ mad_stream_finish(&stream);
+
+ inited = false;
+ user_stop = false;
+ done = false;
+ finish = false;
+ derror = false;
+ eof = false;
+ useeq = false;
+ totalTime = 0.;
+ seekTime = -1.;
+ channels = 0;
+ bks = 0;
+ bitrate = 0;
+ freq = 0;
+ len = 0;
+ input_bytes = 0;
+ output_bytes = 0;
+ output_at = 0;
+ output_size = 0;
+}
+
+bool DecoderMAD::findXingHeader(struct mad_bitptr ptr, unsigned int bitlen)
+{
+ if (bitlen < 64 || mad_bit_read(&ptr, 32) != XING_MAGIC)
+ goto fail;
+
+ xing.flags = mad_bit_read(&ptr, 32);
+ bitlen -= 64;
+
+ if (xing.flags & XING_FRAMES)
+ {
+ if (bitlen < 32)
+ goto fail;
+
+ xing.frames = mad_bit_read(&ptr, 32);
+ bitlen -= 32;
+ }
+
+ if (xing.flags & XING_BYTES)
+ {
+ if (bitlen < 32)
+ goto fail;
+
+ xing.bytes = mad_bit_read(&ptr, 32);
+ bitlen -= 32;
+ }
+
+ if (xing.flags & XING_TOC)
+ {
+ int i;
+
+ if (bitlen < 800)
+ goto fail;
+
+ for (i = 0; i < 100; ++i)
+ xing.toc[i] = mad_bit_read(&ptr, 8);
+
+ bitlen -= 800;
+ }
+
+ if (xing.flags & XING_SCALE)
+ {
+ if (bitlen < 32)
+ goto fail;
+
+ xing.scale = mad_bit_read(&ptr, 32);
+ bitlen -= 32;
+ }
+
+ return true;
+
+fail:
+ xing.flags = 0;
+ xing.frames = 0;
+ xing.bytes = 0;
+ xing.scale = 0;
+ return false;
+}
+
+bool DecoderMAD::findHeader()
+{
+ bool result = false;
+ int count = 0;
+
+ while (1)
+ {
+ if (input_bytes < globalBufferSize)
+ {
+ int bytes = input()->read(input_buf + input_bytes,
+ globalBufferSize - input_bytes);
+ if (bytes <= 0)
+ {
+ if (bytes == -1)
+ result = false;
+ ;
+ break;
+ }
+ input_bytes += bytes;
+ }
+
+ mad_stream_buffer(&stream, (unsigned char *) input_buf, input_bytes);
+
+ bool done = false;
+ while (! done)
+ {
+ if (mad_frame_decode(&frame, &stream) != -1)
+ done = true;
+ else if (!MAD_RECOVERABLE(stream.error))
+ {
+ qWarning("DecoderMAD: Can't decode frame");
+ break;
+ }
+
+ count++;
+ }
+
+ findXingHeader(stream.anc_ptr, stream.anc_bitlen);
+ result = done;
+ if ((stream.error != MAD_ERROR_BUFLEN))
+ break;
+
+ input_bytes = &input_buf[input_bytes] - (char *) stream.next_frame;
+ memmove(input_buf, stream.next_frame, input_bytes);
+ }
+
+ if (result && count)
+ {
+ freq = frame.header.samplerate;
+ channels = MAD_NCHANNELS(&frame.header);
+ bitrate = frame.header.bitrate / 1000;
+ calcLength(&frame.header);
+ }
+
+ return result;
+}
+
+void DecoderMAD::calcLength(struct mad_header *header)
+{
+ if (! input() || input()->isSequential())
+ return;
+
+ totalTime = 0.;
+ if (xing.flags & XING_FRAMES)
+ {
+ mad_timer_t timer;
+
+ timer = header->duration;
+ mad_timer_multiply(&timer, xing.frames);
+
+ totalTime = double(mad_timer_count(timer, MAD_UNITS_MILLISECONDS)) / 1000.;
+ }
+ else if (header->bitrate > 0)
+ totalTime = input()->size() * 8 / header->bitrate;
+}
+
+double DecoderMAD::lengthInSeconds()
+{
+ if (! inited)
+ return 0.;
+ return totalTime;
+}
+
+void DecoderMAD::seek(double pos)
+{
+ seekTime = pos;
+}
+
+void DecoderMAD::stop()
+{
+ user_stop = TRUE;
+}
+
+void DecoderMAD::flush(bool final)
+{
+ ulong min = final ? 0 : bks;
+
+ while ((! done && ! finish) && output_bytes > min)
+ {
+ output()->recycler()->mutex()->lock();
+
+ while ((! done && ! finish) && output()->recycler()->full())
+ {
+ mutex()->unlock();
+ output()->recycler()->cond()->wait(output()->recycler()->mutex());
+
+ mutex()->lock();
+ done = user_stop;
+ }
+
+ if (user_stop || finish)
+ {
+ inited = FALSE;
+ done = TRUE;
+ }
+ else
+ {
+ output_bytes -= produceSound(output_buf, output_bytes, bitrate, channels);
+ output_size += bks;
+ output_at = output_bytes;
+ }
+
+ if (output()->recycler()->full())
+ {
+ output()->recycler()->cond()->wakeOne();
+ }
+
+ output()->recycler()->mutex()->unlock();
+ }
+}
+
+void DecoderMAD::run()
+{
+ mutex()->lock();
+
+ if (! inited)
+ {
+ mutex()->unlock();
+ return;
+ }
+
+ DecoderState::Type stat = DecoderState::Decoding;
+
+ mutex()->unlock();
+
+ dispatch(stat);
+
+ while (! done && ! finish && ! derror)
+ {
+ mutex()->lock();
+
+ if (seekTime >= 0.0)
+ {
+ long seek_pos = long(seekTime * input()->size() / totalTime);
+ input()->seek(seek_pos);
+ output_size = long(seekTime) * long(freq * channels * 16 / 2);
+ input_bytes = 0;
+ output_at = 0;
+ output_bytes = 0;
+ eof = false;
+ }
+
+ finish = eof;
+
+ if (! eof)
+ {
+ if (stream.next_frame && seekTime == -1.)
+ {
+ input_bytes = &input_buf[input_bytes] - (char *) stream.next_frame;
+ memmove(input_buf, stream.next_frame, input_bytes);
+ }
+
+ if (input_bytes < globalBufferSize)
+ {
+ int len = input()->read((char *) input_buf + input_bytes,
+ globalBufferSize - input_bytes);
+
+ if (len == 0)
+ {
+ eof = true;
+ }
+ else if (len < 0)
+ {
+ derror = true;
+ break;
+ }
+
+ input_bytes += len;
+ }
+
+ mad_stream_buffer(&stream, (unsigned char *) input_buf, input_bytes);
+ }
+
+ seekTime = -1.;
+
+ mutex()->unlock();
+
+ // decode
+ while (! done && ! finish && ! derror)
+ {
+ if (mad_frame_decode(&frame, &stream) == -1)
+ {
+ if (stream.error == MAD_ERROR_BUFLEN)
+ break;
+
+ // error in decoding
+ if (! MAD_RECOVERABLE(stream.error))
+ {
+ derror = true;
+ break;
+ }
+ continue;
+ }
+
+ mutex()->lock();
+
+ if (seekTime >= 0.)
+ {
+ mutex()->unlock();
+ break;
+ }
+
+ if (useeq)
+ {
+ unsigned int nch, ch, ns, s, sb;
+
+ nch = MAD_NCHANNELS(&frame.header);
+ ns = MAD_NSBSAMPLES(&frame.header);
+
+ for (ch = 0; ch < nch; ++ch)
+ for (s = 0; s < ns; ++s)
+ for (sb = 0; sb < 32; ++sb)
+ frame.sbsample[ch][s][sb] =
+ mad_f_mul(frame.sbsample[ch][s][sb], eqbands[sb]);
+ }
+
+ mad_synth_frame(&synth, &frame);
+ madOutput();
+ mutex()->unlock();
+ }
+ }
+
+ mutex()->lock();
+
+ if (! user_stop && eof)
+ {
+ flush(TRUE);
+
+ if (output())
+ {
+ output()->recycler()->mutex()->lock();
+ // end of stream
+ while (! output()->recycler()->empty() && ! user_stop)
+ {
+ output()->recycler()->cond()->wakeOne();
+ mutex()->unlock();
+ output()->recycler()->cond()->wait(output()->recycler()->mutex());
+ mutex()->lock();
+ }
+ output()->recycler()->mutex()->unlock();
+ }
+
+ done = TRUE;
+ if (! user_stop)
+ finish = TRUE;
+ }
+
+ if (finish)
+ stat = DecoderState::Finished;
+ else if (user_stop)
+ stat = DecoderState::Stopped;
+
+ mutex()->unlock();
+
+ dispatch(stat);
+
+ if (input())
+ input()->close();
+ deinit();
+
+}
+
+static inline signed int scale(mad_fixed_t sample)
+{
+ /* round */
+ sample += (1L << (MAD_F_FRACBITS - 16));
+
+ /* clip */
+ if (sample >= MAD_F_ONE)
+ sample = MAD_F_ONE - 1;
+ else if (sample < -MAD_F_ONE)
+ sample = -MAD_F_ONE;
+
+ /* quantize */
+ return sample >> (MAD_F_FRACBITS + 1 - 16);
+}
+
+static inline signed long fix_sample(unsigned int bits, mad_fixed_t sample)
+{
+ mad_fixed_t quantized, check;
+ // clip
+ quantized = sample;
+ check = (sample >> MAD_F_FRACBITS) + 1;
+ if (check & ~1)
+ {
+ if (sample >= MAD_F_ONE)
+ quantized = MAD_F_ONE - 1;
+ else if (sample < -MAD_F_ONE)
+ quantized = -MAD_F_ONE;
+ }
+ // quantize
+ quantized &= ~((1L << (MAD_F_FRACBITS + 1 - bits)) - 1);
+ // scale
+ return quantized >> (MAD_F_FRACBITS + 1 - bits);
+}
+
+enum mad_flow DecoderMAD::madOutput()
+{
+ unsigned int samples, channels;
+ mad_fixed_t const *left, *right;
+
+ samples = synth.pcm.length;
+ channels = synth.pcm.channels;
+ left = synth.pcm.samples[0];
+ right = synth.pcm.samples[1];
+
+
+ bitrate = frame.header.bitrate / 1000;
+ done = user_stop;
+
+ while (samples-- && !user_stop)
+ {
+ signed int sample;
+
+ if (output_bytes + 4096 > globalBufferSize)
+ flush();
+
+ sample = fix_sample(16, *left++);
+ *(output_buf + output_at++) = ((sample >> 0) & 0xff);
+ *(output_buf + output_at++) = ((sample >> 8) & 0xff);
+ output_bytes += 2;
+
+ if (channels == 2)
+ {
+ sample = fix_sample(16, *right++);
+ *(output_buf + output_at++) = ((sample >> 0) & 0xff);
+ *(output_buf + output_at++) = ((sample >> 8) & 0xff);
+ output_bytes += 2;
+ }
+ }
+
+ if (done || finish)
+ {
+ return MAD_FLOW_STOP;
+ }
+
+ return MAD_FLOW_CONTINUE;
+}
+
+enum mad_flow DecoderMAD::madError(struct mad_stream *stream,
+ struct mad_frame *)
+{
+ if (MAD_RECOVERABLE(stream->error))
+ return MAD_FLOW_CONTINUE;
+ qFatal("MADERROR!\n");
+ return MAD_FLOW_STOP;
+}
diff --git a/src/plugins/Input/mad/decoder_mad.h b/src/plugins/Input/mad/decoder_mad.h
new file mode 100644
index 000000000..ecbb160cb
--- /dev/null
+++ b/src/plugins/Input/mad/decoder_mad.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com>
+//
+// Use, modification and distribution is allowed without limitation,
+// warranty, or liability of any kind.
+//
+
+#ifndef __decoder_mad_h
+#define __decoder_mad_h
+
+class DecoderMAD;
+
+#include "decoder.h"
+#include "decodermadfactory.h"
+
+extern "C" {
+#include <mad.h>
+}
+
+
+class DecoderMAD : public Decoder
+{
+public:
+ DecoderMAD(QObject *parent = 0, DecoderFactory *d = 0,
+ QIODevice *i = 0, Output *o = 0);
+ virtual ~DecoderMAD();
+
+ // standard decoder API
+ bool initialize();
+ double lengthInSeconds();
+ void seek(double);
+ void stop();
+
+ // Equalizer
+ //bool isEQSupported() const { return TRUE; }
+ //void setEQEnabled(bool);
+ //void setEQ(const EqPreset &);
+
+ static const int maxDecodeRetries;
+ static const int maxFrameSize;
+ static const int maxFrameCheck;
+ static const int initialFrameSize;
+
+
+private:
+ // thread run function
+ void run();
+
+ enum mad_flow madOutput();
+ enum mad_flow madError(struct mad_stream *, struct mad_frame *);
+
+ // helper functions
+ void flush(bool = FALSE);
+ void deinit();
+ bool findHeader();
+ bool findXingHeader(struct mad_bitptr, unsigned int);
+ void calcLength(struct mad_header *);
+
+ bool inited, user_stop, done, finish, derror, eof, useeq;
+ double totalTime, seekTime;
+ int channels;
+ long bitrate, freq, len;
+ unsigned int bks;
+ mad_fixed_t eqbands[32];
+
+ // file input buffer
+ char *input_buf;
+ unsigned long input_bytes;
+
+ // output buffer
+ char *output_buf;
+ unsigned long output_bytes, output_at, output_size;
+
+ // MAD decoder
+ struct {
+ int flags;
+ unsigned long frames;
+ unsigned long bytes;
+ unsigned char toc[100];
+ long scale;
+ } xing;
+
+ enum {
+ XING_FRAMES = 0x0001,
+ XING_BYTES = 0x0002,
+ XING_TOC = 0x0004,
+ XING_SCALE = 0x0008
+ };
+
+ struct mad_stream stream;
+ struct mad_frame frame;
+ struct mad_synth synth;
+};
+
+
+#endif // __decoder_mad_h
diff --git a/src/plugins/Input/mad/decodermadfactory.cpp b/src/plugins/Input/mad/decodermadfactory.cpp
new file mode 100644
index 000000000..8bb04aca1
--- /dev/null
+++ b/src/plugins/Input/mad/decodermadfactory.cpp
@@ -0,0 +1,188 @@
+#include <QtGui>
+#include <QDialog>
+#include <QMessageBox>
+#include <mad.h>
+#include <taglib/tag.h>
+#include <taglib/fileref.h>
+#include <taglib/id3v1tag.h>
+#include <taglib/id3v2tag.h>
+#include <taglib/apetag.h>
+#include <taglib/tfile.h>
+#include <taglib/mpegfile.h>
+
+#include "detailsdialog.h"
+#include "settingsdialog.h"
+#include "decoder_mad.h"
+#include "decodermadfactory.h"
+
+// DecoderMADFactory
+
+bool DecoderMADFactory::supports(const QString &source) const
+{
+ QString ext = source.right(4).toLower();
+ return ext == ".mp1" || ext == ".mp2" || ext == ".mp3";
+}
+
+bool DecoderMADFactory::canDecode(QIODevice *input) const
+{
+ char buf[16 * 512];
+
+ if (input->peek(buf,sizeof(buf)) == sizeof(buf))
+ {
+ struct mad_stream stream;
+ struct mad_header header;
+ int dec_res;
+
+ mad_stream_init (&stream);
+ mad_header_init (&header);
+ mad_stream_buffer (&stream, (unsigned char *) buf, sizeof(buf));
+ stream.error = MAD_ERROR_NONE;
+
+ while ((dec_res = mad_header_decode(&header, &stream)) == -1
+ && MAD_RECOVERABLE(stream.error))
+ ;
+ return dec_res != -1 ? TRUE: FALSE;
+ }
+ return FALSE;
+}
+
+const DecoderProperties DecoderMADFactory::properties() const
+{
+ DecoderProperties properties;
+ properties.name = tr("MPEG Plugin");
+ properties.filter = "*.mp1 *.mp2 *.mp3";
+ properties.description = tr("MPEG Files");
+ properties.contentType = "audio/mp3;audio/mpeg";
+ properties.hasAbout = TRUE;
+ properties.hasSettings = TRUE;
+ return properties;
+}
+
+Decoder *DecoderMADFactory::create(QObject *parent, QIODevice *input, Output *output)
+{
+ return new DecoderMAD(parent, this, input, output);
+}
+
+FileTag *DecoderMADFactory::createTag(const QString &source)
+{
+ FileTag *ftag = new FileTag();
+ TagLib::Tag *tag = 0;
+ TagLib::MPEG::File fileRef(source.toLocal8Bit ());
+
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.beginGroup("MAD");
+ QTextCodec *codec_v1 =
+ QTextCodec::codecForName(settings.value("ID3v1_encoding","UTF-8" )
+ .toByteArray ());
+ QTextCodec *codec_v2 =
+ QTextCodec::codecForName(settings.value("ID3v2_encoding","UTF-8" )
+ .toByteArray ());
+ if (!codec_v1)
+ codec_v1 = QTextCodec::codecForName ("UTF-8");
+ if (!codec_v2)
+ codec_v2 = QTextCodec::codecForName ("UTF-8");
+
+ QTextCodec *codec = 0;
+
+ uint tag_array[3];
+ tag_array[0] = settings.value("tag_1", SettingsDialog::ID3v2).toInt();
+ tag_array[1] = settings.value("tag_2", SettingsDialog::Disabled).toInt();
+ tag_array[2] = settings.value("tag_3", SettingsDialog::Disabled).toInt();
+
+
+ for (int i = 0; i < 3; ++i)
+ {
+ switch ((uint) tag_array[i])
+ {
+ case SettingsDialog::ID3v1:
+ {
+ codec = codec_v1;
+ tag = fileRef.ID3v1Tag();
+ break;
+ }
+ case SettingsDialog::ID3v2:
+ {
+ codec = codec_v2;
+ tag = fileRef.ID3v2Tag();
+ break;
+ }
+ case SettingsDialog::APE:
+ {
+ codec = QTextCodec::codecForName ("UTF-8");
+ tag = fileRef.APETag();
+ break;
+ }
+ case SettingsDialog::Disabled:
+ {
+ break;
+ }
+ }
+ if(tag && !tag->isEmpty())
+ break;
+ }
+ settings.endGroup();
+
+ if (tag && codec)
+ {
+ bool utf = codec->name ().contains("UTF");
+ TagLib::String album = tag->album();
+ TagLib::String artist = tag->artist();
+ TagLib::String comment = tag->comment();
+ TagLib::String genre = tag->genre();
+ TagLib::String title = tag->title();
+
+ ftag->setValue(FileTag::ALBUM,
+ codec->toUnicode(album.toCString(utf)).trimmed());
+ ftag->setValue(FileTag::ARTIST,
+ codec->toUnicode(artist.toCString(utf)).trimmed());
+ ftag->setValue(FileTag::COMMENT,
+ codec->toUnicode(comment.toCString(utf)).trimmed());
+ ftag->setValue(FileTag::GENRE,
+ codec->toUnicode(genre.toCString(utf)).trimmed());
+ ftag->setValue(FileTag::TITLE,
+ codec->toUnicode(title.toCString(utf)).trimmed());
+ ftag->setValue(FileTag::YEAR,
+ tag->year());
+ ftag->setValue(FileTag::TRACK,
+ tag->track());
+ }
+ if (fileRef.audioProperties())
+ ftag->setValue(FileTag::LENGTH,fileRef.audioProperties()->length());
+ return ftag;
+}
+
+QObject* DecoderMADFactory::showDetails(QWidget *parent, const QString &path)
+{
+ DetailsDialog *d = new DetailsDialog(parent, path);
+ d -> show();
+ return d;
+}
+
+void DecoderMADFactory::showSettings(QWidget *parent)
+{
+ SettingsDialog *s = new SettingsDialog(parent);
+ s -> show();
+}
+
+void DecoderMADFactory::showAbout(QWidget *parent)
+{
+ QMessageBox::about (parent, tr("About MPEG Audio Plugin"),
+ tr("Qmmp MPEG Audio Plugin")+"\n"+
+ tr("Compiled against libmad version:")+" "+
+ QString("%1.%2.%3%4").arg(MAD_VERSION_MAJOR)
+ .arg(MAD_VERSION_MINOR)
+ .arg(MAD_VERSION_PATCH).arg(MAD_VERSION_EXTRA)+"\n"+
+ tr("Writen by: Ilya Kotov <forkotov02@hotmail.ru>")+"\n"+
+ tr("Source code based on mq3 progect")
+ );
+}
+
+QTranslator *DecoderMADFactory::createTranslator(QObject *parent)
+{
+ QTranslator *translator = new QTranslator(parent);
+ QString locale = QLocale::system().name();
+ translator->load(QString(":/mad_plugin_") + locale);
+ return translator;
+}
+
+Q_EXPORT_PLUGIN(DecoderMADFactory)
diff --git a/src/plugins/Input/mad/decodermadfactory.h b/src/plugins/Input/mad/decodermadfactory.h
new file mode 100644
index 000000000..2c7da8e47
--- /dev/null
+++ b/src/plugins/Input/mad/decodermadfactory.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef DECODERMADFACTORY_H
+#define DECODERMADFACTORY_H
+
+#include <QObject>
+#include <QString>
+#include <QIODevice>
+#include <QWidget>
+
+#include <decoder.h>
+#include <output.h>
+#include <decoderfactory.h>
+
+
+
+
+class DecoderMADFactory : public QObject,
+ DecoderFactory
+{
+Q_OBJECT
+Q_INTERFACES(DecoderFactory);
+
+public:
+ bool supports(const QString &source) const;
+ bool canDecode(QIODevice *input) const;
+ const DecoderProperties properties() const;
+ Decoder *create(QObject *, QIODevice *, Output *);
+ FileTag *createTag(const QString &source);
+ QObject* showDetails(QWidget *parent, const QString &path);
+ void showSettings(QWidget *parent);
+ void showAbout(QWidget *parent);
+ QTranslator *createTranslator(QObject *parent);
+};
+
+#endif
diff --git a/src/plugins/Input/mad/detailsdialog.cpp b/src/plugins/Input/mad/detailsdialog.cpp
new file mode 100644
index 000000000..af9b466cd
--- /dev/null
+++ b/src/plugins/Input/mad/detailsdialog.cpp
@@ -0,0 +1,294 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include <QTextCodec>
+#include <QSettings>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+
+#include <taglib/tag.h>
+#include <taglib/fileref.h>
+#include <taglib/id3v1tag.h>
+#include <taglib/id3v2tag.h>
+#include <taglib/apetag.h>
+#include <taglib/tfile.h>
+#include <taglib/mpegfile.h>
+#include <taglib/mpegheader.h>
+#include <taglib/mpegproperties.h>
+
+#include "detailsdialog.h"
+
+DetailsDialog::DetailsDialog(QWidget *parent, const QString &path)
+ : QDialog(parent)
+{
+ ui.setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose);
+ m_path = path;
+ setWindowTitle (path.section('/',-1));
+ ui.pathLineEdit->setText(m_path);
+
+ if (!QFile::exists(m_path))
+ return;
+
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.beginGroup("MAD");
+ m_codec_v1 =
+ QTextCodec::codecForName(settings.value("ID3v1_encoding","UTF-8" )
+ .toByteArray ());
+ m_codec_v2 =
+ QTextCodec::codecForName(settings.value("ID3v2_encoding","UTF-8" )
+ .toByteArray ());
+ if (!m_codec_v1)
+ m_codec_v1 = QTextCodec::codecForName ("UTF-8");
+ if (!m_codec_v2)
+ m_codec_v2 = QTextCodec::codecForName ("UTF-8");
+
+ QString tag_name = settings.value("current_tag","ID3v2").toString ();
+
+ if (tag_name == "ID3v1")
+ ui.id3v1RadioButton->setChecked(TRUE);
+ else if (tag_name == "ID3v2")
+ ui.id3v2RadioButton->setChecked(TRUE);
+ else if (tag_name == "APE")
+ ui.apeRadioButton->setChecked(TRUE);
+ else
+ ui.id3v2RadioButton->setChecked(TRUE);
+
+ settings.endGroup();
+
+ loadMPEGInfo();
+ QFileInfo info(m_path);
+ m_rw = info.isWritable();
+ loadTag();
+ connect(ui.saveButton, SIGNAL(clicked()), SLOT(save()));
+ connect(ui.createButton, SIGNAL(clicked()), SLOT(create()));
+ connect(ui.deleteButton, SIGNAL(clicked()), SLOT(deleteTag()));
+ connect(ui.id3v1RadioButton, SIGNAL(clicked()), SLOT(loadTag()));
+ connect(ui.id3v2RadioButton, SIGNAL(clicked()), SLOT(loadTag()));
+ connect(ui.apeRadioButton, SIGNAL(clicked()), SLOT(loadTag()));
+}
+
+
+DetailsDialog::~DetailsDialog()
+{}
+
+void DetailsDialog::loadMPEGInfo()
+{
+ TagLib::MPEG::File f (m_path.toLocal8Bit());
+ //l.label
+ //ui. f.audioProperties()->level();
+ QString text;
+ text = QString("%1").arg(f.audioProperties()->layer());
+ ui.levelLabel->setText("MPEG layer "+text); //TODO: add MPEG version
+ text = QString("%1").arg(f.audioProperties()->bitrate());
+ ui.bitRateLabel->setText(text+" "+tr("kbps"));
+ text = QString("%1").arg(f.audioProperties()->sampleRate());
+ ui.sampleRateLabel->setText(text+" "+tr("Hz"));
+ switch (f.audioProperties()->channelMode())
+ {
+ case TagLib::MPEG::Header::Stereo:
+ ui.modeLabel->setText("Stereo");
+ break;
+ case TagLib::MPEG::Header::JointStereo:
+ ui.modeLabel->setText("Joint stereo");
+ break;
+ case TagLib::MPEG::Header::DualChannel:
+ ui.modeLabel->setText("Dual channel");
+ break;
+ case TagLib::MPEG::Header::SingleChannel:
+ ui.modeLabel->setText("Single channel");
+ break;
+ }
+ text = QString("%1 "+tr("KB")).arg(f.length()/1024);
+ ui.fileSizeLabel->setText(text);
+ /*if (f.audioProperties()->protectionEnabled())
+ ui.errProtectionLabel->setText(tr("Yes"));
+ else
+ ui.errProtectionLabel->setText(tr("No"));*/
+ if (f.audioProperties()->isCopyrighted())
+ ui.copyrightLabel->setText(tr("Yes"));
+ else
+ ui.copyrightLabel->setText(tr("No"));
+ if (f.audioProperties()->isOriginal())
+ ui.originalLabel->setText(tr("Yes"));
+ else
+ ui.originalLabel->setText(tr("No"));
+}
+
+void DetailsDialog::loadTag()
+{
+ TagLib::MPEG::File f (m_path.toLocal8Bit());
+ QTextCodec *codec = QTextCodec::codecForName ("UTF-8");
+ TagLib::Tag *tag = 0;
+
+ if (selectedTag() == TagLib::MPEG::File::ID3v1)
+ {
+ tag = f.ID3v1Tag();
+ codec = m_codec_v1;
+ ui.tagGroupBox->setTitle(tr("ID3v1 Tag"));
+ }
+ else if (selectedTag() == TagLib::MPEG::File::ID3v2)
+ {
+ tag = f.ID3v2Tag();
+ codec = m_codec_v2;
+ ui.tagGroupBox->setTitle(tr("ID3v2 Tag"));
+ }
+ else if (selectedTag() == TagLib::MPEG::File::APE)
+ {
+ ui.tagGroupBox->setTitle(tr("APE Tag"));
+ tag = f.APETag();
+ }
+ ui.saveButton->setEnabled(tag && m_rw);
+ ui.createButton->setEnabled(!tag && m_rw);
+ ui.deleteButton->setEnabled(tag && m_rw);
+ ui.tagsWidget->setEnabled(tag);
+ //clear old values
+ ui.titleLineEdit->clear();
+ ui.artistLineEdit->clear();
+ ui.albumLineEdit->clear();
+ ui.commentLineEdit->clear();
+ ui.yearLineEdit->clear();
+ ui.trackLineEdit->clear();
+ ui.genreLineEdit->clear();
+
+ if (tag)
+ {
+ bool utf = codec->name().contains("UTF");
+ TagLib::String title = tag->title();
+ TagLib::String artist = tag->artist();
+ TagLib::String album = tag->album();
+ TagLib::String comment = tag->comment();
+ TagLib::String genre = tag->genre();
+ QString string = codec->toUnicode(title.toCString(utf)).trimmed();
+ ui.titleLineEdit->setText(string);
+ string = codec->toUnicode(artist.toCString(utf)).trimmed();
+ ui.artistLineEdit->setText(string);
+ string = codec->toUnicode(album.toCString(utf)).trimmed();
+ ui.albumLineEdit->setText(string);
+ string = codec->toUnicode(comment.toCString(utf)).trimmed();
+ ui.commentLineEdit->setText(string);
+ string = QString("%1").arg(tag->year());
+ ui.yearLineEdit->setText(string);
+ string = QString("%1").arg(tag->track());
+ ui.trackLineEdit->setText(string);
+ string = codec->toUnicode(genre.toCString(utf)).trimmed();
+ ui.genreLineEdit->setText(string);
+ }
+}
+
+void DetailsDialog::save()
+{
+ TagLib::MPEG::File* f = new TagLib::MPEG::File(m_path.toLocal8Bit());
+ TagLib::String::Type type = TagLib::String::Latin1;
+
+ QTextCodec *codec = 0;
+ TagLib::Tag *tag = 0;
+
+ if (selectedTag() == TagLib::MPEG::File::ID3v1)
+ {
+ codec = m_codec_v1;
+ tag = f->ID3v1Tag(TRUE);
+ if (codec->name().contains("UTF"))
+ {
+ delete f;
+ loadTag();
+ }
+ }
+ if (selectedTag() == TagLib::MPEG::File::ID3v2)
+ {
+ codec = m_codec_v2;
+ tag = f->ID3v2Tag(TRUE);
+ if (codec->name().contains("UTF"))
+ {
+ TagLib::ID3v2::FrameFactory *factory = TagLib::ID3v2::FrameFactory::instance();
+ factory->setDefaultTextEncoding(TagLib::String::UTF8);
+ f->setID3v2FrameFactory(factory);
+ type = TagLib::String::UTF8;
+ }
+ }
+ if (selectedTag() == TagLib::MPEG::File::APE)
+ {
+ codec = QTextCodec::codecForName ("UTF-8");
+ tag = f->APETag(TRUE);
+ type = TagLib::String::UTF8;
+ }
+
+ tag->setTitle(TagLib::String(codec->fromUnicode(ui.titleLineEdit->text()).constData(), type));
+ tag->setArtist(TagLib::String(codec->fromUnicode(ui.artistLineEdit->text()).constData(), type));
+ tag->setAlbum(TagLib::String(codec->fromUnicode(ui.albumLineEdit->text()).constData(), type));
+ tag->setComment(TagLib::String(codec->fromUnicode(ui.commentLineEdit->text()).constData(), type));
+ tag->setGenre(TagLib::String(codec->fromUnicode(ui.genreLineEdit->text()).constData(), type));
+ tag->setYear(ui.yearLineEdit->text().toUInt());
+ tag->setTrack(ui.trackLineEdit->text().toUInt());
+
+ f->save(selectedTag(), FALSE);
+ delete f;
+ loadTag();
+}
+
+void DetailsDialog::create()
+{
+ TagLib::MPEG::File *f = new TagLib::MPEG::File (m_path.toLocal8Bit());
+ TagLib::Tag *tag = 0;
+ if (selectedTag() == TagLib::MPEG::File::ID3v1)
+ tag = f->ID3v1Tag(TRUE);
+ else if (selectedTag() == TagLib::MPEG::File::ID3v2)
+ tag = f->ID3v2Tag(TRUE);
+ else if (selectedTag() == TagLib::MPEG::File::APE)
+ tag = f->APETag(TRUE);
+
+ f->save(selectedTag(), FALSE);
+ delete f;
+ loadTag();
+ ui.tagsWidget->setEnabled(TRUE);
+ ui.saveButton->setEnabled(m_rw);
+}
+
+void DetailsDialog::deleteTag()
+{
+ TagLib::MPEG::File *f = new TagLib::MPEG::File (m_path.toLocal8Bit());
+ f->strip(selectedTag());
+ delete f;
+ loadTag();
+}
+
+uint DetailsDialog::selectedTag()
+{
+ if (ui.id3v1RadioButton->isChecked())
+ return TagLib::MPEG::File::ID3v1;
+ else if (ui.id3v2RadioButton->isChecked())
+ return TagLib::MPEG::File::ID3v2;
+ else if (ui.apeRadioButton->isChecked())
+ return TagLib::MPEG::File::APE;
+ return TagLib::MPEG::File::ID3v2;
+}
+
+void DetailsDialog::closeEvent (QCloseEvent *)
+{
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.beginGroup("MAD");
+ if (ui.id3v1RadioButton->isChecked())
+ settings.setValue("current_tag","ID3v1");
+ else if (ui.id3v2RadioButton->isChecked())
+ settings.setValue("current_tag","ID3v2");
+ else if (ui.apeRadioButton->isChecked())
+ settings.setValue("current_tag","APE");
+ settings.endGroup();
+}
diff --git a/src/plugins/Input/mad/detailsdialog.h b/src/plugins/Input/mad/detailsdialog.h
new file mode 100644
index 000000000..bc92724a3
--- /dev/null
+++ b/src/plugins/Input/mad/detailsdialog.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef DETAILSDIALOG_H
+#define DETAILSDIALOG_H
+
+#include <QDialog>
+
+#include "ui_detailsdialog.h"
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+
+class QTextCodec;
+
+class DetailsDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ DetailsDialog(QWidget *parent = 0, const QString &path = 0);
+
+ ~DetailsDialog();
+
+protected:
+ virtual void closeEvent (QCloseEvent *);
+
+private slots:
+ void save();
+ void create();
+ void deleteTag();
+ void loadTag();
+
+private:
+ void loadMPEGInfo();
+ uint selectedTag();
+ //void loadTag();
+ //void loadID3v2Tag();
+ Ui::DetailsDialog ui;
+ QString m_path;
+ QTextCodec *m_codec_v1;
+ QTextCodec *m_codec_v2;
+ bool m_rw;
+
+};
+
+#endif
diff --git a/src/plugins/Input/mad/detailsdialog.ui b/src/plugins/Input/mad/detailsdialog.ui
new file mode 100644
index 000000000..6f9a00c31
--- /dev/null
+++ b/src/plugins/Input/mad/detailsdialog.ui
@@ -0,0 +1,392 @@
+<ui version="4.0" >
+ <class>DetailsDialog</class>
+ <widget class="QDialog" name="DetailsDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>593</width>
+ <height>402</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Details</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" colspan="3" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QLabel" name="label_28" >
+ <property name="text" >
+ <string>File path:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="pathLineEdit" >
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item rowspan="2" row="1" column="0" >
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QGroupBox" name="groupBox_3" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title" >
+ <string>Tag Choice</string>
+ </property>
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QRadioButton" name="id3v1RadioButton" >
+ <property name="text" >
+ <string>ID3v1</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="id3v2RadioButton" >
+ <property name="text" >
+ <string>ID3v2</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="apeRadioButton" >
+ <property name="text" >
+ <string>APE</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="minimumSize" >
+ <size>
+ <width>200</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="title" >
+ <string>MPEG Info</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>MPEG level:</string>
+ </property>
+ <property name="textFormat" >
+ <enum>Qt::AutoText</enum>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLabel" name="levelLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Bit rate:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLabel" name="bitRateLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Sample rate:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QLabel" name="sampleRateLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_5" >
+ <property name="text" >
+ <string>File size:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QLabel" name="fileSizeLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="label_6" >
+ <property name="text" >
+ <string>Mode:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" >
+ <widget class="QLabel" name="modeLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" >
+ <widget class="QLabel" name="label_8" >
+ <property name="text" >
+ <string>Copyright:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1" >
+ <widget class="QLabel" name="copyrightLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0" >
+ <widget class="QLabel" name="label_9" >
+ <property name="text" >
+ <string>Original:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1" >
+ <widget class="QLabel" name="originalLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="1" colspan="2" >
+ <widget class="QGroupBox" name="tagGroupBox" >
+ <property name="title" >
+ <string>ID3v1 Tag</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QWidget" native="1" name="tagsWidget" >
+ <property name="enabled" >
+ <bool>true</bool>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_21" >
+ <property name="text" >
+ <string>Title:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="3" >
+ <widget class="QLineEdit" name="titleLineEdit" />
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_22" >
+ <property name="text" >
+ <string>Artist:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" colspan="3" >
+ <widget class="QLineEdit" name="artistLineEdit" />
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_23" >
+ <property name="text" >
+ <string>Album:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" colspan="3" >
+ <widget class="QLineEdit" name="albumLineEdit" />
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_24" >
+ <property name="text" >
+ <string>Comment:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" colspan="3" >
+ <widget class="QLineEdit" name="commentLineEdit" />
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="label_25" >
+ <property name="text" >
+ <string>Year:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" >
+ <widget class="QLineEdit" name="yearLineEdit" />
+ </item>
+ <item row="4" column="2" >
+ <widget class="QLabel" name="label_26" >
+ <property name="text" >
+ <string>Track number:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="3" >
+ <widget class="QLineEdit" name="trackLineEdit" />
+ </item>
+ <item row="5" column="0" >
+ <widget class="QLabel" name="label_27" >
+ <property name="text" >
+ <string>Genre:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1" colspan="3" >
+ <widget class="QLineEdit" name="genreLineEdit" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QPushButton" name="createButton" >
+ <property name="text" >
+ <string>Create</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="deleteButton" >
+ <property name="text" >
+ <string>Delete</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="saveButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Save</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>111</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="2" >
+ <widget class="QPushButton" name="pushButton_3" >
+ <property name="text" >
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>pushButton_3</sender>
+ <signal>clicked()</signal>
+ <receiver>DetailsDialog</receiver>
+ <slot>close()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>623</x>
+ <y>353</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>539</x>
+ <y>352</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/Input/mad/mad.pro b/src/plugins/Input/mad/mad.pro
new file mode 100644
index 000000000..7a320b370
--- /dev/null
+++ b/src/plugins/Input/mad/mad.pro
@@ -0,0 +1,39 @@
+# ???? ?????? ? KDevelop ?????????? qmake.
+# -------------------------------------------
+# ?????????? ???????????? ???????? ???????? ???????: ./Plugins/Input/mad
+# ???? - ??????????:
+
+include(../../plugins.pri)
+
+
+FORMS += detailsdialog.ui \
+ settingsdialog.ui
+HEADERS += decodermadfactory.h \
+ decoder_mad.h \
+ detailsdialog.h \
+ settingsdialog.h
+SOURCES += decoder_mad.cpp \
+ decodermadfactory.cpp \
+ detailsdialog.cpp \
+ settingsdialog.cpp
+
+TARGET=$$PLUGINS_PREFIX/Input/mad
+QMAKE_CLEAN =$$PLUGINS_PREFIX/Input/libmad.so
+
+INCLUDEPATH += ../../../qmmp
+CONFIG += release \
+warn_on \
+plugin \
+link_pkgconfig
+TEMPLATE = lib
+QMAKE_LIBDIR += ../../../../lib
+LIBS += -lqmmp
+PKGCONFIG += taglib mad
+#TRANSLATIONS = translations/mad_plugin_ru.ts
+#RESOURCES = translations/translations.qrc
+
+isEmpty (LIB_DIR){
+LIB_DIR = /lib
+}
+target.path = $$LIB_DIR/qmmp/Input
+INSTALLS += target
diff --git a/src/plugins/Input/mad/settingsdialog.cpp b/src/plugins/Input/mad/settingsdialog.cpp
new file mode 100644
index 000000000..667e8598a
--- /dev/null
+++ b/src/plugins/Input/mad/settingsdialog.cpp
@@ -0,0 +1,107 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include <QTextCodec>
+#include <QSettings>
+#include <QDir>
+
+#include "settingsdialog.h"
+
+SettingsDialog::SettingsDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ ui.setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose);
+ findCodecs();
+ foreach (QTextCodec *codec, codecs)
+ {
+ ui.id3v1EncComboBox->addItem(codec->name());
+ ui.id3v2EncComboBox->addItem(codec->name());
+ }
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.beginGroup("MAD");
+ int pos = ui.id3v1EncComboBox->findText
+ (settings.value("ID3v1_encoding","UTF-8").toString());
+ ui.id3v1EncComboBox->setCurrentIndex(pos);
+ pos = ui.id3v2EncComboBox->findText
+ (settings.value("ID3v2_encoding","UTF-8").toString());
+ ui.id3v2EncComboBox->setCurrentIndex(pos);
+
+ ui.firstTagComboBox->setCurrentIndex(settings.value("tag_1", ID3v2).toInt());
+ ui.secondTagComboBox->setCurrentIndex(settings.value("tag_2", Disabled).toInt());
+ ui.thirdTagComboBox->setCurrentIndex(settings.value("tag_3", Disabled).toInt());
+
+ settings.endGroup();
+ connect(ui.okButton, SIGNAL(clicked()), SLOT(writeSettings()));
+}
+
+
+SettingsDialog::~SettingsDialog()
+{}
+
+void SettingsDialog::writeSettings()
+{
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.beginGroup("MAD");
+ settings.setValue("ID3v1_encoding", ui.id3v1EncComboBox->currentText());
+ settings.setValue("ID3v2_encoding", ui.id3v2EncComboBox->currentText());
+ settings.setValue("tag_1", ui.firstTagComboBox->currentIndex());
+ settings.setValue("tag_2", ui.secondTagComboBox->currentIndex());
+ settings.setValue("tag_3", ui.thirdTagComboBox->currentIndex());
+ settings.endGroup();
+ accept();
+}
+
+void SettingsDialog::findCodecs()
+{
+ QMap<QString, QTextCodec *> codecMap;
+ QRegExp iso8859RegExp("ISO[- ]8859-([0-9]+).*");
+
+ foreach (int mib, QTextCodec::availableMibs())
+ {
+ QTextCodec *codec = QTextCodec::codecForMib(mib);
+
+ QString sortKey = codec->name().toUpper();
+ int rank;
+
+ if (sortKey.startsWith("UTF-8"))
+ {
+ rank = 1;
+ }
+ else if (sortKey.startsWith("UTF-16"))
+ {
+ rank = 2;
+ }
+ else if (iso8859RegExp.exactMatch(sortKey))
+ {
+ if (iso8859RegExp.cap(1).size() == 1)
+ rank = 3;
+ else
+ rank = 4;
+ }
+ else
+ {
+ rank = 5;
+ }
+ sortKey.prepend(QChar('0' + rank));
+
+ codecMap.insert(sortKey, codec);
+ }
+ codecs = codecMap.values();
+}
diff --git a/src/plugins/Input/mad/settingsdialog.h b/src/plugins/Input/mad/settingsdialog.h
new file mode 100644
index 000000000..2ad1ed188
--- /dev/null
+++ b/src/plugins/Input/mad/settingsdialog.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef SETTINGSDIALOG_H
+#define SETTINGSDIALOG_H
+
+#include <QDialog>
+
+
+#include "ui_settingsdialog.h"
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class SettingsDialog : public QDialog
+{
+Q_OBJECT
+public:
+ SettingsDialog(QWidget *parent = 0);
+
+ ~SettingsDialog();
+
+ enum TagType {ID3v1 = 0, ID3v2, APE, Disabled};
+
+private slots:
+ void writeSettings();
+
+private:
+ void findCodecs();
+
+ Ui::SettingsDialog ui;
+ QList<QTextCodec *> codecs;
+
+};
+
+#endif
diff --git a/src/plugins/Input/mad/settingsdialog.ui b/src/plugins/Input/mad/settingsdialog.ui
new file mode 100644
index 000000000..3ace8fcec
--- /dev/null
+++ b/src/plugins/Input/mad/settingsdialog.ui
@@ -0,0 +1,306 @@
+<ui version="4.0" >
+ <class>SettingsDialog</class>
+ <widget class="QDialog" name="SettingsDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>242</width>
+ <height>303</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>MPEG Plugin Settings</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QGroupBox" name="groupBox_2" >
+ <property name="title" >
+ <string>Tag Priority</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QLabel" name="label_15_2" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>First:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="firstTagComboBox" >
+ <property name="currentIndex" >
+ <number>0</number>
+ </property>
+ <item>
+ <property name="text" >
+ <string>ID3v1</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>ID3v2</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>APE</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Disabled</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QLabel" name="label_15_3" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Second:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="secondTagComboBox" >
+ <property name="currentIndex" >
+ <number>0</number>
+ </property>
+ <item>
+ <property name="text" >
+ <string>ID3v1</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>ID3v2</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>APE</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Disabled</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QLabel" name="label_15_4" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Third:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="thirdTagComboBox" >
+ <property name="currentIndex" >
+ <number>0</number>
+ </property>
+ <item>
+ <property name="text" >
+ <string>ID3v1</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>ID3v2</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>APE</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Disabled</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="title" >
+ <string>Encodings</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <property name="leftMargin" >
+ <number>0</number>
+ </property>
+ <property name="topMargin" >
+ <number>0</number>
+ </property>
+ <property name="rightMargin" >
+ <number>0</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_17_2_2" >
+ <property name="text" >
+ <string>ID3v1 encoding:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="id3v1EncComboBox" />
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <property name="leftMargin" >
+ <number>0</number>
+ </property>
+ <property name="topMargin" >
+ <number>0</number>
+ </property>
+ <property name="rightMargin" >
+ <number>0</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_18_2_2" >
+ <property name="text" >
+ <string>ID3v2 encoding:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="id3v2EncComboBox" />
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <property name="leftMargin" >
+ <number>0</number>
+ </property>
+ <property name="topMargin" >
+ <number>0</number>
+ </property>
+ <property name="rightMargin" >
+ <number>0</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>0</number>
+ </property>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>131</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="okButton" >
+ <property name="text" >
+ <string>OK</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelButton" >
+ <property name="text" >
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>cancelButton</sender>
+ <signal>clicked()</signal>
+ <receiver>SettingsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>336</x>
+ <y>210</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>179</x>
+ <y>224</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/Input/mad/translations/mad_plugin_ru.qm b/src/plugins/Input/mad/translations/mad_plugin_ru.qm
new file mode 100644
index 000000000..16bea746b
--- /dev/null
+++ b/src/plugins/Input/mad/translations/mad_plugin_ru.qm
Binary files differ
diff --git a/src/plugins/Input/mad/translations/mad_plugin_ru.ts b/src/plugins/Input/mad/translations/mad_plugin_ru.ts
new file mode 100644
index 000000000..6406f6045
--- /dev/null
+++ b/src/plugins/Input/mad/translations/mad_plugin_ru.ts
@@ -0,0 +1,242 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS><TS version="1.1" language="ru">
+<context>
+ <name>DecoderMADFactory</name>
+ <message>
+ <location filename="../decodermadfactory.cpp" line="27"/>
+ <source>MPEG Plugin</source>
+ <translation>Модуль MPEG</translation>
+ </message>
+ <message>
+ <location filename="../decodermadfactory.cpp" line="39"/>
+ <source>MPEG Files</source>
+ <translation>Файлы MPEG</translation>
+ </message>
+ <message>
+ <location filename="../decodermadfactory.cpp" line="68"/>
+ <source>About MPEG Audio Plugin</source>
+ <translation>Об аудио-модуле MPEG</translation>
+ </message>
+ <message>
+ <location filename="../decodermadfactory.cpp" line="69"/>
+ <source>Qmmp MPEG Audio Plugin</source>
+ <translation>Аудио-модуль MPEG для Qmmp</translation>
+ </message>
+ <message>
+ <location filename="../decodermadfactory.cpp" line="70"/>
+ <source>Compiled against libmad version:</source>
+ <translation>Собрано с версией libmad:</translation>
+ </message>
+ <message>
+ <location filename="../decodermadfactory.cpp" line="74"/>
+ <source>Writen by: Ilya Kotov &lt;forkotov02@hotmail.ru&gt;</source>
+ <translation>Разработчик: Илья Котов &lt;forkotov02@hotmail.ru&gt;</translation>
+ </message>
+ <message>
+ <location filename="../decodermadfactory.cpp" line="76"/>
+ <source>Source code based on mq3 progect</source>
+ <translation>Исходный код основан на проекте mq3</translation>
+ </message>
+</context>
+<context>
+ <name>DetailsDialog</name>
+ <message>
+ <location filename="../detailsdialog.cpp" line="79"/>
+ <source>Hz</source>
+ <translation>Гц</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.cpp" line="106"/>
+ <source>Yes</source>
+ <translation>Есть</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.cpp" line="108"/>
+ <source>No</source>
+ <translation>Нет</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="192"/>
+ <source>ID3v1 Tag</source>
+ <translation>ID3v1-тег</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="442"/>
+ <source>Save</source>
+ <translation>Сохранить</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="351"/>
+ <source>Track number:</source>
+ <translation>Номер трека:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="364"/>
+ <source>Year:</source>
+ <translation>Год:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="374"/>
+ <source>Genre:</source>
+ <translation>Жанр:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="384"/>
+ <source>Comment:</source>
+ <translation>Комментарий:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="394"/>
+ <source>Album:</source>
+ <translation>Альбом:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="404"/>
+ <source>Artist:</source>
+ <translation>Исполнитель:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="414"/>
+ <source>Title:</source>
+ <translation>Название:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="321"/>
+ <source>Close</source>
+ <translation>Закрыть</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="336"/>
+ <source>ID3v2 Tag</source>
+ <translation>ID3v2-тег</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="31"/>
+ <source>MPEG Info</source>
+ <translation>Информация MPEG</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="164"/>
+ <source>-</source>
+ <translation></translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="171"/>
+ <source>Original:</source>
+ <translation>Оригинальный:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="147"/>
+ <source>Copyright:</source>
+ <translation>Авторские права:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="137"/>
+ <source>Mode:</source>
+ <translation>Режим:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="59"/>
+ <source>File size:</source>
+ <translation>Размер файла:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="76"/>
+ <source>Sample rate:</source>
+ <translation>Дискретизация:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="86"/>
+ <source>Bit rate:</source>
+ <translation>Битовая частота:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="117"/>
+ <source>MPEG level:</source>
+ <translation>Уровень MPEG:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="452"/>
+ <source>File path:</source>
+ <translation>Путь к файлу:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.cpp" line="95"/>
+ <source>KB</source>
+ <translation>Кб</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="13"/>
+ <source>Details</source>
+ <translation>Информация</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.cpp" line="77"/>
+ <source>kbps</source>
+ <translation>Кб/с</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <location filename="../settingsdialog.ui" line="25"/>
+ <source>ID3 Tags</source>
+ <translation>ID3-теги</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="45"/>
+ <source>Default tag version:</source>
+ <translation>Версия тегов по умолчанию:</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="62"/>
+ <source>ID3v1</source>
+ <translation></translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="67"/>
+ <source>ID3v2</source>
+ <translation></translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="90"/>
+ <source>Enable ID3v1</source>
+ <translation>Использовать ID3v1</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="97"/>
+ <source>Enable ID3v2</source>
+ <translation>Использовать ID3v2</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="112"/>
+ <source>ID3v1 encoding:</source>
+ <translation>Кодировка ID3v1:</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="165"/>
+ <source>Default</source>
+ <translation>По-умолчанию</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="154"/>
+ <source>ID3v2 encoding:</source>
+ <translation>Кодировка ID3v2:</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="212"/>
+ <source>OK</source>
+ <translation>Применить</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="219"/>
+ <source>Cancel</source>
+ <translation>Отмена</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="13"/>
+ <source>MPEG Plugin Settings</source>
+ <translation>Настройка модуля MPEG</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/plugins/Input/mad/translations/translations.qrc b/src/plugins/Input/mad/translations/translations.qrc
new file mode 100644
index 000000000..34dbabbca
--- /dev/null
+++ b/src/plugins/Input/mad/translations/translations.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+ <qresource>
+ <file>mad_plugin_ru.qm</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/Input/mad/ui_detailsdialog.h b/src/plugins/Input/mad/ui_detailsdialog.h
new file mode 100644
index 000000000..d630be894
--- /dev/null
+++ b/src/plugins/Input/mad/ui_detailsdialog.h
@@ -0,0 +1,400 @@
+/********************************************************************************
+** Form generated from reading ui file 'detailsdialog.ui'
+**
+** Created: Thu Feb 7 00:21:43 2008
+** by: Qt User Interface Compiler version 4.3.0
+**
+** WARNING! All changes made in this file will be lost when recompiling ui file!
+********************************************************************************/
+
+#ifndef UI_DETAILSDIALOG_H
+#define UI_DETAILSDIALOG_H
+
+#include <QtCore/QVariant>
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QButtonGroup>
+#include <QtGui/QDialog>
+#include <QtGui/QGridLayout>
+#include <QtGui/QGroupBox>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QLabel>
+#include <QtGui/QLineEdit>
+#include <QtGui/QPushButton>
+#include <QtGui/QRadioButton>
+#include <QtGui/QSpacerItem>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QWidget>
+
+class Ui_DetailsDialog
+{
+public:
+ QGridLayout *gridLayout;
+ QHBoxLayout *hboxLayout;
+ QLabel *label_28;
+ QLineEdit *pathLineEdit;
+ QVBoxLayout *vboxLayout;
+ QGroupBox *groupBox_3;
+ QHBoxLayout *hboxLayout1;
+ QRadioButton *id3v1RadioButton;
+ QRadioButton *id3v2RadioButton;
+ QRadioButton *apeRadioButton;
+ QGroupBox *groupBox;
+ QGridLayout *gridLayout1;
+ QLabel *label;
+ QLabel *levelLabel;
+ QLabel *label_2;
+ QLabel *bitRateLabel;
+ QLabel *label_3;
+ QLabel *sampleRateLabel;
+ QLabel *label_5;
+ QLabel *fileSizeLabel;
+ QLabel *label_6;
+ QLabel *modeLabel;
+ QLabel *label_8;
+ QLabel *copyrightLabel;
+ QLabel *label_9;
+ QLabel *originalLabel;
+ QGroupBox *tagGroupBox;
+ QVBoxLayout *vboxLayout1;
+ QWidget *tagsWidget;
+ QGridLayout *gridLayout2;
+ QLabel *label_21;
+ QLineEdit *titleLineEdit;
+ QLabel *label_22;
+ QLineEdit *artistLineEdit;
+ QLabel *label_23;
+ QLineEdit *albumLineEdit;
+ QLabel *label_24;
+ QLineEdit *commentLineEdit;
+ QLabel *label_25;
+ QLineEdit *yearLineEdit;
+ QLabel *label_26;
+ QLineEdit *trackLineEdit;
+ QLabel *label_27;
+ QLineEdit *genreLineEdit;
+ QHBoxLayout *hboxLayout2;
+ QPushButton *createButton;
+ QPushButton *deleteButton;
+ QPushButton *saveButton;
+ QSpacerItem *spacerItem;
+ QPushButton *pushButton_3;
+
+ void setupUi(QDialog *DetailsDialog)
+ {
+ if (DetailsDialog->objectName().isEmpty())
+ DetailsDialog->setObjectName(QString::fromUtf8("DetailsDialog"));
+ QSize size(593, 402);
+ size = size.expandedTo(DetailsDialog->minimumSizeHint());
+ DetailsDialog->resize(size);
+ gridLayout = new QGridLayout(DetailsDialog);
+ gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
+ hboxLayout = new QHBoxLayout();
+ hboxLayout->setObjectName(QString::fromUtf8("hboxLayout"));
+ label_28 = new QLabel(DetailsDialog);
+ label_28->setObjectName(QString::fromUtf8("label_28"));
+ label_28->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter);
+
+ hboxLayout->addWidget(label_28);
+
+ pathLineEdit = new QLineEdit(DetailsDialog);
+ pathLineEdit->setObjectName(QString::fromUtf8("pathLineEdit"));
+ pathLineEdit->setReadOnly(true);
+
+ hboxLayout->addWidget(pathLineEdit);
+
+
+ gridLayout->addLayout(hboxLayout, 0, 0, 1, 3);
+
+ vboxLayout = new QVBoxLayout();
+ vboxLayout->setObjectName(QString::fromUtf8("vboxLayout"));
+ groupBox_3 = new QGroupBox(DetailsDialog);
+ groupBox_3->setObjectName(QString::fromUtf8("groupBox_3"));
+ QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ sizePolicy.setHorizontalStretch(0);
+ sizePolicy.setVerticalStretch(0);
+ sizePolicy.setHeightForWidth(groupBox_3->sizePolicy().hasHeightForWidth());
+ groupBox_3->setSizePolicy(sizePolicy);
+ hboxLayout1 = new QHBoxLayout(groupBox_3);
+ hboxLayout1->setObjectName(QString::fromUtf8("hboxLayout1"));
+ id3v1RadioButton = new QRadioButton(groupBox_3);
+ id3v1RadioButton->setObjectName(QString::fromUtf8("id3v1RadioButton"));
+
+ hboxLayout1->addWidget(id3v1RadioButton);
+
+ id3v2RadioButton = new QRadioButton(groupBox_3);
+ id3v2RadioButton->setObjectName(QString::fromUtf8("id3v2RadioButton"));
+
+ hboxLayout1->addWidget(id3v2RadioButton);
+
+ apeRadioButton = new QRadioButton(groupBox_3);
+ apeRadioButton->setObjectName(QString::fromUtf8("apeRadioButton"));
+
+ hboxLayout1->addWidget(apeRadioButton);
+
+
+ vboxLayout->addWidget(groupBox_3);
+
+ groupBox = new QGroupBox(DetailsDialog);
+ groupBox->setObjectName(QString::fromUtf8("groupBox"));
+ groupBox->setMinimumSize(QSize(200, 16));
+ gridLayout1 = new QGridLayout(groupBox);
+ gridLayout1->setObjectName(QString::fromUtf8("gridLayout1"));
+ label = new QLabel(groupBox);
+ label->setObjectName(QString::fromUtf8("label"));
+ label->setTextFormat(Qt::AutoText);
+ label->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ gridLayout1->addWidget(label, 0, 0, 1, 1);
+
+ levelLabel = new QLabel(groupBox);
+ levelLabel->setObjectName(QString::fromUtf8("levelLabel"));
+
+ gridLayout1->addWidget(levelLabel, 0, 1, 1, 1);
+
+ label_2 = new QLabel(groupBox);
+ label_2->setObjectName(QString::fromUtf8("label_2"));
+ label_2->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ gridLayout1->addWidget(label_2, 1, 0, 1, 1);
+
+ bitRateLabel = new QLabel(groupBox);
+ bitRateLabel->setObjectName(QString::fromUtf8("bitRateLabel"));
+
+ gridLayout1->addWidget(bitRateLabel, 1, 1, 1, 1);
+
+ label_3 = new QLabel(groupBox);
+ label_3->setObjectName(QString::fromUtf8("label_3"));
+ label_3->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ gridLayout1->addWidget(label_3, 2, 0, 1, 1);
+
+ sampleRateLabel = new QLabel(groupBox);
+ sampleRateLabel->setObjectName(QString::fromUtf8("sampleRateLabel"));
+
+ gridLayout1->addWidget(sampleRateLabel, 2, 1, 1, 1);
+
+ label_5 = new QLabel(groupBox);
+ label_5->setObjectName(QString::fromUtf8("label_5"));
+ label_5->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ gridLayout1->addWidget(label_5, 3, 0, 1, 1);
+
+ fileSizeLabel = new QLabel(groupBox);
+ fileSizeLabel->setObjectName(QString::fromUtf8("fileSizeLabel"));
+
+ gridLayout1->addWidget(fileSizeLabel, 3, 1, 1, 1);
+
+ label_6 = new QLabel(groupBox);
+ label_6->setObjectName(QString::fromUtf8("label_6"));
+ label_6->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ gridLayout1->addWidget(label_6, 4, 0, 1, 1);
+
+ modeLabel = new QLabel(groupBox);
+ modeLabel->setObjectName(QString::fromUtf8("modeLabel"));
+
+ gridLayout1->addWidget(modeLabel, 4, 1, 1, 1);
+
+ label_8 = new QLabel(groupBox);
+ label_8->setObjectName(QString::fromUtf8("label_8"));
+ label_8->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ gridLayout1->addWidget(label_8, 5, 0, 1, 1);
+
+ copyrightLabel = new QLabel(groupBox);
+ copyrightLabel->setObjectName(QString::fromUtf8("copyrightLabel"));
+
+ gridLayout1->addWidget(copyrightLabel, 5, 1, 1, 1);
+
+ label_9 = new QLabel(groupBox);
+ label_9->setObjectName(QString::fromUtf8("label_9"));
+ label_9->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ gridLayout1->addWidget(label_9, 6, 0, 1, 1);
+
+ originalLabel = new QLabel(groupBox);
+ originalLabel->setObjectName(QString::fromUtf8("originalLabel"));
+
+ gridLayout1->addWidget(originalLabel, 6, 1, 1, 1);
+
+
+ vboxLayout->addWidget(groupBox);
+
+
+ gridLayout->addLayout(vboxLayout, 1, 0, 2, 1);
+
+ tagGroupBox = new QGroupBox(DetailsDialog);
+ tagGroupBox->setObjectName(QString::fromUtf8("tagGroupBox"));
+ vboxLayout1 = new QVBoxLayout(tagGroupBox);
+ vboxLayout1->setObjectName(QString::fromUtf8("vboxLayout1"));
+ tagsWidget = new QWidget(tagGroupBox);
+ tagsWidget->setObjectName(QString::fromUtf8("tagsWidget"));
+ tagsWidget->setEnabled(true);
+ gridLayout2 = new QGridLayout(tagsWidget);
+ gridLayout2->setObjectName(QString::fromUtf8("gridLayout2"));
+ label_21 = new QLabel(tagsWidget);
+ label_21->setObjectName(QString::fromUtf8("label_21"));
+ label_21->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ gridLayout2->addWidget(label_21, 0, 0, 1, 1);
+
+ titleLineEdit = new QLineEdit(tagsWidget);
+ titleLineEdit->setObjectName(QString::fromUtf8("titleLineEdit"));
+
+ gridLayout2->addWidget(titleLineEdit, 0, 1, 1, 3);
+
+ label_22 = new QLabel(tagsWidget);
+ label_22->setObjectName(QString::fromUtf8("label_22"));
+ label_22->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ gridLayout2->addWidget(label_22, 1, 0, 1, 1);
+
+ artistLineEdit = new QLineEdit(tagsWidget);
+ artistLineEdit->setObjectName(QString::fromUtf8("artistLineEdit"));
+
+ gridLayout2->addWidget(artistLineEdit, 1, 1, 1, 3);
+
+ label_23 = new QLabel(tagsWidget);
+ label_23->setObjectName(QString::fromUtf8("label_23"));
+ label_23->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ gridLayout2->addWidget(label_23, 2, 0, 1, 1);
+
+ albumLineEdit = new QLineEdit(tagsWidget);
+ albumLineEdit->setObjectName(QString::fromUtf8("albumLineEdit"));
+
+ gridLayout2->addWidget(albumLineEdit, 2, 1, 1, 3);
+
+ label_24 = new QLabel(tagsWidget);
+ label_24->setObjectName(QString::fromUtf8("label_24"));
+ label_24->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ gridLayout2->addWidget(label_24, 3, 0, 1, 1);
+
+ commentLineEdit = new QLineEdit(tagsWidget);
+ commentLineEdit->setObjectName(QString::fromUtf8("commentLineEdit"));
+
+ gridLayout2->addWidget(commentLineEdit, 3, 1, 1, 3);
+
+ label_25 = new QLabel(tagsWidget);
+ label_25->setObjectName(QString::fromUtf8("label_25"));
+ label_25->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ gridLayout2->addWidget(label_25, 4, 0, 1, 1);
+
+ yearLineEdit = new QLineEdit(tagsWidget);
+ yearLineEdit->setObjectName(QString::fromUtf8("yearLineEdit"));
+
+ gridLayout2->addWidget(yearLineEdit, 4, 1, 1, 1);
+
+ label_26 = new QLabel(tagsWidget);
+ label_26->setObjectName(QString::fromUtf8("label_26"));
+ label_26->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ gridLayout2->addWidget(label_26, 4, 2, 1, 1);
+
+ trackLineEdit = new QLineEdit(tagsWidget);
+ trackLineEdit->setObjectName(QString::fromUtf8("trackLineEdit"));
+
+ gridLayout2->addWidget(trackLineEdit, 4, 3, 1, 1);
+
+ label_27 = new QLabel(tagsWidget);
+ label_27->setObjectName(QString::fromUtf8("label_27"));
+ label_27->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ gridLayout2->addWidget(label_27, 5, 0, 1, 1);
+
+ genreLineEdit = new QLineEdit(tagsWidget);
+ genreLineEdit->setObjectName(QString::fromUtf8("genreLineEdit"));
+
+ gridLayout2->addWidget(genreLineEdit, 5, 1, 1, 3);
+
+
+ vboxLayout1->addWidget(tagsWidget);
+
+ hboxLayout2 = new QHBoxLayout();
+ hboxLayout2->setObjectName(QString::fromUtf8("hboxLayout2"));
+ createButton = new QPushButton(tagGroupBox);
+ createButton->setObjectName(QString::fromUtf8("createButton"));
+
+ hboxLayout2->addWidget(createButton);
+
+ deleteButton = new QPushButton(tagGroupBox);
+ deleteButton->setObjectName(QString::fromUtf8("deleteButton"));
+
+ hboxLayout2->addWidget(deleteButton);
+
+ saveButton = new QPushButton(tagGroupBox);
+ saveButton->setObjectName(QString::fromUtf8("saveButton"));
+ saveButton->setEnabled(false);
+
+ hboxLayout2->addWidget(saveButton);
+
+
+ vboxLayout1->addLayout(hboxLayout2);
+
+
+ gridLayout->addWidget(tagGroupBox, 1, 1, 1, 2);
+
+ spacerItem = new QSpacerItem(111, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
+
+ gridLayout->addItem(spacerItem, 2, 1, 1, 1);
+
+ pushButton_3 = new QPushButton(DetailsDialog);
+ pushButton_3->setObjectName(QString::fromUtf8("pushButton_3"));
+
+ gridLayout->addWidget(pushButton_3, 2, 2, 1, 1);
+
+
+ retranslateUi(DetailsDialog);
+ QObject::connect(pushButton_3, SIGNAL(clicked()), DetailsDialog, SLOT(close()));
+
+ QMetaObject::connectSlotsByName(DetailsDialog);
+ } // setupUi
+
+ void retranslateUi(QDialog *DetailsDialog)
+ {
+ DetailsDialog->setWindowTitle(QApplication::translate("DetailsDialog", "Details", 0, QApplication::UnicodeUTF8));
+ label_28->setText(QApplication::translate("DetailsDialog", "File path:", 0, QApplication::UnicodeUTF8));
+ groupBox_3->setTitle(QApplication::translate("DetailsDialog", "Tag Choice", 0, QApplication::UnicodeUTF8));
+ id3v1RadioButton->setText(QApplication::translate("DetailsDialog", "ID3v1", 0, QApplication::UnicodeUTF8));
+ id3v2RadioButton->setText(QApplication::translate("DetailsDialog", "ID3v2", 0, QApplication::UnicodeUTF8));
+ apeRadioButton->setText(QApplication::translate("DetailsDialog", "APE", 0, QApplication::UnicodeUTF8));
+ groupBox->setTitle(QApplication::translate("DetailsDialog", "MPEG Info", 0, QApplication::UnicodeUTF8));
+ label->setText(QApplication::translate("DetailsDialog", "MPEG level:", 0, QApplication::UnicodeUTF8));
+ levelLabel->setText(QApplication::translate("DetailsDialog", "-", 0, QApplication::UnicodeUTF8));
+ label_2->setText(QApplication::translate("DetailsDialog", "Bit rate:", 0, QApplication::UnicodeUTF8));
+ bitRateLabel->setText(QApplication::translate("DetailsDialog", "-", 0, QApplication::UnicodeUTF8));
+ label_3->setText(QApplication::translate("DetailsDialog", "Sample rate:", 0, QApplication::UnicodeUTF8));
+ sampleRateLabel->setText(QApplication::translate("DetailsDialog", "-", 0, QApplication::UnicodeUTF8));
+ label_5->setText(QApplication::translate("DetailsDialog", "File size:", 0, QApplication::UnicodeUTF8));
+ fileSizeLabel->setText(QApplication::translate("DetailsDialog", "-", 0, QApplication::UnicodeUTF8));
+ label_6->setText(QApplication::translate("DetailsDialog", "Mode:", 0, QApplication::UnicodeUTF8));
+ modeLabel->setText(QApplication::translate("DetailsDialog", "-", 0, QApplication::UnicodeUTF8));
+ label_8->setText(QApplication::translate("DetailsDialog", "Copyright:", 0, QApplication::UnicodeUTF8));
+ copyrightLabel->setText(QApplication::translate("DetailsDialog", "-", 0, QApplication::UnicodeUTF8));
+ label_9->setText(QApplication::translate("DetailsDialog", "Original:", 0, QApplication::UnicodeUTF8));
+ originalLabel->setText(QApplication::translate("DetailsDialog", "-", 0, QApplication::UnicodeUTF8));
+ tagGroupBox->setTitle(QApplication::translate("DetailsDialog", "ID3v1 Tag", 0, QApplication::UnicodeUTF8));
+ label_21->setText(QApplication::translate("DetailsDialog", "Title:", 0, QApplication::UnicodeUTF8));
+ label_22->setText(QApplication::translate("DetailsDialog", "Artist:", 0, QApplication::UnicodeUTF8));
+ label_23->setText(QApplication::translate("DetailsDialog", "Album:", 0, QApplication::UnicodeUTF8));
+ label_24->setText(QApplication::translate("DetailsDialog", "Comment:", 0, QApplication::UnicodeUTF8));
+ label_25->setText(QApplication::translate("DetailsDialog", "Year:", 0, QApplication::UnicodeUTF8));
+ label_26->setText(QApplication::translate("DetailsDialog", "Track number:", 0, QApplication::UnicodeUTF8));
+ label_27->setText(QApplication::translate("DetailsDialog", "Genre:", 0, QApplication::UnicodeUTF8));
+ createButton->setText(QApplication::translate("DetailsDialog", "Create", 0, QApplication::UnicodeUTF8));
+ deleteButton->setText(QApplication::translate("DetailsDialog", "Delete", 0, QApplication::UnicodeUTF8));
+ saveButton->setText(QApplication::translate("DetailsDialog", "Save", 0, QApplication::UnicodeUTF8));
+ pushButton_3->setText(QApplication::translate("DetailsDialog", "Close", 0, QApplication::UnicodeUTF8));
+ Q_UNUSED(DetailsDialog);
+ } // retranslateUi
+
+};
+
+namespace Ui {
+ class DetailsDialog: public Ui_DetailsDialog {};
+} // namespace Ui
+
+#endif // UI_DETAILSDIALOG_H
diff --git a/src/plugins/Input/mad/ui_settingsdialog.h b/src/plugins/Input/mad/ui_settingsdialog.h
new file mode 100644
index 000000000..47cdac64f
--- /dev/null
+++ b/src/plugins/Input/mad/ui_settingsdialog.h
@@ -0,0 +1,245 @@
+/********************************************************************************
+** Form generated from reading ui file 'settingsdialog.ui'
+**
+** Created: Thu Feb 7 00:21:43 2008
+** by: Qt User Interface Compiler version 4.3.0
+**
+** WARNING! All changes made in this file will be lost when recompiling ui file!
+********************************************************************************/
+
+#ifndef UI_SETTINGSDIALOG_H
+#define UI_SETTINGSDIALOG_H
+
+#include <QtCore/QVariant>
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QButtonGroup>
+#include <QtGui/QComboBox>
+#include <QtGui/QDialog>
+#include <QtGui/QGroupBox>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QLabel>
+#include <QtGui/QPushButton>
+#include <QtGui/QSpacerItem>
+#include <QtGui/QVBoxLayout>
+
+class Ui_SettingsDialog
+{
+public:
+ QVBoxLayout *vboxLayout;
+ QGroupBox *groupBox_2;
+ QVBoxLayout *vboxLayout1;
+ QHBoxLayout *hboxLayout;
+ QLabel *label_15_2;
+ QComboBox *firstTagComboBox;
+ QHBoxLayout *hboxLayout1;
+ QLabel *label_15_3;
+ QComboBox *secondTagComboBox;
+ QHBoxLayout *hboxLayout2;
+ QLabel *label_15_4;
+ QComboBox *thirdTagComboBox;
+ QGroupBox *groupBox;
+ QVBoxLayout *vboxLayout2;
+ QHBoxLayout *hboxLayout3;
+ QLabel *label_17_2_2;
+ QComboBox *id3v1EncComboBox;
+ QHBoxLayout *hboxLayout4;
+ QLabel *label_18_2_2;
+ QComboBox *id3v2EncComboBox;
+ QHBoxLayout *hboxLayout5;
+ QSpacerItem *spacerItem;
+ QPushButton *okButton;
+ QPushButton *cancelButton;
+
+ void setupUi(QDialog *SettingsDialog)
+ {
+ if (SettingsDialog->objectName().isEmpty())
+ SettingsDialog->setObjectName(QString::fromUtf8("SettingsDialog"));
+ QSize size(242, 303);
+ size = size.expandedTo(SettingsDialog->minimumSizeHint());
+ SettingsDialog->resize(size);
+ vboxLayout = new QVBoxLayout(SettingsDialog);
+ vboxLayout->setObjectName(QString::fromUtf8("vboxLayout"));
+ groupBox_2 = new QGroupBox(SettingsDialog);
+ groupBox_2->setObjectName(QString::fromUtf8("groupBox_2"));
+ vboxLayout1 = new QVBoxLayout(groupBox_2);
+ vboxLayout1->setObjectName(QString::fromUtf8("vboxLayout1"));
+ hboxLayout = new QHBoxLayout();
+ hboxLayout->setObjectName(QString::fromUtf8("hboxLayout"));
+ label_15_2 = new QLabel(groupBox_2);
+ label_15_2->setObjectName(QString::fromUtf8("label_15_2"));
+ QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ sizePolicy.setHorizontalStretch(0);
+ sizePolicy.setVerticalStretch(0);
+ sizePolicy.setHeightForWidth(label_15_2->sizePolicy().hasHeightForWidth());
+ label_15_2->setSizePolicy(sizePolicy);
+ label_15_2->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ hboxLayout->addWidget(label_15_2);
+
+ firstTagComboBox = new QComboBox(groupBox_2);
+ firstTagComboBox->setObjectName(QString::fromUtf8("firstTagComboBox"));
+
+ hboxLayout->addWidget(firstTagComboBox);
+
+
+ vboxLayout1->addLayout(hboxLayout);
+
+ hboxLayout1 = new QHBoxLayout();
+ hboxLayout1->setObjectName(QString::fromUtf8("hboxLayout1"));
+ label_15_3 = new QLabel(groupBox_2);
+ label_15_3->setObjectName(QString::fromUtf8("label_15_3"));
+ sizePolicy.setHeightForWidth(label_15_3->sizePolicy().hasHeightForWidth());
+ label_15_3->setSizePolicy(sizePolicy);
+ label_15_3->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ hboxLayout1->addWidget(label_15_3);
+
+ secondTagComboBox = new QComboBox(groupBox_2);
+ secondTagComboBox->setObjectName(QString::fromUtf8("secondTagComboBox"));
+
+ hboxLayout1->addWidget(secondTagComboBox);
+
+
+ vboxLayout1->addLayout(hboxLayout1);
+
+ hboxLayout2 = new QHBoxLayout();
+ hboxLayout2->setObjectName(QString::fromUtf8("hboxLayout2"));
+ label_15_4 = new QLabel(groupBox_2);
+ label_15_4->setObjectName(QString::fromUtf8("label_15_4"));
+ sizePolicy.setHeightForWidth(label_15_4->sizePolicy().hasHeightForWidth());
+ label_15_4->setSizePolicy(sizePolicy);
+ label_15_4->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ hboxLayout2->addWidget(label_15_4);
+
+ thirdTagComboBox = new QComboBox(groupBox_2);
+ thirdTagComboBox->setObjectName(QString::fromUtf8("thirdTagComboBox"));
+
+ hboxLayout2->addWidget(thirdTagComboBox);
+
+
+ vboxLayout1->addLayout(hboxLayout2);
+
+
+ vboxLayout->addWidget(groupBox_2);
+
+ groupBox = new QGroupBox(SettingsDialog);
+ groupBox->setObjectName(QString::fromUtf8("groupBox"));
+ vboxLayout2 = new QVBoxLayout(groupBox);
+ vboxLayout2->setObjectName(QString::fromUtf8("vboxLayout2"));
+ hboxLayout3 = new QHBoxLayout();
+ hboxLayout3->setSpacing(6);
+ hboxLayout3->setObjectName(QString::fromUtf8("hboxLayout3"));
+ hboxLayout3->setContentsMargins(0, 0, 0, 0);
+ label_17_2_2 = new QLabel(groupBox);
+ label_17_2_2->setObjectName(QString::fromUtf8("label_17_2_2"));
+ label_17_2_2->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ hboxLayout3->addWidget(label_17_2_2);
+
+ id3v1EncComboBox = new QComboBox(groupBox);
+ id3v1EncComboBox->setObjectName(QString::fromUtf8("id3v1EncComboBox"));
+
+ hboxLayout3->addWidget(id3v1EncComboBox);
+
+
+ vboxLayout2->addLayout(hboxLayout3);
+
+ hboxLayout4 = new QHBoxLayout();
+ hboxLayout4->setSpacing(6);
+ hboxLayout4->setObjectName(QString::fromUtf8("hboxLayout4"));
+ hboxLayout4->setContentsMargins(0, 0, 0, 0);
+ label_18_2_2 = new QLabel(groupBox);
+ label_18_2_2->setObjectName(QString::fromUtf8("label_18_2_2"));
+ label_18_2_2->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
+
+ hboxLayout4->addWidget(label_18_2_2);
+
+ id3v2EncComboBox = new QComboBox(groupBox);
+ id3v2EncComboBox->setObjectName(QString::fromUtf8("id3v2EncComboBox"));
+
+ hboxLayout4->addWidget(id3v2EncComboBox);
+
+
+ vboxLayout2->addLayout(hboxLayout4);
+
+
+ vboxLayout->addWidget(groupBox);
+
+ hboxLayout5 = new QHBoxLayout();
+ hboxLayout5->setSpacing(6);
+ hboxLayout5->setObjectName(QString::fromUtf8("hboxLayout5"));
+ hboxLayout5->setContentsMargins(0, 0, 0, 0);
+ spacerItem = new QSpacerItem(131, 31, QSizePolicy::Expanding, QSizePolicy::Minimum);
+
+ hboxLayout5->addItem(spacerItem);
+
+ okButton = new QPushButton(SettingsDialog);
+ okButton->setObjectName(QString::fromUtf8("okButton"));
+
+ hboxLayout5->addWidget(okButton);
+
+ cancelButton = new QPushButton(SettingsDialog);
+ cancelButton->setObjectName(QString::fromUtf8("cancelButton"));
+
+ hboxLayout5->addWidget(cancelButton);
+
+
+ vboxLayout->addLayout(hboxLayout5);
+
+
+ retranslateUi(SettingsDialog);
+ QObject::connect(cancelButton, SIGNAL(clicked()), SettingsDialog, SLOT(reject()));
+
+ firstTagComboBox->setCurrentIndex(0);
+ secondTagComboBox->setCurrentIndex(0);
+ thirdTagComboBox->setCurrentIndex(0);
+
+
+ QMetaObject::connectSlotsByName(SettingsDialog);
+ } // setupUi
+
+ void retranslateUi(QDialog *SettingsDialog)
+ {
+ SettingsDialog->setWindowTitle(QApplication::translate("SettingsDialog", "MPEG Plugin Settings", 0, QApplication::UnicodeUTF8));
+ groupBox_2->setTitle(QApplication::translate("SettingsDialog", "Tag Priority", 0, QApplication::UnicodeUTF8));
+ label_15_2->setText(QApplication::translate("SettingsDialog", "First:", 0, QApplication::UnicodeUTF8));
+ firstTagComboBox->clear();
+ firstTagComboBox->insertItems(0, QStringList()
+ << QApplication::translate("SettingsDialog", "ID3v1", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("SettingsDialog", "ID3v2", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("SettingsDialog", "APE", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("SettingsDialog", "Disabled", 0, QApplication::UnicodeUTF8)
+ );
+ label_15_3->setText(QApplication::translate("SettingsDialog", "Second:", 0, QApplication::UnicodeUTF8));
+ secondTagComboBox->clear();
+ secondTagComboBox->insertItems(0, QStringList()
+ << QApplication::translate("SettingsDialog", "ID3v1", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("SettingsDialog", "ID3v2", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("SettingsDialog", "APE", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("SettingsDialog", "Disabled", 0, QApplication::UnicodeUTF8)
+ );
+ label_15_4->setText(QApplication::translate("SettingsDialog", "Third:", 0, QApplication::UnicodeUTF8));
+ thirdTagComboBox->clear();
+ thirdTagComboBox->insertItems(0, QStringList()
+ << QApplication::translate("SettingsDialog", "ID3v1", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("SettingsDialog", "ID3v2", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("SettingsDialog", "APE", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("SettingsDialog", "Disabled", 0, QApplication::UnicodeUTF8)
+ );
+ groupBox->setTitle(QApplication::translate("SettingsDialog", "Encodings", 0, QApplication::UnicodeUTF8));
+ label_17_2_2->setText(QApplication::translate("SettingsDialog", "ID3v1 encoding:", 0, QApplication::UnicodeUTF8));
+ label_18_2_2->setText(QApplication::translate("SettingsDialog", "ID3v2 encoding:", 0, QApplication::UnicodeUTF8));
+ okButton->setText(QApplication::translate("SettingsDialog", "OK", 0, QApplication::UnicodeUTF8));
+ cancelButton->setText(QApplication::translate("SettingsDialog", "Cancel", 0, QApplication::UnicodeUTF8));
+ Q_UNUSED(SettingsDialog);
+ } // retranslateUi
+
+};
+
+namespace Ui {
+ class SettingsDialog: public Ui_SettingsDialog {};
+} // namespace Ui
+
+#endif // UI_SETTINGSDIALOG_H
diff --git a/src/plugins/Input/mpc/CMakeLists.txt b/src/plugins/Input/mpc/CMakeLists.txt
new file mode 100644
index 000000000..dccd6dd6b
--- /dev/null
+++ b/src/plugins/Input/mpc/CMakeLists.txt
@@ -0,0 +1,86 @@
+project(libmpc)
+
+cmake_minimum_required(VERSION 2.4.0)
+
+
+INCLUDE(UsePkgConfig)
+INCLUDE(FindQt4)
+
+find_package(Qt4 REQUIRED) # find and setup Qt4 for this project
+include(${QT_USE_FILE})
+
+# qt plugin
+ADD_DEFINITIONS( -Wall )
+ADD_DEFINITIONS(${QT_DEFINITIONS})
+ADD_DEFINITIONS(-DQT_PLUGIN)
+ADD_DEFINITIONS(-DQT_NO_DEBUG)
+ADD_DEFINITIONS(-DQT_SHARED)
+ADD_DEFINITIONS(-DQT_THREAD)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+SET(QT_INCLUDES
+ ${QT_INCLUDES}
+ ${CMAKE_CURRENT_BINARY_DIR}/../../../
+)
+
+# libqmmp
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+link_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+
+# libmpc and taglib
+PKGCONFIG(taglib TAGLIB_INCLUDE_DIR TAGLIB_LINK_DIR TAGLIB_LINK_FLAGS TAGLIB_CFLAGS)
+
+IF(NOT TAGLIB_LINK_FLAGS)
+ SET(TAGLIB_LINK_FLAGS -ltag)
+ SET(TAGLIB_INCLUDE_DIR /usr/include/taglib)
+ SET(TAGLIB_CFLAGS -I/usr/include/taglib)
+ENDIF(NOT TAGLIB_LINK_FLAGS)
+
+include_directories(${FLAC_INCLUDE_DIR} ${TAGLIB_INCLUDE_DIR})
+link_directories(${FLAC_LINK_DIR} ${TAGLIB_LINK_DIR})
+
+ADD_DEFINITIONS(${TAGLIB_CFLAGS})
+
+
+SET(libmpc_SRCS
+ decoder_mpc.cpp
+ decodermpcfactory.cpp
+ detailsdialog.cpp
+)
+
+SET(libmpc_MOC_HDRS
+ decodermpcfactory.h
+ decoder_mpc.h
+ detailsdialog.h
+)
+
+SET(libmpc_RCCS translations/translations.qrc)
+
+QT4_ADD_RESOURCES(libmpc_RCC_SRCS ${libmpc_RCCS})
+
+QT4_WRAP_CPP(libmpc_MOC_SRCS ${libmpc_MOC_HDRS})
+
+# user interface
+
+
+SET(libmpc_UIS
+ detailsdialog.ui
+)
+
+QT4_WRAP_UI(libmpc_UIS_H ${libmpc_UIS})
+# Don't forget to include output directory, otherwise
+# the UI file won't be wrapped!
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+ADD_LIBRARY(mpc SHARED ${libmpc_SRCS} ${libmpc_MOC_SRCS} ${libmpc_UIS_H}
+ ${libmpc_RCC_SRCS})
+target_link_libraries(mpc ${QT_LIBRARIES} -lqmmp -lmpcdec ${TAGLIB_LINK_FLAGS} ${TAGLIB_CFLAGS})
+install(TARGETS mpc DESTINATION ${LIB_DIR}/qmmp/Input PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ)
+
+# clean remaining files
+
+SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES
+ "CMakeCache.txt;Makefile;cmake_install.cmake"
+)
+
diff --git a/src/plugins/Input/mpc/Makefile b/src/plugins/Input/mpc/Makefile
new file mode 100644
index 000000000..7aa3ee7b3
--- /dev/null
+++ b/src/plugins/Input/mpc/Makefile
@@ -0,0 +1,254 @@
+#############################################################################
+# Makefile for building: libmpc.so
+# Generated by qmake (2.01a) (Qt 4.3.1) on: Thu Feb 7 14:07:02 2008
+# Project: mpc.pro
+# Template: lib
+# Command: /usr/local/Trolltech/Qt-4.3.1/bin/qmake -unix -o Makefile mpc.pro
+#############################################################################
+
+####### Compiler, tools and options
+
+CC = gcc
+CXX = g++
+DEFINES = -DQT_NO_DEBUG -DQT_PLUGIN -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED
+CFLAGS = -pipe -O2 -I/usr/include/taglib -Wall -W -D_REENTRANT -fPIC $(DEFINES)
+CXXFLAGS = -pipe -O2 -I/usr/include/taglib -Wall -W -D_REENTRANT -fPIC $(DEFINES)
+INCPATH = -I/usr/local/Trolltech/Qt-4.3.1/mkspecs/linux-g++ -I. -I/usr/local/Trolltech/Qt-4.3.1/include/QtCore -I/usr/local/Trolltech/Qt-4.3.1/include/QtCore -I/usr/local/Trolltech/Qt-4.3.1/include/QtGui -I/usr/local/Trolltech/Qt-4.3.1/include/QtGui -I/usr/local/Trolltech/Qt-4.3.1/include -I../../../qmmp -I.build/moc -I.build/ui
+LINK = g++
+LFLAGS = -Wl,-rpath,/usr/local/Trolltech/Qt-4.3.1/lib -shared
+LIBS = $(SUBLIBS) -L../../../../lib -L/usr/local/Trolltech/Qt-4.3.1/lib -lqmmp -L/usr/lib -lmpcdec -I/usr/include -ltag -lQtGui -L/usr/local/Trolltech/Qt-4.3.1/lib -L/usr/X11R6/lib -lpng -lSM -lICE -pthread -pthread -lXi -lXrender -lXrandr -lXfixes -lXcursor -lXinerama -lfreetype -lfontconfig -lXext -lX11 -lQtCore -lz -lm -pthread -lgthread-2.0 -lglib-2.0 -lrt -ldl -lpthread
+AR = ar cqs
+RANLIB =
+QMAKE = /usr/local/Trolltech/Qt-4.3.1/bin/qmake
+TAR = tar -cf
+COMPRESS = gzip -9f
+COPY = cp -f
+SED = sed
+COPY_FILE = $(COPY)
+COPY_DIR = $(COPY) -r
+INSTALL_FILE = install -m 644 -p
+INSTALL_DIR = $(COPY_DIR)
+INSTALL_PROGRAM = install -m 755 -p
+DEL_FILE = rm -f
+SYMLINK = ln -sf
+DEL_DIR = rmdir
+MOVE = mv -f
+CHK_DIR_EXISTS= test -d
+MKDIR = mkdir -p
+
+####### Output directory
+
+OBJECTS_DIR = .build/obj/
+
+####### Files
+
+SOURCES = decoder_mpc.cpp \
+ decodermpcfactory.cpp \
+ detailsdialog.cpp .build/moc/moc_decodermpcfactory.cpp \
+ .build/moc/moc_detailsdialog.cpp
+OBJECTS = .build/obj/decoder_mpc.o \
+ .build/obj/decodermpcfactory.o \
+ .build/obj/detailsdialog.o \
+ .build/obj/moc_decodermpcfactory.o \
+ .build/obj/moc_detailsdialog.o
+DIST = /usr/local/Trolltech/Qt-4.3.1/mkspecs/common/g++.conf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/common/unix.conf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/common/linux.conf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/qconfig.pri \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/qt_functions.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/qt_config.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/exclusive_builds.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/default_pre.prf \
+ ../../../../qmmp.pri \
+ ../../plugins.pri \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/release.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/default_post.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/link_pkgconfig.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/warn_on.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/qt.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/unix/thread.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/moc.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/resources.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/uic.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/yacc.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/lex.prf \
+ mpc.pro
+QMAKE_TARGET = mpc
+DESTDIR = ../../../../lib/qmmp/Input/
+TARGET = libmpc.so
+TARGETD = libmpc.so
+
+first: all
+####### Implicit rules
+
+.SUFFIXES: .o .c .cpp .cc .cxx .C
+
+.cpp.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.cc.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.cxx.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.C.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(INCPATH) -o "$@" "$<"
+
+####### Build rules
+
+all: Makefile ../../../../lib/qmmp/Input/$(TARGET)
+
+../../../../lib/qmmp/Input/$(TARGET): .build/ui/ui_detailsdialog.h $(OBJECTS) $(SUBLIBS) $(OBJCOMP)
+ @$(CHK_DIR_EXISTS) ../../../../lib/qmmp/Input/ || $(MKDIR) ../../../../lib/qmmp/Input/
+ -$(DEL_FILE) $(TARGET)
+ $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) $(OBJCOMP)
+ -$(MOVE) $(TARGET) ../../../../lib/qmmp/Input/
+
+
+
+Makefile: mpc.pro /usr/local/Trolltech/Qt-4.3.1/mkspecs/linux-g++/qmake.conf /usr/local/Trolltech/Qt-4.3.1/mkspecs/common/g++.conf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/common/unix.conf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/common/linux.conf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/qconfig.pri \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/qt_functions.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/qt_config.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/exclusive_builds.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/default_pre.prf \
+ ../../../../qmmp.pri \
+ ../../plugins.pri \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/release.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/default_post.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/link_pkgconfig.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/warn_on.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/qt.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/unix/thread.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/moc.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/resources.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/uic.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/yacc.prf \
+ /usr/local/Trolltech/Qt-4.3.1/mkspecs/features/lex.prf \
+ /usr/local/Trolltech/Qt-4.3.1/lib/libQtGui.prl \
+ /usr/local/Trolltech/Qt-4.3.1/lib/libQtCore.prl
+ $(QMAKE) -unix -o Makefile mpc.pro
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/common/g++.conf:
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/common/unix.conf:
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/common/linux.conf:
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/qconfig.pri:
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/features/qt_functions.prf:
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/features/qt_config.prf:
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/features/exclusive_builds.prf:
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/features/default_pre.prf:
+../../../../qmmp.pri:
+../../plugins.pri:
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/features/release.prf:
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/features/default_post.prf:
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/features/link_pkgconfig.prf:
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/features/warn_on.prf:
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/features/qt.prf:
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/features/unix/thread.prf:
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/features/moc.prf:
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/features/resources.prf:
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/features/uic.prf:
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/features/yacc.prf:
+/usr/local/Trolltech/Qt-4.3.1/mkspecs/features/lex.prf:
+/usr/local/Trolltech/Qt-4.3.1/lib/libQtGui.prl:
+/usr/local/Trolltech/Qt-4.3.1/lib/libQtCore.prl:
+qmake: FORCE
+ @$(QMAKE) -unix -o Makefile mpc.pro
+
+dist:
+ @$(CHK_DIR_EXISTS) .build/obj/mpc1.0.0 || $(MKDIR) .build/obj/mpc1.0.0
+ $(COPY_FILE) --parents $(SOURCES) $(DIST) .build/obj/mpc1.0.0/ && $(COPY_FILE) --parents decodermpcfactory.h decoder_mpc.h detailsdialog.h .build/obj/mpc1.0.0/ && $(COPY_FILE) --parents decoder_mpc.cpp decodermpcfactory.cpp detailsdialog.cpp .build/obj/mpc1.0.0/ && $(COPY_FILE) --parents detailsdialog.ui .build/obj/mpc1.0.0/ && (cd `dirname .build/obj/mpc1.0.0` && $(TAR) mpc1.0.0.tar mpc1.0.0 && $(COMPRESS) mpc1.0.0.tar) && $(MOVE) `dirname .build/obj/mpc1.0.0`/mpc1.0.0.tar.gz . && $(DEL_FILE) -r .build/obj/mpc1.0.0
+
+
+clean:compiler_clean
+ -$(DEL_FILE) $(OBJECTS)
+ -$(DEL_FILE) ../../../../lib/qmmp/Input/libmpc.so
+ -$(DEL_FILE) *~ core *.core
+
+
+####### Sub-libraries
+
+distclean: clean
+ -$(DEL_FILE) $(TARGET)
+ -$(DEL_FILE) Makefile
+
+
+mocclean: compiler_moc_header_clean compiler_moc_source_clean
+
+mocables: compiler_moc_header_make_all compiler_moc_source_make_all
+
+compiler_moc_header_make_all: .build/moc/moc_decodermpcfactory.cpp .build/moc/moc_detailsdialog.cpp
+compiler_moc_header_clean:
+ -$(DEL_FILE) .build/moc/moc_decodermpcfactory.cpp .build/moc/moc_detailsdialog.cpp
+.build/moc/moc_decodermpcfactory.cpp: decodermpcfactory.h
+ /usr/local/Trolltech/Qt-4.3.1/bin/moc $(DEFINES) $(INCPATH) decodermpcfactory.h -o .build/moc/moc_decodermpcfactory.cpp
+
+.build/moc/moc_detailsdialog.cpp: .build/ui/ui_detailsdialog.h \
+ detailsdialog.h
+ /usr/local/Trolltech/Qt-4.3.1/bin/moc $(DEFINES) $(INCPATH) detailsdialog.h -o .build/moc/moc_detailsdialog.cpp
+
+compiler_rcc_make_all:
+compiler_rcc_clean:
+compiler_image_collection_make_all: qmake_image_collection.cpp
+compiler_image_collection_clean:
+ -$(DEL_FILE) qmake_image_collection.cpp
+compiler_moc_source_make_all:
+compiler_moc_source_clean:
+compiler_uic_make_all: .build/ui/ui_detailsdialog.h
+compiler_uic_clean:
+ -$(DEL_FILE) .build/ui/ui_detailsdialog.h
+.build/ui/ui_detailsdialog.h: detailsdialog.ui
+ /usr/local/Trolltech/Qt-4.3.1/bin/uic detailsdialog.ui -o .build/ui/ui_detailsdialog.h
+
+compiler_yacc_decl_make_all:
+compiler_yacc_decl_clean:
+compiler_yacc_impl_make_all:
+compiler_yacc_impl_clean:
+compiler_lex_make_all:
+compiler_lex_clean:
+compiler_clean: compiler_moc_header_clean compiler_uic_clean
+
+####### Compile
+
+.build/obj/decoder_mpc.o: decoder_mpc.cpp decoder_mpc.h
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o .build/obj/decoder_mpc.o decoder_mpc.cpp
+
+.build/obj/decodermpcfactory.o: decodermpcfactory.cpp detailsdialog.h \
+ .build/ui/ui_detailsdialog.h \
+ decoder_mpc.h \
+ decodermpcfactory.h
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o .build/obj/decodermpcfactory.o decodermpcfactory.cpp
+
+.build/obj/detailsdialog.o: detailsdialog.cpp detailsdialog.h \
+ .build/ui/ui_detailsdialog.h
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o .build/obj/detailsdialog.o detailsdialog.cpp
+
+.build/obj/moc_decodermpcfactory.o: .build/moc/moc_decodermpcfactory.cpp
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o .build/obj/moc_decodermpcfactory.o .build/moc/moc_decodermpcfactory.cpp
+
+.build/obj/moc_detailsdialog.o: .build/moc/moc_detailsdialog.cpp
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o .build/obj/moc_detailsdialog.o .build/moc/moc_detailsdialog.cpp
+
+####### Install
+
+install_target: first FORCE
+ @$(CHK_DIR_EXISTS) $(INSTALL_ROOT)/lib/qmmp/Input/ || $(MKDIR) $(INSTALL_ROOT)/lib/qmmp/Input/
+ -$(INSTALL_PROGRAM) "../../../../lib/qmmp/Input/$(TARGET)" "$(INSTALL_ROOT)/lib/qmmp/Input/$(TARGET)"
+ -strip --strip-unneeded "$(INSTALL_ROOT)/lib/qmmp/Input/$(TARGET)"
+
+uninstall_target: FORCE
+ -$(DEL_FILE) "$(INSTALL_ROOT)/lib/qmmp/Input/$(TARGET)"
+ -$(DEL_DIR) $(INSTALL_ROOT)/lib/qmmp/Input/
+
+
+install: install_target FORCE
+
+uninstall: uninstall_target FORCE
+
+FORCE:
+
diff --git a/src/plugins/Input/mpc/decoder_mpc.cpp b/src/plugins/Input/mpc/decoder_mpc.cpp
new file mode 100644
index 000000000..10591a384
--- /dev/null
+++ b/src/plugins/Input/mpc/decoder_mpc.cpp
@@ -0,0 +1,386 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+
+#include <QObject>
+#include <QIODevice>
+
+#include "constants.h"
+#include "buffer.h"
+#include "output.h"
+#include "recycler.h"
+
+#include "decoder_mpc.h"
+
+// this function used from xmms
+inline static void copyBuffer(MPC_SAMPLE_FORMAT* pInBuf, char* pOutBuf, unsigned pLength)
+{
+ unsigned pSize = 16;
+ int clipMin = -1 << (pSize - 1);
+ int clipMax = (1 << (pSize - 1)) - 1;
+ int floatScale = 1 << (pSize - 1);
+ for (unsigned n = 0; n < 2 * pLength; n++)
+ {
+ int val;
+#ifdef MPC_FIXED_POINT
+ val = shiftSigned(pInBuf[n], pSize - MPC_FIXED_POINT_SCALE_SHIFT);
+#else
+ val = (int) (pInBuf[n] * floatScale);
+#endif
+ if (val < clipMin)
+ val = clipMin;
+ else if (val > clipMax)
+ val = clipMax;
+ unsigned shift = 0;
+ do
+ {
+ pOutBuf[n * 2 + (shift / 8)] = (unsigned char) ((val >> shift) & 0xFF);
+ shift += 8;
+ }
+ while (shift < pSize);
+ }
+}
+
+// mpc callbacks
+
+static mpc_int32_t mpc_callback_read (void *data, void *buffer, mpc_int32_t size)
+{
+ DecoderMPC *dmpc = (DecoderMPC *) data;
+ qint64 res;
+
+ res = dmpc->input()->read((char *)buffer, size);
+
+ return res;
+}
+
+static mpc_bool_t mpc_callback_seek (void *data, mpc_int32_t offset)
+{
+ DecoderMPC *dmpc = (DecoderMPC *) data;
+
+ return dmpc->input()->seek(offset); // ? TRUE : FALSE;
+}
+
+static mpc_int32_t mpc_callback_tell (void *data)
+{
+ DecoderMPC *dmpc = (DecoderMPC *) data;
+ return dmpc->input()->pos ();
+}
+
+static mpc_bool_t mpc_callback_canseek (void *data)
+{
+ DecoderMPC *dmpc = (DecoderMPC *) data;
+ return !dmpc->input()->isSequential () ;
+}
+
+static mpc_int32_t mpc_callback_get_size (void *data)
+{
+ DecoderMPC *dmpc = (DecoderMPC *) data;
+ return dmpc->input()->size();
+}
+
+// Decoder class
+
+DecoderMPC::DecoderMPC(QObject *parent, DecoderFactory *d, QIODevice *i, Output *o)
+ : Decoder(parent, d, i, o)
+{
+ inited = FALSE;
+ user_stop = FALSE;
+ stat = 0;
+ output_buf = 0;
+ output_bytes = 0;
+ output_at = 0;
+ bks = 0;
+ done = FALSE;
+ finish = FALSE;
+ len = 0;
+ freq = 0;
+ bitrate = 0;
+ seekTime = -1.0;
+ totalTime = 0.0;
+ chan = 0;
+ output_size = 0;
+ m_data = 0;
+
+
+
+
+}
+
+
+DecoderMPC::~DecoderMPC()
+{
+ deinit();
+ if(data())
+ {
+ delete data();
+ m_data = 0;
+ }
+ if (output_buf)
+ delete [] output_buf;
+ output_buf = 0;
+}
+
+
+void DecoderMPC::stop()
+{
+ user_stop = TRUE;
+}
+
+
+void DecoderMPC::flush(bool final)
+{
+ ulong min = final ? 0 : bks;
+
+ while ((! done && ! finish) && output_bytes > min)
+ {
+ output()->recycler()->mutex()->lock ();
+
+ while ((! done && ! finish) && output()->recycler()->full())
+ {
+ mutex()->unlock();
+
+ output()->recycler()->cond()->wait(output()->recycler()->mutex());
+
+ mutex()->lock ();
+ done = user_stop;
+ }
+
+ if (user_stop || finish)
+ {
+ inited = FALSE;
+ done = TRUE;
+ }
+ else
+ {
+ output_bytes -= produceSound(output_buf, output_bytes, bitrate, chan);
+ output_size += bks;
+ output_at = output_bytes;
+ }
+
+ if (output()->recycler()->full())
+ {
+ output()->recycler()->cond()->wakeOne();
+ }
+
+ output()->recycler()->mutex()->unlock();
+ }
+}
+
+
+bool DecoderMPC::initialize()
+{
+ bks = blockSize();
+ inited = user_stop = done = finish = FALSE;
+ len = freq = bitrate = 0;
+ stat = chan = 0;
+ output_size = 0;
+ seekTime = -1.0;
+ totalTime = 0.0;
+
+
+ if (! input())
+ {
+ error("DecoderMPC: cannot initialize. No input.");
+
+ return FALSE;
+ }
+
+ if (! output_buf)
+ output_buf = new char[globalBufferSize];
+ output_at = 0;
+ output_bytes = 0;
+
+ if (! input())
+ {
+ error("DecoderMPC: cannot initialize. No input.");
+
+ return FALSE;
+ }
+
+ if (! output_buf)
+ output_buf = new char[globalBufferSize];
+ output_at = 0;
+ output_bytes = 0;
+
+ if (! input()->isOpen())
+ {
+ if (! input()->open(QIODevice::ReadOnly))
+ {
+ error("DecoderMPC: cannot open input.");
+ return FALSE;
+ }
+ }
+ if (!m_data)
+ {
+ m_data = new mpc_data;
+ }
+
+ qDebug("DecoderMPC: setting callbacks");
+ m_data->reader.read = mpc_callback_read;
+ m_data->reader.seek = mpc_callback_seek;
+ m_data->reader.tell = mpc_callback_tell;
+ m_data->reader.canseek = mpc_callback_canseek;
+ m_data->reader.get_size = mpc_callback_get_size;
+ m_data->reader.data = this;
+
+ mpc_streaminfo_init (&m_data->info);
+
+ if (mpc_streaminfo_read (&m_data->info, &m_data->reader) != ERROR_CODE_OK)
+ return FALSE;
+ chan = data()->info.channels;
+ configure(data()->info.sample_freq, chan, 16, data()->info.bitrate);
+
+ mpc_decoder_setup (&data()->decoder, &data()->reader);
+
+ //mpc_decoder_scale_output (&data()->decoder, 3.0);
+
+ if (!mpc_decoder_initialize (&data()->decoder, &data()->info))
+ {
+ error("DecoderMPC: cannot get info.");
+ return FALSE;
+ }
+ totalTime = mpc_streaminfo_get_length(&data()->info);
+ inited = TRUE;
+ qDebug("DecoderMPC: initialize succes");
+ return TRUE;
+}
+
+
+double DecoderMPC::lengthInSeconds()
+{
+ if (! inited)
+ return 0;
+
+ return totalTime;
+}
+
+
+void DecoderMPC::seek(double pos)
+{
+ seekTime = pos;
+}
+
+
+void DecoderMPC::deinit()
+{
+ //FLAC__stream_decoder_finish (data()->decoder);
+ inited = user_stop = done = finish = FALSE;
+ len = freq = bitrate = 0;
+ stat = chan = 0;
+ output_size = 0;
+}
+
+void DecoderMPC::run()
+{
+ mpc_uint32_t vbrAcc = 0;
+ mpc_uint32_t vbrUpd = 0;
+ mutex()->lock ();
+
+ if (! inited)
+ {
+ mutex()->unlock();
+
+ return;
+ }
+ stat = DecoderState::Decoding;
+ mutex()->unlock();
+ {
+ dispatch(DecoderState ((DecoderState::Type) stat));
+ }
+
+ while (! done && ! finish)
+ {
+ mutex()->lock ();
+ // decode
+
+ if (seekTime >= 0.0)
+ {
+ mpc_decoder_seek_seconds(&data()->decoder, seekTime);
+ seekTime = -1.0;
+ }
+ MPC_SAMPLE_FORMAT buffer[MPC_DECODER_BUFFER_LENGTH];
+
+ len = mpc_decoder_decode (&data()->decoder, buffer, &vbrAcc, &vbrUpd);
+
+ copyBuffer(buffer, (char *) (output_buf + output_at), len);
+
+ len = len * 4;
+
+ if (len > 0)
+ {
+ bitrate = vbrUpd * data()->info.sample_freq / 1152;
+ output_at += len;
+ output_bytes += len;
+
+ if (output())
+ flush();
+
+ }
+ else if (len == 0)
+ {
+ flush(TRUE);
+
+ if (output())
+ {
+ output()->recycler()->mutex()->lock ();
+ // end of stream
+ while (! output()->recycler()->empty() && ! user_stop)
+ {
+ output()->recycler()->cond()->wakeOne();
+ mutex()->unlock();
+ output()->recycler()->cond()->wait(output()->recycler()->mutex());
+ mutex()->lock ();
+ }
+ output()->recycler()->mutex()->unlock();
+ }
+
+ done = TRUE;
+ if (! user_stop)
+ {
+ finish = TRUE;
+ }
+ }
+ else
+ {
+ // error in read
+ error("DecoderMPC: Error while decoding stream, File appears to be "
+ "corrupted");
+
+ finish = TRUE;
+ }
+
+ mutex()->unlock();
+ }
+
+ mutex()->lock ();
+
+ if (finish)
+ stat = DecoderState::Finished;
+ else if (user_stop)
+ stat = DecoderState::Stopped;
+
+ mutex()->unlock();
+
+ {
+ dispatch(DecoderState ((DecoderState::Type) stat));
+ }
+
+ deinit();
+}
diff --git a/src/plugins/Input/mpc/decoder_mpc.h b/src/plugins/Input/mpc/decoder_mpc.h
new file mode 100644
index 000000000..3b17b100e
--- /dev/null
+++ b/src/plugins/Input/mpc/decoder_mpc.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef __decoder_mpc_h
+#define __decoder_mpc_h
+
+#include <mpcdec/mpcdec.h>
+
+#include "decoder.h"
+
+struct mpc_data
+{
+ mpc_decoder decoder;
+ mpc_reader reader;
+ mpc_streaminfo info;
+};
+
+class DecoderMPC : public Decoder
+{
+public:
+ DecoderMPC(QObject *, DecoderFactory *, QIODevice *, Output *);
+ virtual ~DecoderMPC();
+
+ // Standard Decoder API
+ bool initialize();
+ double lengthInSeconds();
+ void seek(double);
+ void stop();
+
+ // Equalizer
+ bool isEQSupported() const { return FALSE; }
+ void setEQEnabled(bool) { ; }
+ void setEQGain(int) { ; }
+ void setEQBands(int[10]) { ; }
+
+ struct mpc_data *data() { return m_data; }
+
+
+private:
+ // thread run function
+ void run();
+ struct mpc_data *m_data;
+ // helper functions
+ void flush(bool = FALSE);
+ void deinit();
+
+ bool inited, user_stop;
+ int stat;
+
+ // output buffer
+ char *output_buf;
+ ulong output_bytes, output_at;
+
+ unsigned int bks;
+ bool done, finish;
+ long len, freq, bitrate;
+ int chan;
+ unsigned long output_size;
+ double totalTime, seekTime;
+};
+
+
+#endif // __decoder_mpc_h
diff --git a/src/plugins/Input/mpc/decodermpcfactory.cpp b/src/plugins/Input/mpc/decodermpcfactory.cpp
new file mode 100644
index 000000000..f2874a08d
--- /dev/null
+++ b/src/plugins/Input/mpc/decodermpcfactory.cpp
@@ -0,0 +1,95 @@
+#include <QtGui>
+#include <taglib/tag.h>
+#include <taglib/fileref.h>
+
+#include "detailsdialog.h"
+#include "decoder_mpc.h"
+#include "decodermpcfactory.h"
+
+
+// DecoderMPCFactory
+
+bool DecoderMPCFactory::supports(const QString &source) const
+{
+
+ return (source.right(4).toLower() == ".mpc");
+}
+
+bool DecoderMPCFactory::canDecode(QIODevice *) const
+{
+ return FALSE;
+}
+
+const DecoderProperties DecoderMPCFactory::properties() const
+{
+ DecoderProperties properties;
+ properties.name = tr("Musepack Plugin");
+ properties.filter = "*.mpc";
+ properties.description = tr("Musepack Files");
+ //properties.contentType = ;
+ properties.hasAbout = TRUE;
+ properties.hasSettings = FALSE;
+ return properties;
+}
+
+Decoder *DecoderMPCFactory::create(QObject *parent, QIODevice *input,
+ Output *output)
+{
+ return new DecoderMPC(parent, this, input, output);
+}
+
+FileTag *DecoderMPCFactory::createTag(const QString &source)
+{
+ FileTag *ftag = new FileTag();
+
+ TagLib::FileRef fileRef(source.toLocal8Bit ());
+ TagLib::Tag *tag = fileRef.tag();
+
+ if (tag && !tag->isEmpty())
+ {
+ ftag->setValue(FileTag::ALBUM,
+ QString::fromUtf8(tag->album().toCString(TRUE)).trimmed());
+ ftag->setValue(FileTag::ARTIST,
+ QString::fromUtf8(tag->artist().toCString(TRUE)).trimmed());
+ ftag->setValue(FileTag::COMMENT,
+ QString::fromUtf8(tag->comment().toCString(TRUE)).trimmed());
+ ftag->setValue(FileTag::GENRE,
+ QString::fromUtf8(tag->genre().toCString(TRUE)).trimmed());
+ ftag->setValue(FileTag::TITLE,
+ QString::fromUtf8(tag->title().toCString(TRUE)).trimmed());
+ ftag->setValue(FileTag::YEAR, tag->year());
+ ftag->setValue(FileTag::TRACK, tag->track());
+ }
+
+ if (fileRef.audioProperties())
+ ftag->setValue(FileTag::LENGTH, fileRef.audioProperties()->length());
+
+ return ftag;
+}
+
+QObject* DecoderMPCFactory::showDetails(QWidget *parent, const QString &path)
+{
+ DetailsDialog *d = new DetailsDialog(parent, path);
+ d -> show();
+ return d;
+}
+
+void DecoderMPCFactory::showSettings(QWidget *)
+{}
+
+void DecoderMPCFactory::showAbout(QWidget *parent)
+{
+ QMessageBox::about (parent, tr("About Musepack Audio Plugin"),
+ tr("Qmmp Musepack Audio Plugin")+"\n"+
+ tr("Writen by: Ilya Kotov <forkotov02@hotmail.ru>"));
+}
+
+QTranslator *DecoderMPCFactory::createTranslator(QObject *parent)
+{
+ QTranslator *translator = new QTranslator(parent);
+ QString locale = QLocale::system().name();
+ translator->load(QString(":/mpc_plugin_") + locale);
+ return translator;
+}
+
+Q_EXPORT_PLUGIN(DecoderMPCFactory)
diff --git a/src/plugins/Input/mpc/decodermpcfactory.h b/src/plugins/Input/mpc/decodermpcfactory.h
new file mode 100644
index 000000000..0f8dda55f
--- /dev/null
+++ b/src/plugins/Input/mpc/decodermpcfactory.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef DECODERMPCFACTORY_H
+#define DECODERMPCFACTORY_H
+
+#include <QObject>
+#include <QString>
+#include <QIODevice>
+#include <QWidget>
+
+#include <decoder.h>
+#include <output.h>
+#include <decoderfactory.h>
+#include <filetag.h>
+
+
+
+
+class DecoderMPCFactory : public QObject,
+ DecoderFactory
+{
+Q_OBJECT
+Q_INTERFACES(DecoderFactory);
+
+public:
+ bool supports(const QString &source) const;
+ bool canDecode(QIODevice *input) const;
+ const DecoderProperties properties() const;
+ Decoder *create(QObject *, QIODevice *, Output *);
+ FileTag *createTag(const QString &source);
+ QObject* showDetails(QWidget *parent, const QString &path);
+ void showSettings(QWidget *parent);
+ void showAbout(QWidget *parent);
+ QTranslator *createTranslator(QObject *parent);
+};
+
+#endif
diff --git a/src/plugins/Input/mpc/detailsdialog.cpp b/src/plugins/Input/mpc/detailsdialog.cpp
new file mode 100644
index 000000000..472046717
--- /dev/null
+++ b/src/plugins/Input/mpc/detailsdialog.cpp
@@ -0,0 +1,115 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include <taglib/tag.h>
+#include <taglib/fileref.h>
+#include <taglib/mpcfile.h>
+
+#include <QFile>
+#include <QFileInfo>
+
+#include "detailsdialog.h"
+
+#define QStringToTString_qt4(s) TagLib::String(s.toUtf8().constData(), TagLib::String::UTF8)
+
+DetailsDialog::DetailsDialog(QWidget *parent, const QString &path)
+ : QDialog(parent)
+{
+ ui.setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose);
+ m_path = path;
+ setWindowTitle (path.section('/',-1));
+ path.section('/',-1);
+ ui.pathLineEdit->setText(m_path);
+ if(QFile::exists(m_path))
+ {
+ loadMPCInfo();
+ loadTag();
+ }
+}
+
+
+DetailsDialog::~DetailsDialog()
+{}
+
+void DetailsDialog::loadMPCInfo()
+{
+ TagLib::MPC::File f (m_path.toLocal8Bit());
+ QString text;
+ text = QString("%1").arg(f.audioProperties()->length()/60);
+ text +=":"+QString("%1").arg(f.audioProperties()->length()%60,2,10,QChar('0'));
+ ui.lengthLabel->setText(text);
+ text = QString("%1").arg(f.audioProperties()->sampleRate());
+ ui.sampleRateLabel->setText(text+" "+tr("Hz"));
+ text = QString("%1").arg(f.audioProperties()->channels());
+ ui.channelsLabel->setText(text);
+ text = QString("%1").arg(f.audioProperties()->bitrate());
+ ui.bitrateLabel->setText(text+" "+tr("kbps"));
+ text = QString("%1").arg(f.audioProperties()->mpcVersion());
+ ui.versionLabel->setText(text);
+ text = QString("%1 "+tr("KB")).arg(f.length()/1024);
+ ui.fileSizeLabel->setText(text);
+}
+
+void DetailsDialog::loadTag()
+{
+ TagLib::FileRef f (m_path.toLocal8Bit());
+
+ if (f.tag())
+ { //TODO: load codec name from config
+
+ TagLib::String title = f.tag()->title();
+ TagLib::String artist = f.tag()->artist();
+ TagLib::String album = f.tag()->album();
+ TagLib::String comment = f.tag()->comment();
+ TagLib::String genre = f.tag()->genre();
+ QString string = QString::fromUtf8(title.toCString(TRUE)).trimmed();
+ ui.titleLineEdit->setText(string);
+ string = QString::fromUtf8(artist.toCString(TRUE)).trimmed();
+ ui.artistLineEdit->setText(string);
+ string = QString::fromUtf8(album.toCString(TRUE)).trimmed();
+ ui.albumLineEdit->setText(string);
+ string = QString::fromUtf8(comment.toCString(TRUE)).trimmed();
+ ui.commentLineEdit->setText(string);
+ string = QString("%1").arg(f.tag()->year());
+ ui.yearLineEdit->setText(string);
+ string = QString("%1").arg(f.tag()->track());
+ ui.trackLineEdit->setText(string);
+ string = QString::fromUtf8(genre.toCString(TRUE)).trimmed();
+ ui.genreLineEdit->setText(string);
+ }
+ QFileInfo info(m_path);
+ ui.saveButton->setEnabled(info.isWritable());
+ connect(ui.saveButton, SIGNAL(clicked()), SLOT(saveTag()));
+}
+
+void DetailsDialog::saveTag()
+{
+ TagLib::FileRef f (m_path.toLocal8Bit());
+
+ f.tag()->setTitle(QStringToTString_qt4(ui.titleLineEdit->text()));
+ f.tag()->setArtist(QStringToTString_qt4(ui.artistLineEdit->text()));
+ f.tag()->setAlbum(QStringToTString_qt4(ui.albumLineEdit->text()));
+ f.tag()->setComment(QStringToTString_qt4(ui.commentLineEdit->text()));
+ f.tag()->setGenre(QStringToTString_qt4(ui.genreLineEdit->text()));
+ f.tag()->setYear(ui.yearLineEdit->text().toUInt());
+ f.tag()->setTrack(ui.trackLineEdit->text().toUInt());
+
+ f.save();
+}
diff --git a/src/plugins/Input/mpc/detailsdialog.h b/src/plugins/Input/mpc/detailsdialog.h
new file mode 100644
index 000000000..70540bda1
--- /dev/null
+++ b/src/plugins/Input/mpc/detailsdialog.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef DETAILSDIALOG_H
+#define DETAILSDIALOG_H
+
+#include <QDialog>
+
+#include "ui_detailsdialog.h"
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class DetailsDialog : public QDialog
+{
+Q_OBJECT
+public:
+ DetailsDialog(QWidget *parent = 0, const QString &path = 0);
+
+ ~DetailsDialog();
+
+private slots:
+ void saveTag();
+
+private:
+ void loadMPCInfo();
+ void loadTag();
+ Ui::DetailsDialog ui;
+ QString m_path;
+
+};
+
+#endif
diff --git a/src/plugins/Input/mpc/detailsdialog.ui b/src/plugins/Input/mpc/detailsdialog.ui
new file mode 100644
index 000000000..918dd3abf
--- /dev/null
+++ b/src/plugins/Input/mpc/detailsdialog.ui
@@ -0,0 +1,349 @@
+<ui version="4.0" >
+ <class>DetailsDialog</class>
+ <widget class="QDialog" name="DetailsDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>449</width>
+ <height>375</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Details</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item rowspan="2" row="1" column="0" colspan="2" >
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="minimumSize" >
+ <size>
+ <width>175</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="title" >
+ <string>Musepack Info</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="6" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>74</width>
+ <height>151</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1" colspan="2" >
+ <widget class="QLabel" name="fileSizeLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Length:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="2" >
+ <widget class="QLabel" name="lengthLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Sample rate:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" colspan="2" >
+ <widget class="QLabel" name="sampleRateLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_10" >
+ <property name="layoutDirection" >
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text" >
+ <string>Channels:</string>
+ </property>
+ <property name="textFormat" >
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_5" >
+ <property name="text" >
+ <string>File size:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Bitrate:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" colspan="2" >
+ <widget class="QLabel" name="channelsLabel" >
+ <property name="layoutDirection" >
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" colspan="2" >
+ <widget class="QLabel" name="bitrateLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" >
+ <widget class="QLabel" name="label_4" >
+ <property name="text" >
+ <string>Stream version:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1" colspan="2" >
+ <widget class="QLabel" name="versionLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="3" >
+ <widget class="QLineEdit" name="pathLineEdit" >
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_28" >
+ <property name="text" >
+ <string>File path:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="3" >
+ <widget class="QPushButton" name="pushButton_3" >
+ <property name="text" >
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>111</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="2" colspan="2" >
+ <widget class="QGroupBox" name="groupBox_2" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title" >
+ <string>Musepack Tag</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="6" column="1" colspan="2" >
+ <widget class="QPushButton" name="saveButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Save</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="3" >
+ <widget class="QLineEdit" name="trackLineEdit" />
+ </item>
+ <item row="4" column="2" >
+ <widget class="QLabel" name="label_26" >
+ <property name="text" >
+ <string>Track number:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" >
+ <widget class="QLineEdit" name="yearLineEdit" />
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="label_25" >
+ <property name="text" >
+ <string>Year:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" >
+ <widget class="QLabel" name="label_27" >
+ <property name="text" >
+ <string>Genre:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_24" >
+ <property name="text" >
+ <string>Comment:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_23" >
+ <property name="text" >
+ <string>Album:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_22" >
+ <property name="text" >
+ <string>Artist:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_21" >
+ <property name="text" >
+ <string>Title:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="3" >
+ <widget class="QLineEdit" name="titleLineEdit" />
+ </item>
+ <item row="1" column="1" colspan="3" >
+ <widget class="QLineEdit" name="artistLineEdit" />
+ </item>
+ <item row="2" column="1" colspan="3" >
+ <widget class="QLineEdit" name="albumLineEdit" />
+ </item>
+ <item row="3" column="1" colspan="3" >
+ <widget class="QLineEdit" name="commentLineEdit" />
+ </item>
+ <item row="5" column="1" colspan="2" >
+ <widget class="QLineEdit" name="genreLineEdit" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>pushButton_3</sender>
+ <signal>clicked()</signal>
+ <receiver>DetailsDialog</receiver>
+ <slot>close()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>623</x>
+ <y>353</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>539</x>
+ <y>352</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/Input/mpc/mpc.pro b/src/plugins/Input/mpc/mpc.pro
new file mode 100644
index 000000000..f1a50683d
--- /dev/null
+++ b/src/plugins/Input/mpc/mpc.pro
@@ -0,0 +1,32 @@
+include(../../plugins.pri)
+
+FORMS += detailsdialog.ui
+HEADERS += decodermpcfactory.h \
+ decoder_mpc.h \
+ detailsdialog.h
+SOURCES += decoder_mpc.cpp \
+ decodermpcfactory.cpp \
+ detailsdialog.cpp
+
+TARGET=$$PLUGINS_PREFIX/Input/mpc
+QMAKE_CLEAN =$$PLUGINS_PREFIX/Input/libmpc.so
+
+
+INCLUDEPATH += ../../../qmmp
+CONFIG += release \
+warn_on \
+plugin \
+link_pkgconfig
+TEMPLATE = lib
+QMAKE_LIBDIR += ../../../../lib
+LIBS += -lqmmp -L/usr/lib -lmpcdec -I/usr/include
+PKGCONFIG += taglib
+#TRANSLATIONS = translations/mpc_plugin_ru.ts
+#RESOURCES = translations/translations.qrc
+
+isEmpty (LIB_DIR){
+LIB_DIR = /lib
+}
+
+target.path = $$LIB_DIR/qmmp/Input
+INSTALLS += target
diff --git a/src/plugins/Input/mpc/translations/mpc_plugin_ru.qm b/src/plugins/Input/mpc/translations/mpc_plugin_ru.qm
new file mode 100644
index 000000000..0eb8c1533
--- /dev/null
+++ b/src/plugins/Input/mpc/translations/mpc_plugin_ru.qm
Binary files differ
diff --git a/src/plugins/Input/mpc/translations/mpc_plugin_ru.ts b/src/plugins/Input/mpc/translations/mpc_plugin_ru.ts
new file mode 100644
index 000000000..53ecd8dc8
--- /dev/null
+++ b/src/plugins/Input/mpc/translations/mpc_plugin_ru.ts
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS><TS version="1.1" language="ru">
+<context>
+ <name>DecoderMPCFactory</name>
+ <message>
+ <location filename="../decodermpcfactory.cpp" line="21"/>
+ <source>Musepack Plugin</source>
+ <translation>Модуль Musepack</translation>
+ </message>
+ <message>
+ <location filename="../decodermpcfactory.cpp" line="35"/>
+ <source>Musepack Files</source>
+ <translation>Файлы Musepack</translation>
+ </message>
+ <message>
+ <location filename="../decodermpcfactory.cpp" line="63"/>
+ <source>About Musepack Audio Plugin</source>
+ <translation>Об аудио-модуле Musepack</translation>
+ </message>
+ <message>
+ <location filename="../decodermpcfactory.cpp" line="64"/>
+ <source>Qmmp Musepack Audio Plugin</source>
+ <translation>Аудио-модуль Musepack для Qmmp</translation>
+ </message>
+ <message>
+ <location filename="../decodermpcfactory.cpp" line="65"/>
+ <source>Writen by: Ilya Kotov &lt;forkotov02@hotmail.ru&gt;</source>
+ <translation>Разработчик: Илья Котов &lt;forkotov02@hotmail.ru&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>DetailsDialog</name>
+ <message>
+ <location filename="../detailsdialog.cpp" line="52"/>
+ <source>Hz</source>
+ <translation>Гц</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="31"/>
+ <source>Musepack Info</source>
+ <translation>Информация Musepack</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="160"/>
+ <source>-</source>
+ <translation></translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="63"/>
+ <source>Length:</source>
+ <translation>Длительность:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="80"/>
+ <source>Sample rate:</source>
+ <translation>Дискретизация:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="100"/>
+ <source>Channels:</source>
+ <translation>Каналов:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="113"/>
+ <source>File size:</source>
+ <translation>Размер файла:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="123"/>
+ <source>Bitrate:</source>
+ <translation>Битовая частота:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="150"/>
+ <source>Stream version:</source>
+ <translation>Версия потока:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="177"/>
+ <source>File path:</source>
+ <translation>Путь к файлу:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="187"/>
+ <source>Close</source>
+ <translation>Закрыть</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="215"/>
+ <source>Musepack Tag</source>
+ <translation>Musepack-тег</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="230"/>
+ <source>Save</source>
+ <translation>Сохранить</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="240"/>
+ <source>Track number:</source>
+ <translation>Номер трека:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="253"/>
+ <source>Year:</source>
+ <translation>Год:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="263"/>
+ <source>Genre:</source>
+ <translation>Жанр:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="273"/>
+ <source>Comment:</source>
+ <translation>Комментарий:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="283"/>
+ <source>Album:</source>
+ <translation>Альбом:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="293"/>
+ <source>Artist:</source>
+ <translation>Исполнитель:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="303"/>
+ <source>Title:</source>
+ <translation>Название:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="13"/>
+ <source>Details</source>
+ <translation>Информация</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.cpp" line="56"/>
+ <source>kbps</source>
+ <translation>Кб/с</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.cpp" line="59"/>
+ <source>KB</source>
+ <translation>Кб</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/plugins/Input/mpc/translations/translations.qrc b/src/plugins/Input/mpc/translations/translations.qrc
new file mode 100644
index 000000000..cc88de9ce
--- /dev/null
+++ b/src/plugins/Input/mpc/translations/translations.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+ <qresource>
+ <file>mpc_plugin_ru.qm</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/Input/sndfile/CMakeLists.txt b/src/plugins/Input/sndfile/CMakeLists.txt
new file mode 100644
index 000000000..974db398e
--- /dev/null
+++ b/src/plugins/Input/sndfile/CMakeLists.txt
@@ -0,0 +1,74 @@
+project(libsndfile)
+
+cmake_minimum_required(VERSION 2.4.0)
+
+
+INCLUDE(UsePkgConfig)
+INCLUDE(FindQt4)
+
+find_package(Qt4 REQUIRED) # find and setup Qt4 for this project
+include(${QT_USE_FILE})
+
+# qt plugin
+ADD_DEFINITIONS( -Wall )
+ADD_DEFINITIONS(${QT_DEFINITIONS})
+ADD_DEFINITIONS(-DQT_PLUGIN)
+ADD_DEFINITIONS(-DQT_NO_DEBUG)
+ADD_DEFINITIONS(-DQT_SHARED)
+ADD_DEFINITIONS(-DQT_THREAD)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+SET(QT_INCLUDES
+ ${QT_INCLUDES}
+ ${CMAKE_CURRENT_BINARY_DIR}/../../../
+)
+
+# libqmmp
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+link_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+
+# libsndfile
+PKGCONFIG(sndfile SNDFILE_INCLUDE_DIR SNDFILE_LINK_DIR SNDFILE_LINK_FLAGS SNDFILE_CFLAGS)
+
+IF(NOT SNDFILE_LINK_FLAGS)
+ SET(SNDFILE_LINK_FLAGS -lsndfile)
+ SET(SNDFILE_INCLUDE_DIR /usr/include)
+ SET(SNDFILE_CFLAGS -I/usr/include)
+ENDIF(NOT SNDFILE_LINK_FLAGS)
+
+include_directories(${SNDFILE_INCLUDE_DIR})
+link_directories(${SNDFILE_LINK_DIR})
+
+ADD_DEFINITIONS(${SNDFILE_CFLAGS})
+
+
+SET(libsndfile_SRCS
+ decoder_sndfile.cpp
+ decodersndfilefactory.cpp
+)
+
+SET(libsndfile_MOC_HDRS
+ decodersndfilefactory.h
+ decoder_sndfile.h
+)
+
+#SET(libsndfile_RCCS translations/translations.qrc)
+
+#QT4_ADD_RESOURCES(libsndfile_RCC_SRCS ${libsndfile_RCCS})
+
+QT4_WRAP_CPP(libsndfile_MOC_SRCS ${libsndfile_MOC_HDRS})
+
+
+# Don't forget to include output directory, otherwise
+# the UI file won't be wrapped!
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+ADD_LIBRARY(sndfile SHARED ${libsndfile_SRCS} ${libsndfile_MOC_SRCS} ${libsndfile_UIS_H}
+ ${libsndfile_RCC_SRCS})
+
+target_link_libraries(sndfile ${QT_LIBRARIES} -lqmmp ${SNDFILE_LINK_FLAGS})
+install(TARGETS sndfile DESTINATION ${LIB_DIR}/qmmp/Input)
+
+
+
diff --git a/src/plugins/Input/sndfile/decoder_sndfile.cpp b/src/plugins/Input/sndfile/decoder_sndfile.cpp
new file mode 100644
index 000000000..b4baa2ba4
--- /dev/null
+++ b/src/plugins/Input/sndfile/decoder_sndfile.cpp
@@ -0,0 +1,282 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QObject>
+#include <QFile>
+#include <QFileInfo>
+
+
+
+#include "constants.h"
+#include "buffer.h"
+#include "output.h"
+#include "recycler.h"
+
+#include "decoder_sndfile.h"
+
+// Decoder class
+
+DecoderSndFile::DecoderSndFile(QObject *parent, DecoderFactory *d, QIODevice *i, Output *o)
+ : Decoder(parent, d, i, o)
+{
+ m_inited = FALSE;
+ m_user_stop = FALSE;
+ m_output_buf = 0;
+ m_output_bytes = 0;
+ m_output_at = 0;
+ bks = 0;
+ m_done = FALSE;
+ m_finish = FALSE;
+ m_freq = 0;
+ m_bitrate = 0;
+ m_seekTime = -1.0;
+ m_totalTime = 0.0;
+ m_chan = 0;
+ m_output_size = 0;
+ m_buf = 0;
+ m_sndfile = 0;
+}
+
+
+DecoderSndFile::~DecoderSndFile()
+{
+ deinit();
+}
+
+
+void DecoderSndFile::stop()
+{
+ m_user_stop = TRUE;
+}
+
+
+void DecoderSndFile::flush(bool final)
+{
+ ulong min = final ? 0 : bks;
+
+ while ((! m_done && ! m_finish) && m_output_bytes > min)
+ {
+ output()->recycler()->mutex()->lock ();
+
+ while ((! m_done && ! m_finish) && output()->recycler()->full())
+ {
+ mutex()->unlock();
+
+ output()->recycler()->cond()->wait(output()->recycler()->mutex());
+
+ mutex()->lock ();
+ m_done = m_user_stop;
+ }
+
+ if (m_user_stop || m_finish)
+ {
+ m_inited = FALSE;
+ m_done = TRUE;
+ }
+ else
+ {
+ m_output_bytes -= produceSound(m_output_buf, m_output_bytes, m_bitrate, m_chan);
+ m_output_size += bks;
+ m_output_at = m_output_bytes;
+ }
+
+ if (output()->recycler()->full())
+ {
+ output()->recycler()->cond()->wakeOne();
+ }
+
+ output()->recycler()->mutex()->unlock();
+ }
+}
+
+
+bool DecoderSndFile::initialize()
+{
+ bks = blockSize();
+ m_inited = m_user_stop = m_done = m_finish = FALSE;
+ m_freq = m_bitrate = 0;
+ m_output_size = 0;
+ m_seekTime = -1.0;
+ m_totalTime = 0.0;
+ SF_INFO snd_info;
+
+
+ if (! input())
+ {
+ error("DecoderSndFile: cannot initialize. No input.");
+
+ return FALSE;
+ }
+
+ if (! m_output_buf)
+ m_output_buf = new char[globalBufferSize];
+ m_output_at = 0;
+ m_output_bytes = 0;
+
+ QString filename = qobject_cast<QFile*>(input())->fileName ();
+ input()->close();
+
+ memset (&snd_info, 0, sizeof(snd_info));
+ snd_info.format=0;
+ m_sndfile = sf_open(filename.toLocal8Bit(), SFM_READ, &snd_info);
+ if (!m_sndfile)
+ {
+ qWarning("DecoderSndFile: failed to open: %s", qPrintable(filename));
+ return FALSE;
+ }
+
+ m_freq = snd_info.samplerate;
+ m_chan = snd_info.channels;
+
+ m_totalTime = (double) snd_info.frames / m_freq;
+
+ m_bitrate = QFileInfo(filename).size () * 8.0 / m_totalTime / 1000.0 + 0.5;
+
+ configure(m_freq, m_chan, 16, m_bitrate);
+ m_buf = new short[blockSize() / sizeof(short)];
+ m_inited = TRUE;
+ qDebug("DecoderSndFile: detected format: %08X", snd_info.format);
+ qDebug("DecoderSndFile: initialize succes");
+ return TRUE;
+}
+
+
+double DecoderSndFile::lengthInSeconds()
+{
+ if (! m_inited)
+ return 0;
+
+ return m_totalTime;
+}
+
+
+void DecoderSndFile::seek(double pos)
+{
+ m_seekTime = pos;
+}
+
+
+void DecoderSndFile::deinit()
+{
+ m_inited = m_user_stop = m_done = m_finish = FALSE;
+ m_freq = m_bitrate = m_chan = 0;
+ m_output_size = 0;
+ if (m_inited)
+ {
+ delete m_buf;
+ m_buf = 0;
+ sf_close(m_sndfile);
+ m_sndfile = 0;
+ }
+}
+
+void DecoderSndFile::run()
+{
+
+ long len = 0;
+ int stat = 0;
+
+ mutex()->lock ();
+
+ if (! m_inited)
+ {
+ mutex()->unlock();
+
+ return;
+ }
+
+ stat = DecoderState::Decoding;
+ mutex()->unlock();
+
+ {
+ dispatch(DecoderState ((DecoderState::Type) stat));
+ }
+
+ while (! m_done && ! m_finish)
+ {
+ mutex()->lock ();
+ // decode
+
+ if (m_seekTime >= 0.0)
+ {
+ m_output_size = sf_seek(m_sndfile, m_freq*m_seekTime, SEEK_SET);
+ m_seekTime = -1.0;
+ }
+
+ len = sizeof(short)* sf_read_short (m_sndfile, m_buf, blockSize() / sizeof(short));
+
+ if (len > 0)
+ {
+ memmove((char *)(m_output_buf + m_output_at), (char *) m_buf, len);
+ m_output_at += len;
+ m_output_bytes += len;
+
+ if (output())
+ flush();
+ }
+ else if (len == 0)
+ {
+ flush(TRUE);
+
+ if (output())
+ {
+ output()->recycler()->mutex()->lock ();
+ // end of stream
+ while (! output()->recycler()->empty() && ! m_user_stop)
+ {
+ output()->recycler()->cond()->wakeOne();
+ mutex()->unlock();
+ output()->recycler()->cond()->wait(output()->recycler()->mutex());
+ mutex()->lock ();
+ }
+ output()->recycler()->mutex()->unlock();
+ }
+
+ m_done = TRUE;
+ if (! m_user_stop)
+ {
+ m_finish = TRUE;
+ }
+ }
+ else
+ {
+ // error in read
+ error("DecoderSndFile: Error while decoding stream, File appears to be "
+ "corrupted");
+
+ m_finish = TRUE;
+ }
+
+ mutex()->unlock();
+ }
+
+ mutex()->lock ();
+
+ if (m_finish)
+ stat = DecoderState::Finished;
+ else if (m_user_stop)
+ stat = DecoderState::Stopped;
+
+ mutex()->unlock();
+
+ dispatch(DecoderState ((DecoderState::Type) stat));
+ deinit();
+}
+
diff --git a/src/plugins/Input/sndfile/decoder_sndfile.h b/src/plugins/Input/sndfile/decoder_sndfile.h
new file mode 100644
index 000000000..53bb8fd81
--- /dev/null
+++ b/src/plugins/Input/sndfile/decoder_sndfile.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef DECODER_AUDIOFILE_H
+#define DECODER_AUDIOFILE_H
+
+extern "C"{
+#include <sndfile.h>
+}
+#include "decoder.h"
+
+
+class DecoderSndFile : public Decoder
+{
+public:
+ DecoderSndFile(QObject *, DecoderFactory *, QIODevice *, Output *);
+ virtual ~DecoderSndFile();
+
+ // Standard Decoder API
+ bool initialize();
+ double lengthInSeconds();
+ void seek(double);
+ void stop();
+
+
+private:
+ // thread run function
+ void run();
+ // helper functions
+ void flush(bool = FALSE);
+ void deinit();
+
+ // output buffer
+ char *m_output_buf;
+
+ SNDFILE *m_sndfile;
+ ulong m_output_bytes, m_output_at;
+ //struct sndfile_data *m_data;
+ short *m_buf;
+ unsigned int bks;
+ bool m_done, m_finish, m_inited, m_user_stop;
+ long m_freq, m_bitrate;
+ int m_chan;
+ unsigned long m_output_size;
+ double m_totalTime, m_seekTime;
+};
+
+
+#endif // DECODER_SNDFILE_H
diff --git a/src/plugins/Input/sndfile/decodersndfilefactory.cpp b/src/plugins/Input/sndfile/decodersndfilefactory.cpp
new file mode 100644
index 000000000..b918d32fc
--- /dev/null
+++ b/src/plugins/Input/sndfile/decodersndfilefactory.cpp
@@ -0,0 +1,126 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include <QtGui>
+#include <sndfile.h>
+
+#include "decoder_sndfile.h"
+#include "decodersndfilefactory.h"
+
+
+// DecoderSndFileFactory
+
+bool DecoderSndFileFactory::supports(const QString &source) const
+{
+
+ return (source.right(4).toLower() == ".wav") ||
+ (source.right(3).toLower() == ".au") ||
+ (source.right(4).toLower() == ".snd") ||
+ (source.right(4).toLower() == ".aif") ||
+ (source.right(5).toLower() == ".aiff") ||
+ (source.right(5).toLower() == ".8svx") ||
+ (source.right(4).toLower() == ".wav") ||
+ (source.right(4).toLower() == ".sph") ||
+ (source.right(3).toLower() == ".sf") ||
+ (source.right(4).toLower() == ".voc");
+}
+
+bool DecoderSndFileFactory::canDecode(QIODevice *) const
+{
+ return FALSE;
+}
+
+const DecoderProperties DecoderSndFileFactory::properties() const
+{
+ DecoderProperties properties;
+ properties.name = tr("Sndfile Plugin");
+ properties.filter = "*.wav *.au *.snd *.aif *.aiff *.8svx *.sph *.sf *.voc";
+ properties.description = tr("PCM Files");
+ //properties.contentType = "";
+ properties.hasAbout = TRUE;
+ properties.hasSettings = FALSE;
+ return properties;
+}
+
+Decoder *DecoderSndFileFactory::create(QObject *parent, QIODevice *input,
+ Output *output)
+{
+ return new DecoderSndFile(parent, this, input, output);
+}
+
+FileTag *DecoderSndFileFactory::createTag(const QString &source)
+{
+ FileTag *ftag = new FileTag();
+ SF_INFO snd_info;
+ SNDFILE *sndfile = 0;
+ memset (&snd_info, 0, sizeof(snd_info));
+ snd_info.format = 0;
+ sndfile = sf_open(source.toLocal8Bit(), SFM_READ, &snd_info);
+ if (!sndfile)
+ return ftag;
+
+ if (sf_get_string(sndfile, SF_STR_TITLE))
+ {
+ char* title = strdup(sf_get_string(sndfile, SF_STR_TITLE));
+ ftag->setValue(FileTag::TITLE, QString::fromUtf8(title).trimmed());
+ }
+ if (sf_get_string(sndfile, SF_STR_ARTIST))
+ {
+ char* artist = strdup(sf_get_string(sndfile, SF_STR_ARTIST));
+ ftag->setValue(FileTag::ARTIST, QString::fromUtf8(artist).trimmed());
+ }
+ if (sf_get_string(sndfile, SF_STR_COMMENT))
+ {
+ char* comment = strdup(sf_get_string(sndfile, SF_STR_COMMENT));
+ ftag->setValue(FileTag::COMMENT, QString::fromUtf8(comment).trimmed());
+ }
+
+ ftag->setValue(FileTag::LENGTH ,int(snd_info.frames / snd_info.samplerate));
+
+ sf_close(sndfile);
+ return ftag;
+}
+
+QObject* DecoderSndFileFactory::showDetails(QWidget *parent, const QString &path)
+{
+ return 0;
+}
+
+void DecoderSndFileFactory::showSettings(QWidget *)
+{}
+
+void DecoderSndFileFactory::showAbout(QWidget *parent)
+{
+ char version [128] ;
+ sf_command (NULL, SFC_GET_LIB_VERSION, version, sizeof (version)) ;
+ QMessageBox::about (parent, tr("About Sndfile Audio Plugin"),
+ tr("Qmmp Sndfile Audio Plugin")+"\n"+
+ tr("Compiled against")+" "+QString(version)+"\n" +
+ tr("Writen by: Ilya Kotov <forkotov02@hotmail.ru>"));
+}
+
+QTranslator *DecoderSndFileFactory::createTranslator(QObject *parent)
+{
+ QTranslator *translator = new QTranslator(parent);
+ QString locale = QLocale::system().name();
+ translator->load(QString(":/sndfile_plugin_") + locale);
+ return translator;
+}
+
+Q_EXPORT_PLUGIN(DecoderSndFileFactory)
diff --git a/src/plugins/Input/sndfile/decodersndfilefactory.h b/src/plugins/Input/sndfile/decodersndfilefactory.h
new file mode 100644
index 000000000..8439594fb
--- /dev/null
+++ b/src/plugins/Input/sndfile/decodersndfilefactory.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef DECODERSNDFILEFACTORY_H
+#define DECODERSNDFILEFACTORY_H
+
+#include <QObject>
+#include <QString>
+#include <QIODevice>
+#include <QWidget>
+
+#include <decoder.h>
+#include <output.h>
+#include <decoderfactory.h>
+#include <filetag.h>
+
+
+
+
+class DecoderSndFileFactory : public QObject,
+ DecoderFactory
+{
+Q_OBJECT
+Q_INTERFACES(DecoderFactory);
+
+public:
+ bool supports(const QString &source) const;
+ bool canDecode(QIODevice *input) const;
+ const DecoderProperties properties() const;
+ Decoder *create(QObject *, QIODevice *, Output *);
+ FileTag *createTag(const QString &source);
+ QObject* showDetails(QWidget *parent, const QString &path);
+ void showSettings(QWidget *parent);
+ void showAbout(QWidget *parent);
+ QTranslator *createTranslator(QObject *parent);
+};
+
+#endif
diff --git a/src/plugins/Input/sndfile/sndfile.pro b/src/plugins/Input/sndfile/sndfile.pro
new file mode 100644
index 000000000..701ea58fb
--- /dev/null
+++ b/src/plugins/Input/sndfile/sndfile.pro
@@ -0,0 +1,28 @@
+include(../../plugins.pri)
+
+HEADERS += decodersndfilefactory.h \
+ decoder_sndfile.h
+SOURCES += decoder_sndfile.cpp \
+ decodersndfilefactory.cpp
+
+TARGET=$$PLUGINS_PREFIX/Input/sndfile
+QMAKE_CLEAN =$$PLUGINS_PREFIX/Input/libsndfile.so
+
+INCLUDEPATH += ../../../qmmp
+CONFIG += release \
+warn_on \
+plugin \
+link_pkgconfig
+TEMPLATE = lib
+QMAKE_LIBDIR += ../../../../lib
+LIBS += -lqmmp -L/usr/lib -I/usr/include
+
+PKGCONFIG += sndfile
+#TRANSLATIONS = translations/ffmpeg_plugin_ru.ts
+#RESOURCES = translations/translations.qrc
+
+isEmpty (LIB_DIR){
+LIB_DIR = /lib
+}
+target.path = $$LIB_DIR/qmmp/Input
+INSTALLS += target
diff --git a/src/plugins/Input/vorbis/CMakeLists.txt b/src/plugins/Input/vorbis/CMakeLists.txt
new file mode 100644
index 000000000..baf5bad8c
--- /dev/null
+++ b/src/plugins/Input/vorbis/CMakeLists.txt
@@ -0,0 +1,96 @@
+project(libvorbis)
+
+cmake_minimum_required(VERSION 2.4.0)
+
+
+INCLUDE(UsePkgConfig)
+INCLUDE(FindQt4)
+
+find_package(Qt4 REQUIRED) # find and setup Qt4 for this project
+include(${QT_USE_FILE})
+
+# qt plugin
+ADD_DEFINITIONS( -Wall )
+ADD_DEFINITIONS(${QT_DEFINITIONS})
+ADD_DEFINITIONS(-DQT_PLUGIN)
+ADD_DEFINITIONS(-DQT_NO_DEBUG)
+ADD_DEFINITIONS(-DQT_SHARED)
+ADD_DEFINITIONS(-DQT_THREAD)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+SET(QT_INCLUDES
+ ${QT_INCLUDES}
+ ${CMAKE_CURRENT_BINARY_DIR}/../../../
+)
+
+# libqmmp
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+link_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+
+# libvorbis and taglib
+PKGCONFIG(ogg OGG_INCLUDE_DIR OGG_LINK_DIR OGG_LINK_FLAGS OGG_CFLAGS)
+PKGCONFIG(vorbis VORBIS_INCLUDE_DIR VORBIS_LINK_DIR VORBIS_LINK_FLAGS VORBIS_CFLAGS)
+PKGCONFIG(vorbisfile VORBISFILE_INCLUDE_DIR VORBISFILE_LINK_DIR VORBISFILE_LINK_FLAGS VORBISFILE_CFLAGS)
+
+PKGCONFIG(taglib TAGLIB_INCLUDE_DIR TAGLIB_LINK_DIR TAGLIB_LINK_FLAGS TAGLIB_CFLAGS)
+
+IF(NOT OGG_LINK_FLAGS)
+ SET(OGG_LINK_FLAGS -logg)
+ENDIF(NOT OGG_LINK_FLAGS)
+
+IF(NOT VORBIS_LINK_FLAGS)
+ SET(VORBIS_LINK_FLAGS -lvorbis)
+ENDIF(NOT VORBIS_LINK_FLAGS)
+
+IF(NOT VORBISFILE_LINK_FLAGS)
+ SET(VORBISFILE_LINK_FLAGS -lvorbisfile)
+ENDIF(NOT VORBISFILE_LINK_FLAGS)
+
+IF(NOT TAGLIB_LINK_FLAGS)
+ SET(TAGLIB_LINK_FLAGS -ltag)
+ SET(TAGLIB_INCLUDE_DIR /usr/include/taglib)
+ SET(TAGLIB_CFLAGS -I/usr/include/taglib)
+ENDIF(NOT TAGLIB_LINK_FLAGS)
+
+include_directories(${VORBIS_INCLUDE_DIR} ${TAGLIB_INCLUDE_DIR})
+link_directories(${VORBIS_LINK_DIR} ${TAGLIB_LINK_DIR})
+
+#ADD_DEFINITIONS(${VORBIS_CFLAGS})
+ADD_DEFINITIONS(${TAGLIB_CFLAGS})
+
+
+SET(libvorbis_SRCS
+ decoder_vorbis.cpp
+ decodervorbisfactory.cpp
+ detailsdialog.cpp
+)
+
+SET(libvorbis_MOC_HDRS
+ decodervorbisfactory.h
+ decoder_vorbis.h
+ detailsdialog.h
+)
+
+SET(libvorbis_RCCS translations/translations.qrc)
+
+QT4_ADD_RESOURCES(libvorbis_RCC_SRCS ${libvorbis_RCCS})
+
+QT4_WRAP_CPP(libvorbis_MOC_SRCS ${libvorbis_MOC_HDRS})
+
+# user interface
+
+
+SET(libvorbis_UIS
+ detailsdialog.ui
+)
+
+QT4_WRAP_UI(libvorbis_UIS_H ${libvorbis_UIS})
+# Don't forget to include output directory, otherwise
+# the UI file won't be wrapped!
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+ADD_LIBRARY(vorbis SHARED ${libvorbis_SRCS} ${libvorbis_MOC_SRCS} ${libvorbis_UIS_H}
+ ${libvorbis_RCC_SRCS})
+target_link_libraries(vorbis ${QT_LIBRARIES} -lqmmp ${VORBIS_LINK_FLAGS} ${VORBISFILE_LINK_FLAGS} ${OGG_LINK_FLAGS} ${TAGLIB_LINK_FLAGS} ${TAGLIB_CFLAGS})
+install(TARGETS vorbis DESTINATION ${LIB_DIR}/qmmp/Input PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ)
diff --git a/src/plugins/Input/vorbis/decoder_vorbis.cpp b/src/plugins/Input/vorbis/decoder_vorbis.cpp
new file mode 100644
index 000000000..31fb99c6f
--- /dev/null
+++ b/src/plugins/Input/vorbis/decoder_vorbis.cpp
@@ -0,0 +1,425 @@
+// Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com>
+//
+// Use, modification and distribution is allowed without limitation,
+// warranty, or liability of any kind.
+//
+
+#include "decoder_vorbis.h"
+#include "constants.h"
+#include "buffer.h"
+#include "output.h"
+#include "recycler.h"
+#include "filetag.h"
+
+#include <QObject>
+#include <QIODevice>
+
+
+// ic functions for OggVorbis
+
+static size_t oggread (void *buf, size_t size, size_t nmemb, void *src)
+{
+ if (! src) return 0;
+
+ DecoderVorbis *dogg = (DecoderVorbis *) src;
+ int len = dogg->input()->read((char *) buf, (size * nmemb));
+ return len / size;
+}
+
+
+static int oggseek(void *src, int64_t offset, int whence)
+{
+ DecoderVorbis *dogg = (DecoderVorbis *) src;
+
+ if ( dogg->input()->isSequential ())
+ return -1;
+
+ long start = 0;
+ switch (whence)
+ {
+ case SEEK_END:
+ start = dogg->input()->size();
+ break;
+
+ case SEEK_CUR:
+ start = dogg->input()->pos();
+ break;
+
+ case SEEK_SET:
+ default:
+ start = 0;
+ }
+
+ if (dogg->input()->seek(start + offset))
+ return 0;
+ return -1;
+}
+
+
+static int oggclose(void *src)
+{
+ DecoderVorbis *dogg = (DecoderVorbis *) src;
+ dogg->input()->close();
+ return 0;
+}
+
+
+static long oggtell(void *src)
+{
+ DecoderVorbis *dogg = (DecoderVorbis *) src;
+ long t = dogg->input()->pos();
+ return t;
+}
+
+
+// Decoder class
+
+DecoderVorbis::DecoderVorbis(QObject *parent, DecoderFactory *d, QIODevice *i, Output *o)
+ : Decoder(parent, d, i, o)
+{
+ inited = FALSE;
+ user_stop = FALSE;
+ stat = 0;
+ output_buf = 0;
+ output_bytes = 0;
+ output_at = 0;
+ bks = 0;
+ done = FALSE;
+ finish = FALSE;
+ len = 0;
+ freq = 0;
+ bitrate = 0;
+ seekTime = -1.0;
+ totalTime = 0.0;
+ chan = 0;
+ output_size = 0;
+}
+
+
+DecoderVorbis::~DecoderVorbis()
+{
+ deinit();
+
+ if (output_buf)
+ delete [] output_buf;
+ output_buf = 0;
+}
+
+
+void DecoderVorbis::stop()
+{
+ user_stop = TRUE;
+}
+
+
+void DecoderVorbis::flush(bool final)
+{
+ ulong min = final ? 0 : bks;
+
+ while ((! done && ! finish) && output_bytes > min)
+ {
+ output()->recycler()->mutex()->lock ();
+
+ while ((! done && ! finish) && output()->recycler()->full())
+ {
+ mutex()->unlock();
+
+ output()->recycler()->cond()->wait(output()->recycler()->mutex());
+
+ mutex()->lock ();
+ done = user_stop;
+ }
+
+ if (user_stop || finish)
+ {
+ inited = FALSE;
+ done = TRUE;
+ }
+ else
+ {
+ /*ulong sz = output_bytes < bks ? output_bytes : bks;
+ Buffer *b = output()->recycler()->get();
+
+ memcpy(b->data, output_buf, sz);
+ if (sz != bks) memset(b->data + sz, 0, bks - sz);
+
+ b->nbytes = bks;
+ b->rate = bitrate;
+ output_size += b->nbytes;
+ output()->recycler()->add();
+
+ output_bytes -= sz;
+ memmove(output_buf, output_buf + sz, output_bytes);*/
+ output_bytes -= produceSound(output_buf, output_bytes, bitrate, chan);
+ output_size += bks;
+ output_at = output_bytes;
+ }
+
+ if (output()->recycler()->full())
+ {
+ output()->recycler()->cond()->wakeOne();
+ }
+
+ output()->recycler()->mutex()->unlock();
+ }
+}
+
+
+bool DecoderVorbis::initialize()
+{
+ qDebug("DecoderVorbis: initialize");
+ bks = blockSize();
+
+ inited = user_stop = done = finish = FALSE;
+ len = freq = bitrate = 0;
+ stat = chan = 0;
+ output_size = 0;
+ seekTime = -1.0;
+ totalTime = 0.0;
+ if (! input())
+ {
+ qDebug("DecoderVorbis: cannot initialize. No input");
+
+ return FALSE;
+ }
+
+ if (! output_buf)
+ output_buf = new char[globalBufferSize];
+ output_at = 0;
+ output_bytes = 0;
+
+ if (! input()->isOpen())
+ {
+ if (! input()->open(QIODevice::ReadOnly))
+ {
+ qWarning(qPrintable("DecoderVorbis: failed to open input. " +
+ input()->errorString () + "."));
+ return FALSE;
+ }
+ }
+
+ ov_callbacks oggcb =
+ {
+ oggread,
+ oggseek,
+ oggclose,
+ oggtell
+ };
+ if (ov_open_callbacks(this, &oggfile, NULL, 0, oggcb) < 0)
+ {
+ qWarning("DecoderVorbis: cannot open stream");
+
+ return FALSE;
+ }
+
+ freq = 0;
+ bitrate = ov_bitrate(&oggfile, -1) / 1000;
+ chan = 0;
+
+ totalTime = long(ov_time_total(&oggfile, 0));
+ totalTime = totalTime < 0 ? 0 : totalTime;
+
+ vorbis_info *ogginfo = ov_info(&oggfile, -1);
+ if (ogginfo)
+ {
+ freq = ogginfo->rate;
+ chan = ogginfo->channels;
+ }
+
+ configure(freq, chan, 16, bitrate);
+
+ inited = TRUE;
+ return TRUE;
+}
+
+
+double DecoderVorbis::lengthInSeconds()
+{
+ if (! inited)
+ return 0;
+
+ return totalTime;
+}
+
+
+void DecoderVorbis::seek(double pos)
+{
+ seekTime = pos;
+}
+
+
+void DecoderVorbis::deinit()
+{
+ if (inited)
+ ov_clear(&oggfile);
+ inited = user_stop = done = finish = FALSE;
+ len = freq = bitrate = 0;
+ stat = chan = 0;
+ output_size = 0;
+}
+
+void DecoderVorbis::updateTags()
+{
+ int i;
+ vorbis_comment *comments;
+
+ FileTag tag;
+ comments = ov_comment (&oggfile, -1);
+ for (i = 0; i < comments->comments; i++)
+ {
+ if (!strncasecmp(comments->user_comments[i], "title=",
+ strlen ("title=")))
+ tag.setValue(FileTag::TITLE, QString::fromUtf8(comments->user_comments[i]
+ + strlen ("title=")));
+ else if (!strncasecmp(comments->user_comments[i],
+ "artist=", strlen ("artist=")))
+ tag.setValue(FileTag::ARTIST,
+ QString::fromUtf8(comments->user_comments[i]
+ + strlen ("artist=")));
+ else if (!strncasecmp(comments->user_comments[i],
+ "album=", strlen ("album=")))
+ tag.setValue(FileTag::ALBUM,
+ QString::fromUtf8(comments->user_comments[i]
+ + strlen ("album=")));
+ else if (!strncasecmp(comments->user_comments[i],
+ "comment=", strlen ("comment=")))
+ tag.setValue(FileTag::COMMENT,
+ QString::fromUtf8(comments->user_comments[i]
+ + strlen ("comment=")));
+ else if (!strncasecmp(comments->user_comments[i],
+ "genre=", strlen ("genre=")))
+ tag.setValue(FileTag::GENRE, QString::fromUtf8 (comments->user_comments[i]
+ + strlen ("genre=")));
+ else if (!strncasecmp(comments->user_comments[i],
+ "tracknumber=",
+ strlen ("tracknumber=")))
+ tag.setValue(FileTag::TRACK, atoi (comments->user_comments[i]
+ + strlen ("tracknumber=")));
+ else if (!strncasecmp(comments->user_comments[i],
+ "track=", strlen ("track=")))
+ tag.setValue(FileTag::TRACK, atoi (comments->user_comments[i]
+ + strlen ("track=")));
+ else if (!strncasecmp(comments->user_comments[i],
+ "date=", strlen ("date=")))
+ tag.setValue(FileTag::YEAR, atoi (comments->user_comments[i]
+ + strlen ("date=")));
+
+ }
+ tag.setValue(FileTag::LENGTH, uint(totalTime));
+ dispatch(tag);
+}
+
+void DecoderVorbis::run()
+{
+ mutex()->lock ();
+
+ if (! inited)
+ {
+ mutex()->unlock();
+
+ return;
+ }
+
+ //stat = DecoderEvent::Decoding;
+ stat = DecoderState::Decoding;
+ mutex()->unlock();
+
+ {
+ //DecoderEvent e((DecoderEvent::Type) stat);
+ //dispatch(e);
+ //DecoderStatus st ((DecoderStatus::Type) stat);
+ dispatch(DecoderState ((DecoderState::Type) stat));
+
+ //emit statusChanged(stat);
+ }
+
+ int section = 0;
+ int last_section = -1;
+
+ while (! done && ! finish)
+ {
+ mutex()->lock ();
+ // decode
+
+ if (seekTime >= 0.0)
+ {
+ ov_time_seek(&oggfile, double(seekTime));
+ seekTime = -1.0;
+
+ output_size = long(ov_time_tell(&oggfile)) * long(freq * chan * 2);
+ }
+ len = -1;
+ while (len < 0)
+ {
+ len = ov_read(&oggfile, (char *) (output_buf + output_at), bks, 0, 2, 1,
+ &section);
+ }
+ if (section != last_section)
+ updateTags();
+ last_section = section;
+
+ if (len > 0)
+ {
+ bitrate = ov_bitrate_instant(&oggfile) / 1000;
+
+ output_at += len;
+ output_bytes += len;
+
+ if (output())
+ flush();
+ }
+ else if (len == 0)
+ {
+ flush(TRUE);
+
+ if (output())
+ {
+ output()->recycler()->mutex()->lock ();
+ // end of stream
+ while (! output()->recycler()->empty() && ! user_stop)
+ {
+ output()->recycler()->cond()->wakeOne();
+ mutex()->unlock();
+ output()->recycler()->cond()->wait(output()->recycler()->mutex());
+ mutex()->lock ();
+ }
+ output()->recycler()->mutex()->unlock();
+ }
+
+ done = TRUE;
+ if (! user_stop)
+ {
+ finish = TRUE;
+ }
+ }
+ else
+ {
+ // error in read
+ error("DecoderVorbis: Error while decoding stream, File appears to be "
+ "corrupted");
+
+ finish = TRUE;
+ }
+
+ mutex()->unlock();
+ }
+
+ mutex()->lock ();
+
+ if (finish)
+ stat = DecoderState::Finished;
+ else if (user_stop)
+ stat = DecoderState::Stopped;
+
+ mutex()->unlock();
+
+ {
+ /*DecoderEvent e((DecoderEvent::Type) stat);
+ dispatch(e);*/
+ //DecoderStatus st ((DecoderStatus::Type) stat);
+ //emit statusChanged(st);
+ dispatch(DecoderState ((DecoderState::Type) stat));
+ }
+
+ deinit();
+}
diff --git a/src/plugins/Input/vorbis/decoder_vorbis.h b/src/plugins/Input/vorbis/decoder_vorbis.h
new file mode 100644
index 000000000..091d856ff
--- /dev/null
+++ b/src/plugins/Input/vorbis/decoder_vorbis.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com>
+//
+// Use, modification and distribution is allowed without limitation,
+// warranty, or liability of any kind.
+//
+
+#ifndef __decoder_vorbis_h
+#define __decoder_vorbis_h
+
+#include "decoder.h"
+
+#include <vorbis/vorbisfile.h>
+
+
+class DecoderVorbis : public Decoder
+{
+public:
+ DecoderVorbis(QObject *, DecoderFactory *, QIODevice *, Output *);
+ virtual ~DecoderVorbis();
+
+ // Standard Decoder API
+ bool initialize();
+ double lengthInSeconds();
+ void seek(double);
+ void stop();
+
+ // Equalizer
+ bool isEQSupported() const { return FALSE; }
+ void setEQEnabled(bool) { ; }
+ void setEQGain(int) { ; }
+ void setEQBands(int[10]) { ; }
+
+
+private:
+ // thread run function
+ void run();
+
+ // helper functions
+ void flush(bool = FALSE);
+ void deinit();
+
+ void updateTags();
+
+ bool inited, user_stop;
+ int stat;
+
+ // output buffer
+ char *output_buf;
+ ulong output_bytes, output_at;
+
+ // OggVorbis Decoder
+ OggVorbis_File oggfile;
+
+ unsigned int bks;
+ bool done, finish;
+ long len, freq, bitrate;
+ int chan;
+ unsigned long output_size;
+ double totalTime, seekTime;
+};
+
+
+#endif // __decoder_vorbis_h
diff --git a/src/plugins/Input/vorbis/decodervorbisfactory.cpp b/src/plugins/Input/vorbis/decodervorbisfactory.cpp
new file mode 100644
index 000000000..c3b31ec52
--- /dev/null
+++ b/src/plugins/Input/vorbis/decodervorbisfactory.cpp
@@ -0,0 +1,105 @@
+#include <QtGui>
+#include <taglib/tag.h>
+#include <taglib/fileref.h>
+#include <tag.h>
+
+#include "detailsdialog.h"
+#include "decoder_vorbis.h"
+#include "decodervorbisfactory.h"
+
+
+// DecoderOggFactory
+
+bool DecoderVorbisFactory::supports(const QString &source) const
+{
+ return source.right(4).toLower() == ".ogg";
+}
+
+bool DecoderVorbisFactory::canDecode(QIODevice *input) const
+{
+ char buf[36];
+ if (input->peek(buf, 36) == 36 && !memcmp(buf, "OggS", 4)
+ && !memcmp(buf + 29, "vorbis", 6))
+ return TRUE;
+
+ return FALSE;
+}
+
+const DecoderProperties DecoderVorbisFactory::properties() const
+{
+ DecoderProperties properties;
+ properties.name = tr("Ogg Vorbis Plugin");
+ properties.filter = "*.ogg";
+ properties.description = tr("Ogg Vorbis Files");
+ properties.contentType = "application/ogg;audio/x-vorbis+ogg";
+ properties.hasAbout = TRUE;
+ properties.hasSettings = FALSE;
+ return properties;
+}
+
+Decoder *DecoderVorbisFactory::create(QObject *parent, QIODevice *input,
+ Output *output)
+{
+ return new DecoderVorbis(parent, this, input, output);
+}
+
+FileTag *DecoderVorbisFactory::createTag(const QString &source)
+{
+ FileTag *ftag = new FileTag();
+
+ TagLib::FileRef fileRef(source.toLocal8Bit ());
+ TagLib::Tag *tag = fileRef.tag();
+
+ if (tag && !tag->isEmpty())
+ {
+ ftag->setValue(FileTag::ALBUM,
+ QString::fromUtf8(tag->album().toCString(TRUE)).trimmed());
+ ftag->setValue(FileTag::ARTIST,
+ QString::fromUtf8(tag->artist().toCString(TRUE)).trimmed());
+ ftag->setValue(FileTag::COMMENT,
+ QString::fromUtf8(tag->comment().toCString(TRUE)).trimmed());
+ ftag->setValue(FileTag::GENRE,
+ QString::fromUtf8(tag->genre().toCString(TRUE)).trimmed());
+ ftag->setValue(FileTag::TITLE,
+ QString::fromUtf8(tag->title().toCString(TRUE)).trimmed());
+ ftag->setValue(FileTag::YEAR, tag->year());
+ ftag->setValue(FileTag::TRACK, tag->track());
+ }
+
+ if (fileRef.audioProperties())
+ ftag->setValue(FileTag::LENGTH, fileRef.audioProperties()->length());
+
+ return ftag;
+}
+
+QObject* DecoderVorbisFactory::showDetails(QWidget *parent, const QString &path)
+{
+ DetailsDialog *d = new DetailsDialog(parent, path);
+ d -> show();
+ return d;
+}
+
+void DecoderVorbisFactory::showSettings(QWidget *)
+{
+ /*SettingsDialog *s = new SettingsDialog(parent);
+ s -> show();*/
+}
+
+void DecoderVorbisFactory::showAbout(QWidget *parent)
+{
+ QMessageBox::about (parent, tr("About Ogg Vorbis Audio Plugin"),
+ tr("Qmmp Ogg Vorbis Audio Plugin")+"\n"+
+ tr("Writen by: Ilya Kotov <forkotov02@hotmail.ru>")+"\n"+
+ tr("Source code based on mq3 progect")
+ );
+}
+
+QTranslator *DecoderVorbisFactory::createTranslator(QObject *parent)
+{
+ QTranslator *translator = new QTranslator(parent);
+ QString locale = QLocale::system().name();
+ translator->load(QString(":/vorbis_plugin_") + locale);
+ return translator;
+}
+
+Q_EXPORT_PLUGIN(DecoderVorbisFactory)
diff --git a/src/plugins/Input/vorbis/decodervorbisfactory.h b/src/plugins/Input/vorbis/decodervorbisfactory.h
new file mode 100644
index 000000000..6830fc102
--- /dev/null
+++ b/src/plugins/Input/vorbis/decodervorbisfactory.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef DECODERVORBISFACTORY_H
+#define DECODERVORBISFACTORY_H
+
+#include <QObject>
+#include <QString>
+#include <QIODevice>
+#include <QWidget>
+
+#include <decoder.h>
+#include <output.h>
+#include <decoderfactory.h>
+#include <filetag.h>
+
+
+
+
+class DecoderVorbisFactory : public QObject,
+ DecoderFactory
+{
+Q_OBJECT
+Q_INTERFACES(DecoderFactory);
+
+public:
+ bool supports(const QString &source) const;
+ bool canDecode(QIODevice *input) const;
+ const DecoderProperties properties() const;
+ Decoder *create(QObject *, QIODevice *, Output *);
+ FileTag *createTag(const QString &source);
+ QObject* showDetails(QWidget *parent, const QString &path);
+ void showSettings(QWidget *parent);
+ void showAbout(QWidget *parent);
+ QTranslator *createTranslator(QObject *parent);
+};
+
+#endif
diff --git a/src/plugins/Input/vorbis/detailsdialog.cpp b/src/plugins/Input/vorbis/detailsdialog.cpp
new file mode 100644
index 000000000..bbe441703
--- /dev/null
+++ b/src/plugins/Input/vorbis/detailsdialog.cpp
@@ -0,0 +1,120 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include <taglib/tag.h>
+#include <taglib/fileref.h>
+#include <taglib/vorbisfile.h>
+
+#include <QFile>
+#include <QFileInfo>
+
+#include "detailsdialog.h"
+
+#define QStringToTString_qt4(s) TagLib::String(s.toUtf8().constData(), TagLib::String::UTF8)
+
+DetailsDialog::DetailsDialog(QWidget *parent, const QString &path)
+ : QDialog(parent)
+{
+ ui.setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose);
+ m_path = path;
+ setWindowTitle (path.section('/',-1));
+ path.section('/',-1);
+ ui.pathLineEdit->setText(m_path);
+ if(QFile::exists(m_path))
+ {
+ loadVorbisInfo();
+ loadTag();
+ }
+}
+
+
+DetailsDialog::~DetailsDialog()
+{}
+
+void DetailsDialog::loadVorbisInfo()
+{
+ TagLib::Ogg::Vorbis::File f (m_path.toLocal8Bit());
+ //l.label
+ //ui. f.audioProperties()->level();
+ QString text;
+ text = QString("%1").arg(f.audioProperties()->length()/60);
+ text +=":"+QString("%1").arg(f.audioProperties()->length()%60,2,10,QChar('0'));
+ ui.lengthLabel->setText(text);
+ text = QString("%1").arg(f.audioProperties()->sampleRate());
+ ui.sampleRateLabel->setText(text+" "+tr("Hz"));
+ text = QString("%1").arg(f.audioProperties()->channels());
+ ui.channelsLabel->setText(text);
+ text = QString("%1").arg(f.audioProperties()->bitrateNominal());
+ ui.nominalLabel->setText(text+" "+tr("kbps"));
+ text = QString("%1").arg(f.audioProperties()->bitrateMaximum());
+ ui.maximumLabel->setText(text+" "+tr("kbps"));
+ text = QString("%1").arg(f.audioProperties()->bitrateMinimum());
+ ui.minimumLabel->setText(text+" "+tr("kbps"));
+ text = QString("%1 "+tr("KB")).arg(f.length()/1024);
+ ui.fileSizeLabel->setText(text);
+
+}
+
+void DetailsDialog::loadTag()
+{
+ TagLib::FileRef f (m_path.toLocal8Bit());
+
+ if (f.tag())
+ { //TODO: load codec name from config
+
+ TagLib::String title = f.tag()->title();
+ TagLib::String artist = f.tag()->artist();
+ TagLib::String album = f.tag()->album();
+ TagLib::String comment = f.tag()->comment();
+ TagLib::String genre = f.tag()->genre();
+ QString string = QString::fromUtf8(title.toCString(TRUE)).trimmed();
+ ui.titleLineEdit->setText(string);
+ string = QString::fromUtf8(artist.toCString(TRUE)).trimmed();
+ ui.artistLineEdit->setText(string);
+ string = QString::fromUtf8(album.toCString(TRUE)).trimmed();
+ ui.albumLineEdit->setText(string);
+ string = QString::fromUtf8(comment.toCString(TRUE)).trimmed();
+ ui.commentLineEdit->setText(string);
+ string = QString("%1").arg(f.tag()->year());
+ ui.yearLineEdit->setText(string);
+ string = QString("%1").arg(f.tag()->track());
+ ui.trackLineEdit->setText(string);
+ string = QString::fromUtf8(genre.toCString(TRUE)).trimmed();
+ ui.genreLineEdit->setText(string);
+ }
+ QFileInfo info(m_path);
+ ui.saveButton->setEnabled(info.isWritable());
+ connect(ui.saveButton, SIGNAL(clicked()), SLOT(saveTag()));
+}
+
+void DetailsDialog::saveTag()
+{
+ TagLib::FileRef f (m_path.toLocal8Bit());
+
+ f.tag()->setTitle(QStringToTString_qt4(ui.titleLineEdit->text()));
+ f.tag()->setArtist(QStringToTString_qt4(ui.artistLineEdit->text()));
+ f.tag()->setAlbum(QStringToTString_qt4(ui.albumLineEdit->text()));
+ f.tag()->setComment(QStringToTString_qt4(ui.commentLineEdit->text()));
+ f.tag()->setGenre(QStringToTString_qt4(ui.genreLineEdit->text()));
+ f.tag()->setYear(ui.yearLineEdit->text().toUInt());
+ f.tag()->setTrack(ui.trackLineEdit->text().toUInt());
+
+ f.save();
+}
diff --git a/src/plugins/Input/vorbis/detailsdialog.h b/src/plugins/Input/vorbis/detailsdialog.h
new file mode 100644
index 000000000..94d4243b8
--- /dev/null
+++ b/src/plugins/Input/vorbis/detailsdialog.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef DETAILSDIALOG_H
+#define DETAILSDIALOG_H
+
+#include <QDialog>
+
+#include "ui_detailsdialog.h"
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class DetailsDialog : public QDialog
+{
+Q_OBJECT
+public:
+ DetailsDialog(QWidget *parent = 0, const QString &path = 0);
+
+ ~DetailsDialog();
+
+private slots:
+ void saveTag();
+
+private:
+ void loadVorbisInfo();
+ void loadTag();
+ Ui::DetailsDialog ui;
+ QString m_path;
+
+};
+
+#endif
diff --git a/src/plugins/Input/vorbis/detailsdialog.ui b/src/plugins/Input/vorbis/detailsdialog.ui
new file mode 100644
index 000000000..1804ab268
--- /dev/null
+++ b/src/plugins/Input/vorbis/detailsdialog.ui
@@ -0,0 +1,384 @@
+<ui version="4.0" >
+ <class>DetailsDialog</class>
+ <widget class="QDialog" name="DetailsDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>536</width>
+ <height>375</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Details</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item rowspan="2" row="1" column="0" colspan="2" >
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="minimumSize" >
+ <size>
+ <width>220</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="title" >
+ <string>Ogg Vorbis Info</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="2" column="1" >
+ <widget class="QLabel" name="fileSizeLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QLabel" name="channelsLabel" >
+ <property name="layoutDirection" >
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Length:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLabel" name="lengthLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Sample rate:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLabel" name="sampleRateLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_10" >
+ <property name="layoutDirection" >
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text" >
+ <string>Channels:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="4" column="0" colspan="2" >
+ <widget class="QGroupBox" name="groupBox_3" >
+ <property name="title" >
+ <string>Bit Rate</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignHCenter</set>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="1" column="1" >
+ <widget class="QLabel" name="maximumLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QLabel" name="minimumLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_9" >
+ <property name="layoutDirection" >
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text" >
+ <string>Minimum:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLabel" name="nominalLabel" >
+ <property name="text" >
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_8" >
+ <property name="text" >
+ <string>Maximum:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_7" >
+ <property name="text" >
+ <string>Nominal:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_5" >
+ <property name="text" >
+ <string>File size:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="3" >
+ <widget class="QLineEdit" name="pathLineEdit" >
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_28" >
+ <property name="text" >
+ <string>File path:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="3" >
+ <widget class="QPushButton" name="pushButton_3" >
+ <property name="text" >
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>111</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="2" colspan="2" >
+ <widget class="QGroupBox" name="groupBox_2" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title" >
+ <string>Ogg Vorbis Tag</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="6" column="1" colspan="2" >
+ <widget class="QPushButton" name="saveButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Save</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="3" >
+ <widget class="QLineEdit" name="trackLineEdit" />
+ </item>
+ <item row="4" column="2" >
+ <widget class="QLabel" name="label_26" >
+ <property name="text" >
+ <string>Track number:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" >
+ <widget class="QLineEdit" name="yearLineEdit" />
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="label_25" >
+ <property name="text" >
+ <string>Year:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" >
+ <widget class="QLabel" name="label_27" >
+ <property name="text" >
+ <string>Genre:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_24" >
+ <property name="text" >
+ <string>Comment:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_23" >
+ <property name="text" >
+ <string>Album:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_22" >
+ <property name="text" >
+ <string>Artist:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_21" >
+ <property name="text" >
+ <string>Title:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="3" >
+ <widget class="QLineEdit" name="titleLineEdit" />
+ </item>
+ <item row="1" column="1" colspan="3" >
+ <widget class="QLineEdit" name="artistLineEdit" />
+ </item>
+ <item row="2" column="1" colspan="3" >
+ <widget class="QLineEdit" name="albumLineEdit" />
+ </item>
+ <item row="3" column="1" colspan="3" >
+ <widget class="QLineEdit" name="commentLineEdit" />
+ </item>
+ <item row="5" column="1" colspan="2" >
+ <widget class="QLineEdit" name="genreLineEdit" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>pushButton_3</sender>
+ <signal>clicked()</signal>
+ <receiver>DetailsDialog</receiver>
+ <slot>close()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>623</x>
+ <y>353</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>539</x>
+ <y>352</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/Input/vorbis/translations/translations.qrc b/src/plugins/Input/vorbis/translations/translations.qrc
new file mode 100644
index 000000000..c5cacdfb0
--- /dev/null
+++ b/src/plugins/Input/vorbis/translations/translations.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+ <qresource>
+ <file>vorbis_plugin_ru.qm</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/Input/vorbis/translations/vorbis_plugin_ru.qm b/src/plugins/Input/vorbis/translations/vorbis_plugin_ru.qm
new file mode 100644
index 000000000..a6a3a77b7
--- /dev/null
+++ b/src/plugins/Input/vorbis/translations/vorbis_plugin_ru.qm
Binary files differ
diff --git a/src/plugins/Input/vorbis/translations/vorbis_plugin_ru.ts b/src/plugins/Input/vorbis/translations/vorbis_plugin_ru.ts
new file mode 100644
index 000000000..16cf81ea3
--- /dev/null
+++ b/src/plugins/Input/vorbis/translations/vorbis_plugin_ru.ts
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS><TS version="1.1" language="ru">
+<context>
+ <name>DecoderVorbisFactory</name>
+ <message>
+ <location filename="../decodervorbisfactory.cpp" line="21"/>
+ <source>Ogg Vorbis Plugin</source>
+ <translation>Модуль Ogg Vorbis</translation>
+ </message>
+ <message>
+ <location filename="../decodervorbisfactory.cpp" line="34"/>
+ <source>Ogg Vorbis Files</source>
+ <translation>Файлы Ogg Vorbis</translation>
+ </message>
+ <message>
+ <location filename="../decodervorbisfactory.cpp" line="64"/>
+ <source>About Ogg Vorbis Audio Plugin</source>
+ <translation>Об аудио-модуле Ogg Vorbis</translation>
+ </message>
+ <message>
+ <location filename="../decodervorbisfactory.cpp" line="65"/>
+ <source>Qmmp Ogg Vorbis Audio Plugin</source>
+ <translation>Аудио-модуль Ogg Vorbis для Qmmp</translation>
+ </message>
+ <message>
+ <location filename="../decodervorbisfactory.cpp" line="66"/>
+ <source>Writen by: Ilya Kotov &lt;forkotov02@hotmail.ru&gt;</source>
+ <translation>Разработчик: Илья Котов &lt;forkotov02@hotmail.ru&gt;</translation>
+ </message>
+ <message>
+ <location filename="../decodervorbisfactory.cpp" line="68"/>
+ <source>Source code based on mq3 progect</source>
+ <translation>Исходный код основан на проекте mq3</translation>
+ </message>
+</context>
+<context>
+ <name>DetailsDialog</name>
+ <message>
+ <location filename="../detailsdialog.cpp" line="54"/>
+ <source>Hz</source>
+ <translation>Гц</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="265"/>
+ <source>Save</source>
+ <translation>Сохранить</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="275"/>
+ <source>Track number:</source>
+ <translation>Номер трека:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="288"/>
+ <source>Year:</source>
+ <translation>Год:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="298"/>
+ <source>Genre:</source>
+ <translation>Жанр:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="308"/>
+ <source>Comment:</source>
+ <translation>Комментарий:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="318"/>
+ <source>Album:</source>
+ <translation>Альбом:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="328"/>
+ <source>Artist:</source>
+ <translation>Исполнитель:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="338"/>
+ <source>Title:</source>
+ <translation>Название:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="222"/>
+ <source>Close</source>
+ <translation>Закрыть</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="162"/>
+ <source>-</source>
+ <translation></translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="192"/>
+ <source>File size:</source>
+ <translation>Размер файла:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="77"/>
+ <source>Sample rate:</source>
+ <translation>Дискретизация:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="212"/>
+ <source>File path:</source>
+ <translation>Путь к файлу:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="31"/>
+ <source>Ogg Vorbis Info</source>
+ <translation>Информация Ogg Vorbis</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="60"/>
+ <source>Length:</source>
+ <translation>Длительность:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="97"/>
+ <source>Channels:</source>
+ <translation>Каналов:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="120"/>
+ <source>Bit Rate</source>
+ <translation>Битовая частота</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="152"/>
+ <source>Minimum:</source>
+ <translation>Минимальная:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="169"/>
+ <source>Maximum:</source>
+ <translation>Максимальная:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="179"/>
+ <source>Nominal:</source>
+ <translation>Номинальная:</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="250"/>
+ <source>Ogg Vorbis Tag</source>
+ <translation>Оgg Vorbis-тег</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.cpp" line="62"/>
+ <source>kbps</source>
+ <translation>Кб/с</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.cpp" line="63"/>
+ <source>KB</source>
+ <translation>Кб</translation>
+ </message>
+ <message>
+ <location filename="../detailsdialog.ui" line="13"/>
+ <source>Details</source>
+ <translation>Информация</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/plugins/Input/vorbis/vorbis.pro b/src/plugins/Input/vorbis/vorbis.pro
new file mode 100644
index 000000000..afd7b6510
--- /dev/null
+++ b/src/plugins/Input/vorbis/vorbis.pro
@@ -0,0 +1,35 @@
+# ???? ?????? ? KDevelop ?????????? qmake.
+# -------------------------------------------
+# ?????????? ???????????? ???????? ???????? ???????: ./Plugins/Input/ogg
+# ???? - ??????????:
+
+include(../../plugins.pri)
+
+FORMS += detailsdialog.ui
+HEADERS += decodervorbisfactory.h \
+ decoder_vorbis.h \
+ detailsdialog.h
+SOURCES += decoder_vorbis.cpp \
+ decodervorbisfactory.cpp \
+ detailsdialog.cpp
+
+TARGET=$$PLUGINS_PREFIX/Input/vorbis
+QMAKE_CLEAN =$$PLUGINS_PREFIX/Input/libvorbis.so
+
+INCLUDEPATH += ../../../qmmp
+CONFIG += release \
+warn_on \
+plugin \
+link_pkgconfig
+TEMPLATE = lib
+QMAKE_LIBDIR += ../../../../lib
+LIBS += -lqmmp -L/usr/lib
+PKGCONFIG += taglib ogg vorbisfile vorbis
+#TRANSLATIONS = translations/vorbis_plugin_ru.ts
+#RESOURCES = translations/translations.qrc
+
+isEmpty (LIB_DIR){
+LIB_DIR = /lib
+}
+target.path = $$LIB_DIR/qmmp/Input
+INSTALLS += target
diff --git a/src/plugins/Misc/CommandLineOptions/IncDecVolumeOption.pro b/src/plugins/Misc/CommandLineOptions/IncDecVolumeOption.pro
new file mode 100644
index 000000000..1832a0166
--- /dev/null
+++ b/src/plugins/Misc/CommandLineOptions/IncDecVolumeOption.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = IncDecVolumeOption
diff --git a/src/plugins/Misc/CommandLineOptions/IncDecVolumeOption/IncDecVolumeOption.pro b/src/plugins/Misc/CommandLineOptions/IncDecVolumeOption/IncDecVolumeOption.pro
new file mode 100644
index 000000000..fdcef5e38
--- /dev/null
+++ b/src/plugins/Misc/CommandLineOptions/IncDecVolumeOption/IncDecVolumeOption.pro
@@ -0,0 +1,26 @@
+include(../../../../../qmmp.pri)
+
+QMMPSRCROOT = ../../../../
+
+INCLUDEPATH += $$QMMPSRCROOT/ui \
+ $$QMMPSRCROOT/qmmp \
+ $$QMMPSRCROOT
+
+HEADERS += incdecvolumeoption.h \
+ $$QMMPSRCROOT/ui/mainwindow.h \
+ $$QMMPSRCROOT/qmmp/soundcore.h
+
+SOURCES += incdecvolumeoption.cpp \
+ $$QMMPSRCROOT/qmmp/soundcore.cpp \
+ $$QMMPSRCROOT/ui/mainwindow.cpp
+
+DESTDIR = ../
+QMAKE_CLEAN = ../libincdecvolumeoption.so
+
+
+
+CONFIG += release warn_on plugin
+
+TEMPLATE = lib
+
+
diff --git a/src/plugins/Misc/CommandLineOptions/IncDecVolumeOption/Makefile b/src/plugins/Misc/CommandLineOptions/IncDecVolumeOption/Makefile
new file mode 100644
index 000000000..0ac10a77d
--- /dev/null
+++ b/src/plugins/Misc/CommandLineOptions/IncDecVolumeOption/Makefile
@@ -0,0 +1,301 @@
+#############################################################################
+# Makefile for building: libIncDecVolumeOption.so
+# Generated by qmake (2.01a) (Qt 4.3.0) on: Thu Feb 7 01:34:34 2008
+# Project: IncDecVolumeOption.pro
+# Template: lib
+# Command: /usr/local/Trolltech/Qt-4.3.0/bin/qmake -unix -o Makefile IncDecVolumeOption.pro
+#############################################################################
+
+####### Compiler, tools and options
+
+CC = gcc
+CXX = g++
+DEFINES = -DQT_NO_DEBUG -DQT_PLUGIN -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED
+CFLAGS = -pipe -O2 -Wall -W -D_REENTRANT -fPIC $(DEFINES)
+CXXFLAGS = -pipe -O2 -Wall -W -D_REENTRANT -fPIC $(DEFINES)
+INCPATH = -I/usr/local/Trolltech/Qt-4.3.0/mkspecs/linux-g++ -I. -I/usr/local/Trolltech/Qt-4.3.0/include/QtCore -I/usr/local/Trolltech/Qt-4.3.0/include/QtCore -I/usr/local/Trolltech/Qt-4.3.0/include/QtGui -I/usr/local/Trolltech/Qt-4.3.0/include/QtGui -I/usr/local/Trolltech/Qt-4.3.0/include -I../../../../ui -I../../../../qmmp -I../../../.. -I.build/moc -I./.build/ui/
+LINK = g++
+LFLAGS = -Wl,-rpath,/usr/local/Trolltech/Qt-4.3.0/lib -shared
+LIBS = $(SUBLIBS) -L/usr/local/Trolltech/Qt-4.3.0/lib -lQtGui -L/usr/local/Trolltech/Qt-4.3.0/lib -L/usr/X11R6/lib -lpng -lSM -lICE -pthread -pthread -lXi -lXrender -lXrandr -lXfixes -lXcursor -lXinerama -lfreetype -lfontconfig -lXext -lX11 -lQtCore -lz -lm -pthread -lgthread-2.0 -lrt -lglib-2.0 -ldl -lpthread
+AR = ar cqs
+RANLIB =
+QMAKE = /usr/local/Trolltech/Qt-4.3.0/bin/qmake
+TAR = tar -cf
+COMPRESS = gzip -9f
+COPY = cp -f
+SED = sed
+COPY_FILE = $(COPY)
+COPY_DIR = $(COPY) -r
+INSTALL_FILE = install -m 644 -p
+INSTALL_DIR = $(COPY_DIR)
+INSTALL_PROGRAM = install -m 755 -p
+DEL_FILE = rm -f
+SYMLINK = ln -sf
+DEL_DIR = rmdir
+MOVE = mv -f
+CHK_DIR_EXISTS= test -d
+MKDIR = mkdir -p
+
+####### Output directory
+
+OBJECTS_DIR = .build/obj/
+
+####### Files
+
+SOURCES = incdecvolumeoption.cpp \
+ ../../../../qmmp/soundcore.cpp \
+ ../../../../ui/mainwindow.cpp .build/moc/moc_incdecvolumeoption.cpp \
+ .build/moc/moc_mainwindow.cpp \
+ .build/moc/moc_soundcore.cpp
+OBJECTS = .build/obj/incdecvolumeoption.o \
+ .build/obj/soundcore.o \
+ .build/obj/mainwindow.o \
+ .build/obj/moc_incdecvolumeoption.o \
+ .build/obj/moc_mainwindow.o \
+ .build/obj/moc_soundcore.o
+DIST = /usr/local/Trolltech/Qt-4.3.0/mkspecs/common/g++.conf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/common/unix.conf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/common/linux.conf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/qconfig.pri \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt_functions.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt_config.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/exclusive_builds.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/default_pre.prf \
+ /rest/qmmp/qmmp/qmmp.pri \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/release.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/default_post.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/warn_on.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/unix/thread.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/moc.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/resources.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/uic.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/yacc.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/lex.prf \
+ IncDecVolumeOption.pro
+QMAKE_TARGET = IncDecVolumeOption
+DESTDIR = ../
+TARGET = libIncDecVolumeOption.so
+TARGETD = libIncDecVolumeOption.so
+
+first: all
+####### Implicit rules
+
+.SUFFIXES: .o .c .cpp .cc .cxx .C
+
+.cpp.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.cc.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.cxx.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.C.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(INCPATH) -o "$@" "$<"
+
+####### Build rules
+
+all: Makefile ../$(TARGET)
+
+../$(TARGET): $(OBJECTS) $(SUBLIBS) $(OBJCOMP)
+ @$(CHK_DIR_EXISTS) ../ || $(MKDIR) ../
+ -$(DEL_FILE) $(TARGET)
+ $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) $(OBJCOMP)
+ -$(MOVE) $(TARGET) ../
+
+
+
+Makefile: IncDecVolumeOption.pro /usr/local/Trolltech/Qt-4.3.0/mkspecs/linux-g++/qmake.conf /usr/local/Trolltech/Qt-4.3.0/mkspecs/common/g++.conf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/common/unix.conf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/common/linux.conf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/qconfig.pri \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt_functions.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt_config.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/exclusive_builds.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/default_pre.prf \
+ /rest/qmmp/qmmp/qmmp.pri \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/release.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/default_post.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/warn_on.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/unix/thread.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/moc.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/resources.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/uic.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/yacc.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/lex.prf \
+ /usr/local/Trolltech/Qt-4.3.0/lib/libQtGui.prl \
+ /usr/local/Trolltech/Qt-4.3.0/lib/libQtCore.prl
+ $(QMAKE) -unix -o Makefile IncDecVolumeOption.pro
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/common/g++.conf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/common/unix.conf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/common/linux.conf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/qconfig.pri:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt_functions.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt_config.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/exclusive_builds.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/default_pre.prf:
+/rest/qmmp/qmmp/qmmp.pri:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/release.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/default_post.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/warn_on.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/unix/thread.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/moc.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/resources.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/uic.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/yacc.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/lex.prf:
+/usr/local/Trolltech/Qt-4.3.0/lib/libQtGui.prl:
+/usr/local/Trolltech/Qt-4.3.0/lib/libQtCore.prl:
+qmake: FORCE
+ @$(QMAKE) -unix -o Makefile IncDecVolumeOption.pro
+
+dist:
+ @$(CHK_DIR_EXISTS) .build/obj/IncDecVolumeOption1.0.0 || $(MKDIR) .build/obj/IncDecVolumeOption1.0.0
+ $(COPY_FILE) --parents $(SOURCES) $(DIST) .build/obj/IncDecVolumeOption1.0.0/ && $(COPY_FILE) --parents incdecvolumeoption.h ../../../../ui/mainwindow.h ../../../../qmmp/soundcore.h .build/obj/IncDecVolumeOption1.0.0/ && $(COPY_FILE) --parents incdecvolumeoption.cpp ../../../../qmmp/soundcore.cpp ../../../../ui/mainwindow.cpp .build/obj/IncDecVolumeOption1.0.0/ && (cd `dirname .build/obj/IncDecVolumeOption1.0.0` && $(TAR) IncDecVolumeOption1.0.0.tar IncDecVolumeOption1.0.0 && $(COMPRESS) IncDecVolumeOption1.0.0.tar) && $(MOVE) `dirname .build/obj/IncDecVolumeOption1.0.0`/IncDecVolumeOption1.0.0.tar.gz . && $(DEL_FILE) -r .build/obj/IncDecVolumeOption1.0.0
+
+
+clean:compiler_clean
+ -$(DEL_FILE) $(OBJECTS)
+ -$(DEL_FILE) ../libincdecvolumeoption.so
+ -$(DEL_FILE) *~ core *.core
+
+
+####### Sub-libraries
+
+distclean: clean
+ -$(DEL_FILE) $(TARGET)
+ -$(DEL_FILE) Makefile
+
+
+mocclean: compiler_moc_header_clean compiler_moc_source_clean
+
+mocables: compiler_moc_header_make_all compiler_moc_source_make_all
+
+compiler_moc_header_make_all: .build/moc/moc_incdecvolumeoption.cpp .build/moc/moc_mainwindow.cpp .build/moc/moc_soundcore.cpp
+compiler_moc_header_clean:
+ -$(DEL_FILE) .build/moc/moc_incdecvolumeoption.cpp .build/moc/moc_mainwindow.cpp .build/moc/moc_soundcore.cpp
+.build/moc/moc_incdecvolumeoption.cpp: incdecvolumeoption.h
+ /usr/local/Trolltech/Qt-4.3.0/bin/moc $(DEFINES) $(INCPATH) incdecvolumeoption.h -o .build/moc/moc_incdecvolumeoption.cpp
+
+.build/moc/moc_mainwindow.cpp: ../../../../qmmp/output.h \
+ ../../../../qmmp/visual.h \
+ ../../../../qmmp/outputfactory.h \
+ ../../../../qmmp/visualfactory.h \
+ ../../../../qmmp/recycler.h \
+ ../../../../qmmp/decoder.h \
+ ../../../../qmmp/filetag.h \
+ ../../../../ui/display.h \
+ ../../../../ui/pixmapwidget.h \
+ ../../../../ui/mediafile.h \
+ ../../../../qmmp/decoderfactory.h \
+ ../../../../ui/titlebar.h \
+ ../../../../ui/playlist.h \
+ ../../../../ui/mainwindow.h \
+ ../../../../ui/mainwindow.h
+ /usr/local/Trolltech/Qt-4.3.0/bin/moc $(DEFINES) $(INCPATH) ../../../../ui/mainwindow.h -o .build/moc/moc_mainwindow.cpp
+
+.build/moc/moc_soundcore.cpp: ../../../../qmmp/decoder.h \
+ ../../../../qmmp/filetag.h \
+ ../../../../qmmp/output.h \
+ ../../../../qmmp/visual.h \
+ ../../../../qmmp/outputfactory.h \
+ ../../../../qmmp/visualfactory.h \
+ ../../../../qmmp/recycler.h \
+ ../../../../qmmp/soundcore.h
+ /usr/local/Trolltech/Qt-4.3.0/bin/moc $(DEFINES) $(INCPATH) ../../../../qmmp/soundcore.h -o .build/moc/moc_soundcore.cpp
+
+compiler_rcc_make_all:
+compiler_rcc_clean:
+compiler_image_collection_make_all: qmake_image_collection.cpp
+compiler_image_collection_clean:
+ -$(DEL_FILE) qmake_image_collection.cpp
+compiler_moc_source_make_all:
+compiler_moc_source_clean:
+compiler_uic_make_all:
+compiler_uic_clean:
+compiler_yacc_decl_make_all:
+compiler_yacc_decl_clean:
+compiler_yacc_impl_make_all:
+compiler_yacc_impl_clean:
+compiler_lex_make_all:
+compiler_lex_clean:
+compiler_clean: compiler_moc_header_clean
+
+####### Compile
+
+.build/obj/incdecvolumeoption.o: incdecvolumeoption.cpp incdecvolumeoption.h
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o .build/obj/incdecvolumeoption.o incdecvolumeoption.cpp
+
+.build/obj/soundcore.o: ../../../../qmmp/soundcore.cpp ../../../../qmmp/decoderfactory.h \
+ ../../../../qmmp/constants.h \
+ ../../../../qmmp/config.h \
+ ../../../../qmmp/streamreader.h \
+ ../../../../qmmp/effect.h \
+ ../../../../qmmp/soundcore.h \
+ ../../../../qmmp/decoder.h \
+ ../../../../qmmp/filetag.h \
+ ../../../../qmmp/output.h \
+ ../../../../qmmp/visual.h \
+ ../../../../qmmp/outputfactory.h \
+ ../../../../qmmp/visualfactory.h \
+ ../../../../qmmp/recycler.h
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o .build/obj/soundcore.o ../../../../qmmp/soundcore.cpp
+
+.build/obj/mainwindow.o: ../../../../ui/mainwindow.cpp ../../../../ui/textscroller.h \
+ ../../../../ui/mainwindow.h \
+ ../../../../qmmp/output.h \
+ ../../../../qmmp/visual.h \
+ ../../../../qmmp/outputfactory.h \
+ ../../../../qmmp/visualfactory.h \
+ ../../../../qmmp/recycler.h \
+ ../../../../qmmp/decoder.h \
+ ../../../../qmmp/filetag.h \
+ ../../../../ui/display.h \
+ ../../../../ui/pixmapwidget.h \
+ ../../../../ui/mediafile.h \
+ ../../../../qmmp/decoderfactory.h \
+ ../../../../ui/titlebar.h \
+ ../../../../ui/playlist.h \
+ ../../../../qmmp/constants.h \
+ ../../../../qmmp/config.h \
+ ../../../../ui/fileloader.h \
+ ../../../../ui/skin.h \
+ ../../../../ui/playlistmodel.h \
+ ../../../../ui/configdialog.h \
+ ../../../../ui/dock.h \
+ ../../../../ui/eqwidget.h \
+ ../../../../ui/mainvisual.h \
+ ../../../../ui/logscale.h \
+ ../../../../ui/playlistformat.h \
+ ../../../../ui/jumptotrackdialog.h \
+ ../../../../ui/aboutdialog.h \
+ ../../../../ui/filedialog.h \
+ ../../../../ui/listwidget.h \
+ ../../../../ui/visualmenu.h \
+ ../../../../ui/commandlineoption.h
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o .build/obj/mainwindow.o ../../../../ui/mainwindow.cpp
+
+.build/obj/moc_incdecvolumeoption.o: .build/moc/moc_incdecvolumeoption.cpp
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o .build/obj/moc_incdecvolumeoption.o .build/moc/moc_incdecvolumeoption.cpp
+
+.build/obj/moc_mainwindow.o: .build/moc/moc_mainwindow.cpp
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o .build/obj/moc_mainwindow.o .build/moc/moc_mainwindow.cpp
+
+.build/obj/moc_soundcore.o: .build/moc/moc_soundcore.cpp
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o .build/obj/moc_soundcore.o .build/moc/moc_soundcore.cpp
+
+####### Install
+
+install: FORCE
+
+uninstall: FORCE
+
+FORCE:
+
diff --git a/src/plugins/Misc/CommandLineOptions/IncDecVolumeOption/incdecvolumeoption.cpp b/src/plugins/Misc/CommandLineOptions/IncDecVolumeOption/incdecvolumeoption.cpp
new file mode 100644
index 000000000..4bd35a910
--- /dev/null
+++ b/src/plugins/Misc/CommandLineOptions/IncDecVolumeOption/incdecvolumeoption.cpp
@@ -0,0 +1,53 @@
+#include <QtPlugin>
+
+#include "incdecvolumeoption.h"
+#include <soundcore.h>
+#include "mainwindow.h"
+
+bool IncDecVolumeCommandLineOption::identify(const QString & str) const
+{
+ if(
+ str == QString("--volume-inc") ||
+ str == QString("--volume-dec")
+ )
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+const QString IncDecVolumeCommandLineOption::helpString() const
+{
+ return QString(
+ "--volume-inc Increase volume with step 10\n"
+ "--volume-dec Decrease volume with step 10\n"
+ );
+}
+
+
+void IncDecVolumeCommandLineOption::executeCommand(const QString & option_string, MainWindow *mw)
+{
+ if (option_string == "--volume-inc")
+ {
+ int l = 0;
+ int r = 0;
+ mw->soundCore()->volume(&l,&r);
+ mw->soundCore()->setVolume(l+10,r+10);
+ }
+ else if (option_string == "--volume-dec")
+ {
+ int l = 0;
+ int r = 0;
+ mw->soundCore()->volume(&l,&r);
+ mw->soundCore()->setVolume(l-10,r-10);
+ }
+}
+
+const QString IncDecVolumeCommandLineOption::name() const
+{
+ return "IncDecVolumeCommandLineOption";
+}
+
+Q_EXPORT_PLUGIN(IncDecVolumeCommandLineOption)
+
diff --git a/src/plugins/Misc/CommandLineOptions/IncDecVolumeOption/incdecvolumeoption.h b/src/plugins/Misc/CommandLineOptions/IncDecVolumeOption/incdecvolumeoption.h
new file mode 100644
index 000000000..6fbf3d24a
--- /dev/null
+++ b/src/plugins/Misc/CommandLineOptions/IncDecVolumeOption/incdecvolumeoption.h
@@ -0,0 +1,23 @@
+#ifndef IncDecVolumeCommandLineOption_H
+#define IncDecVolumeCommandLineOption_H
+
+#include <commandlineoption.h>
+
+#include <QString>
+#include <QObject>
+
+class MainWindow;
+
+class IncDecVolumeCommandLineOption : public QObject, public CommandLineOption
+{
+Q_OBJECT
+Q_INTERFACES(CommandLineOption)
+public:
+ virtual bool identify(const QString& opt_str)const;
+ virtual const QString name()const;
+ virtual const QString helpString()const;
+ virtual void executeCommand(const QString& opt_str,MainWindow* mw);
+};
+
+#endif
+
diff --git a/src/plugins/Misc/FileDialogs/FileDialogs.pro b/src/plugins/Misc/FileDialogs/FileDialogs.pro
new file mode 100644
index 000000000..a15058c1f
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/FileDialogs.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS = Qt3FileDialog \
+ QmmpFileDialog \ No newline at end of file
diff --git a/src/plugins/Misc/FileDialogs/Makefile b/src/plugins/Misc/FileDialogs/Makefile
new file mode 100644
index 000000000..5e0580ccf
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/Makefile
@@ -0,0 +1,134 @@
+#############################################################################
+# Makefile for building: FileDialogs
+# Generated by qmake (2.01a) (Qt 4.2.3) on: Tue Jul 24 19:08:22 2007
+# Project: FileDialogs.pro
+# Template: subdirs
+# Command: /usr/local/Trolltech/Qt-4.2.3/bin/qmake -unix -o Makefile FileDialogs.pro
+#############################################################################
+
+first: make_default
+MAKEFILE = Makefile
+QMAKE = /usr/local/Trolltech/Qt-4.2.3/bin/qmake
+DEL_FILE = rm -f
+CHK_DIR_EXISTS= test -d
+MKDIR = mkdir -p
+COPY = cp -f
+COPY_FILE = $(COPY)
+COPY_DIR = $(COPY) -r
+INSTALL_FILE = install -m 644 -p
+INSTALL_PROGRAM = install -m 755 -p
+INSTALL_DIR = $(COPY_DIR)
+DEL_FILE = rm -f
+SYMLINK = ln -sf
+DEL_DIR = rmdir
+MOVE = mv -f
+CHK_DIR_EXISTS= test -d
+MKDIR = mkdir -p
+SUBTARGETS = \
+ sub-Qt3FileDialog \
+ sub-QmmpFileDialog
+
+Qt3FileDialog/$(MAKEFILE):
+ @$(CHK_DIR_EXISTS) Qt3FileDialog/ || $(MKDIR) Qt3FileDialog/
+ cd Qt3FileDialog && $(QMAKE) Qt3FileDialog.pro -unix -o $(MAKEFILE)
+sub-Qt3FileDialog-qmake_all: FORCE
+ @$(CHK_DIR_EXISTS) Qt3FileDialog/ || $(MKDIR) Qt3FileDialog/
+ cd Qt3FileDialog && $(QMAKE) Qt3FileDialog.pro -unix -o $(MAKEFILE)
+sub-Qt3FileDialog: Qt3FileDialog/$(MAKEFILE) FORCE
+ cd Qt3FileDialog && $(MAKE) -f $(MAKEFILE)
+sub-Qt3FileDialog-make_default: Qt3FileDialog/$(MAKEFILE) FORCE
+ cd Qt3FileDialog && $(MAKE) -f $(MAKEFILE)
+sub-Qt3FileDialog-make_first: Qt3FileDialog/$(MAKEFILE) FORCE
+ cd Qt3FileDialog && $(MAKE) -f $(MAKEFILE) first
+sub-Qt3FileDialog-all: Qt3FileDialog/$(MAKEFILE) FORCE
+ cd Qt3FileDialog && $(MAKE) -f $(MAKEFILE) all
+sub-Qt3FileDialog-clean: Qt3FileDialog/$(MAKEFILE) FORCE
+ cd Qt3FileDialog && $(MAKE) -f $(MAKEFILE) clean
+sub-Qt3FileDialog-distclean: Qt3FileDialog/$(MAKEFILE) FORCE
+ cd Qt3FileDialog && $(MAKE) -f $(MAKEFILE) distclean
+sub-Qt3FileDialog-install_subtargets: Qt3FileDialog/$(MAKEFILE) FORCE
+ cd Qt3FileDialog && $(MAKE) -f $(MAKEFILE) install
+sub-Qt3FileDialog-uninstall_subtargets: Qt3FileDialog/$(MAKEFILE) FORCE
+ cd Qt3FileDialog && $(MAKE) -f $(MAKEFILE) uninstall
+QmmpFileDialog/$(MAKEFILE):
+ @$(CHK_DIR_EXISTS) QmmpFileDialog/ || $(MKDIR) QmmpFileDialog/
+ cd QmmpFileDialog && $(QMAKE) QmmpFileDialog.pro -unix -o $(MAKEFILE)
+sub-QmmpFileDialog-qmake_all: FORCE
+ @$(CHK_DIR_EXISTS) QmmpFileDialog/ || $(MKDIR) QmmpFileDialog/
+ cd QmmpFileDialog && $(QMAKE) QmmpFileDialog.pro -unix -o $(MAKEFILE)
+sub-QmmpFileDialog: QmmpFileDialog/$(MAKEFILE) FORCE
+ cd QmmpFileDialog && $(MAKE) -f $(MAKEFILE)
+sub-QmmpFileDialog-make_default: QmmpFileDialog/$(MAKEFILE) FORCE
+ cd QmmpFileDialog && $(MAKE) -f $(MAKEFILE)
+sub-QmmpFileDialog-make_first: QmmpFileDialog/$(MAKEFILE) FORCE
+ cd QmmpFileDialog && $(MAKE) -f $(MAKEFILE) first
+sub-QmmpFileDialog-all: QmmpFileDialog/$(MAKEFILE) FORCE
+ cd QmmpFileDialog && $(MAKE) -f $(MAKEFILE) all
+sub-QmmpFileDialog-clean: QmmpFileDialog/$(MAKEFILE) FORCE
+ cd QmmpFileDialog && $(MAKE) -f $(MAKEFILE) clean
+sub-QmmpFileDialog-distclean: QmmpFileDialog/$(MAKEFILE) FORCE
+ cd QmmpFileDialog && $(MAKE) -f $(MAKEFILE) distclean
+sub-QmmpFileDialog-install_subtargets: QmmpFileDialog/$(MAKEFILE) FORCE
+ cd QmmpFileDialog && $(MAKE) -f $(MAKEFILE) install
+sub-QmmpFileDialog-uninstall_subtargets: QmmpFileDialog/$(MAKEFILE) FORCE
+ cd QmmpFileDialog && $(MAKE) -f $(MAKEFILE) uninstall
+
+Makefile: FileDialogs.pro /usr/local/Trolltech/Qt-4.2.3/mkspecs/linux-g++/qmake.conf /usr/local/Trolltech/Qt-4.2.3/mkspecs/common/unix.conf \
+ /usr/local/Trolltech/Qt-4.2.3/mkspecs/common/g++.conf \
+ /usr/local/Trolltech/Qt-4.2.3/mkspecs/common/linux.conf \
+ /usr/local/Trolltech/Qt-4.2.3/mkspecs/qconfig.pri \
+ /usr/local/Trolltech/Qt-4.2.3/mkspecs/features/qt_functions.prf \
+ /usr/local/Trolltech/Qt-4.2.3/mkspecs/features/qt_config.prf \
+ /usr/local/Trolltech/Qt-4.2.3/mkspecs/features/exclusive_builds.prf \
+ /usr/local/Trolltech/Qt-4.2.3/mkspecs/features/default_pre.prf \
+ /usr/local/Trolltech/Qt-4.2.3/mkspecs/features/release.prf \
+ /usr/local/Trolltech/Qt-4.2.3/mkspecs/features/default_post.prf \
+ /usr/local/Trolltech/Qt-4.2.3/mkspecs/features/warn_on.prf \
+ /usr/local/Trolltech/Qt-4.2.3/mkspecs/features/qt.prf \
+ /usr/local/Trolltech/Qt-4.2.3/mkspecs/features/unix/thread.prf \
+ /usr/local/Trolltech/Qt-4.2.3/mkspecs/features/moc.prf \
+ /usr/local/Trolltech/Qt-4.2.3/mkspecs/features/resources.prf \
+ /usr/local/Trolltech/Qt-4.2.3/mkspecs/features/uic.prf
+ $(QMAKE) -unix -o Makefile FileDialogs.pro
+/usr/local/Trolltech/Qt-4.2.3/mkspecs/common/unix.conf:
+/usr/local/Trolltech/Qt-4.2.3/mkspecs/common/g++.conf:
+/usr/local/Trolltech/Qt-4.2.3/mkspecs/common/linux.conf:
+/usr/local/Trolltech/Qt-4.2.3/mkspecs/qconfig.pri:
+/usr/local/Trolltech/Qt-4.2.3/mkspecs/features/qt_functions.prf:
+/usr/local/Trolltech/Qt-4.2.3/mkspecs/features/qt_config.prf:
+/usr/local/Trolltech/Qt-4.2.3/mkspecs/features/exclusive_builds.prf:
+/usr/local/Trolltech/Qt-4.2.3/mkspecs/features/default_pre.prf:
+/usr/local/Trolltech/Qt-4.2.3/mkspecs/features/release.prf:
+/usr/local/Trolltech/Qt-4.2.3/mkspecs/features/default_post.prf:
+/usr/local/Trolltech/Qt-4.2.3/mkspecs/features/warn_on.prf:
+/usr/local/Trolltech/Qt-4.2.3/mkspecs/features/qt.prf:
+/usr/local/Trolltech/Qt-4.2.3/mkspecs/features/unix/thread.prf:
+/usr/local/Trolltech/Qt-4.2.3/mkspecs/features/moc.prf:
+/usr/local/Trolltech/Qt-4.2.3/mkspecs/features/resources.prf:
+/usr/local/Trolltech/Qt-4.2.3/mkspecs/features/uic.prf:
+qmake: qmake_all FORCE
+ @$(QMAKE) -unix -o Makefile FileDialogs.pro
+
+qmake_all: sub-Qt3FileDialog-qmake_all sub-QmmpFileDialog-qmake_all FORCE
+
+make_default: sub-Qt3FileDialog-make_default sub-QmmpFileDialog-make_default FORCE
+make_first: sub-Qt3FileDialog-make_first sub-QmmpFileDialog-make_first FORCE
+all: sub-Qt3FileDialog-all sub-QmmpFileDialog-all FORCE
+clean: sub-Qt3FileDialog-clean sub-QmmpFileDialog-clean FORCE
+distclean: sub-Qt3FileDialog-distclean sub-QmmpFileDialog-distclean FORCE
+ -$(DEL_FILE) Makefile
+install_subtargets: sub-Qt3FileDialog-install_subtargets sub-QmmpFileDialog-install_subtargets FORCE
+uninstall_subtargets: sub-Qt3FileDialog-uninstall_subtargets sub-QmmpFileDialog-uninstall_subtargets FORCE
+
+/usr/local/Trolltech/Qt-4.2.3/bin/moc:
+ (cd $(QTDIR)/src/tools/moc && $(MAKE))
+
+mocclean: compiler_moc_header_clean compiler_moc_source_clean
+
+mocables: compiler_moc_header_make_all compiler_moc_source_make_all
+install: install_subtargets FORCE
+
+uninstall: uninstall_subtargets FORCE
+
+FORCE:
+
diff --git a/src/plugins/Misc/FileDialogs/QmmpFileDialog/QmmpFileDialog.pro b/src/plugins/Misc/FileDialogs/QmmpFileDialog/QmmpFileDialog.pro
new file mode 100644
index 000000000..d9b8a96df
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/QmmpFileDialog/QmmpFileDialog.pro
@@ -0,0 +1,28 @@
+QMMPROOT = ../../../qmmp
+
+INCLUDEPATH += $$QMMPROOT/src
+INCLUDEPATH += $$QMMPROOT/lib
+
+HEADERS += qmmpfiledialog.h \
+ qmmpfiledialogimpl.h \
+ $$QMMPROOT/src/filedialog.h \
+ $$QMMPROOT/src/playlistmodel.h
+
+SOURCES += qmmpfiledialog.cpp \
+ qmmpfiledialogimpl.cpp \
+ $$QMMPROOT/src/filedialog.cpp \
+ $$QMMPROOT/src/playlistmodel.cpp
+
+
+FORMS += qmmpfiledialog.ui
+
+RESOURCES += images/images.qrc
+
+DESTDIR = ../
+QMAKE_CLEAN += ../libqmmpfiledialog.so
+
+
+CONFIG += release warn_on plugin
+
+TEMPLATE = lib
+
diff --git a/src/plugins/Misc/FileDialogs/QmmpFileDialog/images/cdup.png b/src/plugins/Misc/FileDialogs/QmmpFileDialog/images/cdup.png
new file mode 100644
index 000000000..5d966a77b
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/QmmpFileDialog/images/cdup.png
Binary files differ
diff --git a/src/plugins/Misc/FileDialogs/QmmpFileDialog/images/detail.png b/src/plugins/Misc/FileDialogs/QmmpFileDialog/images/detail.png
new file mode 100644
index 000000000..2e552a425
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/QmmpFileDialog/images/detail.png
Binary files differ
diff --git a/src/plugins/Misc/FileDialogs/QmmpFileDialog/images/images.qrc b/src/plugins/Misc/FileDialogs/QmmpFileDialog/images/images.qrc
new file mode 100644
index 000000000..c194a6b91
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/QmmpFileDialog/images/images.qrc
@@ -0,0 +1,8 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+ <qresource>
+ <file>cdup.png</file>
+ <file>detail.png</file>
+ <file>list.png</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/Misc/FileDialogs/QmmpFileDialog/images/list.png b/src/plugins/Misc/FileDialogs/QmmpFileDialog/images/list.png
new file mode 100644
index 000000000..13b44a620
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/QmmpFileDialog/images/list.png
Binary files differ
diff --git a/src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialog.cpp b/src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialog.cpp
new file mode 100644
index 000000000..fce9f6e53
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialog.cpp
@@ -0,0 +1,44 @@
+#include <QtPlugin>
+
+#include "qmmpfiledialogimpl.h"
+#include "qmmpfiledialog.h"
+
+
+
+QmmpFileDialog::QmmpFileDialog()
+{
+ m_dialog = new QmmpFileDialogImpl();
+ connect(m_dialog,SIGNAL(filesAdded(const QStringList&)),this,SIGNAL(filesAdded(const QStringList&)));
+}
+
+void QmmpFileDialog::handleSelected(/*const QStringList& s */)
+{
+}
+
+bool QmmpFileDialog::modal()const
+{
+ return FALSE;
+}
+
+QmmpFileDialog::~QmmpFileDialog()
+{
+ qWarning("QmmpFileDialog::~QmmpFileDialog()");
+ delete m_dialog;
+}
+void QmmpFileDialog::raise(const QString& d,Mode m,const QStringList& f)
+{
+ m_dialog->setModeAndMask(d,m,f);
+ m_dialog->show();
+ m_dialog->raise();
+}
+
+
+FileDialog* QmmpFileDialogFactory::create(){ return new QmmpFileDialog();}
+
+QString QmmpFileDialogFactory::name(){return QmmpFileDialogFactoryName;}
+
+QString QmmpFileDialogFactory::QmmpFileDialogFactoryName = "Qmmp File Dialog";
+
+
+Q_EXPORT_PLUGIN(QmmpFileDialogFactory)
+
diff --git a/src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialog.h b/src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialog.h
new file mode 100644
index 000000000..30a4fef59
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialog.h
@@ -0,0 +1,40 @@
+#ifndef QMMPFILEDIALOG_H
+#define QMMPFILEDIALOG_H
+
+#include <filedialog.h>
+
+class QmmpFileDialogImpl;
+
+class QmmpFileDialog : public FileDialog
+{
+Q_OBJECT
+ public:
+ QmmpFileDialog();
+ virtual ~QmmpFileDialog();
+ virtual bool modal()const;
+ virtual void raise(const QString&,Mode = AddFiles,const QStringList& = QStringList());
+ public slots:
+ void handleSelected();
+
+ private:
+ QmmpFileDialogImpl * m_dialog;
+};
+
+
+
+
+class QmmpFileDialogFactory : public QObject, public FileDialogFactory
+{
+ Q_OBJECT
+ Q_INTERFACES(FileDialogFactory);
+ public:
+ virtual FileDialog* create();
+ virtual QString name();
+ virtual ~QmmpFileDialogFactory(){;}
+ static QString QmmpFileDialogFactoryName;
+};
+
+
+#endif
+
+
diff --git a/src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialog.ui b/src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialog.ui
new file mode 100644
index 000000000..dbfb2edc2
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialog.ui
@@ -0,0 +1,216 @@
+<ui version="4.0" >
+ <class>QmmpFileDialog</class>
+ <widget class="QDialog" name="QmmpFileDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>517</width>
+ <height>312</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Add Files</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Look in:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="lookInComboBox" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="editable" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="upToolButton" >
+ <property name="text" >
+ <string>Up</string>
+ </property>
+ <property name="icon" >
+ <iconset resource="images/images.qrc" >:/cdup.png</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="listToolButton" >
+ <property name="toolTip" >
+ <string>List view</string>
+ </property>
+ <property name="text" >
+ <string>lst</string>
+ </property>
+ <property name="icon" >
+ <iconset resource="images/images.qrc" >:/list.png</iconset>
+ </property>
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="iconToolButton" >
+ <property name="toolTip" >
+ <string>Icon view</string>
+ </property>
+ <property name="text" >
+ <string>icn</string>
+ </property>
+ <property name="icon" >
+ <iconset resource="images/images.qrc" >:/detail.png</iconset>
+ </property>
+ <property name="iconSize" >
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QListView" name="fileListView" >
+ <property name="editTriggers" >
+ <set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="dragEnabled" >
+ <bool>true</bool>
+ </property>
+ <property name="dragDropMode" >
+ <enum>QAbstractItemView::NoDragDrop</enum>
+ </property>
+ <property name="alternatingRowColors" >
+ <bool>false</bool>
+ </property>
+ <property name="selectionMode" >
+ <enum>QAbstractItemView::ExtendedSelection</enum>
+ </property>
+ <property name="selectionBehavior" >
+ <enum>QAbstractItemView::SelectItems</enum>
+ </property>
+ <property name="movement" >
+ <enum>QListView::Static</enum>
+ </property>
+ <property name="layoutMode" >
+ <enum>QListView::Batched</enum>
+ </property>
+ <property name="viewMode" >
+ <enum>QListView::ListMode</enum>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>File name:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="fileNameLineEdit" />
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="addPushButton" >
+ <property name="text" >
+ <string>Add</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="closePushButton" >
+ <property name="text" >
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="images/images.qrc" />
+ </resources>
+ <connections>
+ <connection>
+ <sender>closePushButton</sender>
+ <signal>clicked()</signal>
+ <receiver>QmmpFileDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>459</x>
+ <y>291</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>153</x>
+ <y>289</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialogimpl.cpp b/src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialogimpl.cpp
new file mode 100644
index 000000000..984cc7204
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialogimpl.cpp
@@ -0,0 +1,109 @@
+#include "qmmpfiledialogimpl.h"
+
+#include <QDirModel>
+#include <QFileInfo>
+
+QmmpFileDialogImpl::QmmpFileDialogImpl( QWidget * parent, Qt::WindowFlags f) : QDialog(parent,f)
+{
+ setupUi(this);
+ setAttribute(Qt::WA_QuitOnClose, FALSE);
+ m_model = new QDirModel(this);
+ m_model->setSorting(QDir::Type /*| QDir::Name*/);
+ fileListView->setModel(m_model);
+ //fileListView->setViewMode(QListView::IconMode);
+ listToolButton->setChecked(true);
+}
+
+QmmpFileDialogImpl::~QmmpFileDialogImpl()
+{
+}
+
+void QmmpFileDialogImpl::on_lookInComboBox_activated(const QString&)
+{
+ qWarning("TODO: %s %d",__FILE__,__LINE__);
+}
+
+void QmmpFileDialogImpl::on_upToolButton_clicked()
+{
+ fileListView->setRootIndex(m_model->parent(fileListView->rootIndex()));
+ lookInComboBox->setEditText(m_model->filePath(fileListView->rootIndex()));
+}
+
+void QmmpFileDialogImpl::on_fileListView_doubleClicked(const QModelIndex& ind)
+{
+ if(ind.isValid())
+ {
+ QFileInfo info = m_model->fileInfo(ind);
+ if(info.isDir())
+ {
+ fileListView->setRootIndex(ind);
+ lookInComboBox->setEditText(m_model->filePath(ind));
+ }
+ else
+ {
+ QStringList l;
+ l << m_model->filePath(ind);
+ emit filesAdded(l);
+ }
+ }
+
+}
+
+void QmmpFileDialogImpl::on_fileNameLineEdit_returnPressed()
+{
+ on_addPushButton_clicked();
+}
+
+void QmmpFileDialogImpl::on_addPushButton_clicked()
+{
+ QModelIndexList ml = fileListView->selectionModel()->selectedIndexes();
+ QStringList l;
+ foreach(QModelIndex i,ml)
+ l << m_model->filePath(i);
+ qWarning("!!!!!!!!!");
+ emit filesAdded(l);
+}
+
+void QmmpFileDialogImpl::setModeAndMask(const QString& d,FileDialog::Mode m, const QStringList & mask)
+{
+ if(m == FileDialog::AddFiles)
+ {
+ setWindowTitle("Add Files");
+ m_model->setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
+ }
+ else if(m == FileDialog::AddDirs)
+ {
+ setWindowTitle("Add Dirs");
+ m_model->setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
+ }
+ else
+ {
+ setWindowTitle("Save File");
+ m_model->setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
+ qWarning("To be implemented...");
+ }
+
+ m_model->setSorting(QDir::Type);
+ fileListView->setRootIndex(m_model->index(d));
+ m_model->sort(0);
+ lookInComboBox->setEditText(d);
+}
+
+void QmmpFileDialogImpl::on_listToolButton_toggled(bool yes)
+{
+ if(yes)
+ {
+ iconToolButton->setChecked(false);
+ fileListView->setViewMode(QListView::ListMode);
+ }
+}
+
+void QmmpFileDialogImpl::on_iconToolButton_toggled(bool yes)
+{
+ if(yes)
+ {
+ listToolButton->setChecked(false);
+ fileListView->setViewMode(QListView::IconMode);
+ }
+}
+
diff --git a/src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialogimpl.h b/src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialogimpl.h
new file mode 100644
index 000000000..2be25bf05
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/QmmpFileDialog/qmmpfiledialogimpl.h
@@ -0,0 +1,33 @@
+#ifndef QMMPFILEDIALOGIMPL_H
+#define QMMPFILEDIALOGIMPL_H
+
+#include "ui_qmmpfiledialog.h"
+#include <QDialog>
+
+#include "filedialog.h"
+
+class QDirModel;
+
+
+class QmmpFileDialogImpl : public QDialog , private Ui::QmmpFileDialog
+{
+Q_OBJECT
+public:
+ QmmpFileDialogImpl( QWidget * parent = 0, Qt::WindowFlags f = 0 );
+ ~QmmpFileDialogImpl();
+ void setModeAndMask(const QString&,FileDialog::Mode m,const QStringList& mask);
+protected slots:
+ void on_lookInComboBox_activated(const QString&);
+ void on_upToolButton_clicked();
+ void on_fileListView_doubleClicked(const QModelIndex&);
+ void on_fileNameLineEdit_returnPressed();
+ void on_addPushButton_clicked();
+ void on_listToolButton_toggled(bool);
+ void on_iconToolButton_toggled(bool);
+signals:
+ void filesAdded(const QStringList&);
+protected:
+ QDirModel* m_model;
+
+};
+#endif //QMMPFILEDIALOGIMPL_H
diff --git a/src/plugins/Misc/FileDialogs/Qt3FileDialog/Qt3FileDialog.pro b/src/plugins/Misc/FileDialogs/Qt3FileDialog/Qt3FileDialog.pro
new file mode 100644
index 000000000..7954ebf01
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/Qt3FileDialog/Qt3FileDialog.pro
@@ -0,0 +1,28 @@
+QMMPROOT = ../../../qmmp
+
+INCLUDEPATH += $$QMMPROOT/src
+INCLUDEPATH += $$QMMPROOT/lib
+
+HEADERS += qt3filedialogfactory.h \
+ qt3filedialog.h \
+ $$QMMPROOT/src/filedialog.h \
+ $$QMMPROOT/src/playlistmodel.h
+
+SOURCES += qt3filedialog.cpp \
+ qt3filedialogfactory.cpp \
+ $$QMMPROOT/src/filedialog.cpp \
+ $$QMMPROOT/src/playlistmodel.cpp
+
+
+DESTDIR = ../
+QMAKE_CLEAN += ../libqt3filedialog.so
+
+
+CONFIG += release warn_on plugin
+
+TEMPLATE = lib
+
+QT += qt3support
+
+#target.path = /plugins/FileDialogs
+#INSTALLS += target
diff --git a/src/plugins/Misc/FileDialogs/Qt3FileDialog/qt3filedialog.cpp b/src/plugins/Misc/FileDialogs/Qt3FileDialog/qt3filedialog.cpp
new file mode 100644
index 000000000..b9b9bc898
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/Qt3FileDialog/qt3filedialog.cpp
@@ -0,0 +1,35 @@
+#include "qt3filedialog.h"
+#include <Q3FileDialog>
+
+Qt3SupportFileDialog::~Qt3SupportFileDialog()
+{
+ qWarning("Qt3SupportFileDialog::~Qt3SupportFileDialog()");
+}
+
+QString Qt3SupportFileDialog::existingDirectory(QWidget * parent , const QString & caption, const QString & dir)
+{
+ return Q3FileDialog::getExistingDirectory ( dir,
+ parent,
+ 0,
+ caption,
+ true,
+ true );
+}
+
+QString Qt3SupportFileDialog::openFileName(QWidget * parent,const QString & caption,const QString & /*dir*/,const QString & filter,
+ QString * selectedFilter)
+{
+ return Q3FileDialog::getOpenFileName ( QString(),filter,parent,0,caption,selectedFilter);
+}
+
+QStringList Qt3SupportFileDialog::openFileNames(QWidget * parent, const QString & caption , const QString & dir ,
+ const QString & filter, QString * selectedFilter)
+{
+ return Q3FileDialog::getOpenFileNames(filter,dir,parent,0,caption,selectedFilter);
+}
+
+QString Qt3SupportFileDialog::saveFileName ( QWidget * parent, const QString & caption,
+ const QString &, const QString & filter, QString * selectedFilter)
+{
+ return Q3FileDialog::getSaveFileName(QString(),filter,parent,0,caption,selectedFilter);
+}
diff --git a/src/plugins/Misc/FileDialogs/Qt3FileDialog/qt3filedialog.h b/src/plugins/Misc/FileDialogs/Qt3FileDialog/qt3filedialog.h
new file mode 100644
index 000000000..bbce2e3c8
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/Qt3FileDialog/qt3filedialog.h
@@ -0,0 +1,23 @@
+#ifndef QT3FILEDIALOG_H
+#define QT3FILEDIALOG_H
+
+#include <filedialog.h>
+
+
+class Qt3SupportFileDialog : public FileDialog
+{
+ public:
+ virtual ~Qt3SupportFileDialog();
+ virtual QString existingDirectory(QWidget * parent , const QString & , const QString & dir);
+ virtual QString openFileName(QWidget * parent,const QString & caption,const QString & dir,const QString & filter,
+ QString * selectedFilter);
+ virtual QStringList openFileNames(QWidget * parent, const QString & caption , const QString & dir ,
+ const QString & filter, QString * selectedFilter);
+ virtual QString saveFileName ( QWidget * parent, const QString & caption,
+ const QString & dir, const QString & filter, QString * selectedFilter);
+
+};
+
+#endif
+
+
diff --git a/src/plugins/Misc/FileDialogs/Qt3FileDialog/qt3filedialogfactory.cpp b/src/plugins/Misc/FileDialogs/Qt3FileDialog/qt3filedialogfactory.cpp
new file mode 100644
index 000000000..45b4260bb
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/Qt3FileDialog/qt3filedialogfactory.cpp
@@ -0,0 +1,20 @@
+#include <QtPlugin>
+#include "qt3filedialogfactory.h"
+#include "qt3filedialog.h"
+
+
+FileDialog* Qt3SupportFileDialogFactory::create()
+{
+ return new Qt3SupportFileDialog();
+}
+
+QString Qt3SupportFileDialogFactory::name()
+{
+ return Qt3SupportFileDialogFactory::Qt3SupportFileDialogFactoryName;
+}
+
+
+QString Qt3SupportFileDialogFactory::Qt3SupportFileDialogFactoryName = "Qt3 File Dialog";
+
+Q_EXPORT_PLUGIN(Qt3SupportFileDialogFactory)
+
diff --git a/src/plugins/Misc/FileDialogs/Qt3FileDialog/qt3filedialogfactory.h b/src/plugins/Misc/FileDialogs/Qt3FileDialog/qt3filedialogfactory.h
new file mode 100644
index 000000000..e5d3b4595
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/Qt3FileDialog/qt3filedialogfactory.h
@@ -0,0 +1,19 @@
+#ifndef QT3FILEDIALOGFACTORY_H
+#define QT3FILEDIALOGFACTORY_H
+
+
+#include <filedialog.h>
+
+class Qt3SupportFileDialogFactory : public QObject, public FileDialogFactory
+{
+ Q_OBJECT
+ Q_INTERFACES(FileDialogFactory);
+ public:
+ virtual FileDialog* create();
+ virtual QString name();
+ virtual ~Qt3SupportFileDialogFactory(){;}
+ static QString Qt3SupportFileDialogFactoryName;
+};
+
+#endif
+
diff --git a/src/plugins/Misc/FileDialogs/Qt3FileDialog/readme b/src/plugins/Misc/FileDialogs/Qt3FileDialog/readme
new file mode 100644
index 000000000..966f7201d
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/Qt3FileDialog/readme
@@ -0,0 +1,14 @@
+This is simple example of File Dialog plugin.
+Requires Qt3Support library. This plugin developed
+mostly for QMMP customizing demonstration -
+we don't think that somebody will prefer use Qt3
+look&feel :)
+
+Build: Change QMMPROOT variable in .pro file according your
+QMMP build tree location.Then qmake && make
+
+Install: copy library into ~/.qmmp/plugins/FileDialogs directory.
+
+
+ vovanec@gmail.com
+
diff --git a/src/plugins/Misc/FileDialogs/libQmmpFileDialog.so b/src/plugins/Misc/FileDialogs/libQmmpFileDialog.so
new file mode 100755
index 000000000..d04ccf53a
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/libQmmpFileDialog.so
Binary files differ
diff --git a/src/plugins/Misc/FileDialogs/libQt3FileDialog.so b/src/plugins/Misc/FileDialogs/libQt3FileDialog.so
new file mode 100755
index 000000000..efbb0d313
--- /dev/null
+++ b/src/plugins/Misc/FileDialogs/libQt3FileDialog.so
Binary files differ
diff --git a/src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/CSVPlaylistFormat.pro b/src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/CSVPlaylistFormat.pro
new file mode 100644
index 000000000..11c27c3d3
--- /dev/null
+++ b/src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/CSVPlaylistFormat.pro
@@ -0,0 +1,20 @@
+QMMPROOT = ../../../qmmp
+
+HEADERS += csvplaylistformat.h
+
+SOURCES += csvplaylistformat.cpp \
+ $$QMMPROOT/src/mediafile.cpp
+
+DESTDIR = ../
+QMAKE_CLEAN = ../libcsvplaylistformat.so
+
+INCLUDEPATH += $$QMMPROOT/src \
+ $$QMMPROOT/lib
+
+CONFIG += release warn_on plugin
+
+TEMPLATE = lib
+
+#QMAKE_LIBDIR += ../../../
+#LIBS += -lqmmp -L/usr/lib -I/usr/include
+
diff --git a/src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/Makefile b/src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/Makefile
new file mode 100644
index 000000000..5afa50b01
--- /dev/null
+++ b/src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/Makefile
@@ -0,0 +1,213 @@
+#############################################################################
+# Makefile for building: libCSVPlaylistFormat.so
+# Generated by qmake (2.01a) (Qt 4.3.0) on: Mon Dec 24 01:59:02 2007
+# Project: CSVPlaylistFormat.pro
+# Template: lib
+# Command: /usr/local/Trolltech/Qt-4.3.0/bin/qmake -unix -o Makefile CSVPlaylistFormat.pro
+#############################################################################
+
+####### Compiler, tools and options
+
+CC = gcc
+CXX = g++
+DEFINES = -DQT_NO_DEBUG -DQT_PLUGIN -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED
+CFLAGS = -pipe -O2 -Wall -W -D_REENTRANT -fPIC $(DEFINES)
+CXXFLAGS = -pipe -O2 -Wall -W -D_REENTRANT -fPIC $(DEFINES)
+INCPATH = -I/usr/local/Trolltech/Qt-4.3.0/mkspecs/linux-g++ -I. -I/usr/local/Trolltech/Qt-4.3.0/include/QtCore -I/usr/local/Trolltech/Qt-4.3.0/include/QtCore -I/usr/local/Trolltech/Qt-4.3.0/include/QtGui -I/usr/local/Trolltech/Qt-4.3.0/include/QtGui -I/usr/local/Trolltech/Qt-4.3.0/include -I../../../qmmp/src -I../../../qmmp/lib -I. -I.
+LINK = g++
+LFLAGS = -Wl,-rpath,/usr/local/Trolltech/Qt-4.3.0/lib -shared
+LIBS = $(SUBLIBS) -L/usr/local/Trolltech/Qt-4.3.0/lib -lQtGui -L/usr/local/Trolltech/Qt-4.3.0/lib -L/usr/X11R6/lib -lpng -lSM -lICE -pthread -pthread -lXi -lXrender -lXrandr -lXfixes -lXcursor -lXinerama -lfreetype -lfontconfig -lXext -lX11 -lQtCore -lz -lm -pthread -lgthread-2.0 -lrt -lglib-2.0 -ldl -lpthread
+AR = ar cqs
+RANLIB =
+QMAKE = /usr/local/Trolltech/Qt-4.3.0/bin/qmake
+TAR = tar -cf
+COMPRESS = gzip -9f
+COPY = cp -f
+SED = sed
+COPY_FILE = $(COPY)
+COPY_DIR = $(COPY) -r
+INSTALL_FILE = install -m 644 -p
+INSTALL_DIR = $(COPY_DIR)
+INSTALL_PROGRAM = install -m 755 -p
+DEL_FILE = rm -f
+SYMLINK = ln -sf
+DEL_DIR = rmdir
+MOVE = mv -f
+CHK_DIR_EXISTS= test -d
+MKDIR = mkdir -p
+
+####### Output directory
+
+OBJECTS_DIR = ./
+
+####### Files
+
+SOURCES = csvplaylistformat.cpp \
+ ../../../qmmp/src/mediafile.cpp moc_csvplaylistformat.cpp
+OBJECTS = csvplaylistformat.o \
+ mediafile.o \
+ moc_csvplaylistformat.o
+DIST = /usr/local/Trolltech/Qt-4.3.0/mkspecs/common/g++.conf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/common/unix.conf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/common/linux.conf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/qconfig.pri \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt_functions.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt_config.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/exclusive_builds.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/default_pre.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/release.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/default_post.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/warn_on.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/unix/thread.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/moc.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/resources.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/uic.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/yacc.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/lex.prf \
+ CSVPlaylistFormat.pro
+QMAKE_TARGET = CSVPlaylistFormat
+DESTDIR = ../
+TARGET = libCSVPlaylistFormat.so
+TARGETD = libCSVPlaylistFormat.so
+
+first: all
+####### Implicit rules
+
+.SUFFIXES: .o .c .cpp .cc .cxx .C
+
+.cpp.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.cc.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.cxx.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.C.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(INCPATH) -o "$@" "$<"
+
+####### Build rules
+
+all: Makefile ../$(TARGET)
+
+../$(TARGET): $(OBJECTS) $(SUBLIBS) $(OBJCOMP)
+ @$(CHK_DIR_EXISTS) ../ || $(MKDIR) ../
+ -$(DEL_FILE) $(TARGET)
+ $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) $(OBJCOMP)
+ -$(MOVE) $(TARGET) ../
+
+
+
+Makefile: CSVPlaylistFormat.pro /usr/local/Trolltech/Qt-4.3.0/mkspecs/linux-g++/qmake.conf /usr/local/Trolltech/Qt-4.3.0/mkspecs/common/g++.conf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/common/unix.conf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/common/linux.conf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/qconfig.pri \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt_functions.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt_config.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/exclusive_builds.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/default_pre.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/release.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/default_post.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/warn_on.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/unix/thread.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/moc.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/resources.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/uic.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/yacc.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/lex.prf \
+ /usr/local/Trolltech/Qt-4.3.0/lib/libQtGui.prl \
+ /usr/local/Trolltech/Qt-4.3.0/lib/libQtCore.prl
+ $(QMAKE) -unix -o Makefile CSVPlaylistFormat.pro
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/common/g++.conf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/common/unix.conf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/common/linux.conf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/qconfig.pri:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt_functions.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt_config.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/exclusive_builds.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/default_pre.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/release.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/default_post.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/warn_on.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/unix/thread.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/moc.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/resources.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/uic.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/yacc.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/lex.prf:
+/usr/local/Trolltech/Qt-4.3.0/lib/libQtGui.prl:
+/usr/local/Trolltech/Qt-4.3.0/lib/libQtCore.prl:
+qmake: FORCE
+ @$(QMAKE) -unix -o Makefile CSVPlaylistFormat.pro
+
+dist:
+ @$(CHK_DIR_EXISTS) .tmp/CSVPlaylistFormat1.0.0 || $(MKDIR) .tmp/CSVPlaylistFormat1.0.0
+ $(COPY_FILE) --parents $(SOURCES) $(DIST) .tmp/CSVPlaylistFormat1.0.0/ && $(COPY_FILE) --parents csvplaylistformat.h .tmp/CSVPlaylistFormat1.0.0/ && $(COPY_FILE) --parents csvplaylistformat.cpp ../../../qmmp/src/mediafile.cpp .tmp/CSVPlaylistFormat1.0.0/ && (cd `dirname .tmp/CSVPlaylistFormat1.0.0` && $(TAR) CSVPlaylistFormat1.0.0.tar CSVPlaylistFormat1.0.0 && $(COMPRESS) CSVPlaylistFormat1.0.0.tar) && $(MOVE) `dirname .tmp/CSVPlaylistFormat1.0.0`/CSVPlaylistFormat1.0.0.tar.gz . && $(DEL_FILE) -r .tmp/CSVPlaylistFormat1.0.0
+
+
+clean:compiler_clean
+ -$(DEL_FILE) $(OBJECTS)
+ -$(DEL_FILE) ../libcsvplaylistformat.so
+ -$(DEL_FILE) *~ core *.core
+
+
+####### Sub-libraries
+
+distclean: clean
+ -$(DEL_FILE) $(TARGET)
+ -$(DEL_FILE) Makefile
+
+
+mocclean: compiler_moc_header_clean compiler_moc_source_clean
+
+mocables: compiler_moc_header_make_all compiler_moc_source_make_all
+
+compiler_moc_header_make_all: moc_csvplaylistformat.cpp
+compiler_moc_header_clean:
+ -$(DEL_FILE) moc_csvplaylistformat.cpp
+moc_csvplaylistformat.cpp: csvplaylistformat.h
+ /usr/local/Trolltech/Qt-4.3.0/bin/moc $(DEFINES) $(INCPATH) csvplaylistformat.h -o moc_csvplaylistformat.cpp
+
+compiler_rcc_make_all:
+compiler_rcc_clean:
+compiler_image_collection_make_all: qmake_image_collection.cpp
+compiler_image_collection_clean:
+ -$(DEL_FILE) qmake_image_collection.cpp
+compiler_moc_source_make_all:
+compiler_moc_source_clean:
+compiler_uic_make_all:
+compiler_uic_clean:
+compiler_yacc_decl_make_all:
+compiler_yacc_decl_clean:
+compiler_yacc_impl_make_all:
+compiler_yacc_impl_clean:
+compiler_lex_make_all:
+compiler_lex_clean:
+compiler_clean: compiler_moc_header_clean
+
+####### Compile
+
+csvplaylistformat.o: csvplaylistformat.cpp csvplaylistformat.h
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o csvplaylistformat.o csvplaylistformat.cpp
+
+mediafile.o: ../../../qmmp/src/mediafile.cpp ../../../qmmp/src/mediafile.h
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o mediafile.o ../../../qmmp/src/mediafile.cpp
+
+moc_csvplaylistformat.o: moc_csvplaylistformat.cpp
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_csvplaylistformat.o moc_csvplaylistformat.cpp
+
+####### Install
+
+install: FORCE
+
+uninstall: FORCE
+
+FORCE:
+
diff --git a/src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/csvplaylistformat.cpp b/src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/csvplaylistformat.cpp
new file mode 100644
index 000000000..bff8a20b5
--- /dev/null
+++ b/src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/csvplaylistformat.cpp
@@ -0,0 +1,72 @@
+#include <QtPlugin>
+#include <QFileInfo>
+
+#include "csvplaylistformat.h"
+#include <mediafile.h>
+
+
+bool CSVPlaylistFormat::hasFormat(const QString & f)
+{
+ foreach(QString s,m_supported_formats)
+ if(f == s)
+ return true;
+
+ return false;
+}
+
+QStringList CSVPlaylistFormat::getExtensions() const
+{
+ return m_supported_formats;
+}
+
+CSVPlaylistFormat::CSVPlaylistFormat()
+{
+ m_supported_formats << "csv";
+}
+
+QString CSVPlaylistFormat::name() const
+{
+ return "CSVPlaylistFormat";
+}
+
+
+QStringList CSVPlaylistFormat::decode(const QString & contents)
+{
+ qWarning("CONTENTS: %s",qPrintable(contents));
+ QStringList out;
+ QStringList splitted = contents.split("\n");
+ if(!splitted.isEmpty())
+ {
+ foreach(QString str, splitted)
+ {
+ QStringList song = str.split(";");
+ qWarning("SONG: %s",qPrintable(song[0]));
+ if(song.count() > 1)
+ {
+ QString unverified = song[1];
+ if(QFileInfo(unverified).exists())
+ out << QFileInfo(unverified).absoluteFilePath();
+ else
+ qWarning("File %s does not exist",unverified.toLocal8Bit().data());
+ }
+
+ }
+ return out;
+ }
+ else
+ qWarning("Error parsing CSV playlist format");
+
+ return QStringList();
+}
+
+QString CSVPlaylistFormat::encode(const QList< MediaFile * > & contents)
+{
+ QStringList out;
+ foreach(MediaFile* f,contents)
+ out.append(f->title() + ";" + f->path() + ";" + QString::number(f->length()));
+
+ return out.join("\n");
+}
+
+Q_EXPORT_PLUGIN(CSVPlaylistFormat)
+
diff --git a/src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/csvplaylistformat.h b/src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/csvplaylistformat.h
new file mode 100644
index 000000000..45e93d346
--- /dev/null
+++ b/src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/csvplaylistformat.h
@@ -0,0 +1,33 @@
+#ifndef CSVPLAYLISTFORMAT_H
+#define CSVPLAYLISTFORMAT_H
+
+#include <playlistformat.h>
+
+#include <QStringList>
+
+class MediaFile;
+
+/*!
+ * Example of custom playlist CSV semicolon separated format.
+ * Each line represents a song in the next format:
+ * TITLE;FILEPATH;DURATION
+ */
+
+class CSVPlaylistFormat : public QObject, public PlaylistFormat
+{
+Q_OBJECT
+Q_INTERFACES(PlaylistFormat)
+public:
+ CSVPlaylistFormat();
+ virtual ~CSVPlaylistFormat(){;}
+ virtual QStringList decode(const QString& contents);
+ virtual QString encode(const QList<MediaFile*>& contents);
+ virtual QStringList getExtensions()const;
+ virtual bool hasFormat(const QString& ext);
+ virtual QString name()const;
+protected:
+ QStringList m_supported_formats;
+};
+
+#endif //CSVPLAYLISTFORMAT_H
+
diff --git a/src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/moc_csvplaylistformat.cpp b/src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/moc_csvplaylistformat.cpp
new file mode 100644
index 000000000..133bf4692
--- /dev/null
+++ b/src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/moc_csvplaylistformat.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+** Meta object code from reading C++ file 'csvplaylistformat.h'
+**
+** Created: Mon Dec 24 01:59:05 2007
+** by: The Qt Meta Object Compiler version 59 (Qt 4.3.0)
+**
+** WARNING! All changes made in this file will be lost!
+*****************************************************************************/
+
+#include "csvplaylistformat.h"
+#if !defined(Q_MOC_OUTPUT_REVISION)
+#error "The header file 'csvplaylistformat.h' doesn't include <QObject>."
+#elif Q_MOC_OUTPUT_REVISION != 59
+#error "This file was generated using the moc from 4.3.0. It"
+#error "cannot be used with the include files from this version of Qt."
+#error "(The moc has changed too much.)"
+#endif
+
+static const uint qt_meta_data_CSVPlaylistFormat[] = {
+
+ // content:
+ 1, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 0, 0, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_CSVPlaylistFormat[] = {
+ "CSVPlaylistFormat\0"
+};
+
+const QMetaObject CSVPlaylistFormat::staticMetaObject = {
+ { &QObject::staticMetaObject, qt_meta_stringdata_CSVPlaylistFormat,
+ qt_meta_data_CSVPlaylistFormat, 0 }
+};
+
+const QMetaObject *CSVPlaylistFormat::metaObject() const
+{
+ return &staticMetaObject;
+}
+
+void *CSVPlaylistFormat::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_CSVPlaylistFormat))
+ return static_cast<void*>(const_cast< CSVPlaylistFormat*>(this));
+ if (!strcmp(_clname, "PlaylistFormat"))
+ return static_cast< PlaylistFormat*>(const_cast< CSVPlaylistFormat*>(this));
+ if (!strcmp(_clname, "PlaylistFormatInterface/1.0"))
+ return static_cast< PlaylistFormat*>(const_cast< CSVPlaylistFormat*>(this));
+ return QObject::qt_metacast(_clname);
+}
+
+int CSVPlaylistFormat::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QObject::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ return _id;
+}
diff --git a/src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/readme b/src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/readme
new file mode 100644
index 000000000..a047e358b
--- /dev/null
+++ b/src/plugins/Misc/PlaylistFormats/CSVPlaylistFormat/readme
@@ -0,0 +1,12 @@
+This is simple example of custom Playlist Format plugin.
+It represents CVS semicolon-separated format storage.
+This plugin developed mostly for QMMP customizing demonstration.
+
+Build: Change QMMPROOT variable in .pro file according your
+QMMP build tree location.Then qmake && make
+
+Install: copy library into ~/.qmmp/plugins/PlaylistFormats directory.
+
+
+ vovanec@gmail.com
+
diff --git a/src/plugins/Misc/PlaylistFormats/Makefile b/src/plugins/Misc/PlaylistFormats/Makefile
new file mode 100644
index 000000000..cbf632042
--- /dev/null
+++ b/src/plugins/Misc/PlaylistFormats/Makefile
@@ -0,0 +1,112 @@
+#############################################################################
+# Makefile for building: PlaylistFormats
+# Generated by qmake (2.01a) (Qt 4.3.0) on: Mon Dec 24 01:59:00 2007
+# Project: PlaylistFormats.pro
+# Template: subdirs
+# Command: /usr/local/Trolltech/Qt-4.3.0/bin/qmake -unix -o Makefile PlaylistFormats.pro
+#############################################################################
+
+first: make_default
+MAKEFILE = Makefile
+QMAKE = /usr/local/Trolltech/Qt-4.3.0/bin/qmake
+DEL_FILE = rm -f
+CHK_DIR_EXISTS= test -d
+MKDIR = mkdir -p
+COPY = cp -f
+COPY_FILE = $(COPY)
+COPY_DIR = $(COPY) -r
+INSTALL_FILE = install -m 644 -p
+INSTALL_PROGRAM = install -m 755 -p
+INSTALL_DIR = $(COPY_DIR)
+DEL_FILE = rm -f
+SYMLINK = ln -sf
+DEL_DIR = rmdir
+MOVE = mv -f
+CHK_DIR_EXISTS= test -d
+MKDIR = mkdir -p
+SUBTARGETS = \
+ sub-CSVPlaylistFormat
+
+CSVPlaylistFormat//$(MAKEFILE):
+ @$(CHK_DIR_EXISTS) CSVPlaylistFormat/ || $(MKDIR) CSVPlaylistFormat/
+ cd CSVPlaylistFormat/ && $(QMAKE) CSVPlaylistFormat.pro -unix -o $(MAKEFILE)
+sub-CSVPlaylistFormat-qmake_all: FORCE
+ @$(CHK_DIR_EXISTS) CSVPlaylistFormat/ || $(MKDIR) CSVPlaylistFormat/
+ cd CSVPlaylistFormat/ && $(QMAKE) CSVPlaylistFormat.pro -unix -o $(MAKEFILE)
+sub-CSVPlaylistFormat: CSVPlaylistFormat//$(MAKEFILE) FORCE
+ cd CSVPlaylistFormat/ && $(MAKE) -f $(MAKEFILE)
+sub-CSVPlaylistFormat-make_default: CSVPlaylistFormat//$(MAKEFILE) FORCE
+ cd CSVPlaylistFormat/ && $(MAKE) -f $(MAKEFILE)
+sub-CSVPlaylistFormat-make_first: CSVPlaylistFormat//$(MAKEFILE) FORCE
+ cd CSVPlaylistFormat/ && $(MAKE) -f $(MAKEFILE) first
+sub-CSVPlaylistFormat-all: CSVPlaylistFormat//$(MAKEFILE) FORCE
+ cd CSVPlaylistFormat/ && $(MAKE) -f $(MAKEFILE) all
+sub-CSVPlaylistFormat-clean: CSVPlaylistFormat//$(MAKEFILE) FORCE
+ cd CSVPlaylistFormat/ && $(MAKE) -f $(MAKEFILE) clean
+sub-CSVPlaylistFormat-distclean: CSVPlaylistFormat//$(MAKEFILE) FORCE
+ cd CSVPlaylistFormat/ && $(MAKE) -f $(MAKEFILE) distclean
+sub-CSVPlaylistFormat-install_subtargets: CSVPlaylistFormat//$(MAKEFILE) FORCE
+ cd CSVPlaylistFormat/ && $(MAKE) -f $(MAKEFILE) install
+sub-CSVPlaylistFormat-uninstall_subtargets: CSVPlaylistFormat//$(MAKEFILE) FORCE
+ cd CSVPlaylistFormat/ && $(MAKE) -f $(MAKEFILE) uninstall
+
+Makefile: PlaylistFormats.pro /usr/local/Trolltech/Qt-4.3.0/mkspecs/linux-g++/qmake.conf /usr/local/Trolltech/Qt-4.3.0/mkspecs/common/g++.conf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/common/unix.conf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/common/linux.conf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/qconfig.pri \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt_functions.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt_config.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/exclusive_builds.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/default_pre.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/release.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/default_post.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/warn_on.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/unix/thread.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/moc.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/resources.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/uic.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/yacc.prf \
+ /usr/local/Trolltech/Qt-4.3.0/mkspecs/features/lex.prf
+ $(QMAKE) -unix -o Makefile PlaylistFormats.pro
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/common/g++.conf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/common/unix.conf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/common/linux.conf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/qconfig.pri:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt_functions.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt_config.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/exclusive_builds.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/default_pre.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/release.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/default_post.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/warn_on.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/qt.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/unix/thread.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/moc.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/resources.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/uic.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/yacc.prf:
+/usr/local/Trolltech/Qt-4.3.0/mkspecs/features/lex.prf:
+qmake: qmake_all FORCE
+ @$(QMAKE) -unix -o Makefile PlaylistFormats.pro
+
+qmake_all: sub-CSVPlaylistFormat-qmake_all FORCE
+
+make_default: sub-CSVPlaylistFormat-make_default FORCE
+make_first: sub-CSVPlaylistFormat-make_first FORCE
+all: sub-CSVPlaylistFormat-all FORCE
+clean: sub-CSVPlaylistFormat-clean FORCE
+distclean: sub-CSVPlaylistFormat-distclean FORCE
+ -$(DEL_FILE) Makefile
+install_subtargets: sub-CSVPlaylistFormat-install_subtargets FORCE
+uninstall_subtargets: sub-CSVPlaylistFormat-uninstall_subtargets FORCE
+
+mocclean: compiler_moc_header_clean compiler_moc_source_clean
+
+mocables: compiler_moc_header_make_all compiler_moc_source_make_all
+install: install_subtargets FORCE
+
+uninstall: uninstall_subtargets FORCE
+
+FORCE:
+
diff --git a/src/plugins/Misc/PlaylistFormats/PlaylistFormats.pro b/src/plugins/Misc/PlaylistFormats/PlaylistFormats.pro
new file mode 100644
index 000000000..4235b3190
--- /dev/null
+++ b/src/plugins/Misc/PlaylistFormats/PlaylistFormats.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = CSVPlaylistFormat \ No newline at end of file
diff --git a/src/plugins/Misc/PlaylistFormats/libCSVPlaylistFormat.so b/src/plugins/Misc/PlaylistFormats/libCSVPlaylistFormat.so
new file mode 100755
index 000000000..f9677157c
--- /dev/null
+++ b/src/plugins/Misc/PlaylistFormats/libCSVPlaylistFormat.so
Binary files differ
diff --git a/src/plugins/Output/CMakeLists.txt b/src/plugins/Output/CMakeLists.txt
new file mode 100644
index 000000000..864d945c1
--- /dev/null
+++ b/src/plugins/Output/CMakeLists.txt
@@ -0,0 +1,24 @@
+SET(USE_ALSA TRUE CACHE BOOL "enable/disable alsa plugin")
+SET(USE_JACK TRUE CACHE BOOL "enable/disable jack plugin")
+SET(USE_OSS TRUE CACHE BOOL "enable/disable oss plugin")
+
+IF(USE_ALSA)
+MESSAGE( STATUS "ALSA ON")
+add_subdirectory(alsa)
+ELSE(USE_ALSA)
+MESSAGE( STATUS "ALSA OFF")
+ENDIF(USE_ALSA)
+
+IF(USE_JACK)
+MESSAGE( STATUS "JACK ON")
+add_subdirectory(jack)
+ELSE(USE_JACK)
+MESSAGE( STATUS "JACK OFF")
+ENDIF(USE_JACK)
+
+IF(USE_OSS)
+MESSAGE( STATUS "OSS ON")
+add_subdirectory(oss)
+ELSE(USE_OSS)
+MESSAGE( STATUS "OSS OFF")
+ENDIF(USE_OSS) \ No newline at end of file
diff --git a/src/plugins/Output/Output.pro b/src/plugins/Output/Output.pro
new file mode 100644
index 000000000..eed8b9f14
--- /dev/null
+++ b/src/plugins/Output/Output.pro
@@ -0,0 +1,26 @@
+# ???? ?????? ? KDevelop ?????????? qmake.
+# -------------------------------------------
+# ?????????? ???????????? ???????? ???????? ???????: ./Plugins/Output
+# ???? - ?????? ? ?????????????
+
+include(../../../qmmp.pri)
+
+CONFIG += release warn_on
+TEMPLATE = subdirs
+
+SUBDIRS += alsa
+
+contains(CONFIG, JACK_PLUGIN){
+ SUBDIRS += jack
+ message(***********************)
+ message(* JACK plugin enabled *)
+ message(***********************)
+}
+
+contains(CONFIG, OSS_PLUGIN){
+ SUBDIRS += oss
+ message(**********************)
+ message(* OSS plugin enabled *)
+ message(**********************)
+}
+
diff --git a/src/plugins/Output/alsa/CMakeLists.txt b/src/plugins/Output/alsa/CMakeLists.txt
new file mode 100644
index 000000000..92f7af8d9
--- /dev/null
+++ b/src/plugins/Output/alsa/CMakeLists.txt
@@ -0,0 +1,65 @@
+project(libalsa)
+
+cmake_minimum_required(VERSION 2.4.0)
+
+
+INCLUDE(UsePkgConfig)
+INCLUDE(FindQt4)
+
+find_package(Qt4 REQUIRED) # find and setup Qt4 for this project
+include(${QT_USE_FILE})
+
+# qt plugin
+ADD_DEFINITIONS( -Wall )
+ADD_DEFINITIONS(${QT_DEFINITIONS})
+ADD_DEFINITIONS(-DQT_PLUGIN)
+ADD_DEFINITIONS(-DQT_NO_DEBUG)
+ADD_DEFINITIONS(-DQT_SHARED)
+ADD_DEFINITIONS(-DQT_THREAD)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+SET(QT_INCLUDES
+ ${QT_INCLUDES}
+ ${CMAKE_CURRENT_BINARY_DIR}/../../../
+)
+
+# libqmmp
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+link_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+
+SET(libalsa_SRCS
+ outputalsa.cpp
+ outputalsafactory.cpp
+ settingsdialog.cpp
+)
+
+SET(libalsa_MOC_HDRS
+ outputalsa.h
+ outputalsafactory.h
+ settingsdialog.h
+)
+
+SET(libalsa_RCCS translations/translations.qrc)
+
+QT4_ADD_RESOURCES(libalsa_RCC_SRCS ${libalsa_RCCS})
+
+QT4_WRAP_CPP(libalsa_MOC_SRCS ${libalsa_MOC_HDRS})
+
+# user interface
+
+
+SET(libalsa_UIS
+ settingsdialog.ui
+)
+
+QT4_WRAP_UI(libalsa_UIS_H ${libalsa_UIS})
+# Don't forget to include output directory, otherwise
+# the UI file won't be wrapped!
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+ADD_LIBRARY(alsa SHARED ${libalsa_SRCS} ${libalsa_MOC_SRCS} ${libalsa_UIS_H}
+ ${libalsa_RCC_SRCS})
+target_link_libraries(alsa ${QT_LIBRARIES} -lqmmp -lasound)
+install(TARGETS alsa DESTINATION ${LIB_DIR}/qmmp/Output PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ)
+
diff --git a/src/plugins/Output/alsa/alsa.pro b/src/plugins/Output/alsa/alsa.pro
new file mode 100644
index 000000000..465fabe4a
--- /dev/null
+++ b/src/plugins/Output/alsa/alsa.pro
@@ -0,0 +1,37 @@
+# ???? ?????? ? KDevelop ?????????? qmake.
+# -------------------------------------------
+# ?????????? ???????????? ???????? ???????? ???????: ./Plugins/Output/alsa
+# ???? - ??????????:
+
+include(../../plugins.pri)
+
+HEADERS += outputalsa.h \
+ outputalsafactory.h \
+ settingsdialog.h
+SOURCES += outputalsa.cpp \
+ outputalsafactory.cpp \
+ settingsdialog.cpp
+
+TARGET=$$PLUGINS_PREFIX/Output/alsa
+QMAKE_CLEAN =$$PLUGINS_PREFIX/Output/libalsa.so
+
+
+INCLUDEPATH += ../../../qmmp
+QMAKE_LIBDIR += ../../../../lib
+
+CONFIG += release \
+warn_on \
+thread \
+plugin
+TEMPLATE = lib
+LIBS += -lqmmp -lasound
+FORMS += settingsdialog.ui
+#TRANSLATIONS = translations/alsa_plugin_ru.ts
+#RESOURCES = translations/translations.qrc
+
+isEmpty (LIB_DIR){
+LIB_DIR = /lib
+}
+
+target.path = $$LIB_DIR/qmmp/Output
+INSTALLS += target
diff --git a/src/plugins/Output/alsa/outputalsa.cpp b/src/plugins/Output/alsa/outputalsa.cpp
new file mode 100644
index 000000000..66c031bbb
--- /dev/null
+++ b/src/plugins/Output/alsa/outputalsa.cpp
@@ -0,0 +1,539 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QObject>
+#include <QApplication>
+#include <QtGlobal>
+#include <QDir>
+#include <QSettings>
+#include <QTimer>
+
+#include <stdio.h>
+#include <string.h>
+#include <iostream>
+
+#include "outputalsa.h"
+#include "constants.h"
+#include "buffer.h"
+#include "visual.h"
+
+OutputALSA::OutputALSA(QObject * parent, bool useVolume)
+ : Output(parent), m_inited(FALSE), m_pause(FALSE), m_play(FALSE),
+ m_userStop(FALSE), m_totalWritten(0), m_currentSeconds(-1),
+ m_bps(-1), m_frequency(-1), m_channels(-1), m_precision(-1)
+{
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ QString dev_name = settings.value("ALSA/device","default").toString();
+ pcm_name = strdup(dev_name.toAscii().data());
+ stream = SND_PCM_STREAM_PLAYBACK;
+ snd_pcm_hw_params_alloca(&hwparams);
+ pcm_handle = 0;
+ //alsa mixer
+ mixer = 0;
+ if (useVolume)
+ {
+ QString card = settings.value("ALSA/mixer_card","hw:0").toString();
+ QString dev = settings.value("ALSA/mixer_device", "PCM").toString();
+ setupMixer(card, dev);
+ }
+}
+
+OutputALSA::~OutputALSA()
+{
+ uninitialize();
+ free (pcm_name);
+ if (mixer)
+ snd_mixer_close(mixer);
+}
+
+void OutputALSA::stop()
+{
+ m_userStop = TRUE;
+}
+
+void OutputALSA::status()
+{
+ long ct = (m_totalWritten - latency()) / m_bps;
+
+ if (ct < 0)
+ ct = 0;
+
+ if (ct > m_currentSeconds)
+ {
+ m_currentSeconds = ct;
+ dispatch(m_currentSeconds, m_totalWritten, m_rate,
+ m_frequency, m_precision, m_channels);
+ }
+}
+
+long OutputALSA::written()
+{
+ return m_totalWritten;
+}
+
+void OutputALSA::seek(long pos)
+{
+ m_totalWritten = (pos * m_bps);
+ m_currentSeconds = -1;
+}
+
+void OutputALSA::configure(long freq, int chan, int prec, int brate)
+{
+ // we need to configure
+ if (freq != m_frequency || chan != m_channels || prec != m_precision)
+ {
+ m_frequency = freq;
+ m_channels = chan;
+ m_precision = prec;
+ m_bps = freq * chan * (prec / 8);
+ snd_pcm_hw_params_alloca(&hwparams);
+ if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0)
+ {
+ qWarning("OutputALSA: Can not configure this PCM device.");
+ return;
+ }
+
+ uint rate = m_frequency; /* Sample rate */
+ uint exact_rate = m_frequency; /* Sample rate returned by */
+
+ /* load settings from config */
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.beginGroup("ALSA");
+ uint buffer_time = settings.value("buffer_time",500).toUInt()*1000;
+ uint period_time = settings.value("period_time",100).toUInt()*1000;
+ settings.endGroup();
+
+ if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
+ {
+ qWarning("OutputALSA: Error setting access.");
+ return;
+ }
+
+
+ if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0)
+ {
+ qDebug("OutputALSA: Error setting format.");
+ return;
+ }
+
+
+ exact_rate = rate;// = 11000;
+ qDebug("OutputALSA: frequency=%d, channels=%d, bitrate=%d",
+ rate, chan, brate);
+ if (snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_rate, 0) < 0)
+ {
+ qWarning("OutputALSA: Error setting rate.\n");
+ return;
+ }
+ if (rate != exact_rate)
+ {
+ qWarning("OutputALSA: The rate %d Hz is not supported by your hardware.\n==> Using %d Hz instead.", rate, exact_rate);
+ }
+
+ uint c = m_channels;
+ if (snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c) < 0)
+ {
+ qWarning("OutputALSA: Error setting channels.");
+ return;
+ }
+
+ if (snd_pcm_hw_params_set_period_time_near(pcm_handle, hwparams,
+ &period_time ,0) < 0 )
+ {
+ qWarning("OutputALSA: Error setting HW buffer.");
+ return;
+ }
+ if (snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams,
+ &buffer_time ,0) < 0 )
+ {
+ qWarning("Error setting HW buffer.\n");
+ return;
+ }
+ if (snd_pcm_hw_params(pcm_handle, hwparams) < 0)
+ {
+ qWarning("OutputALSA: Error setting HW params.");
+ return;
+ }
+ }
+}
+
+void OutputALSA::reset()
+{
+ if (pcm_handle)
+ {
+ snd_pcm_close(pcm_handle);
+ pcm_handle = 0;
+ }
+ if (snd_pcm_open(&pcm_handle, pcm_name, stream, SND_PCM_NONBLOCK) < 0)
+ {
+ qWarning ("OutputALSA: Error opening PCM device %s", pcm_name);
+ return;
+ }
+}
+
+
+void OutputALSA::pause()
+{
+ if (!m_play)
+ return;
+ m_pause = (m_pause) ? FALSE : TRUE;
+ OutputState::Type state = m_pause ? OutputState::Paused: OutputState::Playing;
+ dispatch(state);
+}
+
+bool OutputALSA::initialize()
+{
+ m_inited = m_pause = m_play = m_userStop = FALSE;
+
+ if (!pcm_handle < 0)
+ return FALSE;
+
+ m_currentSeconds = -1;
+ m_totalWritten = 0;
+ if (snd_pcm_open(&pcm_handle, pcm_name, stream, SND_PCM_NONBLOCK) < 0)
+ {
+ qWarning ("OutputALSA: Error opening PCM device %s", pcm_name);
+ return FALSE;
+ }
+
+ m_inited = TRUE;
+ return TRUE;
+}
+
+
+long OutputALSA::latency()
+{
+ long used = 0;
+
+ /*if (! m_pause)
+ {
+ if (ioctl(audio_fd, SNDCTL_DSP_GETODELAY, &used) == -1)
+ used = 0;
+ }*/
+
+ return used;
+}
+
+void OutputALSA::run()
+{
+
+ mutex()->lock ();
+ if (! m_inited)
+ {
+ mutex()->unlock();
+ return;
+ }
+
+ m_play = TRUE;
+
+ mutex()->unlock();
+
+ Buffer *b = 0;
+ bool done = FALSE;
+ unsigned long n = 0;
+ long m = 0;
+ snd_pcm_uframes_t l;
+
+ dispatch(OutputState::Playing);
+
+ while (! done)
+ {
+ mutex()->lock ();
+ recycler()->mutex()->lock ();
+
+ done = m_userStop;
+
+ while (! done && (recycler()->empty() || m_pause))
+ {
+ mutex()->unlock();
+ recycler()->cond()->wakeOne();
+ recycler()->cond()->wait(recycler()->mutex());
+ mutex()->lock ();
+ done = m_userStop;
+ status();
+ }
+
+ if (! b)
+ {
+ b = recycler()->next();
+ if (b->rate)
+ m_rate = b->rate;
+ }
+
+ recycler()->cond()->wakeOne();
+ recycler()->mutex()->unlock();
+
+ if (b)
+ {
+ l = snd_pcm_bytes_to_frames(pcm_handle, b->nbytes - n);
+ while (l>0)
+ {
+ m = snd_pcm_writei (pcm_handle, b->data+n, l);
+
+ if (m > 0)
+ {
+ n += snd_pcm_frames_to_bytes(pcm_handle, m);
+ l -= m;
+ status();
+ dispatchVisual(b, m_totalWritten, m_channels, m_precision);
+ }
+ else if (m == -EAGAIN)
+ {
+ mutex()->unlock();
+ snd_pcm_wait(pcm_handle, 500);
+ mutex()->lock ();
+ }
+ else if (m == -EPIPE)
+ {
+ qDebug ("OutputALSA: underrun!");
+ if ((m = snd_pcm_prepare(pcm_handle)) < 0)
+ {
+ qDebug ("OutputALSA: Can't recover after underrun: %s",
+ snd_strerror(m));
+ /* TODO: reopen the device */
+ break;
+ }
+ }
+ else if (m == -ESTRPIPE)
+ {
+ qDebug ("OutputALSA: Suspend, trying to resume");
+ while ((m = snd_pcm_resume(pcm_handle))
+ == -EAGAIN)
+ sleep (1);
+ if (m < 0)
+ {
+ qDebug ("OutputALSA: Failed, restarting");
+ if ((m = snd_pcm_prepare(pcm_handle))
+ < 0)
+ {
+ qDebug ("OutputALSA: Failed to restart device: %s.",
+ snd_strerror(m));
+ break;
+ }
+ }
+ }
+ else if (m < 0)
+ {
+ qDebug ("OutputALSA: Can't play: %s", snd_strerror(m));
+ break;
+ }
+ }
+ status();
+ // force buffer change
+ m_totalWritten += n;
+ n = b->nbytes;
+ m = 0;
+ }
+ if (n == b->nbytes)
+ {
+ recycler()->mutex()->lock ();
+ recycler()->done();
+ recycler()->mutex()->unlock();
+ b = 0;
+ n = 0;
+ }
+ mutex()->unlock();
+ }
+
+ mutex()->lock ();
+
+ m_play = FALSE;
+
+ dispatch(OutputState::Stopped);
+
+ mutex()->unlock();
+
+}
+
+void OutputALSA::uninitialize()
+{
+ if (!m_inited)
+ return;
+ m_inited = FALSE;
+ m_pause = FALSE;
+ m_play = FALSE;
+ m_userStop = FALSE;
+ m_totalWritten = 0;
+ m_currentSeconds = -1;
+ m_bps = -1;
+ m_frequency = -1;
+ m_channels = -1;
+ m_precision = -1;
+ if (pcm_handle)
+ {
+ qDebug("OutputALSA: closing pcm_handle");
+ snd_pcm_close(pcm_handle);
+ pcm_handle = 0;
+ }
+ dispatch(OutputState::Stopped);
+}
+/* ****** MIXER ******* */
+
+int OutputALSA::setupMixer(QString card, QString device)
+{
+ char *name;
+ long int a, b;
+ long alsa_min_vol = 0, alsa_max_vol = 100;
+ int err, index;
+
+ qDebug("OutputALSA: setupMixer()");
+
+ if ((err = getMixer(&mixer, card)) < 0)
+ return err;
+
+ parseMixerName(device.toAscii().data(), &name, &index);
+
+ pcm_element = getMixerElem(mixer, name, index);
+
+ free(name);
+
+ if (!pcm_element)
+ {
+ qWarning("OutputALSA: Failed to find mixer element");
+ return -1;
+ }
+
+ /* This hack was copied from xmms.
+ * Work around a bug in alsa-lib up to 1.0.0rc2 where the
+ * new range don't take effect until the volume is changed.
+ * This hack should be removed once we depend on Alsa 1.0.0.
+ */
+ snd_mixer_selem_get_playback_volume(pcm_element,
+ SND_MIXER_SCHN_FRONT_LEFT, &a);
+ snd_mixer_selem_get_playback_volume(pcm_element,
+ SND_MIXER_SCHN_FRONT_RIGHT, &b);
+
+ snd_mixer_selem_get_playback_volume_range(pcm_element,
+ &alsa_min_vol, &alsa_max_vol);
+ snd_mixer_selem_set_playback_volume_range(pcm_element, 0, 100);
+
+ if (alsa_max_vol == 0)
+ {
+ pcm_element = NULL;
+ return -1;
+ }
+
+ setVolume(a * 100 / alsa_max_vol, b * 100 / alsa_max_vol);
+
+ qDebug("OutputALSA: setupMixer() succes");
+
+ return 0;
+}
+
+void OutputALSA::parseMixerName(char *str, char **name, int *index)
+{
+ char *end;
+
+ while (isspace(*str))
+ str++;
+
+ if ((end = strchr(str, ',')) != NULL)
+ {
+ *name = strndup(str, end - str);
+ end++;
+ *index = atoi(end);
+ }
+ else
+ {
+ *name = strdup(str);
+ *index = 0;
+ }
+}
+
+snd_mixer_elem_t* OutputALSA::getMixerElem(snd_mixer_t *mixer, char *name, int index)
+{
+ snd_mixer_selem_id_t* selem_id;
+ snd_mixer_elem_t* elem;
+ snd_mixer_selem_id_alloca(&selem_id);
+
+ if (index != -1)
+ snd_mixer_selem_id_set_index(selem_id, index);
+ if (name != NULL)
+ snd_mixer_selem_id_set_name(selem_id, name);
+
+ elem = snd_mixer_find_selem(mixer, selem_id);
+
+ return elem;
+}
+
+void OutputALSA::setVolume(int l, int r)
+{
+
+ if (!pcm_element)
+ return;
+
+ snd_mixer_selem_set_playback_volume(pcm_element,
+ SND_MIXER_SCHN_FRONT_LEFT, l);
+ snd_mixer_selem_set_playback_volume(pcm_element,
+ SND_MIXER_SCHN_FRONT_RIGHT, r);
+}
+
+void OutputALSA::volume(int * l, int * r)
+{
+ if (!pcm_element)
+ return;
+ snd_mixer_handle_events(mixer);
+ snd_mixer_selem_get_playback_volume(pcm_element,
+ SND_MIXER_SCHN_FRONT_LEFT, (long int*)l);
+ snd_mixer_selem_get_playback_volume(pcm_element,
+ SND_MIXER_SCHN_FRONT_RIGHT, (long int*)r);
+}
+
+int OutputALSA::getMixer(snd_mixer_t **mixer, QString card)
+{
+ char *dev;
+ int err;
+
+
+ dev = strdup(card.toAscii().data());
+
+ if ((err = snd_mixer_open(mixer, 0)) < 0)
+ {
+ qWarning("OutputALSA: Failed to open empty mixer: %s",
+ snd_strerror(-err));
+ mixer = NULL;
+ return -1;
+ }
+ if ((err = snd_mixer_attach(*mixer, dev)) < 0)
+ {
+ qWarning("OutputALSA: Attaching to mixer %s failed: %s",
+ dev, snd_strerror(-err));
+ return -1;
+ }
+ if ((err = snd_mixer_selem_register(*mixer, NULL, NULL)) < 0)
+ {
+ qWarning("OutputALSA: Failed to register mixer: %s",
+ snd_strerror(-err));
+ return -1;
+ }
+ if ((err = snd_mixer_load(*mixer)) < 0)
+ {
+ qWarning("OutputALSA: Failed to load mixer: %s",
+ snd_strerror(-err));
+ return -1;
+ }
+
+ free(dev);
+
+ return (*mixer != NULL);
+}
+
+
+
diff --git a/src/plugins/Output/alsa/outputalsa.h b/src/plugins/Output/alsa/outputalsa.h
new file mode 100644
index 000000000..f3dd222fe
--- /dev/null
+++ b/src/plugins/Output/alsa/outputalsa.h
@@ -0,0 +1,85 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef OUTPUTALSA_H
+#define OUTPUTALSA_H
+
+class OutputALSA;
+
+#include <output.h>
+#include <QObject>
+extern "C" {
+#include <alsa/asoundlib.h>
+}
+#if defined( Q_OS_WIN32 )
+#include <dsound.h>
+#include "constants.h"
+#endif
+
+
+class OutputALSA : public Output
+{
+Q_OBJECT
+public:
+ OutputALSA(QObject * parent = 0, bool useVolume = TRUE);
+ ~OutputALSA();
+
+ bool initialize();
+ bool isInitialized() const { return m_inited; }
+ void uninitialize();
+ void configure(long, int, int, int);
+ void stop();
+ void pause();
+ long written();
+ long latency();
+ void seek(long);
+ void setVolume(int l, int r);
+ void volume(int *l, int *r);
+ void checkVolume();
+
+private:
+ // thread run function
+ void run();
+
+ // helper functions
+ void reset();
+ void status();
+
+ bool m_inited, m_pause, m_play, m_userStop;
+ long m_totalWritten, m_currentSeconds, m_bps;
+ int m_rate, m_frequency, m_channels, m_precision;
+ //alsa
+ snd_pcm_t *pcm_handle;
+ snd_pcm_stream_t stream;
+ snd_pcm_hw_params_t *hwparams;
+ char *pcm_name;
+ //alsa
+
+ //alsa mixer
+ int setupMixer(QString card, QString device);
+ void parseMixerName(char *str, char **name, int *index);
+ int getMixer(snd_mixer_t **mixer, QString card);
+ snd_mixer_elem_t* getMixerElem(snd_mixer_t *mixer, char *name, int index);
+ snd_mixer_t *mixer;
+ snd_mixer_elem_t *pcm_element;
+};
+
+
+#endif // OUTPUTALSA_H
diff --git a/src/plugins/Output/alsa/outputalsafactory.cpp b/src/plugins/Output/alsa/outputalsafactory.cpp
new file mode 100644
index 000000000..641ff1278
--- /dev/null
+++ b/src/plugins/Output/alsa/outputalsafactory.cpp
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QtGui>
+
+#include "settingsdialog.h"
+#include "outputalsa.h"
+#include "outputalsafactory.h"
+
+
+const OutputProperties OutputALSAFactory::properties() const
+{
+ OutputProperties properties;
+ properties.name = tr("ALSA Plugin");
+ properties.hasAbout = TRUE;
+ properties.hasSettings = TRUE;
+ return properties;
+}
+
+Output* OutputALSAFactory::create(QObject* parent, bool volume)
+{
+ return new OutputALSA(parent, volume);
+}
+
+void OutputALSAFactory::showSettings(QWidget* parent)
+{
+ SettingsDialog *s = new SettingsDialog(parent);
+ s -> show();
+}
+
+void OutputALSAFactory::showAbout(QWidget *parent)
+{
+ QMessageBox::about (parent, tr("About ALSA Output Plugin"),
+ tr("Qmmp ALSA Output Plugin")+"\n"+
+ tr("Writen by: Ilya Kotov <forkotov02@hotmail.ru>"));
+}
+
+QTranslator *OutputALSAFactory::createTranslator(QObject *parent)
+{
+ QTranslator *translator = new QTranslator(parent);
+ QString locale = QLocale::system().name();
+ translator->load(QString(":/alsa_plugin_") + locale);
+ return translator;
+}
+
+Q_EXPORT_PLUGIN(OutputALSAFactory)
diff --git a/src/plugins/Output/alsa/outputalsafactory.h b/src/plugins/Output/alsa/outputalsafactory.h
new file mode 100644
index 000000000..afaa18358
--- /dev/null
+++ b/src/plugins/Output/alsa/outputalsafactory.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef OUTPUTALSAFACTORY_H
+#define OUTPUTALSAFACTORY_H
+
+
+#include <QObject>
+#include <QString>
+#include <QIODevice>
+#include <QWidget>
+
+#include <output.h>
+#include <outputfactory.h>
+
+
+class OutputALSAFactory : public QObject,
+ OutputFactory
+{
+Q_OBJECT
+Q_INTERFACES(OutputFactory);
+
+public:
+ const OutputProperties properties() const;
+ Output* create(QObject* parent, bool volume);
+ void showSettings(QWidget* parent);
+ void showAbout(QWidget *parent);
+ QTranslator *createTranslator(QObject *parent);
+
+};
+
+#endif
diff --git a/src/plugins/Output/alsa/settingsdialog.cpp b/src/plugins/Output/alsa/settingsdialog.cpp
new file mode 100644
index 000000000..89c6cae84
--- /dev/null
+++ b/src/plugins/Output/alsa/settingsdialog.cpp
@@ -0,0 +1,237 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include <QSettings>
+#include <QDir>
+
+extern "C"
+{
+#include <alsa/asoundlib.h>
+}
+
+#include "settingsdialog.h"
+
+SettingsDialog::SettingsDialog ( QWidget *parent )
+ : QDialog ( parent )
+{
+ ui.setupUi ( this );
+ setAttribute ( Qt::WA_DeleteOnClose );
+ ui.deviceComboBox->setEditable ( TRUE );
+ getCards();
+ connect (ui.deviceComboBox, SIGNAL(activated(int)),SLOT(setText(int)));
+ connect(ui.okButton, SIGNAL(clicked()), SLOT(writeSettings()));
+ connect(ui.mixerCardComboBox, SIGNAL(activated(int)), SLOT(showMixerDevices(int)));
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.beginGroup("ALSA");
+ ui.deviceComboBox->setEditText(settings.value("device","default").toString());
+ ui.bufferSpinBox->setValue(settings.value("buffer_time",500).toInt());
+ ui.periodSpinBox->setValue(settings.value("period_time",100).toInt());
+
+ int d = m_cards.indexOf(settings.value("mixer_card","hw:0").toString());
+ if (d >= 0)
+ ui.mixerCardComboBox->setCurrentIndex(d);
+
+ showMixerDevices(ui.mixerCardComboBox->currentIndex ());
+ d = ui.mixerDeviceComboBox->findText(settings.value("mixer_device",
+ "PCM").toString());
+
+ if (d >= 0)
+ ui.mixerDeviceComboBox->setCurrentIndex(d);
+
+ settings.endGroup();
+}
+
+
+SettingsDialog::~SettingsDialog()
+{}
+
+void SettingsDialog::getCards()
+{
+ int card = -1, err;
+
+ m_devices.clear();
+ m_devices << "default";
+ ui.deviceComboBox->addItem("Default PCM device (default)");
+
+ if ((err = snd_card_next(&card)) !=0)
+ qWarning("SettingsDialog (ALSA): snd_next_card() failed: %s",
+ snd_strerror(-err));
+
+ while (card > -1)
+ {
+ getCardDevices(card);
+ m_cards << QString("hw:%1").arg(card);
+ if ((err = snd_card_next(&card)) !=0)
+ {
+ qWarning("SettingsDialog (ALSA): snd_next_card() failed: %s",
+ snd_strerror(-err));
+ break;
+ }
+ }
+}
+
+void SettingsDialog::getCardDevices(int card)
+{
+ int pcm_device = -1, err;
+ snd_pcm_info_t *pcm_info;
+ snd_ctl_t *ctl;
+ char dev[64], *card_name;
+
+ sprintf(dev, "hw:%i", card);
+
+ if ((err = snd_ctl_open(&ctl, dev, 0)) < 0)
+ {
+ qWarning("SettingsDialog (ALSA): snd_ctl_open() failed: %s",
+ snd_strerror(-err));
+ return;
+ }
+
+ if ((err = snd_card_get_name(card, &card_name)) != 0)
+ {
+ qWarning("SettingsDialog (ALSA): snd_card_get_name() failed: %s",
+ snd_strerror(-err));
+ card_name = "Unknown soundcard";
+ }
+ ui.mixerCardComboBox->addItem(QString(card_name));
+
+ snd_pcm_info_alloca(&pcm_info);
+
+ qDebug("SettingsDialog (ALSA): detected sound cards:");
+
+ for (;;)
+ {
+ QString device;
+ if ((err = snd_ctl_pcm_next_device(ctl, &pcm_device)) < 0)
+ {
+ qWarning("SettingsDialog (ALSA): snd_ctl_pcm_next_device() failed: %s",
+ snd_strerror(-err));
+ pcm_device = -1;
+ }
+ if (pcm_device < 0)
+ break;
+
+ snd_pcm_info_set_device(pcm_info, pcm_device);
+ snd_pcm_info_set_subdevice(pcm_info, 0);
+ snd_pcm_info_set_stream(pcm_info, SND_PCM_STREAM_PLAYBACK);
+
+ if ((err = snd_ctl_pcm_info(ctl, pcm_info)) < 0)
+ {
+ if (err != -ENOENT)
+ qWarning("SettingsDialog (ALSA): get_devices_for_card(): "
+ "snd_ctl_pcm_info() "
+ "failed (%d:%d): %s.", card,
+ pcm_device, snd_strerror(-err));
+ }
+ device = QString("hw:%1,%2").arg(card).arg(pcm_device);
+ m_devices << device;
+ QString str;
+ str = QString(card_name) + ": "+
+ snd_pcm_info_get_name(pcm_info)+" ("+device+")";
+ qDebug(str.toAscii());
+ ui.deviceComboBox->addItem(str);
+ }
+
+ snd_ctl_close(ctl);
+}
+
+void SettingsDialog::getMixerDevices(QString card)
+{
+ ui.mixerDeviceComboBox->clear();
+ int err;
+ snd_mixer_t *mixer;
+ snd_mixer_elem_t *current;
+
+ if ((err = getMixer(&mixer, card)) < 0)
+ return;
+
+ current = snd_mixer_first_elem(mixer);
+
+ while (current)
+ {
+ const char *sname = snd_mixer_selem_get_name(current);
+ if (snd_mixer_selem_is_active(current) &&
+ snd_mixer_selem_has_playback_volume(current))
+ ui.mixerDeviceComboBox->addItem(QString(sname));
+ current = snd_mixer_elem_next(current);
+ }
+}
+
+void SettingsDialog::setText(int n)
+{
+ ui.deviceComboBox->setEditText(m_devices.at(n));
+}
+
+void SettingsDialog::writeSettings()
+{
+ qDebug("SettingsDialog (ALSA):: writeSettings()");
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.beginGroup("ALSA");
+ settings.setValue("device", ui.deviceComboBox->currentText ());
+ settings.setValue("buffer_time",ui.bufferSpinBox->value());
+ settings.setValue("period_time",ui.periodSpinBox->value());
+ QString card = m_cards.at(ui.mixerCardComboBox->currentIndex());
+ settings.setValue("mixer_card", card);
+ settings.setValue("mixer_device", ui.mixerDeviceComboBox->currentText ());
+ settings.endGroup();
+ accept();
+}
+
+int SettingsDialog::getMixer(snd_mixer_t **mixer, QString card)
+{
+ char *dev;
+ int err;
+
+ dev = strdup(QString(card).toAscii().data());
+ if ((err = snd_mixer_open(mixer, 0)) < 0)
+ {
+ qWarning("SettingsDialog (ALSA): alsa_get_mixer(): "
+ "Failed to open empty mixer: %s", snd_strerror(-err));
+ mixer = NULL;
+ return -1;
+ }
+ if ((err = snd_mixer_attach(*mixer, dev)) < 0)
+ {
+ qWarning("SettingsDialog (ALSA): alsa_get_mixer(): "
+ "Attaching to mixer %s failed: %s", dev, snd_strerror(-err));
+ return -1;
+ }
+ if ((err = snd_mixer_selem_register(*mixer, NULL, NULL)) < 0)
+ {
+ qWarning("SettingsDialog (ALSA): alsa_get_mixer(): "
+ "Failed to register mixer: %s", snd_strerror(-err));
+ return -1;
+ }
+ if ((err = snd_mixer_load(*mixer)) < 0)
+ {
+ qWarning("SettingsDialog (ALSA): alsa_get_mixer(): Failed to load mixer: %s",
+ snd_strerror(-err));
+ return -1;
+ }
+
+ free (dev);
+
+ return (*mixer != NULL);
+}
+
+void SettingsDialog::showMixerDevices(int d)
+{
+ if (0<=d && d<m_cards.size())
+ getMixerDevices(m_cards.at(d));
+}
+
diff --git a/src/plugins/Output/alsa/settingsdialog.h b/src/plugins/Output/alsa/settingsdialog.h
new file mode 100644
index 000000000..467b25a03
--- /dev/null
+++ b/src/plugins/Output/alsa/settingsdialog.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef SETTINGSDIALOG_H
+#define SETTINGSDIALOG_H
+
+#include <QDialog>
+
+extern "C"{
+#include <alsa/asoundlib.h>
+}
+//#include <alsa/pcm_plugin.h>
+
+#include "ui_settingsdialog.h"
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class SettingsDialog : public QDialog
+{
+Q_OBJECT
+public:
+ SettingsDialog(QWidget *parent = 0);
+
+ ~SettingsDialog();
+
+private slots:
+ void setText(int);
+ void writeSettings();
+ void showMixerDevices(int);
+
+private:
+ Ui::SettingsDialog ui;
+ void getCards();
+ void getCardDevices(int card);
+ void getMixerDevices(QString card);
+ int getMixer(snd_mixer_t **mixer, QString card);
+ QStringList m_devices;
+ QList <QString> m_cards;
+
+};
+
+#endif
diff --git a/src/plugins/Output/alsa/settingsdialog.ui b/src/plugins/Output/alsa/settingsdialog.ui
new file mode 100644
index 000000000..2f9a20753
--- /dev/null
+++ b/src/plugins/Output/alsa/settingsdialog.ui
@@ -0,0 +1,261 @@
+<ui version="4.0" >
+ <class>SettingsDialog</class>
+ <widget class="QDialog" name="SettingsDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>403</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>ALSA Plugin Settings</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="0" colspan="3" >
+ <widget class="QTabWidget" name="tabWidget" >
+ <property name="currentIndex" >
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab" >
+ <attribute name="title" >
+ <string>Device Settings</string>
+ </attribute>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="title" >
+ <string>Audio device</string>
+ </property>
+ <widget class="QComboBox" name="deviceComboBox" >
+ <property name="geometry" >
+ <rect>
+ <x>11</x>
+ <y>47</y>
+ <width>338</width>
+ <height>22</height>
+ </rect>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2" >
+ <property name="title" >
+ <string>Mixer</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="1" >
+ <widget class="QComboBox" name="mixerCardComboBox" />
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Mixer card:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_4" >
+ <property name="text" >
+ <string>Mixer device:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QComboBox" name="mixerDeviceComboBox" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_2" >
+ <attribute name="title" >
+ <string>Advanced Settings</string>
+ </attribute>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="groupBox_3" >
+ <property name="title" >
+ <string>Soundcard</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="2" column="1" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>111</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>188</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QSpinBox" name="periodSpinBox" >
+ <property name="maximum" >
+ <number>5000</number>
+ </property>
+ <property name="minimum" >
+ <number>20</number>
+ </property>
+ <property name="value" >
+ <number>100</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QSpinBox" name="bufferSpinBox" >
+ <property name="maximum" >
+ <number>10000</number>
+ </property>
+ <property name="minimum" >
+ <number>200</number>
+ </property>
+ <property name="value" >
+ <number>500</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Buffer time (ms):</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Period time (ms):</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>188</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>191</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="2" >
+ <widget class="QPushButton" name="cancelButton" >
+ <property name="text" >
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QPushButton" name="okButton" >
+ <property name="text" >
+ <string>OK</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>cancelButton</sender>
+ <signal>clicked()</signal>
+ <receiver>SettingsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>338</x>
+ <y>283</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>164</x>
+ <y>294</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/Output/alsa/translations/alsa_plugin_cs.ts b/src/plugins/Output/alsa/translations/alsa_plugin_cs.ts
new file mode 100644
index 000000000..3108490ec
--- /dev/null
+++ b/src/plugins/Output/alsa/translations/alsa_plugin_cs.ts
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS><TS version="1.1" language="pl">
+<defaultcodec></defaultcodec>
+<context>
+ <name>OutputALSAFactory</name>
+ <message>
+ <location filename="../outputalsafactory.cpp" line="30"/>
+ <source>ALSA Plugin</source>
+ <translation>Plugin ALSA</translation>
+ </message>
+ <message>
+ <location filename="../outputalsafactory.cpp" line="47"/>
+ <source>About ALSA Output Plugin</source>
+ <translation>O pluginu ALSA</translation>
+ </message>
+ <message>
+ <location filename="../outputalsafactory.cpp" line="48"/>
+ <source>Qmmp ALSA Output Plugin</source>
+ <translation>Výstupní plugin Qmmp ALSA</translation>
+ </message>
+ <message>
+ <location filename="../outputalsafactory.cpp" line="49"/>
+ <source>Writen by: Ilya Kotov &lt;forkotov02@hotmail.ru&gt;</source>
+ <translation>Autor: Ilja Kotov &lt;forkotov02@hotmail.ru&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <location filename="../settingsdialog.ui" line="13"/>
+ <source>ALSA Plugin Settings</source>
+ <translation>Nastavení pluginu ALSA</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="29"/>
+ <source>Device Settings</source>
+ <translation>Nastavení zařízení</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="41"/>
+ <source>Audio device</source>
+ <translation>Zvukové zařízení</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="58"/>
+ <source>Mixer</source>
+ <translation>Mixér</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="73"/>
+ <source>Mixer card:</source>
+ <translation>Zvuková karta:</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="83"/>
+ <source>Mixer device:</source>
+ <translation>Ovládání hlasitosti:</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="100"/>
+ <source>Advanced Settings</source>
+ <translation>Pokročilá nastavení</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="112"/>
+ <source>Soundcard</source>
+ <translation>Zvuková karta</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="176"/>
+ <source>Buffer time (ms):</source>
+ <translation>Velikost bufferu (ms):</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="186"/>
+ <source>Period time (ms):</source>
+ <translation type="unfinished">Délka periody (ms):</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="229"/>
+ <source>Cancel</source>
+ <translation>Zrušit</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="236"/>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/plugins/Output/alsa/translations/alsa_plugin_ru.qm b/src/plugins/Output/alsa/translations/alsa_plugin_ru.qm
new file mode 100644
index 000000000..78ed38962
--- /dev/null
+++ b/src/plugins/Output/alsa/translations/alsa_plugin_ru.qm
Binary files differ
diff --git a/src/plugins/Output/alsa/translations/alsa_plugin_ru.ts b/src/plugins/Output/alsa/translations/alsa_plugin_ru.ts
new file mode 100644
index 000000000..2c7296750
--- /dev/null
+++ b/src/plugins/Output/alsa/translations/alsa_plugin_ru.ts
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS><TS version="1.1" language="ru">
+<context>
+ <name>OutputALSAFactory</name>
+ <message>
+ <location filename="../outputalsafactory.cpp" line="30"/>
+ <source>ALSA Plugin</source>
+ <translation>Модуль ALSA</translation>
+ </message>
+ <message>
+ <location filename="../outputalsafactory.cpp" line="47"/>
+ <source>About ALSA Output Plugin</source>
+ <translation>О модуле вывода ALSA</translation>
+ </message>
+ <message>
+ <location filename="../outputalsafactory.cpp" line="48"/>
+ <source>Qmmp ALSA Output Plugin</source>
+ <translation>Модуль вывода ALSA для Qmmp</translation>
+ </message>
+ <message>
+ <location filename="../outputalsafactory.cpp" line="49"/>
+ <source>Writen by: Ilya Kotov &lt;forkotov02@hotmail.ru&gt;</source>
+ <translation>Разработчик: Илья Котов &lt;forkotov02@hotmail.ru&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <location filename="../settingsdialog.ui" line="29"/>
+ <source>Device Settings</source>
+ <translation>Параметры устройства</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="41"/>
+ <source>Audio device</source>
+ <translation>Аудио устройство</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="58"/>
+ <source>Mixer</source>
+ <translation>Микшер</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="73"/>
+ <source>Mixer card:</source>
+ <translation>Карта микшера:</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="83"/>
+ <source>Mixer device:</source>
+ <translation>Устройство микшера:</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="100"/>
+ <source>Advanced Settings</source>
+ <translation>Дополнительные настройки</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="112"/>
+ <source>Soundcard</source>
+ <translation>Звуковая карта</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="176"/>
+ <source>Buffer time (ms):</source>
+ <translation>Время буферизации (мс):</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="186"/>
+ <source>Period time (ms):</source>
+ <translation>Время периода (мс):</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="229"/>
+ <source>Cancel</source>
+ <translation>Отмена</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="236"/>
+ <source>OK</source>
+ <translation>Применить</translation>
+ </message>
+ <message>
+ <location filename="../settingsdialog.ui" line="13"/>
+ <source>ALSA Plugin Settings</source>
+ <translation>Настройки модуля ALSA</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/plugins/Output/alsa/translations/translations.qrc b/src/plugins/Output/alsa/translations/translations.qrc
new file mode 100644
index 000000000..beac1cd17
--- /dev/null
+++ b/src/plugins/Output/alsa/translations/translations.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+ <qresource>
+ <file>alsa_plugin_ru.qm</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/Output/jack/CMakeLists.txt b/src/plugins/Output/jack/CMakeLists.txt
new file mode 100644
index 000000000..665a6fb13
--- /dev/null
+++ b/src/plugins/Output/jack/CMakeLists.txt
@@ -0,0 +1,74 @@
+project(libjack)
+
+cmake_minimum_required(VERSION 2.4.0)
+
+
+INCLUDE(UsePkgConfig)
+INCLUDE(FindQt4)
+
+find_package(Qt4 REQUIRED) # find and setup Qt4 for this project
+include(${QT_USE_FILE})
+
+# qt plugin
+ADD_DEFINITIONS( -Wall )
+ADD_DEFINITIONS(${QT_DEFINITIONS})
+ADD_DEFINITIONS(-DQT_PLUGIN)
+ADD_DEFINITIONS(-DQT_NO_DEBUG)
+ADD_DEFINITIONS(-DQT_SHARED)
+ADD_DEFINITIONS(-DQT_THREAD)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+SET(QT_INCLUDES
+ ${QT_INCLUDES}
+ ${CMAKE_CURRENT_BINARY_DIR}/../../../
+)
+
+# libqmmp
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+link_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+
+# libjack and taglib
+PKGCONFIG(jack JACK_INCLUDE_DIR JACK_LINK_DIR JACK_LINK_FLAGS JACK_CFLAGS)
+PKGCONFIG(samplerate SAMPLERATE_INCLUDE_DIR SAMPLERATE_LINK_DIR SAMPLERATE_LINK_FLAGS SAMPLERATE_CFLAGS)
+
+
+IF(NOT JACK_LINK_FLAGS)
+ SET(JACK_LINK_FLAGS -ljack -lrt)
+ENDIF(NOT JACK_LINK_FLAGS)
+
+IF(NOT SAMPLERATE_LINK_FLAGS)
+ SET(SAMPLERATE_LINK_FLAGS -lsamplerate)
+ENDIF(NOT SAMPLERATE_LINK_FLAGS)
+
+include_directories(${JACK_INCLUDE_DIR} ${JACK_INCLUDE_DIR})
+link_directories(${SAMPLERATE_LINK_DIR} ${SAMPLERATE_LINK_DIR})
+
+ADD_DEFINITIONS(${JACK_CFLAGS})
+ADD_DEFINITIONS(${SAMPLERATE_CFLAGS})
+
+
+SET(libjack_SRCS
+ outputjackfactory.cpp
+ outputjack.cpp
+ bio2jack.c
+)
+
+SET(libjack_MOC_HDRS
+ outputjackfactory.h
+ outputjack.h
+ bio2jack.h
+)
+
+SET(libjack_RCCS translations/translations.qrc)
+
+QT4_ADD_RESOURCES(libjack_RCC_SRCS ${libjack_RCCS})
+
+QT4_WRAP_CPP(libjack_MOC_SRCS ${libjack_MOC_HDRS})
+
+
+
+ADD_LIBRARY(jack SHARED ${libjack_SRCS} ${libjack_MOC_SRCS} ${libjack_RCC_SRCS})
+target_link_libraries(jack ${QT_LIBRARIES} -lqmmp ${JACK_LINK_FLAGS} ${SAMPLERATE_LINK_FLAGS})
+install(TARGETS jack DESTINATION ${LIB_DIR}/qmmp/Output PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ)
+
diff --git a/src/plugins/Output/jack/bio2jack.c b/src/plugins/Output/jack/bio2jack.c
new file mode 100644
index 000000000..aef7ea9b7
--- /dev/null
+++ b/src/plugins/Output/jack/bio2jack.c
@@ -0,0 +1,2635 @@
+/*
+ * Copyright 2003-2006 Chris Morgan <cmorgan@alum.wpi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* NOTE: All functions that take a jack_driver_t* do NOT lock the device, in order to get a */
+/* jack_driver_t* you must call getDriver() which will pthread_mutex_lock() */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <math.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <jack/jack.h>
+#include <jack/ringbuffer.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <samplerate.h>
+
+#include "bio2jack.h"
+
+/* enable/disable TRACING through the JACK_Callback() function */
+/* this can sometimes be too much information */
+#define TRACE_CALLBACK 0
+
+/* set to 1 for verbose output */
+#define VERBOSE_OUTPUT 0
+
+/* set to 1 to enable debug messages */
+#define DEBUG_OUTPUT 0
+
+/* set to 1 to enable tracing */
+#define TRACE_ENABLE 0
+
+/* set to 1 to enable the function timers */
+#define TIMER_ENABLE 0
+
+/* set to 1 to enable tracing of getDriver() and releaseDriver() */
+#define TRACE_getReleaseDevice 0
+
+#define ENABLE_WARNINGS 0
+
+#define DEFAULT_RB_SIZE 4096
+
+#define OUTFILE stderr
+
+#if TIMER_ENABLE
+/* This seemingly construct makes timing arbitrary functions really easy
+ all you have to do is place a 'TIMER("start\n")' at the beginning and
+ a 'TIMER("stop\n")' at the end of any function and this does the rest
+ (naturally you can place any printf-compliant text you like in the argument
+ along with the associated values). */
+static struct timeval timer_now;
+#define TIMER(format,args...) gettimeofday(&timer_now,0); \
+ fprintf(OUTFILE, "%ld.%06ld: %s::%s(%d) "format, timer_now.tv_sec, timer_now.tv_usec, __FILE__, __FUNCTION__, __LINE__, ##args)
+#else
+#define TIMER(...)
+#endif
+
+#if TRACE_ENABLE
+#define TRACE(format,args...) fprintf(OUTFILE, "%s::%s(%d) "format, __FILE__, __FUNCTION__, __LINE__,##args); \
+ fflush(OUTFILE);
+#else
+#define TRACE(...)
+#endif
+
+#if DEBUG_OUTPUT
+#define DEBUG(format,args...) fprintf(OUTFILE, "%s::%s(%d) "format, __FILE__, __FUNCTION__, __LINE__,##args); \
+ fflush(OUTFILE);
+#else
+#define DEBUG(...)
+#endif
+
+#if TRACE_CALLBACK
+#define CALLBACK_TRACE(format,args...) fprintf(OUTFILE, "%s::%s(%d) "format, __FILE__, __FUNCTION__, __LINE__,##args); \
+ fflush(OUTFILE);
+#else
+#define CALLBACK_TRACE(...)
+#endif
+
+#if ENABLE_WARNINGS
+#define WARN(format,args...) fprintf(OUTFILE, "WARN: %s::%s(%d) "format, __FILE__,__FUNCTION__,__LINE__,##args); \
+ fflush(OUTFILE);
+#else
+#define WARN(...)
+#endif
+
+#define ERR(format,args...) fprintf(OUTFILE, "ERR: %s::%s(%d) "format, __FILE__,__FUNCTION__,__LINE__,##args); \
+ fflush(OUTFILE);
+
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#define max(a,b) (((a) < (b)) ? (b) : (a))
+
+#define MAX_OUTPUT_PORTS 10
+#define MAX_INPUT_PORTS 10
+
+typedef struct jack_driver_s
+{
+ bool allocated; /* whether or not this device has been allocated */
+
+ int deviceID; /* id of this device */
+ int clientCtr; /* to prevent overlapping client ids */
+ long jack_sample_rate; /* jack samples(frames) per second */
+
+ long client_sample_rate; /* client samples(frames) per second */
+ double output_sample_rate_ratio; /* ratio between jack's output rate & ours */
+ double input_sample_rate_ratio; /* ratio between our input rate & jack's */
+
+ unsigned long num_input_channels; /* number of input channels(1 is mono, 2 stereo etc..) */
+ unsigned long num_output_channels; /* number of output channels(1 is mono, 2 stereo etc..) */
+
+ unsigned long bits_per_channel; /* number of bits per channel (only 8 & 16 are currently supported) */
+
+ unsigned long bytes_per_output_frame; /* (num_output_channels * bits_per_channel) / 8 */
+ unsigned long bytes_per_input_frame; /* (num_input_channels * bits_per_channel) / 8 */
+
+ unsigned long bytes_per_jack_output_frame; /* (num_output_channels * bits_per_channel) / 8 */
+ unsigned long bytes_per_jack_input_frame; /* (num_input_channels * bits_per_channel) / 8 */
+
+ unsigned long latencyMS; /* latency in ms between writing and actual audio output of the written data */
+
+ long clientBytesInJack; /* number of INPUT bytes(from the client of bio2jack) we wrote to jack(not necessary the number of bytes we wrote to jack) */
+ long jack_buffer_size; /* size of the buffer jack will pass in to the process callback */
+
+ unsigned long callback_buffer1_size; /* number of bytes in the buffer allocated for processing data in JACK_Callback */
+ char *callback_buffer1;
+ unsigned long callback_buffer2_size; /* number of bytes in the buffer allocated for processing data in JACK_Callback */
+ char *callback_buffer2;
+
+ unsigned long rw_buffer1_size; /* number of bytes in the buffer allocated for processing data in JACK_(Read|Write) */
+ char *rw_buffer1;
+
+ struct timeval previousTime; /* time of last JACK_Callback() write to jack, allows for MS accurate bytes played */
+
+ unsigned long written_client_bytes; /* input bytes we wrote to jack, not necessarily actual bytes we wrote to jack due to channel and other conversion */
+ unsigned long played_client_bytes; /* input bytes that jack has played */
+
+ unsigned long client_bytes; /* total bytes written by the client of bio2jack via JACK_Write() */
+
+ jack_port_t *output_port[MAX_OUTPUT_PORTS]; /* output ports */
+ jack_port_t *input_port[MAX_OUTPUT_PORTS]; /* input ports */
+
+ jack_client_t *client; /* pointer to jack client */
+
+ char **jack_port_name; /* user given strings for the port names, can be NULL */
+ unsigned int jack_port_name_count; /* the number of port names given */
+
+ unsigned long jack_output_port_flags; /* flags to be passed to jack when opening the output ports */
+ unsigned long jack_input_port_flags; /* flags to be passed to jack when opening the output ports */
+
+ jack_ringbuffer_t *pPlayPtr; /* the playback ringbuffer */
+ jack_ringbuffer_t *pRecPtr; /* the recording ringbuffer */
+
+ SRC_STATE *output_src; /* SRC object for the output stream */
+ SRC_STATE *input_src; /* SRC object for the output stream */
+
+ enum status_enum state; /* one of PLAYING, PAUSED, STOPPED, CLOSED, RESET etc */
+
+ unsigned int volume[MAX_OUTPUT_PORTS]; /* percentage of sample value to preserve, 100 would be no attenuation */
+ enum JACK_VOLUME_TYPE volumeEffectType; /* linear or dbAttenuation, if dbAttenuation volume is the number of dBs of
+ attenuation to apply, 0 volume being no attenuation, full volume */
+
+ long position_byte_offset; /* an offset that we will apply to returned position queries to achieve */
+ /* the position that the user of the driver desires set */
+
+ bool in_use; /* true if this device is currently in use */
+
+ pthread_mutex_t mutex; /* mutex to lock this specific device */
+
+ /* variables used for trying to restart the connection to jack */
+ bool jackd_died; /* true if jackd has died and we should try to restart it */
+ struct timeval last_reconnect_attempt;
+} jack_driver_t;
+
+
+static char *client_name; /* the name bio2jack will use when creating a new
+ jack client. client_name_%deviceID% will be used */
+
+
+static bool do_sample_rate_conversion; /* whether the client has requested sample rate conversion,
+ default to on for improved compatibility */
+
+/*
+ Which SRC converter function we should use when doing sample rate conversion.
+ Default to the fastest of the 'good quality' set.
+ */
+static int preferred_src_converter = SRC_SINC_FASTEST;
+
+static bool init_done = 0; /* just to prevent clients from calling JACK_Init twice, that would be very bad */
+
+static enum JACK_PORT_CONNECTION_MODE port_connection_mode = CONNECT_ALL;
+
+/* enable/disable code that allows us to close a device without actually closing the jack device */
+/* this works around the issue where jack doesn't always close devices by the time the close function call returns */
+#define JACK_CLOSE_HACK 1
+
+typedef jack_default_audio_sample_t sample_t;
+typedef jack_nframes_t nframes_t;
+
+/* allocate devices for output */
+/* if you increase this past 10, you might want to update 'out_client_name = ... ' in JACK_OpenDevice */
+#define MAX_OUTDEVICES 10
+static jack_driver_t outDev[MAX_OUTDEVICES];
+
+static pthread_mutex_t device_mutex = PTHREAD_MUTEX_INITIALIZER; /* this is to lock the entire outDev array
+ to make managing it in a threaded
+ environment sane */
+
+#if JACK_CLOSE_HACK
+static void JACK_CloseDevice(jack_driver_t * drv, bool close_client);
+#else
+static void JACK_CloseDevice(jack_driver_t * drv);
+#endif
+
+
+/* Prototypes */
+static int JACK_OpenDevice(jack_driver_t * drv);
+static unsigned long JACK_GetBytesFreeSpaceFromDriver(jack_driver_t * drv);
+static void JACK_ResetFromDriver(jack_driver_t * drv);
+static long JACK_GetPositionFromDriver(jack_driver_t * drv,
+ enum pos_enum position, int type);
+static void JACK_CleanupDriver(jack_driver_t * drv);
+
+
+/* Return the difference between two timeval structures in terms of milliseconds */
+long
+TimeValDifference(struct timeval *start, struct timeval *end)
+{
+ double long ms; /* milliseconds value */
+
+ ms = end->tv_sec - start->tv_sec; /* compute seconds difference */
+ ms *= (double) 1000; /* convert to milliseconds */
+
+ ms += (double) (end->tv_usec - start->tv_usec) / (double) 1000; /* add on microseconds difference */
+
+ return (long) ms;
+}
+
+/* get a device and lock the devices mutex */
+/* */
+/* also attempt to reconnect to jack since this function is called from */
+/* most other bio2jack functions it provides a good point to attempt reconnection */
+/* */
+/* Ok, I know this looks complicated and it kind of is. The point is that when you're
+ trying to trace mutexes it's more important to know *who* called us than just that
+ we were called. This uses from pre-processor trickery so that the fprintf is actually
+ placed in the function making the getDriver call. Thus, the __FUNCTION__ and __LINE__
+ macros will actually reference our caller, rather than getDriver. The reason the
+ fprintf call is passes as a parameter is because this macro has to still return a
+ jack_driver_t* and we want to log both before *and* after the getDriver call for
+ easier detection of blocked calls.
+ */
+#if TRACE_getReleaseDevice
+#define getDriver(x) _getDriver(x,fprintf(OUTFILE, "%s::%s(%d) getting driver %d\n", __FILE__, __FUNCTION__, __LINE__,x)); TRACE("got driver %d\n",x);
+jack_driver_t *
+_getDriver(int deviceID, int ignored)
+{
+ fflush(OUTFILE);
+#else
+jack_driver_t *
+getDriver(int deviceID)
+{
+#endif
+ jack_driver_t *drv = &outDev[deviceID];
+
+ if(pthread_mutex_lock(&drv->mutex) != 0)
+ ERR("lock returned an error\n");
+
+ /* should we try to restart the jack server? */
+ if(drv->jackd_died && drv->client == 0)
+ {
+ struct timeval now;
+ gettimeofday(&now, 0);
+
+ /* wait 250ms before trying again */
+ if(TimeValDifference(&drv->last_reconnect_attempt, &now) >= 250)
+ {
+ JACK_OpenDevice(drv);
+ drv->last_reconnect_attempt = now;
+ }
+ }
+
+ return drv;
+}
+
+#if TRACE_getReleaseDevice
+#define tryGetDriver(x) _tryGetDriver(x,fprintf(OUTFILE, "%s::%s(%d) trying to get driver %d\n", __FILE__, __FUNCTION__, __LINE__,x)); TRACE("got driver %d\n",x);
+jack_driver_t *
+_tryGetDriver(int deviceID, int ignored)
+{
+ fflush(OUTFILE);
+#else
+jack_driver_t *
+tryGetDriver(int deviceID)
+{
+#endif
+ jack_driver_t *drv = &outDev[deviceID];
+
+ int err;
+ if((err = pthread_mutex_trylock(&drv->mutex)) == 0)
+ return drv;
+
+ if(err == EBUSY)
+ {
+ TRACE("driver %d is busy\n",deviceID);
+ return 0;
+ }
+
+ ERR("lock returned an error\n");
+ return 0;
+}
+
+
+/* release a device's mutex */
+/* */
+/* This macro is similar to the one for getDriver above, only simpler since we only
+ really need to know when the lock was release for the sake of debugging.
+*/
+#if TRACE_getReleaseDevice
+#define releaseDriver(x) TRACE("releasing driver %d\n",x->deviceID); _releaseDriver(x);
+void
+_releaseDriver(jack_driver_t * drv)
+#else
+void
+releaseDriver(jack_driver_t * drv)
+#endif
+{
+ /*
+ #if TRACE_getReleaseDevice
+ TRACE("deviceID == %d\n", drv->deviceID);
+ #endif
+ */
+ if(pthread_mutex_unlock(&drv->mutex) != 0)
+ ERR("lock returned an error\n");
+}
+
+
+/* Return a string corresponding to the input state */
+char *
+DEBUGSTATE(enum status_enum state)
+{
+ if(state == PLAYING)
+ return "PLAYING";
+ else if(state == PAUSED)
+ return "PAUSED";
+ else if(state == STOPPED)
+ return "STOPPED";
+ else if(state == CLOSED)
+ return "CLOSED";
+ else if(state == RESET)
+ return "RESET";
+ else
+ return "unknown state";
+}
+
+
+#define SAMPLE_MAX_16BIT 32767.0f
+#define SAMPLE_MAX_8BIT 255.0f
+
+/* floating point volume routine */
+/* volume should be a value between 0.0 and 1.0 */
+static void
+float_volume_effect(sample_t * buf, unsigned long nsamples, float volume,
+ int skip)
+{
+ if(volume < 0)
+ volume = 0;
+ if(volume > 1.0)
+ volume = 1.0;
+
+ while(nsamples--)
+ {
+ *buf = (*buf) * volume;
+ buf += skip;
+ }
+}
+
+/* place one channel into a multi-channel stream */
+static inline void
+mux(sample_t * dst, sample_t * src, unsigned long nsamples,
+ unsigned long dst_skip)
+{
+ /* ALERT: signed sign-extension portability !!! */
+ while(nsamples--)
+ {
+ *dst = *src;
+ dst += dst_skip;
+ src++;
+ }
+}
+
+/* pull one channel out of a multi-channel stream */
+static void
+demux(sample_t * dst, sample_t * src, unsigned long nsamples,
+ unsigned long src_skip)
+{
+ /* ALERT: signed sign-extension portability !!! */
+ while(nsamples--)
+ {
+ *dst = *src;
+ dst++;
+ src += src_skip;
+ }
+}
+
+/* convert from 16 bit to floating point */
+static inline void
+sample_move_short_float(sample_t * dst, short *src, unsigned long nsamples)
+{
+ /* ALERT: signed sign-extension portability !!! */
+ unsigned long i;
+ for(i = 0; i < nsamples; i++)
+ dst[i] = (sample_t) (src[i]) / SAMPLE_MAX_16BIT;
+}
+
+/* convert from floating point to 16 bit */
+static inline void
+sample_move_float_short(short *dst, sample_t * src, unsigned long nsamples)
+{
+ /* ALERT: signed sign-extension portability !!! */
+ unsigned long i;
+ for(i = 0; i < nsamples; i++)
+ dst[i] = (short) ((src[i]) * SAMPLE_MAX_16BIT);
+}
+
+/* convert from 8 bit to floating point */
+static inline void
+sample_move_char_float(sample_t * dst, unsigned char *src, unsigned long nsamples)
+{
+ /* ALERT: signed sign-extension portability !!! */
+ unsigned long i;
+ for(i = 0; i < nsamples; i++)
+ dst[i] = (sample_t) (src[i]) / SAMPLE_MAX_8BIT;
+}
+
+/* convert from floating point to 8 bit */
+static inline void
+sample_move_float_char(unsigned char *dst, sample_t * src, unsigned long nsamples)
+{
+ /* ALERT: signed sign-extension portability !!! */
+ unsigned long i;
+ for(i = 0; i < nsamples; i++)
+ dst[i] = (char) ((src[i]) * SAMPLE_MAX_8BIT);
+}
+
+/* fill dst buffer with nsamples worth of silence */
+static inline void
+sample_silence_float(sample_t * dst, unsigned long nsamples)
+{
+ /* ALERT: signed sign-extension portability !!! */
+ while(nsamples--)
+ {
+ *dst = 0;
+ dst++;
+ }
+}
+
+static inline bool
+ensure_buffer_size(char **buffer, unsigned long *cur_size,
+ unsigned long needed_size)
+{
+ DEBUG("current size = %lu, needed size = %lu\n", *cur_size, needed_size);
+ if(*cur_size >= needed_size)
+ return TRUE;
+ DEBUG("reallocing\n");
+ char *tmp = realloc(*buffer, needed_size);
+ if(tmp)
+ {
+ *cur_size = needed_size;
+ *buffer = tmp;
+ return TRUE;
+ }
+ DEBUG("reallocing failed\n");
+ return FALSE;
+}
+
+/******************************************************************
+ * JACK_callback
+ *
+ * every time the jack server wants something from us it calls this
+ * function, so we either deliver it some sound to play or deliver it nothing
+ * to play
+ */
+static int
+JACK_callback(nframes_t nframes, void *arg)
+{
+ jack_driver_t *drv = (jack_driver_t *) arg;
+
+ unsigned int i;
+ int src_error = 0;
+
+ TIMER("start\n");
+ gettimeofday(&drv->previousTime, 0); /* record the current time */
+
+ CALLBACK_TRACE("nframes %ld, sizeof(sample_t) == %d\n", (long) nframes,
+ sizeof(sample_t));
+
+ if(!drv->client)
+ ERR("client is closed, this is weird...\n");
+
+ sample_t *out_buffer[MAX_OUTPUT_PORTS];
+ /* retrieve the buffers for the output ports */
+ for(i = 0; i < drv->num_output_channels; i++)
+ out_buffer[i] = (sample_t *) jack_port_get_buffer(drv->output_port[i], nframes);
+
+ sample_t *in_buffer[MAX_INPUT_PORTS];
+ /* retrieve the buffers for the input ports */
+ for(i = 0; i < drv->num_input_channels; i++)
+ in_buffer[i] = (sample_t *) jack_port_get_buffer(drv->input_port[i], nframes);
+
+ /* handle playing state */
+ if(drv->state == PLAYING)
+ {
+ /* handle playback data, if any */
+ if(drv->num_output_channels > 0)
+ {
+ unsigned long jackFramesAvailable = nframes; /* frames we have left to write to jack */
+ unsigned long numFramesToWrite; /* num frames we are writing */
+ size_t inputBytesAvailable = jack_ringbuffer_read_space(drv->pPlayPtr);
+ unsigned long inputFramesAvailable; /* frames we have available */
+
+ inputFramesAvailable = inputBytesAvailable / drv->bytes_per_jack_output_frame;
+ size_t jackBytesAvailable = jackFramesAvailable * drv->bytes_per_jack_output_frame;
+
+ long read = 0;
+
+ CALLBACK_TRACE("playing... jackFramesAvailable = %ld inputFramesAvailable = %ld\n",
+ jackFramesAvailable, inputFramesAvailable);
+
+#if JACK_CLOSE_HACK
+ if(drv->in_use == FALSE)
+ {
+ /* output silence if nothing is being outputted */
+ for(i = 0; i < drv->num_output_channels; i++)
+ sample_silence_float(out_buffer[i], nframes);
+
+ return -1;
+ }
+#endif
+
+ /* make sure our buffer is large enough for the data we are writing */
+ /* ie. callback_buffer2_size < (bytes we already wrote + bytes we are going to write in this loop) */
+ if(!ensure_buffer_size
+ (&drv->callback_buffer2, &drv->callback_buffer2_size,
+ jackBytesAvailable))
+ {
+ ERR("allocated %lu bytes, need %lu bytes\n",
+ drv->callback_buffer2_size, (unsigned long)jackBytesAvailable);
+ return -1;
+ }
+
+ /* do sample rate conversion if needed & requested */
+ if(drv->output_src && drv->output_sample_rate_ratio != 1.0)
+ {
+ long bytes_needed_write = nframes * drv->bytes_per_jack_output_frame;
+
+ /* make a very good guess at how many raw bytes we'll need to satisfy jack's request after conversion */
+ long bytes_needed_read = min(inputBytesAvailable,
+ (double) (bytes_needed_write +
+ drv->
+ output_sample_rate_ratio
+ *
+ drv->
+ bytes_per_jack_output_frame)
+ / drv->output_sample_rate_ratio);
+ DEBUG("guessing that we need %ld bytes in and %ld out for rate conversion ratio = %f\n",
+ bytes_needed_read, bytes_needed_write,
+ drv->output_sample_rate_ratio);
+
+ if(!ensure_buffer_size(&drv->callback_buffer1,
+ &drv->callback_buffer1_size,
+ bytes_needed_read))
+ {
+ ERR("could not realloc callback_buffer2!\n");
+ return 1;
+ }
+ if(!ensure_buffer_size(&drv->callback_buffer2,
+ &drv->callback_buffer2_size,
+ bytes_needed_write))
+ {
+ ERR("could not realloc callback_buffer2!\n");
+ return 1;
+ }
+
+ if(jackFramesAvailable && inputBytesAvailable > 0)
+ {
+ /* read in the data, but don't move the read pointer until we know how much SRC used */
+ jack_ringbuffer_peek(drv->pPlayPtr, drv->callback_buffer1,
+ bytes_needed_read);
+
+ SRC_DATA srcdata;
+ srcdata.data_in = (sample_t *) drv->callback_buffer1;
+ srcdata.input_frames = bytes_needed_read / drv->bytes_per_jack_output_frame;
+ srcdata.src_ratio = drv->output_sample_rate_ratio;
+ srcdata.data_out = (sample_t *) drv->callback_buffer2;
+ srcdata.output_frames = nframes;
+ srcdata.end_of_input = 0; // it's a stream, it never ends
+ DEBUG("input_frames = %ld, output_frames = %ld\n",
+ srcdata.input_frames, srcdata.output_frames);
+ /* convert the sample rate */
+ src_error = src_process(drv->output_src, &srcdata);
+ DEBUG("used = %ld, generated = %ld, error = %d: %s.\n",
+ srcdata.input_frames_used, srcdata.output_frames_gen,
+ src_error, src_strerror(src_error));
+
+ if(src_error == 0)
+ {
+ /* now we can move the read pointer */
+ jack_ringbuffer_read_advance(drv->pPlayPtr,
+ srcdata.
+ input_frames_used *
+ drv->bytes_per_jack_output_frame);
+ /* add on what we wrote */
+ read = srcdata.input_frames_used * drv->bytes_per_output_frame;
+ jackFramesAvailable -= srcdata.output_frames_gen; /* take away what was used */
+ }
+ }
+ }
+ else /* no resampling needed or requested */
+ {
+ /* read as much data from the buffer as is available */
+ if(jackFramesAvailable && inputBytesAvailable > 0)
+ {
+ /* write as many bytes as we have space remaining, or as much as we have data to write */
+ numFramesToWrite = min(jackFramesAvailable, inputFramesAvailable);
+ jack_ringbuffer_read(drv->pPlayPtr, drv->callback_buffer2,
+ jackBytesAvailable);
+ /* add on what we wrote */
+ read = numFramesToWrite * drv->bytes_per_output_frame;
+ jackFramesAvailable -= numFramesToWrite; /* take away what was written */
+ }
+ }
+
+ drv->written_client_bytes += read;
+ drv->played_client_bytes += drv->clientBytesInJack; /* move forward by the previous bytes we wrote since those must have finished by now */
+ drv->clientBytesInJack = read; /* record the input bytes we wrote to jack */
+
+ /* see if we still have jackBytesLeft here, if we do that means that we
+ ran out of wave data to play and had a buffer underrun, fill in
+ the rest of the space with zero bytes so at least there is silence */
+ if(jackFramesAvailable)
+ {
+ WARN("buffer underrun of %ld frames\n", jackFramesAvailable);
+ for(i = 0; i < drv->num_output_channels; i++)
+ sample_silence_float(out_buffer[i] +
+ (nframes - jackFramesAvailable),
+ jackFramesAvailable);
+ }
+
+ /* if we aren't converting or we are converting and src_error == 0 then we should */
+ /* apply volume and demux */
+ if(!(drv->output_src && drv->output_sample_rate_ratio != 1.0) || (src_error == 0))
+ {
+ /* apply volume */
+ for(i = 0; i < drv->num_output_channels; i++)
+ {
+ if(drv->volumeEffectType == dbAttenuation)
+ {
+ /* assume the volume setting is dB of attenuation, a volume of 0 */
+ /* is 0dB attenuation */
+ float volume = powf(10.0, -((float) drv->volume[i]) / 20.0);
+ float_volume_effect((sample_t *) drv->callback_buffer2 + i,
+ (nframes - jackFramesAvailable), volume, drv->num_output_channels);
+ } else
+ {
+ float_volume_effect((sample_t *) drv->callback_buffer2 + i, (nframes - jackFramesAvailable),
+ ((float) drv->volume[i] / 100.0),
+ drv->num_output_channels);
+ }
+ }
+
+ /* demux the stream: we skip over the number of samples we have output channels as the channel data */
+ /* is encoded like chan1,chan2,chan3,chan1,chan2,chan3... */
+ for(i = 0; i < drv->num_output_channels; i++)
+ {
+ demux(out_buffer[i],
+ (sample_t *) drv->callback_buffer2 + i,
+ (nframes - jackFramesAvailable), drv->num_output_channels);
+ }
+ }
+ }
+
+ /* handle record data, if any */
+ if(drv->num_input_channels > 0)
+ {
+ long jack_bytes = nframes * drv->bytes_per_jack_input_frame; /* how many bytes jack is feeding us */
+
+ if(!ensure_buffer_size(&drv->callback_buffer1, &drv->callback_buffer1_size, jack_bytes))
+ {
+ ERR("allocated %lu bytes, need %lu bytes\n",
+ drv->callback_buffer1_size, jack_bytes);
+ return -1;
+ }
+
+ /* mux the invividual channels into one stream */
+ for(i = 0; i < drv->num_input_channels; i++)
+ {
+ mux((sample_t *) drv->callback_buffer1 + i, in_buffer[i],
+ nframes, drv->num_input_channels);
+ }
+
+ /* do sample rate conversion if needed & requested */
+ if(drv->input_src && drv->input_sample_rate_ratio != 1.0)
+ {
+ /* make a very good guess at how many raw bytes we'll need to read all the data jack gave us */
+ long bytes_needed_write = (double) (jack_bytes +
+ drv->input_sample_rate_ratio *
+ drv->bytes_per_jack_input_frame) *
+ drv->input_sample_rate_ratio;
+ DEBUG("guessing that we need %ld bytes in and %ld out for rate conversion ratio = %f\n",
+ nframes * drv->bytes_per_jack_input_frame,
+ bytes_needed_write, drv->input_sample_rate_ratio);
+
+ if(!ensure_buffer_size(&drv->callback_buffer2,
+ &drv->callback_buffer2_size,
+ bytes_needed_write))
+ {
+ ERR("could not realloc callback_buffer2!\n");
+ return 1;
+ }
+
+ SRC_DATA srcdata;
+ srcdata.data_in = (sample_t *) drv->callback_buffer1;
+ srcdata.input_frames = nframes;
+ srcdata.src_ratio = drv->input_sample_rate_ratio;
+ srcdata.data_out = (sample_t *) drv->callback_buffer2;
+ srcdata.output_frames = drv->callback_buffer2_size / drv->bytes_per_jack_input_frame;
+ srcdata.end_of_input = 0; // it's a stream, it never ends
+ DEBUG("input_frames = %ld, output_frames = %ld\n",
+ srcdata.input_frames, srcdata.output_frames);
+ /* convert the sample rate */
+ src_error = src_process(drv->input_src, &srcdata);
+ DEBUG("used = %ld, generated = %ld, error = %d: %s.\n",
+ srcdata.input_frames_used, srcdata.output_frames_gen,
+ src_error, src_strerror(src_error));
+
+ if(src_error == 0)
+ {
+ long write_space = jack_ringbuffer_write_space(drv->pRecPtr);
+ long bytes_used = srcdata.output_frames_gen * drv->bytes_per_jack_input_frame;
+ /* if there isn't enough room, make some. sure this discards data, but when dealing with input sources
+ it seems like it's better to throw away old data than new */
+ if(write_space < bytes_used)
+ {
+ /* the ringbuffer is designed such that only one thread should ever access each pointer.
+ since calling read_advance here will be touching the read pointer which is also accessed
+ by JACK_Read, we need to lock the mutex first for safety */
+ jack_driver_t *d = tryGetDriver(drv->deviceID);
+ if( d )
+ {
+ /* double check the write space after we've gained the lock, just
+ in case JACK_Read was being called before we gained it */
+ write_space = jack_ringbuffer_write_space(drv->pRecPtr);
+ if(write_space < bytes_used)
+ {
+ /* hey, we warn about underruns, we might as well warn about overruns as well */
+ WARN("buffer overrun of %ld bytes\n", jack_bytes - write_space);
+ jack_ringbuffer_read_advance(drv->pRecPtr, bytes_used - write_space);
+ }
+
+ releaseDriver(drv);
+ }
+ }
+
+ jack_ringbuffer_write(drv->pRecPtr, drv->callback_buffer2,
+ bytes_used);
+ }
+ }
+ else /* no resampling needed */
+ {
+ long write_space = jack_ringbuffer_write_space(drv->pRecPtr);
+ /* if there isn't enough room, make some. sure this discards data, but when dealing with input sources
+ it seems like it's better to throw away old data than new */
+ if(write_space < jack_bytes)
+ {
+ /* the ringbuffer is designed such that only one thread should ever access each pointer.
+ since calling read_advance here will be touching the read pointer which is also accessed
+ by JACK_Read, we need to lock the mutex first for safety */
+ jack_driver_t *d = tryGetDriver(drv->deviceID);
+ if( d )
+ {
+ /* double check the write space after we've gained the lock, just
+ in case JACK_Read was being called before we gained it */
+ write_space = jack_ringbuffer_write_space(drv->pRecPtr);
+ if(write_space < jack_bytes)
+ {
+ ERR("buffer overrun of %ld bytes\n", jack_bytes - write_space);
+ jack_ringbuffer_read_advance(drv->pRecPtr, jack_bytes - write_space);
+ }
+ releaseDriver(drv);
+ }
+ }
+
+ jack_ringbuffer_write(drv->pRecPtr, drv->callback_buffer1,
+ jack_bytes);
+ }
+ }
+ }
+ else if(drv->state == PAUSED ||
+ drv->state == STOPPED ||
+ drv->state == CLOSED || drv->state == RESET)
+ {
+ CALLBACK_TRACE("%s, outputting silence\n", DEBUGSTATE(drv->state));
+
+ /* output silence if nothing is being outputted */
+ for(i = 0; i < drv->num_output_channels; i++)
+ sample_silence_float(out_buffer[i], nframes);
+
+ /* if we were told to reset then zero out some variables */
+ /* and transition to STOPPED */
+ if(drv->state == RESET)
+ {
+ drv->written_client_bytes = 0;
+ drv->played_client_bytes = 0; /* number of the clients bytes that jack has played */
+
+ drv->client_bytes = 0; /* bytes that the client wrote to use */
+
+ drv->clientBytesInJack = 0; /* number of input bytes in jack(not necessary the number of bytes written to jack) */
+
+ drv->position_byte_offset = 0;
+
+ if(drv->pPlayPtr)
+ jack_ringbuffer_reset(drv->pPlayPtr);
+
+ if(drv->pRecPtr)
+ jack_ringbuffer_reset(drv->pRecPtr);
+
+ drv->state = STOPPED; /* transition to STOPPED */
+ }
+ }
+
+ CALLBACK_TRACE("done\n");
+ TIMER("finish\n");
+
+ return 0;
+}
+
+
+/******************************************************************
+ * JACK_bufsize
+ *
+ * Called whenever the jack server changes the the max number
+ * of frames passed to JACK_callback
+ */
+static int
+JACK_bufsize(nframes_t nframes, void *arg)
+{
+ jack_driver_t *drv = (jack_driver_t *) arg;
+ TRACE("the maximum buffer size is now %lu frames\n", (long) nframes);
+
+ drv->jack_buffer_size = nframes;
+
+ return 0;
+}
+
+/******************************************************************
+ * JACK_srate
+ */
+int
+JACK_srate(nframes_t nframes, void *arg)
+{
+ jack_driver_t *drv = (jack_driver_t *) arg;
+
+ drv->jack_sample_rate = (long) nframes;
+
+ /* make sure to recalculate the ratios needed for proper sample rate conversion */
+ drv->output_sample_rate_ratio = (double) drv->jack_sample_rate / (double) drv->client_sample_rate;
+ if(drv->output_src) src_set_ratio(drv->output_src, drv->output_sample_rate_ratio);
+
+ drv->input_sample_rate_ratio = (double) drv->client_sample_rate / (double) drv->jack_sample_rate;
+ if(drv->input_src) src_set_ratio(drv->input_src, drv->input_sample_rate_ratio);
+
+ TRACE("the sample rate is now %lu/sec\n", (long) nframes);
+ return 0;
+}
+
+
+/******************************************************************
+ * JACK_shutdown
+ *
+ * if this is called then jack shut down... handle this appropriately */
+void
+JACK_shutdown(void *arg)
+{
+ jack_driver_t *drv = (jack_driver_t *) arg;
+
+ TRACE("\n");
+
+ getDriver(drv->deviceID);
+
+ drv->client = 0; /* reset client */
+ drv->jackd_died = TRUE;
+
+ TRACE("jack shutdown, setting client to 0 and jackd_died to true, closing device\n");
+
+#if JACK_CLOSE_HACK
+ JACK_CloseDevice(drv, TRUE);
+#else
+ JACK_CloseDevice(drv);
+#endif
+
+ TRACE("trying to reconnect right now\n");
+ /* lets see if we can't reestablish the connection */
+ if(JACK_OpenDevice(drv) != ERR_SUCCESS)
+ {
+ ERR("unable to reconnect with jack\n");
+ }
+
+ releaseDriver(drv);
+}
+
+
+/******************************************************************
+ * JACK_Error
+ *
+ * Callback for jack errors
+ */
+static void
+JACK_Error(const char *desc)
+{
+ ERR("%s\n", desc);
+}
+
+
+/******************************************************************
+ * JACK_OpenDevice
+ *
+ * RETURNS: ERR_SUCCESS upon success
+ */
+static int
+JACK_OpenDevice(jack_driver_t * drv)
+{
+ const char **ports;
+ char *our_client_name = 0;
+ unsigned int i;
+ int failed = 0;
+
+ TRACE("creating jack client and setting up callbacks\n");
+
+#if JACK_CLOSE_HACK
+ /* see if this device is already open */
+ if(drv->client)
+ {
+ /* if this device is already in use then it is bad for us to be in here */
+ if(drv->in_use)
+ return ERR_OPENING_JACK;
+
+ TRACE("using existing client\n");
+ drv->in_use = TRUE;
+ return ERR_SUCCESS;
+ }
+#endif
+
+ /* set up an error handler */
+ jack_set_error_function(JACK_Error);
+
+
+ /* build the client name */
+ our_client_name = (char *) malloc(snprintf
+ (our_client_name, 0, "%s_%d_%d%02d", client_name, getpid(),
+ drv->deviceID, drv->clientCtr + 1) + 1);
+ sprintf(our_client_name, "%s_%d_%d%02d", client_name, getpid(),
+ drv->deviceID, drv->clientCtr++);
+
+ /* try to become a client of the JACK server */
+ TRACE("client name '%s'\n", our_client_name);
+ if((drv->client = jack_client_new(our_client_name)) == 0)
+ {
+ /* try once more */
+ TRACE("trying once more to jack_client_new");
+ if((drv->client = jack_client_new(our_client_name)) == 0)
+ {
+ ERR("jack server not running?\n");
+ free(our_client_name);
+ return ERR_OPENING_JACK;
+ }
+ }
+
+ free(our_client_name);
+
+ TRACE("setting up jack callbacks\n");
+
+ /* JACK server to call `JACK_callback()' whenever
+ there is work to be done. */
+ jack_set_process_callback(drv->client, JACK_callback, drv);
+
+ /* setup a buffer size callback */
+ jack_set_buffer_size_callback(drv->client, JACK_bufsize, drv);
+
+ /* tell the JACK server to call `srate()' whenever
+ the sample rate of the system changes. */
+ jack_set_sample_rate_callback(drv->client, JACK_srate, drv);
+
+ /* tell the JACK server to call `jack_shutdown()' if
+ it ever shuts down, either entirely, or if it
+ just decides to stop calling us. */
+ jack_on_shutdown(drv->client, JACK_shutdown, drv);
+
+ /* display the current sample rate. once the client is activated
+ (see below), you should rely on your own sample rate
+ callback (see above) for this value. */
+ drv->jack_sample_rate = jack_get_sample_rate(drv->client);
+ drv->output_sample_rate_ratio = (double) drv->jack_sample_rate / (double) drv->client_sample_rate;
+ drv->input_sample_rate_ratio = (double) drv->client_sample_rate / (double) drv->jack_sample_rate;
+ TRACE("client sample rate: %lu, jack sample rate: %lu, output ratio = %f, input ratio = %f\n",
+ drv->client_sample_rate, drv->jack_sample_rate,
+ drv->output_sample_rate_ratio, drv->input_sample_rate_ratio);
+
+ drv->jack_buffer_size = jack_get_buffer_size(drv->client);
+
+ /* create the output ports */
+ TRACE("creating output ports\n");
+ for(i = 0; i < drv->num_output_channels; i++)
+ {
+ char portname[32];
+ sprintf(portname, "out_%d", i);
+ TRACE("port %d is named '%s'\n", i, portname);
+ /* NOTE: Yes, this is supposed to be JackPortIsOutput since this is an output */
+ /* port FROM bio2jack */
+ drv->output_port[i] = jack_port_register(drv->client, portname,
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput, 0);
+ }
+
+ /* create the input ports */
+ TRACE("creating input ports\n");
+ for(i = 0; i < drv->num_input_channels; i++)
+ {
+ char portname[32];
+ sprintf(portname, "in_%d", i);
+ TRACE("port %d is named '%s'\n", i, portname);
+ /* NOTE: Yes, this is supposed to be JackPortIsInput since this is an input */
+ /* port TO bio2jack */
+ drv->input_port[i] = jack_port_register(drv->client, portname,
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsInput, 0);
+ }
+
+#if JACK_CLOSE_HACK
+ drv->in_use = TRUE;
+#endif
+
+ /* tell the JACK server that we are ready to roll */
+ TRACE("calling jack_activate()\n");
+ if(jack_activate(drv->client))
+ {
+ ERR("cannot activate client\n");
+ return ERR_OPENING_JACK;
+ }
+
+ /* if we have output channels and the port connection mode isn't CONNECT_NONE */
+ /* then we should connect up some ports */
+ if((drv->num_output_channels > 0) && (port_connection_mode != CONNECT_NONE))
+ {
+ /* determine how we are to acquire output port names */
+ if((drv->jack_port_name_count == 0) || (drv->jack_port_name_count == 1))
+ {
+ if(drv->jack_port_name_count == 0)
+ {
+ TRACE("jack_get_ports() passing in NULL/NULL\n");
+ ports = jack_get_ports(drv->client, NULL, NULL,
+ drv->jack_output_port_flags);
+ }
+ else
+ {
+ TRACE("jack_get_ports() passing in port of '%s'\n",
+ drv->jack_port_name[0]);
+ ports = jack_get_ports(drv->client, drv->jack_port_name[0], NULL,
+ drv->jack_output_port_flags);
+ }
+
+ /* display a trace of the output ports we found */
+ unsigned int num_ports = 0;
+ if(ports)
+ {
+ for(i = 0; ports[i]; i++)
+ {
+ TRACE("ports[%d] = '%s'\n", i, ports[i]);
+ num_ports++;
+ }
+ }
+
+ /* ensure that we found enough ports */
+ if(!ports || (i < drv->num_output_channels))
+ {
+ TRACE("ERR: jack_get_ports() failed to find ports with jack port flags of 0x%lX'\n",
+ drv->jack_output_port_flags);
+#if JACK_CLOSE_HACK
+ JACK_CloseDevice(drv, TRUE);
+#else
+ JACK_CloseDevice(drv);
+#endif
+ return ERR_PORT_NOT_FOUND;
+ }
+
+ /* connect a port for each output channel. Note: you can't do this before
+ the client is activated (this may change in the future). */
+ for(i = 0; i < drv->num_output_channels; i++)
+ {
+ TRACE("jack_connect() to port %d('%p')\n", i, drv->output_port[i]);
+ if(jack_connect(drv->client, jack_port_name(drv->output_port[i]), ports[i]))
+ {
+ ERR("cannot connect to output port %d('%s')\n", i, ports[i]);
+ failed = 1;
+ }
+ }
+
+ /* only if we are in CONNECT_ALL mode should we keep connecting ports up beyond */
+ /* the minimum number of ports required for each output channel coming into bio2jack */
+ if(port_connection_mode == CONNECT_ALL)
+ {
+ /* It's much cheaper and easier to let JACK do the processing required to
+ connect 2 channels to 4 or 4 channels to 2 or any other combinations.
+ This effectively eliminates the need for sample_move_d16_d16() */
+ if(drv->num_output_channels < num_ports)
+ {
+ for(i = drv->num_output_channels; ports[i]; i++)
+ {
+ int n = i % drv->num_output_channels;
+ TRACE("jack_connect() to port %d('%p')\n", i, drv->output_port[n]);
+ if(jack_connect(drv->client, jack_port_name(drv->output_port[n]), ports[i]))
+ {
+ // non fatal
+ ERR("cannot connect to output port %d('%s')\n", n, ports[i]);
+ }
+ }
+ }
+ else if(drv->num_output_channels > num_ports)
+ {
+ for(i = num_ports; i < drv->num_output_channels; i++)
+ {
+ int n = i % num_ports;
+ TRACE("jack_connect() to port %d('%p')\n", i, drv->output_port[n]);
+ if(jack_connect(drv->client, jack_port_name(drv->output_port[i]), ports[n]))
+ {
+ // non fatal
+ ERR("cannot connect to output port %d('%s')\n", i, ports[n]);
+ }
+ }
+ }
+ }
+
+ free(ports); /* free the returned array of ports */
+ }
+ else
+ {
+ for(i = 0; i < drv->jack_port_name_count; i++)
+ {
+ TRACE("jack_get_ports() portname %d of '%s\n", i,
+ drv->jack_port_name[i]);
+ ports = jack_get_ports(drv->client, drv->jack_port_name[i], NULL,
+ drv->jack_output_port_flags);
+
+ if(!ports)
+ {
+ ERR("jack_get_ports() failed to find ports with jack port flags of 0x%lX'\n",
+ drv->jack_output_port_flags);
+ return ERR_PORT_NOT_FOUND;
+ }
+
+ TRACE("ports[%d] = '%s'\n", 0, ports[0]); /* display a trace of the output port we found */
+
+ /* connect the port */
+ TRACE("jack_connect() to port %d('%p')\n", i, drv->output_port[i]);
+ if(jack_connect(drv->client, jack_port_name(drv->output_port[i]), ports[0]))
+ {
+ ERR("cannot connect to output port %d('%s')\n", 0, ports[0]);
+ failed = 1;
+ }
+ free(ports); /* free the returned array of ports */
+ }
+ }
+ } /* if( drv->num_output_channels > 0 ) */
+
+
+ if(drv->num_input_channels > 0)
+ {
+ /* determine how we are to acquire input port names */
+ if((drv->jack_port_name_count == 0) || (drv->jack_port_name_count == 1))
+ {
+ if(drv->jack_port_name_count == 0)
+ {
+ TRACE("jack_get_ports() passing in NULL/NULL\n");
+ ports = jack_get_ports(drv->client, NULL, NULL, drv->jack_input_port_flags);
+ }
+ else
+ {
+ TRACE("jack_get_ports() passing in port of '%s'\n",
+ drv->jack_port_name[0]);
+ ports = jack_get_ports(drv->client, drv->jack_port_name[0], NULL,
+ drv->jack_input_port_flags);
+ }
+
+ /* display a trace of the input ports we found */
+ unsigned int num_ports = 0;
+ if(ports)
+ {
+ for(i = 0; ports[i]; i++)
+ {
+ TRACE("ports[%d] = '%s'\n", i, ports[i]);
+ num_ports++;
+ }
+ }
+
+ /* ensure that we found enough ports */
+ if(!ports || (i < drv->num_input_channels))
+ {
+ TRACE("ERR: jack_get_ports() failed to find ports with jack port flags of 0x%lX'\n",
+ drv->jack_input_port_flags);
+#if JACK_CLOSE_HACK
+ JACK_CloseDevice(drv, TRUE);
+#else
+ JACK_CloseDevice(drv);
+#endif
+ return ERR_PORT_NOT_FOUND;
+ }
+
+ /* connect the ports. Note: you can't do this before
+ the client is activated (this may change in the future). */
+ for(i = 0; i < drv->num_input_channels; i++)
+ {
+ TRACE("jack_connect() to port %d('%p')\n", i, drv->input_port[i]);
+ if(jack_connect(drv->client, ports[i], jack_port_name(drv->input_port[i])))
+ {
+ ERR("cannot connect to input port %d('%s')\n", i, ports[i]);
+ failed = 1;
+ }
+ }
+
+ /* It's much cheaper and easier to let JACK do the processing required to
+ connect 2 channels to 4 or 4 channels to 2 or any other combinations.
+ This effectively eliminates the need for sample_move_d16_d16() */
+ if(drv->num_input_channels < num_ports)
+ {
+ for(i = drv->num_input_channels; ports[i]; i++)
+ {
+ int n = i % drv->num_input_channels;
+ TRACE("jack_connect() to port %d('%p')\n", i, drv->input_port[n]);
+ if(jack_connect(drv->client, ports[i], jack_port_name(drv->input_port[n])))
+ {
+ // non fatal
+ ERR("cannot connect to input port %d('%s')\n", n, ports[i]);
+ }
+ }
+ }
+ else if(drv->num_input_channels > num_ports)
+ {
+ for(i = num_ports; i < drv->num_input_channels; i++)
+ {
+ int n = i % num_ports;
+ TRACE("jack_connect() to port %d('%p')\n", i, drv->input_port[n]);
+ if(jack_connect(drv->client, ports[n], jack_port_name(drv->input_port[i])))
+ {
+ // non fatal
+ ERR("cannot connect to input port %d('%s')\n", i, ports[n]);
+ }
+ }
+ }
+
+ free(ports); /* free the returned array of ports */
+ }
+ else
+ {
+ for(i = 0; i < drv->jack_port_name_count; i++)
+ {
+ TRACE("jack_get_ports() portname %d of '%s\n", i,
+ drv->jack_port_name[i]);
+ ports = jack_get_ports(drv->client, drv->jack_port_name[i], NULL,
+ drv->jack_input_port_flags);
+
+ if(!ports)
+ {
+ ERR("jack_get_ports() failed to find ports with jack port flags of 0x%lX'\n",
+ drv->jack_input_port_flags);
+ return ERR_PORT_NOT_FOUND;
+ }
+
+ TRACE("ports[%d] = '%s'\n", 0, ports[0]); /* display a trace of the input port we found */
+
+ /* connect the port */
+ TRACE("jack_connect() to port %d('%p')\n", i, drv->input_port[i]);
+ if(jack_connect(drv->client, jack_port_name(drv->input_port[i]), ports[0]))
+ {
+ ERR("cannot connect to input port %d('%s')\n", 0, ports[0]);
+ failed = 1;
+ }
+ free(ports); /* free the returned array of ports */
+ }
+ }
+ } /* if( drv->num_input_channels > 0 ) */
+
+ /* if something failed we need to shut the client down and return 0 */
+ if(failed)
+ {
+ TRACE("failed, closing and returning error\n");
+#if JACK_CLOSE_HACK
+ JACK_CloseDevice(drv, TRUE);
+#else
+ JACK_CloseDevice(drv);
+#endif
+ return ERR_OPENING_JACK;
+ }
+
+ TRACE("success\n");
+
+ drv->jackd_died = FALSE; /* clear out this flag so we don't keep attempting to restart things */
+ drv->state = PLAYING; /* clients seem to behave much better with this on from the start, especially when recording */
+
+ return ERR_SUCCESS; /* return success */
+}
+
+
+/******************************************************************
+ * JACK_CloseDevice
+ *
+ * Close the connection to the server cleanly.
+ * If close_client is TRUE we close the client for this device instead of
+ * just marking the device as in_use(JACK_CLOSE_HACK only)
+ */
+#if JACK_CLOSE_HACK
+static void
+JACK_CloseDevice(jack_driver_t * drv, bool close_client)
+#else
+static void
+JACK_CloseDevice(jack_driver_t * drv)
+#endif
+{
+ unsigned int i;
+
+#if JACK_CLOSE_HACK
+ if(close_client)
+ {
+#endif
+
+ TRACE("closing the jack client thread\n");
+ if(drv->client)
+ {
+ TRACE("after jack_deactivate()\n");
+ int errorCode = jack_client_close(drv->client);
+ if(errorCode)
+ ERR("jack_client_close() failed returning an error code of %d\n",
+ errorCode);
+ }
+
+ /* reset client */
+ drv->client = 0;
+
+ /* free up the port strings */
+ TRACE("freeing up %d port strings\n", drv->jack_port_name_count);
+ if(drv->jack_port_name_count > 1)
+ {
+ for(i = 0; i < drv->jack_port_name_count; i++)
+ free(drv->jack_port_name[i]);
+ free(drv->jack_port_name);
+ }
+ JACK_CleanupDriver(drv);
+
+ JACK_ResetFromDriver(drv);
+
+#if JACK_CLOSE_HACK
+ } else
+ {
+ TRACE("setting in_use to FALSE\n");
+ drv->in_use = FALSE;
+
+ if(!drv->client)
+ {
+ TRACE("critical error, closing a device that has no client\n");
+ }
+ }
+#endif
+}
+
+
+
+
+/**************************************/
+/* External interface functions below */
+/**************************************/
+
+/* Clear out any buffered data, stop playing, zero out some variables */
+static void
+JACK_ResetFromDriver(jack_driver_t * drv)
+{
+ TRACE("resetting drv->deviceID(%d)\n", drv->deviceID);
+
+ /* NOTE: we use the RESET state so we don't need to worry about clearing out */
+ /* variables that the callback modifies while the callback is running */
+ /* we set the state to RESET and the callback clears the variables out for us */
+ drv->state = RESET; /* tell the callback that we are to reset, the callback will transition this to STOPPED */
+}
+
+/* Clear out any buffered data, stop playing, zero out some variables */
+void
+JACK_Reset(int deviceID)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ TRACE("resetting deviceID(%d)\n", deviceID);
+ JACK_ResetFromDriver(drv);
+ releaseDriver(drv);
+}
+
+
+/*
+ * open the audio device for writing to
+ *
+ * deviceID is set to the opened device
+ * if client is non-zero and in_use is FALSE then just set in_use to TRUE
+ *
+ * return value is zero upon success, non-zero upon failure
+ *
+ * if ERR_RATE_MISMATCH (*rate) will be updated with the jack servers rate
+ */
+int
+JACK_Open(int *deviceID, unsigned int bits_per_channel, unsigned long *rate,
+ int channels)
+{
+ /* we call through to JACK_OpenEx(), but default the input channels to 0 for better backwards
+ compatibility with clients written before recording was available */
+ return JACK_OpenEx(deviceID, bits_per_channel,
+ rate,
+ 0, channels,
+ NULL, 0, JackPortIsPhysical);
+}
+
+/*
+ * see JACK_Open() for comments
+ * NOTE: jack_port_name has three ways of being used:
+ * - NULL - finds all ports with the given flags
+ * - A single regex string used to retrieve all port names
+ * - A series of port names, one for each output channel
+ *
+ * we set *deviceID
+ */
+int
+JACK_OpenEx(int *deviceID, unsigned int bits_per_channel,
+ unsigned long *rate,
+ unsigned int input_channels, unsigned int output_channels,
+ const char **jack_port_name,
+ unsigned int jack_port_name_count, unsigned long jack_port_flags)
+{
+ jack_driver_t *drv = 0;
+ unsigned int i;
+ int retval;
+
+ if(input_channels < 1 && output_channels < 1)
+ {
+ ERR("no input OR output channels, nothing to do\n");
+ return ERR_OPENING_JACK;
+ }
+
+ switch (bits_per_channel)
+ {
+ case 8:
+ case 16:
+ break;
+ default:
+ ERR("invalid bits_per_channel\n");
+ return ERR_OPENING_JACK;
+ }
+
+ /* Lock the device_mutex and find one that's not allocated already.
+ We'll keep this lock until we've either made use of it, or given up. */
+ pthread_mutex_lock(&device_mutex);
+
+ for(i = 0; i < MAX_OUTDEVICES; i++)
+ {
+ if(!outDev[i].allocated)
+ {
+ drv = &outDev[i];
+ break;
+ }
+ }
+
+ if(!drv)
+ {
+ ERR("no more devices available\n");
+ return ERR_OPENING_JACK;
+ }
+
+ /* We found an unallocated device, now lock it for extra saftey */
+ getDriver(drv->deviceID);
+
+ TRACE("bits_per_channel=%d rate=%ld, input_channels=%d, output_channels=%d\n",
+ bits_per_channel, *rate, input_channels, output_channels);
+
+ if(output_channels > MAX_OUTPUT_PORTS)
+ {
+ ERR("output_channels == %d, MAX_OUTPUT_PORTS == %d\n", output_channels,
+ MAX_OUTPUT_PORTS);
+ releaseDriver(drv);
+ pthread_mutex_unlock(&device_mutex);
+ return ERR_TOO_MANY_OUTPUT_CHANNELS;
+ }
+
+ if(input_channels > MAX_INPUT_PORTS)
+ {
+ ERR("input_channels == %d, MAX_INPUT_PORTS == %d\n", input_channels,
+ MAX_INPUT_PORTS);
+ releaseDriver(drv);
+ pthread_mutex_unlock(&device_mutex);
+ return ERR_TOO_MANY_INPUT_CHANNELS;
+ }
+
+ drv->jack_output_port_flags = jack_port_flags | JackPortIsInput; /* port must be input(ie we can put data into it), so mask this in */
+ drv->jack_input_port_flags = jack_port_flags | JackPortIsOutput; /* port must be output(ie we can get data from it), so mask this in */
+
+ /* check that we have the correct number of port names
+ FIXME?: not sure how we should handle output ports vs input ports....
+ */
+ if((jack_port_name_count > 1)
+ && ((jack_port_name_count < output_channels)
+ || (jack_port_name_count < input_channels)))
+ {
+ ERR("specified individual port names but not enough, gave %d names, need %d\n",
+ jack_port_name_count, output_channels);
+ releaseDriver(drv);
+ pthread_mutex_unlock(&device_mutex);
+ return ERR_PORT_NAME_OUTPUT_CHANNEL_MISMATCH;
+ } else
+ {
+ /* copy this data into the device information */
+ drv->jack_port_name_count = jack_port_name_count;
+
+ if(drv->jack_port_name_count != 0)
+ {
+ drv->jack_port_name =
+ (char **) malloc(sizeof(char *) * drv->jack_port_name_count);
+ for(i = 0; i < drv->jack_port_name_count; i++)
+ {
+ drv->jack_port_name[i] = strdup(jack_port_name[i]);
+ TRACE("jack_port_name[%d] == '%s'\n", i, jack_port_name[i]);
+ }
+ } else
+ {
+ drv->jack_port_name = NULL;
+ TRACE("jack_port_name = NULL\n");
+ }
+ }
+
+ /* initialize some variables */
+ drv->in_use = FALSE;
+
+ JACK_ResetFromDriver(drv); /* flushes all queued buffers, sets status to STOPPED and resets some variables */
+
+ /* drv->jack_sample_rate is set by JACK_OpenDevice() */
+ drv->client_sample_rate = *rate;
+ drv->bits_per_channel = bits_per_channel;
+ drv->num_input_channels = input_channels;
+ drv->num_output_channels = output_channels;
+ drv->bytes_per_input_frame = (drv->bits_per_channel * drv->num_input_channels) / 8;
+ drv->bytes_per_output_frame = (drv->bits_per_channel * drv->num_output_channels) / 8;
+ drv->bytes_per_jack_output_frame = sizeof(sample_t) * drv->num_output_channels;
+ drv->bytes_per_jack_input_frame = sizeof(sample_t) * drv->num_input_channels;
+
+ if(drv->num_output_channels > 0)
+ {
+ drv->pPlayPtr = jack_ringbuffer_create(drv->num_output_channels *
+ drv->bytes_per_jack_output_frame *
+ DEFAULT_RB_SIZE);
+ }
+
+ if(drv->num_input_channels > 0)
+ {
+ drv->pRecPtr = jack_ringbuffer_create(drv->num_input_channels *
+ drv->bytes_per_jack_input_frame *
+ DEFAULT_RB_SIZE);
+ }
+
+ DEBUG("bytes_per_output_frame == %ld\n", drv->bytes_per_output_frame);
+ DEBUG("bytes_per_input_frame == %ld\n", drv->bytes_per_input_frame);
+ DEBUG("bytes_per_jack_output_frame == %ld\n",
+ drv->bytes_per_jack_output_frame);
+ DEBUG("bytes_per_jack_input_frame == %ld\n",
+ drv->bytes_per_jack_input_frame);
+
+ /* go and open up the device */
+ retval = JACK_OpenDevice(drv);
+ if(retval != ERR_SUCCESS)
+ {
+ TRACE("error opening jack device\n");
+ releaseDriver(drv);
+ pthread_mutex_unlock(&device_mutex);
+ return retval;
+ }
+ else
+ {
+ TRACE("succeeded opening jack device\n");
+ }
+
+ /* setup SRC objects just in case they'll be needed but only if requested */
+ if(do_sample_rate_conversion)
+ {
+ int error;
+ if(drv->num_output_channels > 0)
+ {
+ drv->output_src = src_new(preferred_src_converter, drv->num_output_channels, &error);
+ if(error != 0)
+ {
+ src_delete(drv->output_src);
+ drv->output_src = 0;
+ ERR("Could not created SRC object for output stream %d: %s\n",
+ error, src_strerror(error));
+ }
+ }
+ if(drv->num_input_channels > 0)
+ {
+ drv->input_src = src_new(preferred_src_converter, drv->num_input_channels, &error);
+ if(error != 0)
+ {
+ src_delete(drv->input_src);
+ drv->input_src = 0;
+ ERR("Could not created SRC object for input stream %d: %s\n",
+ error, src_strerror(error));
+ }
+ }
+ }
+ else if((long) (*rate) != drv->jack_sample_rate)
+ {
+ TRACE("rate of %ld doesn't match jack sample rate of %ld, returning error\n",
+ *rate, drv->jack_sample_rate);
+ *rate = drv->jack_sample_rate;
+#if JACK_CLOSE_HACK
+ JACK_CloseDevice(drv, TRUE);
+#else
+ JACK_CloseDevice(drv);
+#endif
+ releaseDriver(drv);
+ pthread_mutex_unlock(&device_mutex);
+ return ERR_RATE_MISMATCH;
+ }
+
+ drv->allocated = TRUE; /* record that we opened this device */
+
+ DEBUG("sizeof(sample_t) == %d\n", sizeof(sample_t));
+
+ int periodSize = jack_get_buffer_size(drv->client);
+ int periods = 0;
+ /* FIXME: maybe we should keep different latency values for input vs output? */
+ if(drv->num_output_channels > 0)
+ {
+ periods = jack_port_get_total_latency(drv->client,
+ drv->output_port[0]) / periodSize;
+ drv->latencyMS = periodSize * periods * 1000 / (drv->jack_sample_rate *
+ (drv->bits_per_channel / 8 *
+ drv->num_output_channels));
+ }
+ else if(drv->num_input_channels > 0)
+ {
+ periods = jack_port_get_total_latency(drv->client,
+ drv->input_port[0]) / periodSize;
+ drv->latencyMS =
+ periodSize * periods * 1000 / (drv->jack_sample_rate *
+ (drv->bits_per_channel / 8 *
+ drv->num_input_channels));
+ }
+
+ TRACE("drv->latencyMS == %ldms\n", drv->latencyMS);
+
+ *deviceID = drv->deviceID; /* set the deviceID for the caller */
+ releaseDriver(drv);
+ pthread_mutex_unlock(&device_mutex);
+ return ERR_SUCCESS; /* success */
+}
+
+/* Close the jack device */
+//FIXME: add error handling in here at some point...
+/* NOTE: return 0 for success, non-zero for failure */
+int
+JACK_Close(int deviceID)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+
+ TRACE("deviceID(%d)\n", deviceID);
+
+#if JACK_CLOSE_HACK
+ JACK_CloseDevice(drv, TRUE);
+#else
+ JACK_CloseDevice(drv);
+#endif
+
+ JACK_ResetFromDriver(drv); /* reset this device to a normal starting state */
+
+ pthread_mutex_lock(&device_mutex);
+
+ /* free buffer memory */
+ drv->callback_buffer1_size = 0;
+ if(drv->callback_buffer1) free(drv->callback_buffer1);
+ drv->callback_buffer1 = 0;
+
+ drv->callback_buffer2_size = 0;
+ if(drv->callback_buffer2) free(drv->callback_buffer2);
+ drv->callback_buffer2 = 0;
+
+ drv->rw_buffer1_size = 0;
+ if(drv->rw_buffer1) free(drv->rw_buffer1);
+ drv->rw_buffer1 = 0;
+
+ if(drv->pPlayPtr) jack_ringbuffer_free(drv->pPlayPtr);
+ drv->pPlayPtr = 0;
+
+ if(drv->pRecPtr) jack_ringbuffer_free(drv->pRecPtr);
+ drv->pRecPtr = 0;
+
+ /* free the SRC objects */
+ if(drv->output_src) src_delete(drv->output_src);
+ drv->output_src = 0;
+
+ if(drv->input_src) src_delete(drv->input_src);
+ drv->input_src = 0;
+
+ drv->allocated = FALSE; /* release this device */
+
+ pthread_mutex_unlock(&device_mutex);
+
+ releaseDriver(drv);
+
+ return 0;
+}
+
+/* If we haven't already taken in the max allowed data then create a wave header */
+/* to package the audio data and attach the wave header to the end of the */
+/* linked list of wave headers */
+/* These wave headers will be peeled off as they are played by the callback routine */
+/* Return value is the number of bytes written */
+/* NOTE: this function takes the length of data to be written bytes */
+long
+JACK_Write(int deviceID, unsigned char *data, unsigned long bytes)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+
+ long frames_free, frames;
+
+ TIMER("start\n");
+
+ TRACE("deviceID(%d), bytes == %ld\n", deviceID, bytes);
+
+ /* check and see that we have enough space for this audio */
+ frames_free =
+ jack_ringbuffer_write_space(drv->pPlayPtr) /
+ drv->bytes_per_jack_output_frame;
+ frames = bytes / drv->bytes_per_output_frame;
+ TRACE("frames free == %ld, bytes = %lu\n", frames_free, bytes);
+
+ TRACE("state = '%s'\n", DEBUGSTATE(drv->state));
+ /* if we are currently STOPPED we should start playing now...
+ do this before the check for bytes == 0 since some clients like
+ to write 0 bytes the first time out */
+ if(drv->state == STOPPED)
+ {
+ TRACE("currently STOPPED, transitioning to PLAYING\n");
+ drv->state = PLAYING;
+ }
+
+ /* handle the case where the user calls this routine with 0 bytes */
+ if(bytes == 0 || frames_free < 1)
+ {
+ TRACE("no room left\n");
+ TIMER("finish (nothing to do, buffer is full)\n");
+ releaseDriver(drv);
+ return 0; /* indicate that we couldn't write any bytes */
+ }
+
+ frames = min(frames, frames_free);
+ long jack_bytes = frames * drv->bytes_per_jack_output_frame;
+ if(!ensure_buffer_size(&drv->rw_buffer1, &drv->rw_buffer1_size, jack_bytes))
+ {
+ ERR("couldn't allocate enough space for the buffer\n");
+ releaseDriver(drv);
+ return 0;
+ }
+ /* adjust bytes to be how many client bytes we're actually writing */
+ bytes = frames * drv->bytes_per_output_frame;
+
+ /* convert from client samples to jack samples
+ we have to tell it how many samples there are, which is frames * channels */
+ switch (drv->bits_per_channel)
+ {
+ case 8:
+ sample_move_char_float((sample_t *) drv->rw_buffer1, (unsigned char *) data,
+ frames * drv->num_output_channels);
+ break;
+ case 16:
+ sample_move_short_float((sample_t *) drv->rw_buffer1, (short *) data,
+ frames * drv->num_output_channels);
+ break;
+ }
+
+ DEBUG("ringbuffer read space = %d, write space = %d\n",
+ jack_ringbuffer_read_space(drv->pPlayPtr),
+ jack_ringbuffer_write_space(drv->pPlayPtr));
+
+ jack_ringbuffer_write(drv->pPlayPtr, drv->rw_buffer1, jack_bytes);
+ DEBUG("wrote %lu bytes, %lu jack_bytes\n", bytes, jack_bytes);
+
+ DEBUG("ringbuffer read space = %d, write space = %d\n",
+ jack_ringbuffer_read_space(drv->pPlayPtr),
+ jack_ringbuffer_write_space(drv->pPlayPtr));
+
+ drv->client_bytes += bytes; /* update client_bytes */
+
+ TIMER("finish\n");
+
+ DEBUG("returning bytes written of %ld\n", bytes);
+
+ releaseDriver(drv);
+ return bytes; /* return the number of bytes we wrote out */
+}
+
+long
+JACK_Read(int deviceID, unsigned char *data, unsigned long bytes)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+
+ long frames_available, frames;
+
+ TIMER("start\n");
+
+ TRACE("deviceID(%d), bytes == %ld\n", deviceID, bytes);
+
+ /* find out if there's any room to write this data */
+ frames_available =
+ jack_ringbuffer_read_space(drv->pRecPtr) /
+ drv->bytes_per_jack_input_frame;
+ frames = bytes / drv->bytes_per_input_frame;
+ DEBUG("frames available = %ld, bytes = %lu\n", frames_available, bytes);
+
+ TRACE("state = '%s'\n", DEBUGSTATE(drv->state));
+ /* if we are currently STOPPED we should start recording now... */
+ if(drv->state == STOPPED)
+ {
+ TRACE("currently STOPPED, transitioning to PLAYING\n");
+ drv->state = PLAYING;
+ }
+
+ /* handle the case where the user calls this routine with 0 bytes */
+ if(bytes == 0 || frames_available < 1)
+ {
+ TRACE("no bytes in buffer\n");
+
+ TIMER("finish (nothing to do)\n");
+ releaseDriver(drv);
+ return 0;
+ }
+
+ frames = min(frames, frames_available);
+ long jack_bytes = frames * drv->bytes_per_jack_input_frame;
+ if(!ensure_buffer_size(&drv->rw_buffer1, &drv->rw_buffer1_size, jack_bytes))
+ {
+ ERR("couldn't allocate enough space for the buffer\n");
+ releaseDriver(drv);
+ return 0;
+ }
+
+ DEBUG("ringbuffer read space = %d, write space = %d\n",
+ jack_ringbuffer_read_space(drv->pRecPtr),
+ jack_ringbuffer_write_space(drv->pRecPtr));
+
+ jack_ringbuffer_read(drv->pRecPtr, drv->rw_buffer1,
+ frames * drv->bytes_per_jack_input_frame);
+
+ DEBUG("ringbuffer read space = %d, write space = %d\n",
+ jack_ringbuffer_read_space(drv->pRecPtr),
+ jack_ringbuffer_write_space(drv->pRecPtr));
+
+ unsigned int i;
+ for(i = 0; i < drv->num_output_channels; i++)
+ {
+ /* apply volume to the floating value */
+ if(drv->volumeEffectType == dbAttenuation)
+ {
+ /* assume the volume setting is dB of attenuation, a volume of 0 */
+ /* is 0dB attenuation */
+ float volume = powf(10.0, -((float) drv->volume[i]) / 20.0);
+ float_volume_effect((sample_t *) drv->rw_buffer1 + i,
+ frames, volume, drv->num_output_channels);
+ } else
+ {
+ float_volume_effect((sample_t *) drv->rw_buffer1 + i, frames,
+ ((float) drv->volume[i] / 100.0),
+ drv->num_output_channels);
+ }
+ }
+
+ /* convert from jack samples to client samples
+ we have to tell it how many samples there are, which is frames * channels */
+ switch (drv->bits_per_channel)
+ {
+ case 8:
+ sample_move_float_char((unsigned char *) data, (sample_t *) drv->rw_buffer1,
+ frames * drv->num_input_channels);
+ break;
+ case 16:
+ sample_move_float_short((short *) data, (sample_t *) drv->rw_buffer1,
+ frames * drv->num_input_channels);
+ break;
+ }
+
+ TIMER("finish\n");
+
+ long read_bytes = frames * drv->bytes_per_input_frame;
+
+ DEBUG("returning bytes read of %ld\n", bytes);
+
+ releaseDriver(drv);
+ return read_bytes;
+}
+
+/* return ERR_SUCCESS for success */
+static int
+JACK_SetVolumeForChannelFromDriver(jack_driver_t * drv,
+ unsigned int channel, unsigned int volume)
+{
+ /* TODO?: maybe we should have different volume levels for input & output */
+ /* ensure that we have the channel we are setting volume for */
+ if(channel > (drv->num_output_channels - 1))
+ return 1;
+
+ if(volume > 100)
+ volume = 100; /* check for values in excess of max */
+
+ drv->volume[channel] = volume;
+ return ERR_SUCCESS;
+}
+
+/* return ERR_SUCCESS for success */
+int
+JACK_SetVolumeForChannel(int deviceID, unsigned int channel,
+ unsigned int volume)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ int retval = JACK_SetVolumeForChannelFromDriver(drv, channel, volume);
+ releaseDriver(drv);
+ return retval;
+}
+
+/* Set the volume */
+/* return 0 for success */
+/* NOTE: we check for invalid volume values */
+int
+JACK_SetAllVolume(int deviceID, unsigned int volume)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ unsigned int i;
+
+ TRACE("deviceID(%d), setting volume of %d\n", deviceID, volume);
+
+ for(i = 0; i < drv->num_output_channels; i++)
+ {
+ if(JACK_SetVolumeForChannelFromDriver(drv, i, volume) != ERR_SUCCESS)
+ {
+ releaseDriver(drv);
+ return 1;
+ }
+ }
+
+ releaseDriver(drv);
+ return ERR_SUCCESS;
+}
+
+/* Return the current volume in the inputted pointers */
+/* NOTE: we check for null pointers being passed in just in case */
+void
+JACK_GetVolumeForChannel(int deviceID, unsigned int channel,
+ unsigned int *volume)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+
+ /* ensure that we have the channel we are getting volume for */
+ if(channel > (drv->num_output_channels - 1))
+ {
+ ERR("asking for channel index %d but we only have %ld channels\n", channel, drv->num_output_channels);
+ releaseDriver(drv);
+ return;
+ }
+
+ if(volume)
+ *volume = drv->volume[channel];
+
+#if VERBOSE_OUTPUT
+ if(volume)
+ {
+ TRACE("deviceID(%d), returning volume of %d for channel %d\n",
+ deviceID, *volume, channel);
+ }
+ else
+ {
+ TRACE("volume is null, can't dereference it\n");
+ }
+#endif
+
+ releaseDriver(drv);
+}
+
+
+/* linear means 0 volume is silence, 100 is full volume */
+/* dbAttenuation means 0 volume is 0dB attenuation */
+/* Bio2jack defaults to linear */
+enum JACK_VOLUME_TYPE
+JACK_SetVolumeEffectType(int deviceID, enum JACK_VOLUME_TYPE type)
+{
+ enum JACK_VOLUME_TYPE retval;
+ jack_driver_t *drv = getDriver(deviceID);
+
+ TRACE("setting type of '%s'\n",
+ (type == dbAttenuation ? "dbAttenuation" : "linear"));
+
+ retval = drv->volumeEffectType;
+ drv->volumeEffectType = type;
+
+ releaseDriver(drv);
+ return retval;
+}
+
+
+/* Controls the state of the playback(playing, paused, ...) */
+int
+JACK_SetState(int deviceID, enum status_enum state)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+
+ switch (state)
+ {
+ case PAUSED:
+ drv->state = PAUSED;
+ break;
+ case PLAYING:
+ drv->state = PLAYING;
+ break;
+ case STOPPED:
+ drv->state = STOPPED;
+ break;
+ default:
+ TRACE("unknown state of %d\n", state);
+ }
+
+ TRACE("%s\n", DEBUGSTATE(drv->state));
+
+ releaseDriver(drv);
+ return 0;
+}
+
+/* Retrieve the current state of the device */
+enum status_enum
+JACK_GetState(int deviceID)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ enum status_enum return_val;
+
+ return_val = drv->state;
+ releaseDriver(drv);
+
+ TRACE("deviceID(%d), returning current state of %s\n", deviceID,
+ DEBUGSTATE(return_val));
+ return return_val;
+}
+
+/* Retrieve the number of bytes per second we are outputting */
+unsigned long
+JACK_GetOutputBytesPerSecondFromDriver(jack_driver_t * drv)
+{
+ unsigned long return_val;
+
+ return_val = drv->bytes_per_output_frame * drv->client_sample_rate;
+
+#if VERBOSE_OUTPUT
+ TRACE("deviceID(%d), return_val = %ld\n", drv->deviceID, return_val);
+#endif
+
+ return return_val;
+}
+
+/* Retrieve the number of bytes per second we are outputting */
+unsigned long
+JACK_GetOutputBytesPerSecond(int deviceID)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ unsigned long return_val;
+
+ return_val = JACK_GetOutputBytesPerSecondFromDriver(drv);
+ releaseDriver(drv);
+
+ return return_val;
+}
+
+/* Retrieve the number of input bytes(from jack) per second we are outputting
+ to the user of bio2jack */
+static long
+JACK_GetInputBytesPerSecondFromDriver(jack_driver_t * drv)
+{
+ long return_val;
+
+ return_val = drv->bytes_per_input_frame * drv->client_sample_rate;
+#if VERBOSE_OUTPUT
+ TRACE("drv->deviceID(%d), return_val = %ld\n", drv->deviceID, return_val);
+#endif
+
+ return return_val;
+}
+
+/* Retrieve the number of input bytes(from jack) per second we are outputting
+ to the user of bio2jack */
+unsigned long
+JACK_GetInputBytesPerSecond(int deviceID)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ long return_val = JACK_GetInputBytesPerSecondFromDriver(drv);
+ releaseDriver(drv);
+
+#if VERBOSE_OUTPUT
+ TRACE("deviceID(%d), return_val = %ld\n", deviceID, return_val);
+#endif
+
+ return return_val;
+}
+
+/* Return the number of bytes we have buffered thus far for output */
+/* NOTE: convert from output bytes to input bytes in here */
+static long
+JACK_GetBytesStoredFromDriver(jack_driver_t * drv)
+{
+ if(drv->pPlayPtr == 0 || drv->bytes_per_jack_output_frame == 0)
+ return 0;
+
+ /* leave at least one frame in the buffer at all times to prevent underruns */
+ long return_val =
+ jack_ringbuffer_read_space(drv->pPlayPtr) - drv->jack_buffer_size;
+ if(return_val <= 0)
+ {
+ return_val = 0;
+ } else
+ {
+ /* adjust from jack bytes to client bytes */
+ return_val =
+ return_val / drv->bytes_per_jack_output_frame *
+ drv->bytes_per_output_frame;
+ }
+
+ return return_val;
+}
+
+/* An approximation of how many bytes we have to send out to jack */
+/* that is computed as if we were sending jack a continuous stream of */
+/* bytes rather than chunks during discrete callbacks. */
+/* Return the number of bytes we have buffered thus far for output */
+/* NOTE: convert from output bytes to input bytes in here */
+unsigned long
+JACK_GetBytesStored(int deviceID)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ long retval = JACK_GetBytesStoredFromDriver(drv);
+ releaseDriver(drv);
+ TRACE("deviceID(%d), retval = %ld\n", deviceID, retval);
+ return retval;
+}
+
+static unsigned long
+JACK_GetBytesFreeSpaceFromDriver(jack_driver_t * drv)
+{
+ if(drv->pPlayPtr == 0 || drv->bytes_per_jack_output_frame == 0)
+ return 0;
+
+ /* leave at least one frame in the buffer at all times to prevent underruns */
+ long return_val = jack_ringbuffer_write_space(drv->pPlayPtr) - drv->jack_buffer_size;
+ if(return_val <= 0)
+ {
+ return_val = 0;
+ } else
+ {
+ /* adjust from jack bytes to client bytes */
+ return_val =
+ return_val / drv->bytes_per_jack_output_frame *
+ drv->bytes_per_output_frame;
+ }
+
+ return return_val;
+}
+
+/* Return the number of bytes we can write to the device */
+unsigned long
+JACK_GetBytesFreeSpace(int deviceID)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ unsigned long return_val;
+
+ return_val = JACK_GetBytesFreeSpaceFromDriver(drv);
+ releaseDriver(drv);
+
+ TRACE("deviceID(%d), retval == %ld\n", deviceID, return_val);
+
+ return return_val;
+}
+
+/* bytes of space used in the input buffer */
+unsigned long
+JACK_GetBytesUsedSpace(int deviceID)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ long return_val;
+
+ if(drv->pRecPtr == 0 || drv->bytes_per_jack_input_frame == 0)
+ {
+ return_val = 0;
+ } else
+ {
+ /* adjust from jack bytes to client bytes */
+ return_val =
+ jack_ringbuffer_read_space(drv->pRecPtr) /
+ drv->bytes_per_jack_input_frame * drv->bytes_per_input_frame;
+ }
+
+ releaseDriver(drv);
+
+ if(return_val < 0)
+ return_val = 0;
+ TRACE("deviceID(%d), retval == %ld\n", deviceID, return_val);
+
+ return return_val;
+}
+
+/* Get the current position of the driver, either in bytes or */
+/* in milliseconds */
+/* NOTE: this is position relative to input bytes, output bytes may differ greatly due to
+ input vs. output channel count */
+static long
+JACK_GetPositionFromDriver(jack_driver_t * drv, enum pos_enum position,
+ int type)
+{
+ long return_val = 0;
+ struct timeval now;
+ long elapsedMS;
+ double sec2msFactor = 1000;
+
+ char *type_str = "UNKNOWN type";
+
+ /* if we are reset we should return a position of 0 */
+ if(drv->state == RESET)
+ {
+ TRACE("we are currently RESET, returning 0\n");
+ return 0;
+ }
+
+ if(type == WRITTEN)
+ {
+ type_str = "WRITTEN";
+ return_val = drv->client_bytes;
+ } else if(type == WRITTEN_TO_JACK)
+ {
+ type_str = "WRITTEN_TO_JACK";
+ return_val = drv->written_client_bytes;
+ } else if(type == PLAYED) /* account for the elapsed time for the played_bytes */
+ {
+ type_str = "PLAYED";
+ return_val = drv->played_client_bytes;
+ gettimeofday(&now, 0);
+
+ elapsedMS = TimeValDifference(&drv->previousTime, &now); /* find the elapsed milliseconds since last JACK_Callback() */
+
+ TRACE("elapsedMS since last callback is '%ld'\n", elapsedMS);
+
+ /* account for the bytes played since the last JACK_Callback() */
+ /* NOTE: [Xms * (Bytes/Sec)] * (1 sec/1,000ms) */
+ /* NOTE: don't do any compensation if no data has been sent to jack since the last callback */
+ /* as this would result a bogus computed result */
+ if(drv->clientBytesInJack != 0)
+ {
+ return_val += (long) ((double) elapsedMS *
+ ((double) JACK_GetOutputBytesPerSecondFromDriver(drv) /
+ sec2msFactor));
+ } else
+ {
+ TRACE("clientBytesInJack == 0\n");
+ }
+ }
+
+ /* add on the offset */
+ return_val += drv->position_byte_offset;
+
+ /* convert byte position to milliseconds value if necessary */
+ if(position == MILLISECONDS)
+ {
+ if(JACK_GetOutputBytesPerSecondFromDriver(drv) != 0)
+ {
+ return_val = (long) (((double) return_val /
+ (double) JACK_GetOutputBytesPerSecondFromDriver(drv)) *
+ (double) sec2msFactor);
+ } else
+ {
+ return_val = 0;
+ }
+ }
+
+ TRACE("drv->deviceID(%d), type(%s), return_val = %ld\n", drv->deviceID,
+ type_str, return_val);
+
+ return return_val;
+}
+
+/* Get the current position of the driver, either in bytes or */
+/* in milliseconds */
+/* NOTE: this is position relative to input bytes, output bytes may differ greatly due to input vs. output channel count */
+long
+JACK_GetPosition(int deviceID, enum pos_enum position, int type)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ long retval = JACK_GetPositionFromDriver(drv, position, type);
+ releaseDriver(drv);
+ TRACE("retval == %ld\n", retval);
+ return retval;
+}
+
+// Set position always applies to written bytes
+// NOTE: we must apply this instantly because if we pass this as a message
+// to the callback we risk the user sending us audio data in the mean time
+// and there is no need to send this as a message, we don't modify any
+// internal variables
+void
+JACK_SetPositionFromDriver(jack_driver_t * drv, enum pos_enum position,
+ long value)
+{
+ double sec2msFactor = 1000;
+#if TRACE_ENABLE
+ long input_value = value;
+#endif
+
+ /* convert the incoming value from milliseconds into bytes */
+ if(position == MILLISECONDS)
+ {
+ value = (long) (((double) value *
+ (double) JACK_GetOutputBytesPerSecondFromDriver(drv)) /
+ sec2msFactor);
+ }
+
+ /* ensure that if the user asks for the position */
+ /* they will at this instant get the correct position */
+ drv->position_byte_offset = value - drv->client_bytes;
+
+ TRACE("deviceID(%d) input_value of %ld %s, new value of %ld, setting position_byte_offset to %ld\n",
+ drv->deviceID, input_value, (position == MILLISECONDS) ? "ms" : "bytes",
+ value, drv->position_byte_offset);
+}
+
+// Set position always applies to written bytes
+// NOTE: we must apply this instantly because if we pass this as a message
+// to the callback we risk the user sending us audio data in the mean time
+// and there is no need to send this as a message, we don't modify any
+// internal variables
+void
+JACK_SetPosition(int deviceID, enum pos_enum position, long value)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ JACK_SetPositionFromDriver(drv, position, value);
+ releaseDriver(drv);
+
+ TRACE("deviceID(%d) value of %ld\n", drv->deviceID, value);
+}
+
+/* Return the number of bytes per frame, or (output_channels * bits_per_channel) / 8 */
+unsigned long
+JACK_GetBytesPerOutputFrame(int deviceID)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ long return_val = drv->bytes_per_output_frame;
+ releaseDriver(drv);
+ TRACE("deviceID(%d), return_val = %ld\n", deviceID, return_val);
+ return return_val;
+}
+
+/* Return the number of bytes per frame, or (input_channels * bits_per_channel) / 8 */
+unsigned long
+JACK_GetBytesPerInputFrame(int deviceID)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ long return_val = drv->bytes_per_input_frame;
+ releaseDriver(drv);
+ TRACE("deviceID(%d), return_val = %ld\n", deviceID, return_val);
+ return return_val;
+}
+
+/* Return the number of output bytes we buffer max */
+long
+JACK_GetMaxOutputBufferedBytes(int deviceID)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ long return_val;
+
+ if(drv->pPlayPtr == 0 || drv->bytes_per_jack_output_frame == 0) return_val = 0;
+
+ /* adjust from jack bytes to client bytes */
+ return_val =
+ (jack_ringbuffer_read_space(drv->pPlayPtr) +
+ jack_ringbuffer_write_space(drv->pPlayPtr)) /
+ drv->bytes_per_jack_output_frame * drv->bytes_per_output_frame;
+
+ releaseDriver(drv);
+
+ TRACE("return_val = %ld\n", return_val);
+
+ return return_val;
+}
+
+/* Return the number of input bytes we buffer max */
+long
+JACK_GetMaxInputBufferedBytes(int deviceID)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ long return_val;
+
+ if(drv->pRecPtr == 0 || drv->bytes_per_jack_input_frame == 0) return_val = 0;
+
+ /* adjust from jack bytes to client bytes */
+ return_val =
+ (jack_ringbuffer_read_space(drv->pRecPtr) +
+ jack_ringbuffer_write_space(drv->pRecPtr)) /
+ drv->bytes_per_jack_input_frame * drv->bytes_per_input_frame;
+
+ releaseDriver(drv);
+
+ TRACE("return_val = %ld\n", return_val);
+
+ return return_val;
+}
+
+/* Get the number of output channels */
+int
+JACK_GetNumOutputChannels(int deviceID)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ int return_val = drv->num_output_channels;
+ releaseDriver(drv);
+ TRACE("getting num_output_channels of %d\n", return_val);
+ return return_val;
+}
+
+/* Get the number of input channels */
+int
+JACK_GetNumInputChannels(int deviceID)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ int return_val = drv->num_input_channels;
+ releaseDriver(drv);
+ TRACE("getting num_input_channels of %d\n", return_val);
+ return return_val;
+}
+
+/* Get the number of samples per second, the sample rate */
+long
+JACK_GetSampleRate(int deviceID)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ int return_val = drv->client_sample_rate;
+ releaseDriver(drv);
+ TRACE("getting sample_rate of %d\n", return_val);
+ return return_val;
+}
+
+void
+JACK_CleanupDriver(jack_driver_t * drv)
+{
+ TRACE("\n");
+ /* things that need to be reset both in JACK_Init & JACK_CloseDevice */
+ drv->client = 0;
+ drv->in_use = FALSE;
+ drv->state = CLOSED;
+ drv->jack_sample_rate = 0;
+ drv->output_sample_rate_ratio = 1.0;
+ drv->input_sample_rate_ratio = 1.0;
+ drv->jackd_died = FALSE;
+ gettimeofday(&drv->previousTime, 0); /* record the current time */
+ gettimeofday(&drv->last_reconnect_attempt, 0);
+}
+
+/* Initialize the jack porting library to a clean state */
+void
+JACK_Init(void)
+{
+ jack_driver_t *drv;
+ int x, y;
+
+ if(init_done)
+ {
+ TRACE("not initing twice\n");
+ return;
+ }
+
+ init_done = 1;
+
+ TRACE("\n");
+
+ pthread_mutex_lock(&device_mutex);
+
+ /* initialize the device structures */
+ for(x = 0; x < MAX_OUTDEVICES; x++)
+ {
+ drv = &outDev[x];
+
+ pthread_mutex_init(&drv->mutex, NULL);
+
+ getDriver(x);
+
+ memset(drv, 0, sizeof(jack_driver_t));
+ drv->volumeEffectType = linear;
+ drv->deviceID = x;
+
+ for(y = 0; y < MAX_OUTPUT_PORTS; y++) /* make all volume 25% as a default */
+ drv->volume[y] = 25;
+
+ JACK_CleanupDriver(drv);
+ JACK_ResetFromDriver(drv);
+ releaseDriver(drv);
+ }
+
+ client_name = 0; /* initialize the name to null */
+ do_sample_rate_conversion = TRUE; /* default to on */
+ JACK_SetClientName("bio2jack");
+
+ pthread_mutex_unlock(&device_mutex);
+
+ TRACE("finished\n");
+}
+
+/* Get the latency, in frames, of jack */
+long
+JACK_GetJackOutputLatency(int deviceID)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ long return_val = 0;
+
+ if(drv->client && drv->num_output_channels)
+ return_val = jack_port_get_total_latency(drv->client, drv->output_port[0]);
+
+ TRACE("got latency of %ld frames\n", return_val);
+
+ releaseDriver(drv);
+ return return_val;
+}
+
+/* Get the latency, in frames, of jack */
+long
+JACK_GetJackInputLatency(int deviceID)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ long return_val = 0;
+
+ if(drv->client && drv->num_input_channels)
+ return_val = jack_port_get_total_latency(drv->client, drv->input_port[0]);
+
+ TRACE("got latency of %ld frames\n", return_val);
+
+ releaseDriver(drv);
+ return return_val;
+}
+
+/* bytes that jack requests during each callback */
+unsigned long
+JACK_GetJackBufferedBytes(int deviceID)
+{
+ jack_driver_t *drv = getDriver(deviceID);
+ long return_val;
+
+ if(drv->bytes_per_jack_output_frame == 0)
+ {
+ return_val = 0;
+ } else
+ {
+ /* adjust from jack bytes to client bytes */
+ return_val =
+ drv->jack_buffer_size / drv->bytes_per_jack_output_frame *
+ drv->bytes_per_output_frame * drv->num_output_channels;
+ }
+
+ releaseDriver(drv);
+ return return_val;
+}
+
+/* value = TRUE, perform sample rate conversion */
+void
+JACK_DoSampleRateConversion(bool value)
+{
+ do_sample_rate_conversion = value;
+}
+
+/* FIXME: put the filename of the resample library header file with the decoders in here */
+/* consider mapping them in the bio2jack.h header file since its useless to the user unless */
+/* they can figure out wtf the settings on */
+void
+JACK_SetSampleRateConversionFunction(int converter)
+{
+ preferred_src_converter = converter;
+}
+
+/* set the client name that will be reported to jack when we open a */
+/* connection via JACK_OpenDevice() */
+void
+JACK_SetClientName(char *name)
+{
+ if(name)
+ {
+ if(client_name) free(client_name);
+
+ /* jack_client_name_size() is the max length of a client name, including
+ the terminating null. */
+ int size = strlen(name) + 1; /* take into account the terminating null */
+ if(size > jack_client_name_size())
+ size = jack_client_name_size();
+
+ client_name = malloc(size);
+ if(client_name)
+ snprintf(client_name, size, "%s", name);
+ else
+ ERR("unable to allocate %d bytes for client_name\n", size);
+ }
+}
+
+void
+JACK_SetPortConnectionMode(enum JACK_PORT_CONNECTION_MODE mode)
+{
+ port_connection_mode = mode;
+}
diff --git a/src/plugins/Output/jack/bio2jack.h b/src/plugins/Output/jack/bio2jack.h
new file mode 100644
index 000000000..f81a7c777
--- /dev/null
+++ b/src/plugins/Output/jack/bio2jack.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2003-2004 Chris Morgan <cmorgan@alum.wpi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _H_JACK_OUT_H
+#define _H_JACK_OUT_H
+
+#include <jack/jack.h>
+
+#ifdef __cplusplus
+extern "C" {
+#else
+#define bool long
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define ERR_SUCCESS 0
+#define ERR_OPENING_JACK 1
+#define ERR_RATE_MISMATCH 2
+#define ERR_BYTES_PER_OUTPUT_FRAME_INVALID 3
+#define ERR_BYTES_PER_INPUT_FRAME_INVALID 4
+#define ERR_TOO_MANY_OUTPUT_CHANNELS 5
+#define ERR_PORT_NAME_OUTPUT_CHANNEL_MISMATCH 6
+#define ERR_PORT_NOT_FOUND 7
+#define ERR_TOO_MANY_INPUT_CHANNELS 8
+#define ERR_PORT_NAME_INPUT_CHANNEL_MISMATCH 9
+
+enum status_enum { PLAYING, PAUSED, STOPPED, CLOSED, RESET };
+enum pos_enum { BYTES, MILLISECONDS };
+
+#define PLAYED 1 /* played out of the speakers(estimated value but should be close */
+#define WRITTEN_TO_JACK 2 /* amount written out to jack */
+#define WRITTEN 3 /* amount written to the bio2jack device */
+
+/**********************/
+/* External functions */
+void JACK_Init(void); /* call this before any other bio2jack calls */
+void JACK_DoSampleRateConversion(bool value); /* whether the next device that's Open()d should do
+ sample rate conversion if necessary */
+void JACK_SetSampleRateConversionFunction(int converter); /* which SRC converter function should be used
+ for the next Open()d device */
+int JACK_Open(int *deviceID, unsigned int bits_per_sample, unsigned long *rate, int channels); /* Note: defaults to 0 input channels
+ if you need input (record) use OpenEx
+ instead */
+int JACK_OpenEx(int *deviceID, unsigned int bits_per_channel,
+ unsigned long *rate,
+ unsigned int input_channels, unsigned int output_channels,
+ const char **jack_port_name, unsigned int jack_port_name_count,
+ unsigned long jack_port_flags);
+int JACK_Close(int deviceID); /* return 0 for success */
+void JACK_Reset(int deviceID); /* free all buffered data and reset several values in the device */
+long JACK_Write(int deviceID, unsigned char *data, unsigned long bytes); /* returns the number of bytes written */
+long JACK_Read(int deviceID, unsigned char *data, unsigned long bytes); /* returns the number of bytes read */
+
+/* state setting values */
+/* set/get the written/played/buffered value based on a byte or millisecond input value */
+long JACK_GetPosition(int deviceID, enum pos_enum position, int type);
+void JACK_SetPosition(int deviceID, enum pos_enum position, long value);
+
+long JACK_GetJackLatency(int deviceID); /* deprectated, you probably want JACK_GetJackOutputLatency */
+long JACK_GetJackOutputLatency(int deviceID); /* return the output latency in frames */
+long JACK_GetJackInputLatency(int deviceID); /* return the input latency in frames */
+
+int JACK_SetState(int deviceID, enum status_enum state); /* playing, paused, stopped */
+enum status_enum JACK_GetState(int deviceID);
+
+long JACK_GetMaxOutputBufferedBytes(int deviceID);
+long JACK_GetMaxInputBufferedBytes(int deviceID);
+
+/* bytes that jack requests during each callback */
+unsigned long JACK_GetJackBufferedBytes(int deviceID);
+
+/* Properties of the jack driver */
+
+/* linear means 0 volume is silence, 100 is full volume */
+/* dbAttenuation means 0 volume is 0dB attenuation */
+/* Bio2jack defaults to linear */
+/* Note: volume controls only effect output channels for now */
+enum JACK_VOLUME_TYPE { linear, dbAttenuation };
+enum JACK_VOLUME_TYPE JACK_SetVolumeEffectType(int deviceID,
+ enum JACK_VOLUME_TYPE type);
+
+int JACK_SetAllVolume(int deviceID, unsigned int volume); /* returns 0 on success */
+int JACK_SetVolumeForChannel(int deviceID, unsigned int channel, unsigned int volume);
+void JACK_GetVolumeForChannel(int deviceID, unsigned int channel, unsigned int *volume);
+
+
+unsigned long JACK_GetOutputBytesPerSecond(int deviceID); /* bytes_per_output_frame * sample_rate */
+unsigned long JACK_GetInputBytesPerSecond(int deviceID); /* bytes_per_input_frame * sample_rate */
+unsigned long JACK_GetBytesStored(int deviceID); /* bytes currently buffered in the output buffer */
+unsigned long JACK_GetBytesFreeSpace(int deviceID); /* bytes of free space in the output buffer */
+unsigned long JACK_GetBytesUsedSpace(int deviceID); /* bytes of space used in the input buffer */
+unsigned long JACK_GetBytesPerOutputFrame(int deviceID);
+unsigned long JACK_GetBytesPerInputFrame(int deviceID);
+
+/* Note: these will probably be removed in a future release */
+int JACK_GetNumInputChannels(int deviceID);
+int JACK_GetNumOutputChannels(int deviceID);
+
+long JACK_GetSampleRate(int deviceID); /* samples per second */
+
+void JACK_SetClientName(char *name); /* sets the name that bio2jack will use when
+ creating a new jack client. name_%pid%_%deviceID%%counter%
+ will be used
+ NOTE: this defaults to name = bio2jack
+ NOTE: we limit the size of the client name to
+ jack_client_name_size() */
+
+enum JACK_PORT_CONNECTION_MODE
+{
+ CONNECT_ALL, /* connect to all avaliable ports */
+ CONNECT_OUTPUT, /* connect only to the ports we need for output */
+ CONNECT_NONE /* don't connect to any ports */
+};
+
+/* set the mode for port connections */
+/* defaults to CONNECT_ALL */
+void JACK_SetPortConnectionMode(enum JACK_PORT_CONNECTION_MODE mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef JACK_OUT_H */
diff --git a/src/plugins/Output/jack/jack.pro b/src/plugins/Output/jack/jack.pro
new file mode 100644
index 000000000..a943a5b3b
--- /dev/null
+++ b/src/plugins/Output/jack/jack.pro
@@ -0,0 +1,33 @@
+include(../../plugins.pri)
+
+HEADERS += outputjackfactory.h \
+ outputjack.h \
+ bio2jack.h
+
+SOURCES += outputjackfactory.cpp \
+ outputjack.cpp \
+ bio2jack.c
+
+TARGET=$$PLUGINS_PREFIX/Output/jack
+QMAKE_CLEAN =$$PLUGINS_PREFIX/Output/libjack.so
+
+
+INCLUDEPATH += ../../../qmmp
+QMAKE_LIBDIR += ../../../../lib
+CONFIG += release \
+warn_on \
+thread \
+plugin \
+link_pkgconfig
+TEMPLATE = lib
+LIBS += -lqmmp
+PKGCONFIG += jack samplerate
+#TRANSLATIONS = translations/jack_plugin_ru.ts
+#RESOURCES = translations/translations.qrc
+
+isEmpty (LIB_DIR){
+LIB_DIR = /lib
+}
+
+target.path = $$LIB_DIR/qmmp/Output
+INSTALLS += target
diff --git a/src/plugins/Output/jack/outputjack.cpp b/src/plugins/Output/jack/outputjack.cpp
new file mode 100644
index 000000000..c8d3ebe86
--- /dev/null
+++ b/src/plugins/Output/jack/outputjack.cpp
@@ -0,0 +1,208 @@
+#include <QObject>
+#include <QApplication>
+#include <QtGlobal>
+#include <QDir>
+#include <QSettings>
+
+#include "outputjack.h"
+#include "constants.h"
+#include "buffer.h"
+#include "visual.h"
+
+#include <stdio.h>
+#include <string.h>
+
+void OutputJACK::stop()
+{
+ m_userStop = TRUE;
+}
+
+void OutputJACK::status()
+{
+ long ct = (m_totalWritten - latency()) / m_bps;
+
+ if (ct < 0)
+ ct = 0;
+
+ if (ct > m_currentSeconds)
+ {
+ m_currentSeconds = ct;
+ dispatch(m_currentSeconds, m_totalWritten, m_rate,
+ m_frequency, m_precision, m_channels);
+ }
+}
+
+long OutputJACK::written()
+{
+ return m_totalWritten;
+}
+
+void OutputJACK::seek(long pos)
+{
+ recycler()->mutex()->lock ();
+ recycler()->clear();
+ recycler()->mutex()->unlock();
+
+ m_totalWritten = (pos * m_bps);
+ m_currentSeconds = -1;
+}
+
+OutputJACK::OutputJACK(QObject * parent, bool useVolume)
+ : Output(parent), m_inited(FALSE), m_pause(FALSE), m_play(FALSE),
+ m_userStop(FALSE), m_totalWritten(0), m_currentSeconds(-1),
+ m_bps(-1), m_frequency(-1), m_channels(-1), m_precision(-1)
+{
+ JACK_Init();
+}
+
+OutputJACK::~OutputJACK()
+{
+ uninitialize();
+}
+
+void OutputJACK::configure(long freq, int chan, int prec, int brate)
+{
+ qDebug("OutputJACK: configure");
+ m_precision = prec;
+ m_channels = chan;
+ m_frequency = freq;
+ m_bps = freq * chan * (prec / 8);
+ if(JACK_Open(&jack_device, prec, (unsigned long *)&freq, chan))
+ {
+ m_configure = FALSE;
+ return;
+ }
+ else
+ m_configure = TRUE;
+
+ qDebug("OutputJACK: configure end");
+}
+
+void OutputJACK::pause()
+{
+ m_pause = (m_pause) ? FALSE : TRUE;
+ {
+ int state = m_pause ? OutputState::Paused: OutputState::Playing;
+ dispatch(OutputState((OutputState::Type) state));
+ }
+
+}
+
+bool OutputJACK::initialize()
+{
+ m_inited = m_pause = m_play = m_userStop = FALSE;
+ m_currentSeconds = -1;
+ m_totalWritten = 0;
+ if (m_inited)
+ m_inited = TRUE;
+ m_inited = TRUE;
+ m_configure = FALSE;
+ jack_options_t options = JackNullOption;
+ jack_status_t status;
+ jack_client_t *client = jack_client_open ("test_qmmp", options, &status, NULL);
+ if (client == NULL)
+ {
+ qDebug("jack_client_open() failed.");
+ if (status & JackServerFailed)
+ {
+ qDebug("Unable to connect to JACK server.");
+ }
+ return FALSE;
+ }
+ jack_client_close (client);
+ return TRUE;
+}
+
+long OutputJACK::latency()
+{
+ ulong used = 0;
+ return used;
+}
+
+void OutputJACK::run()
+{
+ mutex()->lock ();
+ if (! m_inited)
+ {
+ mutex()->unlock();
+ return;
+ }
+
+ m_play = TRUE;
+ Buffer *b = 0;
+ bool done = FALSE;
+ long m = 0;
+ unsigned long l;
+
+ dispatch(OutputState::Playing);
+
+ mutex()->unlock();
+ while (!done&&m_configure)
+ {
+ mutex()->lock ();
+ recycler()->mutex()->lock ();
+ done = m_userStop;
+
+ while (! done && (recycler()->empty() || m_pause))
+ {
+ mutex()->unlock();
+ recycler()->cond()->wakeOne();
+ recycler()->cond()->wait(recycler()->mutex());
+ mutex()->lock ();
+ done = m_userStop;
+ status();
+ }
+
+ if (! b)
+ {
+ b = recycler()->next();
+ if (b->rate)
+ m_rate = b->rate;
+ }
+
+ recycler()->cond()->wakeOne();
+ recycler()->mutex()->unlock();
+
+ if (b)
+ {
+ l = int(b->nbytes);
+ unsigned char *buf = b->data;
+ m_totalWritten += l;
+ while (l > 0)
+ {
+ m = JACK_Write(jack_device, (unsigned char*)buf, l);
+ if (!m)
+ usleep(2000);
+ usleep(((m/m_channels)*100000)/m_frequency);
+ l-=m;
+ buf+=m;
+ }
+
+ status();
+ dispatchVisual(b, m_totalWritten, m_channels, m_precision);
+ }
+ recycler()->mutex()->lock ();
+ recycler()->done();
+ recycler()->mutex()->unlock();
+ b = 0;
+ mutex()->unlock();
+ }
+ mutex()->lock ();
+ m_play = FALSE;
+ dispatch(OutputState::Stopped);
+ mutex()->unlock();
+}
+
+void OutputJACK::uninitialize()
+{
+ if (!m_inited)
+ return;
+ m_inited = FALSE;
+ m_inited = m_pause = m_play = m_userStop = FALSE;
+ m_currentSeconds = -1;
+ m_totalWritten = 0;
+ if (m_configure)
+ JACK_Close(jack_device);
+ dispatch(OutputState::Stopped);
+}
+
diff --git a/src/plugins/Output/jack/outputjack.h b/src/plugins/Output/jack/outputjack.h
new file mode 100644
index 000000000..e01ced315
--- /dev/null
+++ b/src/plugins/Output/jack/outputjack.h
@@ -0,0 +1,49 @@
+#ifndef OUTPUTJACK_H
+#define OUTPUTJACK_H
+
+class OutputJACK;
+
+#include <output.h>
+#include <QObject>
+extern "C"
+{
+#include <jack/jack.h>
+}
+
+#include "bio2jack.h"
+
+class OutputJACK : public Output
+{
+ Q_OBJECT
+public:
+ OutputJACK(QObject * parent = 0, bool useVolume = TRUE);
+ ~OutputJACK();
+ bool initialize();
+ bool isInitialized() const
+ {
+ return m_inited;
+ }
+ void uninitialize();
+ void configure(long, int, int, int);
+ void stop();
+ void pause();
+ long written();
+ long latency();
+ void seek(long);
+
+private:
+ // thread run function
+ void run();
+ // helper functions
+ void status();
+ QString audio_device;
+ bool m_inited, m_configure, m_pause, m_play, m_userStop;
+ long m_totalWritten, m_currentSeconds, m_bps;
+ int m_rate, m_frequency, m_channels, m_precision, jack_device;
+ bool do_select;
+ int audio_fd;
+};
+
+
+#endif
+
diff --git a/src/plugins/Output/jack/outputjackfactory.cpp b/src/plugins/Output/jack/outputjackfactory.cpp
new file mode 100644
index 000000000..b41ba4487
--- /dev/null
+++ b/src/plugins/Output/jack/outputjackfactory.cpp
@@ -0,0 +1,60 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Zhuravlev Uriy *
+ * stalkerg@gmail.com *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QtGui>
+
+#include "outputjack.h"
+#include "outputjackfactory.h"
+
+
+const OutputProperties OutputJACKFactory::properties() const
+{
+ OutputProperties properties;
+ properties.name = tr("JACK Plugin");
+ properties.hasAbout = TRUE;
+ properties.hasSettings = TRUE;
+ return properties;
+}
+
+Output* OutputJACKFactory::create(QObject* parent, bool volume)
+{
+ return new OutputJACK(parent);
+}
+
+void OutputJACKFactory::showSettings(QWidget*)
+{
+}
+
+void OutputJACKFactory::showAbout(QWidget *parent)
+{
+QMessageBox::about (parent, tr("About Jack Output Plugin"),
+ tr("Qmmp Jack Output Plugin")+"\n"+
+ tr("Writen by: Yuriy Zhuravlev <slalkerg@gmail.com>"));
+}
+
+QTranslator *OutputJACKFactory::createTranslator(QObject *parent)
+{
+ QTranslator *translator = new QTranslator(parent);
+ QString locale = QLocale::system().name();
+ translator->load(QString(":/jack_plugin_") + locale);
+ return translator;
+}
+
+Q_EXPORT_PLUGIN(OutputJACKFactory)
diff --git a/src/plugins/Output/jack/outputjackfactory.h b/src/plugins/Output/jack/outputjackfactory.h
new file mode 100644
index 000000000..cc27990f1
--- /dev/null
+++ b/src/plugins/Output/jack/outputjackfactory.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef OUTPUTJACKFACTORY_H
+#define OUTPUTJACKFACTORY_H
+
+
+#include <QObject>
+#include <QString>
+#include <QIODevice>
+#include <QWidget>
+
+#include <output.h>
+#include <outputfactory.h>
+
+
+class OutputJACKFactory : public QObject,
+ OutputFactory
+{
+Q_OBJECT
+Q_INTERFACES(OutputFactory);
+
+public:
+ const OutputProperties properties() const;
+ Output* create(QObject* parent, bool volume);
+ void showSettings(QWidget* parent);
+ void showAbout(QWidget *parent);
+ QTranslator *createTranslator(QObject *parent);
+
+};
+
+#endif
diff --git a/src/plugins/Output/jack/translations/jack_plugin_ru.qm b/src/plugins/Output/jack/translations/jack_plugin_ru.qm
new file mode 100644
index 000000000..4050034bc
--- /dev/null
+++ b/src/plugins/Output/jack/translations/jack_plugin_ru.qm
Binary files differ
diff --git a/src/plugins/Output/jack/translations/jack_plugin_ru.ts b/src/plugins/Output/jack/translations/jack_plugin_ru.ts
new file mode 100644
index 000000000..6f5057529
--- /dev/null
+++ b/src/plugins/Output/jack/translations/jack_plugin_ru.ts
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS><TS version="1.1" language="ru">
+<context>
+ <name>OutputJACKFactory</name>
+ <message>
+ <location filename="../outputjackfactory.cpp" line="29"/>
+ <source>JACK Plugin</source>
+ <translation>Модуль JACK</translation>
+ </message>
+ <message>
+ <location filename="../outputjackfactory.cpp" line="44"/>
+ <source>About Jack Output Plugin</source>
+ <translation>О модуле вывода Jack</translation>
+ </message>
+ <message>
+ <location filename="../outputjackfactory.cpp" line="45"/>
+ <source>Qmmp Jack Output Plugin</source>
+ <translation>Модуль вывода Jack для Qmmp</translation>
+ </message>
+ <message>
+ <location filename="../outputjackfactory.cpp" line="46"/>
+ <source>Writen by: Yuriy Zhuravlev &lt;slalkerg@gmail.com&gt;</source>
+ <translation>Разработчик: Юрий Журавлёв &lt;slalkerg@gmail.com&gt;</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/plugins/Output/jack/translations/translations.qrc b/src/plugins/Output/jack/translations/translations.qrc
new file mode 100644
index 000000000..af9447328
--- /dev/null
+++ b/src/plugins/Output/jack/translations/translations.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+ <qresource>
+ <file>jack_plugin_ru.qm</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/Output/oss/CMakeLists.txt b/src/plugins/Output/oss/CMakeLists.txt
new file mode 100644
index 000000000..8ab6f8d88
--- /dev/null
+++ b/src/plugins/Output/oss/CMakeLists.txt
@@ -0,0 +1,67 @@
+project(liboss)
+
+cmake_minimum_required(VERSION 2.4.0)
+
+
+INCLUDE(UsePkgConfig)
+INCLUDE(FindQt4)
+
+find_package(Qt4 REQUIRED) # find and setup Qt4 for this project
+include(${QT_USE_FILE})
+
+# qt plugin
+ADD_DEFINITIONS( -Wall )
+ADD_DEFINITIONS(${QT_DEFINITIONS})
+ADD_DEFINITIONS(-DQT_PLUGIN)
+ADD_DEFINITIONS(-DQT_NO_DEBUG)
+ADD_DEFINITIONS(-DQT_SHARED)
+ADD_DEFINITIONS(-DQT_THREAD)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+SET(QT_INCLUDES
+ ${QT_INCLUDES}
+ ${CMAKE_CURRENT_BINARY_DIR}/../../../
+)
+
+# libqmmp
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+link_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+
+
+
+include_directories(${JACK_INCLUDE_DIR} ${JACK_INCLUDE_DIR})
+link_directories(${SAMPLERATE_LINK_DIR} ${SAMPLERATE_LINK_DIR})
+
+ADD_DEFINITIONS(${JACK_CFLAGS})
+ADD_DEFINITIONS(${SAMPLERATE_CFLAGS})
+
+
+SET(liboss_SRCS
+ outputossfactory.cpp
+ outputoss.cpp
+ settingsdialog.cpp
+)
+
+SET(liboss_MOC_HDRS
+ outputossfactory.h
+ outputoss.h
+ settingsdialog.h
+)
+
+#SET(libjack_RCCS translations/translations.qrc)
+
+QT4_ADD_RESOURCES(libjack_RCC_SRCS ${libjack_RCCS})
+
+QT4_WRAP_CPP(liboss_MOC_SRCS ${liboss_MOC_HDRS})
+
+SET(liboss_UIS
+ settingsdialog.ui
+)
+
+QT4_WRAP_UI(liboss_UIS_H ${liboss_UIS})
+
+ADD_LIBRARY(oss SHARED ${liboss_SRCS} ${liboss_MOC_SRCS} ${liboss_UIS_H})
+target_link_libraries(oss ${QT_LIBRARIES} -lqmmp )
+install(TARGETS oss DESTINATION ${LIB_DIR}/qmmp/Output PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ)
+
diff --git a/src/plugins/Output/oss/oss.pro b/src/plugins/Output/oss/oss.pro
new file mode 100644
index 000000000..e401f14b0
--- /dev/null
+++ b/src/plugins/Output/oss/oss.pro
@@ -0,0 +1,36 @@
+include(../../plugins.pri)
+FORMS += settingsdialog.ui
+
+HEADERS += outputossfactory.h \
+ outputoss.h \
+ settingsdialog.h
+
+
+SOURCES += outputossfactory.cpp \
+ outputoss.cpp \
+ settingsdialog.cpp
+
+TARGET=$$PLUGINS_PREFIX/Output/oss
+QMAKE_CLEAN =$$PLUGINS_PREFIX/Output/liboss.so
+
+
+INCLUDEPATH += ../../../qmmp
+QMAKE_LIBDIR += ../../../../lib
+CONFIG += release \
+warn_on \
+thread \
+plugin
+
+TEMPLATE = lib
+LIBS += -lqmmp
+
+#TRANSLATIONS = translations/oss_plugin_ru.ts \
+# translations/oss_plugin_uk_UA.ts \
+# translations/oss_plugin_zh_CN.ts
+#RESOURCES = translations/translations.qrc
+isEmpty (LIB_DIR){
+LIB_DIR = /lib
+}
+
+target.path = $$LIB_DIR/qmmp/Output
+INSTALLS += target
diff --git a/src/plugins/Output/oss/outputoss.cpp b/src/plugins/Output/oss/outputoss.cpp
new file mode 100644
index 000000000..9c52ac777
--- /dev/null
+++ b/src/plugins/Output/oss/outputoss.cpp
@@ -0,0 +1,505 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Uriy Zhuravlev stalkerg@gmail.com *
+ * *
+ * Copyright (c) 2000-2001 Brad Hughes bhughes@trolltech.com *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QApplication>
+
+#include "outputoss.h"
+#include "constants.h"
+#include "buffer.h"
+#include "visual.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <QtGlobal>
+#include <QSettings>
+#include <QDir>
+
+#include <iostream>
+
+//extern Q_EXPORT QApplication* qApp;
+
+
+void OutputOSS::stop()
+{
+ m_userStop = TRUE;
+}
+
+void OutputOSS::status()
+{
+ long ct = (m_totalWritten - latency()) / m_bps;
+
+ if (ct < 0)
+ ct = 0;
+
+ if (ct > m_currentSeconds)
+ {
+ m_currentSeconds = ct;
+ dispatch(m_currentSeconds, m_totalWritten, m_rate,
+ m_frequency, m_precision, m_channels);
+ }
+}
+
+long OutputOSS::written()
+{
+ return m_totalWritten;
+}
+
+void OutputOSS::seek(long pos)
+{
+ recycler()->mutex()->lock();
+ recycler()->clear();
+ recycler()->mutex()->unlock();
+
+ m_totalWritten = (pos * m_bps);
+ m_currentSeconds = -1;
+}
+
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+
+#if defined(__FreeBSD__)
+# include <sys/soundcard.h>
+#elif defined(__linux__)
+# include <linux/soundcard.h>
+#elif defined(__bsdi__)
+# include <sys/soundcard.h>
+#endif
+
+
+OutputOSS::OutputOSS(QObject * parent)
+ : Output(parent), m_inited(FALSE), m_pause(FALSE), m_play(FALSE),
+ m_userStop(FALSE),
+ m_totalWritten(0), m_currentSeconds(-1),
+ m_bps(1), m_frequency(-1), m_channels(-1), m_precision(-1),
+ do_select(TRUE),
+ m_audio_fd(-1), m_mixer_fd(-1)
+{
+QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+m_master = true;
+m_audio_device = settings.value("OSS/device","/dev/dsp").toString();
+m_mixer_device = settings.value("OSS/mixer_device","/dev/mixer").toString();
+openMixer();
+}
+
+OutputOSS::~OutputOSS()
+{
+ if (m_audio_fd > 0)
+ {
+ close(m_audio_fd);
+ m_audio_fd = -1;
+ }
+ if (m_mixer_fd > 0)
+ {
+ close(m_mixer_fd);
+ m_mixer_fd = -1;
+ }
+}
+
+void OutputOSS::configure(long freq, int chan, int prec, int rate)
+{
+ // we need to configure
+ if (freq != m_frequency || chan != m_channels || prec != m_precision) {
+ // we have already configured, but are changing settings...
+ // reset the device
+ resetDSP();
+
+ m_frequency = freq;
+ m_channels = chan;
+ m_precision = prec;
+
+ m_bps = freq * chan * (prec / 8);
+
+ int p;
+ switch(prec) {
+ default:
+ case 16:
+#if defined(AFMT_S16_NE)
+ p = AFMT_S16_NE;
+#else
+ p = AFMT_S16_LE;
+#endif
+ break;
+
+ case 8:
+ p = AFMT_S8;
+ break;
+
+ }
+
+ ioctl(m_audio_fd, SNDCTL_DSP_SETFMT, &p);
+ ioctl(m_audio_fd, SNDCTL_DSP_SAMPLESIZE, &prec);
+ int stereo = (chan > 1) ? 1 : 0;
+ ioctl(m_audio_fd, SNDCTL_DSP_STEREO, &stereo);
+ ioctl(m_audio_fd, SNDCTL_DSP_SPEED, &freq);
+ }
+
+ m_rate = rate;
+}
+
+
+void OutputOSS::reset()
+{
+ if (m_audio_fd > 0)
+ {
+ close(m_audio_fd);
+ m_audio_fd = -1;
+ }
+
+ m_audio_fd = open(m_audio_device.toAscii(), O_WRONLY, 0);
+
+ if (m_audio_fd < 0)
+ {
+ error(QString("OSSOutput: failed to open output device '%1'").
+ arg(m_audio_device));
+ return;
+ }
+
+ int flags;
+ if ((flags = fcntl(m_audio_fd, F_GETFL, 0)) > 0)
+ {
+ flags &= O_NDELAY;
+ fcntl(m_audio_fd, F_SETFL, flags);
+ }
+
+ fd_set afd;
+ FD_ZERO(&afd);
+ FD_SET(m_audio_fd, &afd);
+ struct timeval tv;
+ tv.tv_sec = 0l;
+ tv.tv_usec = 50000l;
+ do_select = (select(m_audio_fd + 1, 0, &afd, 0, &tv) > 0);
+
+ if (m_audio_fd > 0)
+ {
+ close(m_mixer_fd);
+ m_mixer_fd = -1;
+ }
+ openMixer();
+}
+
+void OutputOSS::openMixer()
+{
+ if (m_mixer_fd != -1)
+ return;
+
+ if ((m_mixer_fd = open(m_mixer_device.toAscii(), O_RDWR)) == -1)
+ {
+ return;
+ }
+ if (m_audio_fd < 0)
+ {
+ error(QString("OSSOutput: failed to open mixer device '%1'").
+ arg(m_mixer_device));
+ return;
+ }
+}
+
+void OutputOSS::pause()
+{
+ m_pause = (m_pause) ? FALSE : TRUE;
+}
+
+void OutputOSS::post()
+{
+ if (m_audio_fd < 1)
+ return;
+
+ int unused;
+ ioctl(m_audio_fd, SNDCTL_DSP_POST, &unused);
+}
+
+void OutputOSS::sync()
+{
+ if (m_audio_fd < 1)
+ return;
+
+ int unused;
+ ioctl(m_audio_fd, SNDCTL_DSP_SYNC, &unused);
+}
+
+
+void OutputOSS::resetDSP()
+{
+ if (m_audio_fd < 1)
+ return;
+
+ int unused;
+ ioctl(m_audio_fd, SNDCTL_DSP_RESET, &unused);
+}
+
+
+bool OutputOSS::initialize()
+{
+ m_inited = m_pause = m_play = m_userStop = FALSE;
+
+
+ reset();
+ if (m_audio_fd < 0)
+ return FALSE;
+ if (m_mixer_fd < 0)
+ return FALSE;
+
+
+ m_currentSeconds = -1;
+ m_totalWritten = 0;
+ stat = OutputState::Stopped;
+
+ m_inited = TRUE;
+ return TRUE;
+}
+
+void OutputOSS::uninitialize()
+{
+ if (!m_inited)
+ return;
+ m_inited = FALSE;
+ m_pause = FALSE;
+ m_play = FALSE;
+ m_userStop = FALSE;
+ m_totalWritten = 0;
+ m_currentSeconds = -1;
+ m_bps = -1;
+ m_frequency = -1;
+ m_channels = -1;
+ m_precision = -1;
+ resetDSP();
+ if (m_audio_fd > 0)
+ {
+ close(m_audio_fd);
+ m_audio_fd = -1;
+ }
+ if (m_audio_fd > 0)
+ {
+ close(m_mixer_fd);
+ m_mixer_fd = -1;
+ }
+
+ qDebug("OutputOSS: uninitialize");
+ dispatch(OutputState::Stopped);
+}
+
+long OutputOSS::latency()
+{
+ ulong used = 0;
+
+ if (! m_pause)
+ {
+ if (ioctl(m_audio_fd, SNDCTL_DSP_GETODELAY, &used) == -1)
+ used = 0;
+ }
+
+ return used;
+}
+
+void OutputOSS::run()
+{
+ mutex()->lock();
+
+ if (! m_inited)
+ {
+ mutex()->unlock();
+
+ return;
+ }
+
+ m_play = TRUE;
+
+ mutex()->unlock();
+
+ fd_set afd;
+ struct timeval tv;
+ Buffer *b = 0;
+ bool done = FALSE;
+ unsigned long n = 0, m = 0, l = 0;
+
+ dispatch(OutputState::Playing);
+
+ FD_ZERO(&afd);
+
+ while (! done) {
+ mutex()->lock();
+
+ recycler()->mutex()->lock();
+
+ done = m_userStop;
+
+ while (! done && (recycler()->empty() || m_pause)) {
+ post();
+
+ mutex()->unlock();
+
+ {
+ stat = m_pause ? OutputState::Paused : OutputState::Buffering;
+ OutputState e((OutputState::Type) stat);
+ dispatch(e);
+ }
+
+ recycler()->cond()->wakeOne();
+ recycler()->cond()->wait(recycler()->mutex());
+
+ mutex()->lock();
+ done = m_userStop;
+ status();
+ }
+
+ if (! b) {
+ b = recycler()->next();
+ if (b->rate)
+ m_rate = b->rate;
+ }
+
+ recycler()->cond()->wakeOne();
+ recycler()->mutex()->unlock();
+
+ FD_ZERO(&afd);
+ FD_SET(m_audio_fd, &afd);
+ // nice long poll timeout
+ tv.tv_sec = 5l;
+ tv.tv_usec = 0l;
+
+ if (b &&
+ (! do_select || (select(m_audio_fd + 1, 0, &afd, 0, &tv) > 0 &&
+ FD_ISSET(m_audio_fd, &afd)))) {
+ l = qMin(int(2048), int(b->nbytes - n));
+ if (l > 0) {
+ m = write(m_audio_fd, b->data + n, l);
+ n += m;
+
+ status();
+ dispatchVisual(b, m_totalWritten, m_channels, m_precision);
+ } else {
+ // force buffer change
+ n = b->nbytes;
+ m = 0;
+ }
+ }
+
+ m_totalWritten += m;
+
+ if (n == b->nbytes) {
+ recycler()->mutex()->lock();
+ recycler()->done();
+ recycler()->mutex()->unlock();
+
+ b = 0;
+ n = 0;
+ }
+
+ mutex()->unlock();
+ }
+
+ mutex()->lock();
+
+ if (! m_userStop)
+ sync();
+ resetDSP();
+
+ m_play = FALSE;
+
+ dispatch(OutputState::Stopped);
+ mutex()->unlock();
+}
+
+
+void OutputOSS::setVolume(int l, int r)
+{
+ int v, devs;
+ long cmd;
+
+ ioctl(m_mixer_fd, SOUND_MIXER_READ_DEVMASK, &devs);
+ if ((devs & SOUND_MASK_PCM) && (m_master == false))
+ cmd = SOUND_MIXER_WRITE_PCM;
+ else if ((devs & SOUND_MASK_VOLUME) && (m_master == true))
+ cmd = SOUND_MIXER_WRITE_VOLUME;
+ else
+ {
+ //close(mifd);
+ return;
+ }
+ v = (r << 8) | l;
+ ioctl(m_mixer_fd, cmd, &v);
+}
+
+void OutputOSS::volume(int *ll,int *rr)
+{
+ *ll = 0;
+ *rr = 0;
+ int cmd;
+ int v, devs;
+
+ ioctl(m_mixer_fd, SOUND_MIXER_READ_DEVMASK, &devs);
+ if ((devs & SOUND_MASK_PCM) && (m_master == 0))
+ cmd = SOUND_MIXER_READ_PCM;
+ else if ((devs & SOUND_MASK_VOLUME) && (m_master == 1))
+ cmd = SOUND_MIXER_READ_VOLUME;
+ else
+ return;
+
+ ioctl(m_mixer_fd, cmd, &v);
+ *ll = (v & 0xFF00) >> 8;
+ *rr = (v & 0x00FF);
+
+ *ll = (*ll > 100) ? 100 : *ll;
+ *rr = (*rr > 100) ? 100 : *rr;
+ *ll = (*ll < 0) ? 0 : *ll;
+ *rr = (*rr < 0) ? 0 : *rr;
+}
+
+
+void OutputOSS::checkVolume()
+{
+ long ll = 0, lr = 0, cmd;
+ int v, devs;
+
+ /*
+ * We dont show any errors if this fails, as this is called
+ * rather often
+ */
+// if (!open_mixer_device()) {
+ ioctl(m_mixer_fd, SOUND_MIXER_READ_DEVMASK, &devs);
+ if ((devs & SOUND_MASK_PCM) && (m_master == 0))
+ cmd = SOUND_MIXER_READ_PCM;
+ else if ((devs & SOUND_MASK_VOLUME) && (m_master == 1))
+ cmd = SOUND_MIXER_READ_VOLUME;
+ else
+ return;
+
+ ioctl(m_mixer_fd, cmd, &v);
+ ll = (v & 0xFF00) >> 8;
+ lr = (v & 0x00FF);
+
+ ll = (ll > 100) ? 100 : ll;
+ lr = (lr > 100) ? 100 : lr;
+ ll = (ll < 0) ? 0 : ll;
+ lr = (lr < 0) ? 0 : lr;
+ if (bl!=ll || br!=lr)
+ {
+ bl = ll;
+ br = lr;
+ dispatchVolume(ll,lr);
+ }
+// }
+}
+
+
diff --git a/src/plugins/Output/oss/outputoss.h b/src/plugins/Output/oss/outputoss.h
new file mode 100644
index 000000000..a2f260057
--- /dev/null
+++ b/src/plugins/Output/oss/outputoss.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Uriy Zhuravlev stalkerg@gmail.com *
+ * *
+ * Copyright (c) 2000-2001 Brad Hughes bhughes@trolltech.com *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+
+#ifndef OUTPUTOSS_H
+#define OUTPUTOSS_H
+
+class OutputOSS;
+
+#include <output.h>
+#include <QObject>
+
+class OutputOSS : public Output
+{
+Q_OBJECT
+public:
+ OutputOSS(QObject * parent = 0);
+ virtual ~OutputOSS();
+
+ bool isInitialized() const { return m_inited; }
+ bool initialize();
+ void uninitialize();
+ void configure(long, int, int, int);
+ void stop();
+ void pause();
+ long written();
+ long latency();
+ void seek(long);
+ void setVolume(int l, int r);
+ void volume(int* l,int* r);
+ void checkVolume();
+
+private:
+ // thread run function
+ void run();
+
+ // helper functions
+ void reset();
+ void resetDSP();
+ void status();
+ void post();
+ void sync();
+ void openMixer();
+
+ QString m_audio_device, m_mixer_device;
+
+ bool m_inited, m_pause, m_play, m_userStop, m_master;
+ long m_totalWritten, m_currentSeconds, m_bps;
+ int stat;
+ int m_rate, m_frequency, m_channels, m_precision;
+
+ bool do_select;
+ int m_audio_fd, m_mixer_fd;
+ long bl, br;
+};
+
+
+#endif
diff --git a/src/plugins/Output/oss/outputossfactory.cpp b/src/plugins/Output/oss/outputossfactory.cpp
new file mode 100644
index 000000000..3fa8c07a2
--- /dev/null
+++ b/src/plugins/Output/oss/outputossfactory.cpp
@@ -0,0 +1,70 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Zhuravlev Uriy *
+ * stalkerg@gmail.com *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QtGui>
+
+#include "settingsdialog.h"
+#include "outputoss.h"
+#include "outputossfactory.h"
+
+
+const QString& OutputOSSFactory::name() const
+{
+ static QString name(tr("OSS Plugin"));
+ return name;
+}
+
+Output* OutputOSSFactory::create(QObject* parent,bool)
+{
+ return new OutputOSS(parent);
+}
+
+const OutputProperties OutputOSSFactory::properties() const
+{
+ OutputProperties properties;
+ properties.name = name();
+ properties.hasAbout = TRUE;
+ properties.hasSettings = TRUE;
+ return properties;
+}
+
+void OutputOSSFactory::showSettings(QWidget* parent)
+{
+ SettingsDialog *s = new SettingsDialog(parent);
+ s -> show();
+}
+
+void OutputOSSFactory::showAbout(QWidget *parent)
+{
+QMessageBox::about (parent, tr("About OSS Output Plugin"),
+ tr("Qmmp OSS Output Plugin")+"\n"+
+ tr("Writen by: Yuriy Zhuravlev <slalkerg@gmail.com>")+"\n"+
+ tr("Based on code by:Brad Hughes <bhughes@trolltech.com>"));
+}
+
+QTranslator *OutputOSSFactory::createTranslator(QObject *parent)
+{
+ QTranslator *translator = new QTranslator(parent);
+ QString locale = QLocale::system().name();
+ translator->load(QString(":/oss_plugin_") + locale);
+ return translator;
+}
+
+Q_EXPORT_PLUGIN(OutputOSSFactory)
diff --git a/src/plugins/Output/oss/outputossfactory.h b/src/plugins/Output/oss/outputossfactory.h
new file mode 100644
index 000000000..03166bb94
--- /dev/null
+++ b/src/plugins/Output/oss/outputossfactory.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef OUTPUTOSSFACTORY_H
+#define OUTPUTOSSFACTORY_H
+
+
+#include <QObject>
+#include <QString>
+#include <QIODevice>
+#include <QWidget>
+
+#include <output.h>
+#include <outputfactory.h>
+
+
+class OutputOSSFactory : public QObject,
+ OutputFactory
+{
+Q_OBJECT
+Q_INTERFACES(OutputFactory);
+
+public:
+ const QString& name() const;
+ Output* create(QObject* parent,bool);
+ void showSettings(QWidget* parent);
+ void showAbout(QWidget *parent);
+ QTranslator *createTranslator(QObject *parent);
+ const OutputProperties properties() const;
+};
+
+#endif
diff --git a/src/plugins/Output/oss/settingsdialog.cpp b/src/plugins/Output/oss/settingsdialog.cpp
new file mode 100644
index 000000000..8d75b06eb
--- /dev/null
+++ b/src/plugins/Output/oss/settingsdialog.cpp
@@ -0,0 +1,60 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Zhuravlev Uriy *
+ * stalkerg@gmail.com *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include <QSettings>
+#include <QDir>
+
+#include "settingsdialog.h"
+
+SettingsDialog::SettingsDialog ( QWidget *parent )
+ : QDialog ( parent )
+{
+ ui.setupUi ( this );
+ setAttribute ( Qt::WA_DeleteOnClose );
+ connect(ui.okButton, SIGNAL(clicked()), SLOT(writeSettings()));
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.beginGroup("OSS");
+ ui.lineEdit->insert(settings.value("device","/dev/dsp").toString());
+ ui.lineEdit_2->insert(settings.value("mixer_device","/dev/mixer").toString());
+ ui.bufferSpinBox->setValue(settings.value("buffer_time",500).toInt());
+ ui.periodSpinBox->setValue(settings.value("period_time",100).toInt());
+
+ settings.endGroup();
+}
+
+
+SettingsDialog::~SettingsDialog()
+{}
+
+
+
+void SettingsDialog::writeSettings()
+{
+ qDebug("SettingsDialog (OSS):: writeSettings()");
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.beginGroup("OSS");
+ settings.setValue("device", ui.lineEdit->text());
+ settings.setValue("buffer_time",ui.bufferSpinBox->value());
+ settings.setValue("period_time",ui.periodSpinBox->value());
+ settings.setValue("mixer_device", ui.lineEdit_2->text());
+ settings.endGroup();
+ accept();
+}
+
+
diff --git a/src/plugins/Output/oss/settingsdialog.h b/src/plugins/Output/oss/settingsdialog.h
new file mode 100644
index 000000000..fd75c5698
--- /dev/null
+++ b/src/plugins/Output/oss/settingsdialog.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Zhuravlev Uriy *
+ * stalkerg@gmail.com *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef SETTINGSDIALOG_H
+#define SETTINGSDIALOG_H
+
+#include <QDialog>
+
+
+#include "ui_settingsdialog.h"
+
+/**
+ @author Yuriy Zhuravlev <stalkerg@gmail.com>
+*/
+class SettingsDialog : public QDialog
+{
+Q_OBJECT
+public:
+ SettingsDialog(QWidget *parent = 0);
+
+ ~SettingsDialog();
+
+private slots:
+ void writeSettings();
+
+private:
+ Ui::SettingsDialog ui;
+
+};
+
+#endif
diff --git a/src/plugins/Output/oss/settingsdialog.ui b/src/plugins/Output/oss/settingsdialog.ui
new file mode 100644
index 000000000..ce1c40894
--- /dev/null
+++ b/src/plugins/Output/oss/settingsdialog.ui
@@ -0,0 +1,309 @@
+<ui version="4.0" >
+ <class>SettingsDialog</class>
+ <widget class="QDialog" name="SettingsDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>422</width>
+ <height>334</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>OSS Plugin Settings</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="leftMargin" >
+ <number>9</number>
+ </property>
+ <property name="topMargin" >
+ <number>9</number>
+ </property>
+ <property name="rightMargin" >
+ <number>9</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>9</number>
+ </property>
+ <property name="horizontalSpacing" >
+ <number>6</number>
+ </property>
+ <property name="verticalSpacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="0" colspan="3" >
+ <widget class="QTabWidget" name="tabWidget" >
+ <property name="currentIndex" >
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab" >
+ <attribute name="title" >
+ <string>Device Settings</string>
+ </attribute>
+ <layout class="QVBoxLayout" >
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <property name="leftMargin" >
+ <number>9</number>
+ </property>
+ <property name="topMargin" >
+ <number>9</number>
+ </property>
+ <property name="rightMargin" >
+ <number>9</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="title" >
+ <string>Audio device</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QLineEdit" name="lineEdit" >
+ <property name="text" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2" >
+ <property name="title" >
+ <string>Mixer device</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="leftMargin" >
+ <number>9</number>
+ </property>
+ <property name="topMargin" >
+ <number>9</number>
+ </property>
+ <property name="rightMargin" >
+ <number>9</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>9</number>
+ </property>
+ <property name="horizontalSpacing" >
+ <number>6</number>
+ </property>
+ <property name="verticalSpacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="0" >
+ <widget class="QLineEdit" name="lineEdit_2" >
+ <property name="text" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_2" >
+ <attribute name="title" >
+ <string>Advanced Settings</string>
+ </attribute>
+ <layout class="QVBoxLayout" >
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <property name="leftMargin" >
+ <number>9</number>
+ </property>
+ <property name="topMargin" >
+ <number>9</number>
+ </property>
+ <property name="rightMargin" >
+ <number>9</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="groupBox_3" >
+ <property name="title" >
+ <string>Soundcard</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="leftMargin" >
+ <number>9</number>
+ </property>
+ <property name="topMargin" >
+ <number>9</number>
+ </property>
+ <property name="rightMargin" >
+ <number>9</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>9</number>
+ </property>
+ <property name="horizontalSpacing" >
+ <number>6</number>
+ </property>
+ <property name="verticalSpacing" >
+ <number>6</number>
+ </property>
+ <item row="3" column="1" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>111</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>188</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QSpinBox" name="periodSpinBox" >
+ <property name="minimum" >
+ <number>20</number>
+ </property>
+ <property name="maximum" >
+ <number>5000</number>
+ </property>
+ <property name="value" >
+ <number>100</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QSpinBox" name="bufferSpinBox" >
+ <property name="minimum" >
+ <number>200</number>
+ </property>
+ <property name="maximum" >
+ <number>10000</number>
+ </property>
+ <property name="value" >
+ <number>500</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Buffer time (ms):</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Period time (ms):</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>188</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QCheckBox" name="checkBox" >
+ <property name="text" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>PCM over Master</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>191</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="2" >
+ <widget class="QPushButton" name="cancelButton" >
+ <property name="text" >
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QPushButton" name="okButton" >
+ <property name="text" >
+ <string>OK</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>cancelButton</sender>
+ <signal>clicked()</signal>
+ <receiver>SettingsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>338</x>
+ <y>283</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>164</x>
+ <y>294</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/Output/oss/translations/oss_plugin_cs.ts b/src/plugins/Output/oss/translations/oss_plugin_cs.ts
new file mode 100644
index 000000000..424d320e7
--- /dev/null
+++ b/src/plugins/Output/oss/translations/oss_plugin_cs.ts
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS><TS version="1.1" language="pl">
+<defaultcodec></defaultcodec>
+<context>
+ <name>OutputOSSFactory</name>
+ <message>
+ <location filename="../outputossfactory.cpp" line="30"/>
+ <source>OSS Plugin</source>
+ <translation>Plugin OSS</translation>
+ </message>
+ <message>
+ <location filename="../outputossfactory.cpp" line="47"/>
+ <source>About OSS Output Plugin</source>
+ <translation>O pluginu OSS</translation>
+ </message>
+ <message>
+ <location filename="../outputossfactory.cpp" line="48"/>
+ <source>Qmmp OSS Output Plugin</source>
+ <translation>Výstupní plugin Qmmp OSS</translation>
+ </message>
+ <message>
+ <location filename="../outputossfactory.cpp" line="49"/>
+ <source>Writen by: Yuriy Zhuravlev &lt;slalkerg@gmail.com&gt;</source>
+ <translation>Autor: Jurij Žuravljov &lt;slalkerg@gmail.com&gt;</translation>
+ </message>
+ <message>
+ <location filename="../outputossfactory.cpp" line="50"/>
+ <source>Based on code by:Brad Hughes &lt;bhughes@trolltech.com&gt;</source>
+ <translation>Založeno na kódu Brada Hughese &lt;bhughes@trolltech.com&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <location filename="../ui_settingsdialog.h" line="202"/>
+ <source>OSS Plugin Settings</source>
+ <translation>Nastavení pluginu OSS</translation>
+ </message>
+ <message>
+ <location filename="../ui_settingsdialog.h" line="207"/>
+ <source>Device Settings</source>
+ <translation>Nastavení zařízení</translation>
+ </message>
+ <message>
+ <location filename="../ui_settingsdialog.h" line="203"/>
+ <source>Audio device</source>
+ <translation>Zvukové zařízení</translation>
+ </message>
+ <message>
+ <location filename="../ui_settingsdialog.h" line="205"/>
+ <source>Mixer device</source>
+ <translation>Ovládání hlasitosti</translation>
+ </message>
+ <message>
+ <location filename="../ui_settingsdialog.h" line="213"/>
+ <source>Advanced Settings</source>
+ <translation>Pokročilá nastavení</translation>
+ </message>
+ <message>
+ <location filename="../ui_settingsdialog.h" line="208"/>
+ <source>Soundcard</source>
+ <translation>Zvuková karta</translation>
+ </message>
+ <message>
+ <location filename="../ui_settingsdialog.h" line="209"/>
+ <source>Buffer time (ms):</source>
+ <translation>Velikost bufferu (ms):</translation>
+ </message>
+ <message>
+ <location filename="../ui_settingsdialog.h" line="210"/>
+ <source>Period time (ms):</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../ui_settingsdialog.h" line="212"/>
+ <source>PCM over Master</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../ui_settingsdialog.h" line="214"/>
+ <source>Cancel</source>
+ <translation>Zrušit</translation>
+ </message>
+ <message>
+ <location filename="../ui_settingsdialog.h" line="215"/>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/plugins/Visual/CMakeLists.txt b/src/plugins/Visual/CMakeLists.txt
new file mode 100644
index 000000000..df35bdf14
--- /dev/null
+++ b/src/plugins/Visual/CMakeLists.txt
@@ -0,0 +1,8 @@
+SET(USE_ANALYZER TRUE CACHE BOOL "enable/disable analyzer plugin")
+
+IF(USE_ANALYZER)
+MESSAGE( STATUS "ANALYZER ON")
+add_subdirectory(analyzer)
+ELSE(USE_ANALYZER)
+MESSAGE( STATUS "ANALYZER OFF")
+ENDIF(USE_ANALYZER)
diff --git a/src/plugins/Visual/Visual.pro b/src/plugins/Visual/Visual.pro
new file mode 100644
index 000000000..e30196780
--- /dev/null
+++ b/src/plugins/Visual/Visual.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+SUBDIRS += analyzer
diff --git a/src/plugins/Visual/analyzer/CMakeLists.txt b/src/plugins/Visual/analyzer/CMakeLists.txt
new file mode 100644
index 000000000..7de2ca687
--- /dev/null
+++ b/src/plugins/Visual/analyzer/CMakeLists.txt
@@ -0,0 +1,70 @@
+project(libanalyzer)
+
+cmake_minimum_required(VERSION 2.4.0)
+
+
+
+INCLUDE(FindQt4)
+
+find_package(Qt4 REQUIRED) # find and setup Qt4 for this project
+include(${QT_USE_FILE})
+
+# qt plugin
+ADD_DEFINITIONS( -Wall )
+ADD_DEFINITIONS(${QT_DEFINITIONS})
+ADD_DEFINITIONS(-DQT_PLUGIN)
+ADD_DEFINITIONS(-DQT_NO_DEBUG)
+ADD_DEFINITIONS(-DQT_SHARED)
+ADD_DEFINITIONS(-DQT_THREAD)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+SET(QT_INCLUDES
+ ${QT_INCLUDES}
+ ${CMAKE_CURRENT_BINARY_DIR}/../../../
+)
+
+# libqmmp
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+link_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+
+SET(libanalyzer_SRCS
+ analyzer.cpp
+ colorwidget.cpp
+ settingsdialog.cpp
+ visualanalyzerfactory.cpp
+ fft.c
+)
+
+SET(libanalyzer_MOC_HDRS
+ analyzer.h
+ colorwidget.h
+ fft.h
+ inlines.h
+ settingsdialog.h
+ visualanalyzerfactory.h
+)
+
+#SET(libanalyzer_RCCS translations/translations.qrc)
+
+#QT4_ADD_RESOURCES(libanalyzer_RCC_SRCS ${libanalyzer_RCCS})
+
+QT4_WRAP_CPP(libanalyzer_MOC_SRCS ${libanalyzer_MOC_HDRS})
+
+# user interface
+
+
+SET(libanalyzer_UIS
+ settingsdialog.ui
+)
+
+QT4_WRAP_UI(libanalyzer_UIS_H ${libanalyzer_UIS})
+# Don't forget to include output directory, otherwise
+# the UI file won't be wrapped!
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+ADD_LIBRARY(analyzer SHARED ${libanalyzer_SRCS} ${libanalyzer_MOC_SRCS} ${libanalyzer_UIS_H}
+ ${libanalyzer_RCC_SRCS})
+target_link_libraries(analyzer ${QT_LIBRARIES} -lqmmp)
+install(TARGETS analyzer DESTINATION ${LIB_DIR}/qmmp/Visual PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ)
+
diff --git a/src/plugins/Visual/analyzer/analyzer.cpp b/src/plugins/Visual/analyzer/analyzer.cpp
new file mode 100644
index 000000000..efcb8b7d7
--- /dev/null
+++ b/src/plugins/Visual/analyzer/analyzer.cpp
@@ -0,0 +1,308 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include <QTimer>
+#include <QSettings>
+#include <QPainter>
+#include <QMenu>
+#include <QActionGroup>
+
+#include <buffer.h>
+#include <constants.h>
+#include <output.h>
+#include <math.h>
+#include <stdlib.h>
+
+//#include "skin.h"
+#include "fft.h"
+#include "inlines.h"
+#include "analyzer.h"
+
+
+Analyzer::Analyzer (QWidget *parent)
+ : Visual (parent), m_fps ( 20 )
+{
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ restoreGeometry(settings.value("Analyzer/geometry").toByteArray());
+ setFixedSize(2*300-30,105);
+ m_pixmap = QPixmap (75,20);
+ m_timer = new QTimer (this);
+ connect(m_timer, SIGNAL (timeout()), this, SLOT (timeout()));
+ m_nodes.clear();
+
+ clear();
+ setWindowTitle (tr("Qmmp Analyzer"));
+
+ double peaks_speed[] = { 0.05, 0.1, 0.2, 0.4, 0.8 };
+ double analyzer_speed[] = { 1.2, 1.8, 2.2, 2.8, 2.4 };
+ int intervals[] = { 20 , 40 , 100 , 200 };
+
+ m_peaks_falloff =
+ peaks_speed[settings.value("Analyzer/peaks_falloff", 3).toInt()-1];
+ m_analyzer_falloff =
+ analyzer_speed[settings.value("Analyzer/analyzer_falloff", 3).toInt()-1];
+ m_show_peaks = settings.value("Analyzer/show_peaks", TRUE).toBool();
+ m_timer->setInterval(intervals[settings.value("Analyzer/refresh_rate", 2).toInt() - 1]);
+ m_color1.setNamedColor(settings.value("Analyzer/color1", "Green").toString());
+ m_color2.setNamedColor(settings.value("Analyzer/color2", "Yellow").toString());
+ m_color3.setNamedColor(settings.value("Analyzer/color3", "Red").toString());
+ m_bgColor.setNamedColor(settings.value("Analyzer/bg_color", "Black").toString());
+ m_peakColor.setNamedColor(settings.value("Analyzer/peak_color", "Cyan").toString());
+}
+
+Analyzer::~Analyzer()
+{
+ while (!m_nodes.isEmpty())
+ m_nodes.removeFirst();
+}
+
+void Analyzer::clear()
+{
+ while (!m_nodes.isEmpty())
+ m_nodes.removeFirst();
+ for ( int i = 0; i< 75; ++i )
+ {
+ m_intern_vis_data[i] = 0;
+ m_peaks[i] = 0;
+ }
+ update();
+}
+
+void Analyzer::add ( Buffer *b, unsigned long w, int c, int p )
+{
+ if (!m_timer->isActive ())
+ return;
+ long len = b->nbytes, cnt;
+ short *l = 0, *r = 0;
+
+ len /= c;
+ len /= ( p / 8 );
+ if ( len > 512 )
+ len = 512;
+ cnt = len;
+
+ if ( c == 2 )
+ {
+ l = new short[len];
+ r = new short[len];
+
+ if ( p == 8 )
+ stereo16_from_stereopcm8 ( l, r, b->data, cnt );
+ else if ( p == 16 )
+ stereo16_from_stereopcm16 ( l, r, ( short * ) b->data, cnt );
+ }
+ else if ( c == 1 )
+ {
+ l = new short[len];
+
+ if ( p == 8 )
+ mono16_from_monopcm8 ( l, b->data, cnt );
+ else if ( p == 16 )
+ mono16_from_monopcm16 ( l, ( short * ) b->data, cnt );
+ }
+ else
+ len = 0;
+
+ if (len)
+ m_nodes.append (new VisualNode (l, r, len, w));
+}
+
+void Analyzer::timeout()
+{
+ VisualNode *node = 0;
+
+ if ( /*playing &&*/ output())
+ {
+ //output()->mutex()->lock ();
+ //long olat = output()->latency();
+ //long owrt = output()->written();
+ //output()->mutex()->unlock();
+
+ //long synctime = owrt < olat ? 0 : owrt - olat;
+
+ mutex()->lock ();
+ VisualNode *prev = 0;
+ while ((!m_nodes.isEmpty()))
+ {
+ node = m_nodes.takeFirst();
+ /*if ( node->offset > synctime )
+ break;*/
+
+ if (prev)
+ delete prev;
+ prev = node;
+ }
+ mutex()->unlock();
+ node = prev;
+ }
+
+ if (!node)
+ return;
+ process (node);
+ delete node;
+ update();
+}
+
+void Analyzer::paintEvent (QPaintEvent * e)
+{
+ QPainter painter (this);
+ painter.fillRect(e->rect(),m_bgColor);
+ draw(&painter);
+}
+
+void Analyzer::hideEvent (QHideEvent *)
+{
+ m_timer->stop();
+}
+
+void Analyzer::showEvent (QShowEvent *)
+{
+ m_timer->start();
+}
+
+void Analyzer::closeEvent (QCloseEvent *event)
+{
+ //save geometry
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.setValue("Analyzer/geometry", saveGeometry());
+ Visual::closeEvent(event); //removes visualization before class deleting
+}
+
+bool Analyzer::process (VisualNode *node)
+{
+ static fft_state *state = 0;
+ if ( !state )
+ state = fft_init();
+
+ short dest_l[256];
+ short dest_r[256];
+
+ const int xscale_short[] =
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 15, 20, 27,
+ 36, 47, 62, 82, 107, 141, 184, 255
+ };
+
+ if ( node )
+ {
+ //i = node->length;
+ calc_freq ( dest_l, node->left );
+ if (node->right)
+ calc_freq ( dest_r, node->right );
+ }
+ else
+ return FALSE;
+ const double y_scale = 3.60673760222; /* 20.0 / log(256) */
+ int yl,yr, j;
+
+ for (int i = 0; i < 19; i++)
+ {
+ yl = yr = 0;
+
+ for ( j = xscale_short[i]; j < xscale_short[i + 1]; j++ )
+ {
+ if ( dest_l[j] > yl )
+ yl = dest_l[j];
+ if ( dest_r[j] > yr && node->right)
+ yr = dest_r[j];
+ }
+ yl >>= 7;
+ int magnitude_l = 0;
+ int magnitude_r = 0;
+ if (node->right)
+ {
+ yr >>= 7;
+ }
+ if (yl)
+ {
+ magnitude_l = int(log (yl) * y_scale);
+ if ( magnitude_l > 15 )
+ magnitude_l = 15;
+ if ( magnitude_l < 0 )
+ magnitude_l = 0;
+ }
+ if (yr && node->right)
+ {
+ magnitude_r = int(log (yr) * y_scale);
+ if ( magnitude_r > 15 )
+ magnitude_r = 15;
+ if ( magnitude_r < 0 )
+ magnitude_r = 0;
+ }
+
+ m_intern_vis_data[i] -= m_analyzer_falloff;
+ m_intern_vis_data[i] = magnitude_l > m_intern_vis_data[i]
+ ? magnitude_l : m_intern_vis_data[i];
+ if (node->right)
+ {
+ m_intern_vis_data[37-i] -= m_analyzer_falloff;
+ m_intern_vis_data[37-i] = magnitude_r > m_intern_vis_data[37-i]
+ ? magnitude_r : m_intern_vis_data[37-i];
+ }
+
+ if (m_show_peaks)
+ {
+ m_peaks[i] -= m_peaks_falloff;
+ m_peaks[i] = magnitude_l > m_peaks[i]
+ ? magnitude_l : m_peaks[i];
+ if (node->right)
+ {
+ m_peaks[37-i] -= m_peaks_falloff;
+ m_peaks[37-i] = magnitude_r > m_peaks[37-i]
+ ? magnitude_r : m_peaks[37-i];
+ }
+ }
+ }
+ return TRUE;
+}
+
+void Analyzer::draw (QPainter *p)
+{
+ QBrush brush(Qt::SolidPattern);
+ for (int j = 0; j < 19; ++j)
+ {
+ for (int i = 0; i <= m_intern_vis_data[j]; ++i)
+ {
+ if (i <= 5)
+ brush.setColor(m_color1);
+ else if (i > 5 && i <= 10)
+ brush.setColor(m_color2);
+ else
+ brush.setColor(m_color3);
+ p->fillRect (j*15+1, height() - i*7, 12, 4, brush);
+ }
+
+ for (int i = 0; i <= m_intern_vis_data[19+j]; ++i)
+ {
+ if (i <= 5)
+ brush.setColor(m_color1);
+ else if (i > 5 && i <= 10)
+ brush.setColor(m_color2);
+ else
+ brush.setColor(m_color3);
+ p->fillRect ((j+19)*15+1, height() - i*7, 12, 4, brush);
+ }
+
+ if (m_show_peaks)
+ {
+ p->fillRect (j*15+1, height() - int(m_peaks[j])*7, 12, 4, m_peakColor);
+ p->fillRect ((j+19)*15+1, height() - int(m_peaks[j+19])*7, 12, 4, m_peakColor);
+ }
+ }
+}
diff --git a/src/plugins/Visual/analyzer/analyzer.h b/src/plugins/Visual/analyzer/analyzer.h
new file mode 100644
index 000000000..ab08d3af0
--- /dev/null
+++ b/src/plugins/Visual/analyzer/analyzer.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef ANALYZER_H
+#define ANALYZER_H
+
+#include <QWidget>
+#include <QResizeEvent>
+#include <visual.h>
+#include <constants.h>
+#include <QDir>
+
+class QSettings;
+class QTimer;
+class QMenu;
+class QActionGroup;
+
+class Buffer;
+
+
+class VisualNode
+{
+public:
+ VisualNode(short *l, short *r, unsigned long n, unsigned long o)
+ : left(l), right(r), length(n), offset(o)
+ {
+ // left and right are allocated and then passed to this class
+ // the code that allocated left and right should give up all ownership
+ }
+
+ ~VisualNode()
+ {
+ delete [] left;
+ delete [] right;
+ }
+
+ short *left, *right;
+ long length, offset;
+};
+
+class Analyzer : public Visual
+{
+ Q_OBJECT
+
+public:
+ Analyzer( QWidget *parent = 0);
+ virtual ~Analyzer();
+
+ void add(Buffer *, unsigned long, int, int);
+ void clear();
+ void paintEvent( QPaintEvent * );
+
+protected:
+ virtual void hideEvent (QHideEvent *);
+ virtual void showEvent (QShowEvent *);
+ virtual void closeEvent (QCloseEvent *);
+
+public slots:
+ void timeout();
+
+private slots:
+ void updateSettings();
+
+private:
+ bool process(VisualNode *node);
+ void draw(QPainter *p);
+ QPixmap m_pixmap;
+ QPixmap m_bg;
+ QList <VisualNode*> m_nodes;
+ QTimer *m_timer;
+ int m_fps;
+ double m_intern_vis_data[75];
+ double m_peaks[75];
+ double m_peaks_falloff;
+ double m_analyzer_falloff;
+ bool m_show_peaks;
+ //colors
+ QColor m_color1;
+ QColor m_color2;
+ QColor m_color3;
+ QColor m_bgColor;
+ QColor m_peakColor;
+};
+
+
+#endif
diff --git a/src/plugins/Visual/analyzer/analyzer.pro b/src/plugins/Visual/analyzer/analyzer.pro
new file mode 100644
index 000000000..05d95a1ff
--- /dev/null
+++ b/src/plugins/Visual/analyzer/analyzer.pro
@@ -0,0 +1,35 @@
+include(../../plugins.pri)
+
+TARGET=$$PLUGINS_PREFIX/Visual/analyzer
+QMAKE_CLEAN =$$PLUGINS_PREFIX/Visual/libanalyzer.so
+
+
+#FORMS += detailsdialog.ui
+HEADERS += analyzer.h \
+ fft.h \
+ visualanalyzerfactory.h \
+ inlines.h \
+ colorwidget.h \
+ settingsdialog.h
+SOURCES += analyzer.cpp \
+ fft.c \
+ visualanalyzerfactory.cpp \
+ colorwidget.cpp \
+ settingsdialog.cpp
+INCLUDEPATH += ../../../qmmp
+CONFIG += release \
+warn_on \
+plugin
+TEMPLATE = lib
+QMAKE_LIBDIR += ../../../../lib
+LIBS += -lqmmp -L/usr/lib -I/usr/include
+#TRANSLATIONS = translations/ffmpeg_plugin_ru.ts
+#RESOURCES = translations/translations.qrc
+
+isEmpty(LIB_DIR){
+ LIB_DIR = /lib
+}
+target.path = $$LIB_DIR/qmmp/Visual
+INSTALLS += target
+FORMS += settingsdialog.ui
+
diff --git a/src/plugins/Visual/analyzer/colorwidget.cpp b/src/plugins/Visual/analyzer/colorwidget.cpp
new file mode 100644
index 000000000..7117a6cac
--- /dev/null
+++ b/src/plugins/Visual/analyzer/colorwidget.cpp
@@ -0,0 +1,56 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Ilya Kotov *
+ * qmmeter_freedevelop@mail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include "colorwidget.h"
+
+
+ColorWidget::ColorWidget(QWidget *parent) : QFrame(parent)
+{
+ setFrameShape(QFrame::Box);
+ setAutoFillBackground(TRUE);
+}
+
+
+ColorWidget::~ColorWidget()
+{}
+
+void ColorWidget::mousePressEvent( QMouseEvent *)
+{
+ QColor color = QColorDialog::getColor();
+ if (color.isValid())
+ {
+ QPalette palette;
+ palette.setColor(this->backgroundRole(), color);
+ this->setPalette(palette);
+ }
+}
+
+void ColorWidget::setColor(QString c)
+{
+ QPalette palette;
+ palette.setColor(this->backgroundRole(), c);
+ this->setPalette(palette);
+}
+
+QString ColorWidget::colorName()
+{
+ QPalette palette;
+ palette = this->palette();
+ return (palette.color(this->backgroundRole())).name();
+}
diff --git a/src/plugins/Visual/analyzer/colorwidget.h b/src/plugins/Visual/analyzer/colorwidget.h
new file mode 100644
index 000000000..c145c1035
--- /dev/null
+++ b/src/plugins/Visual/analyzer/colorwidget.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Ilya Kotov *
+ * qmmeter_freedevelop@mail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef COLORWIDGET_H
+#define COLORWIDGET_H
+
+#include <QFrame>
+#include <QColorDialog>
+#include <QPaintEvent>
+
+/**
+@author user
+*/
+class ColorWidget : public QFrame
+{
+ Q_OBJECT
+public:
+ ColorWidget(QWidget *parent = 0);
+
+ ~ColorWidget();
+
+ QString colorName();
+
+public slots:
+ void setColor (QString);
+
+
+protected:
+ virtual void mousePressEvent ( QMouseEvent *);
+
+
+};
+
+#endif
diff --git a/src/fft.c b/src/plugins/Visual/analyzer/fft.c
index 7ca1978a5..7ca1978a5 100644
--- a/src/fft.c
+++ b/src/plugins/Visual/analyzer/fft.c
diff --git a/src/fft.h b/src/plugins/Visual/analyzer/fft.h
index 431afa365..431afa365 100644
--- a/src/fft.h
+++ b/src/plugins/Visual/analyzer/fft.h
diff --git a/src/inlines.h b/src/plugins/Visual/analyzer/inlines.h
index 3efccf0de..3efccf0de 100644
--- a/src/inlines.h
+++ b/src/plugins/Visual/analyzer/inlines.h
diff --git a/src/plugins/Visual/analyzer/settingsdialog.cpp b/src/plugins/Visual/analyzer/settingsdialog.cpp
new file mode 100644
index 000000000..badadc190
--- /dev/null
+++ b/src/plugins/Visual/analyzer/settingsdialog.cpp
@@ -0,0 +1,62 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QSettings>
+#include <QDir>
+
+#include "settingsdialog.h"
+
+SettingsDialog::SettingsDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ ui.setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose, TRUE);
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ ui.analyzerComboBox->setCurrentIndex(settings.value("Analyzer/analyzer_falloff", 3).toInt()-1);
+ ui.peaksCheckBox->setChecked(settings.value("Analyzer/show_peaks", TRUE).toBool());
+ ui.peaksComboBox->setCurrentIndex(settings.value("Analyzer/peaks_falloff", 3).toInt()-1);
+ ui.fpsComboBox->setCurrentIndex(settings.value("Analyzer/refresh_rate", 2).toInt()-1);
+ ui.colorWidget1->setColor(settings.value("Analyzer/color1", "Green").toString());
+ ui.colorWidget2->setColor(settings.value("Analyzer/color2", "Yellow").toString());
+ ui.colorWidget3->setColor(settings.value("Analyzer/color3", "Red").toString());
+ ui.bgColorWidget->setColor(settings.value("Analyzer/bg_color", "Black").toString());
+ ui.peakColorWidget->setColor(settings.value("Analyzer/peak_color", "Cyan").toString());
+ connect (ui.okButton, SIGNAL(clicked()),SLOT(writeSettings()));
+}
+
+
+SettingsDialog::~SettingsDialog()
+{
+}
+
+void SettingsDialog::writeSettings()
+{
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ settings.setValue("Analyzer/analyzer_falloff", ui.analyzerComboBox->currentIndex() + 1);
+ settings.setValue("Analyzer/peaks_falloff", ui.peaksComboBox->currentIndex() + 1);
+ settings.setValue("Analyzer/refresh_rate", ui.fpsComboBox->currentIndex() + 1);
+ settings.setValue("Analyzer/show_peaks", ui.peaksCheckBox->isChecked());
+ settings.setValue("Analyzer/color1", ui.colorWidget1->colorName());
+ settings.setValue("Analyzer/color2", ui.colorWidget2->colorName());
+ settings.setValue("Analyzer/color3", ui.colorWidget3->colorName());
+ settings.setValue("Analyzer/bg_color", ui.bgColorWidget->colorName());
+ settings.setValue("Analyzer/peak_color", ui.peakColorWidget->colorName());
+ accept();
+}
diff --git a/src/plugins/Visual/analyzer/settingsdialog.h b/src/plugins/Visual/analyzer/settingsdialog.h
new file mode 100644
index 000000000..b7c466477
--- /dev/null
+++ b/src/plugins/Visual/analyzer/settingsdialog.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef SETTINGSDIALOG_H
+#define SETTINGSDIALOG_H
+
+#include <QDialog>
+
+#include "ui_settingsdialog.h"
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class SettingsDialog : public QDialog
+{
+Q_OBJECT
+public:
+ SettingsDialog(QWidget *parent = 0);
+
+ ~SettingsDialog();
+
+private slots:
+ void writeSettings();
+
+private:
+ Ui::SettingsDialog ui;
+
+};
+
+#endif
diff --git a/src/plugins/Visual/analyzer/settingsdialog.ui b/src/plugins/Visual/analyzer/settingsdialog.ui
new file mode 100644
index 000000000..4ddd391a3
--- /dev/null
+++ b/src/plugins/Visual/analyzer/settingsdialog.ui
@@ -0,0 +1,403 @@
+<ui version="4.0" >
+ <class>SettingsDialog</class>
+ <widget class="QDialog" name="SettingsDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>292</width>
+ <height>327</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Analyzer Plugin Settings</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" colspan="3" >
+ <widget class="QGroupBox" name="groupBox_2" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Minimum" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title" >
+ <string>General</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QCheckBox" name="peaksCheckBox" >
+ <property name="layoutDirection" >
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text" >
+ <string>Show peaks</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_10" >
+ <property name="text" >
+ <string>Analyzer falloff:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QComboBox" name="analyzerComboBox" >
+ <property name="currentIndex" >
+ <number>2</number>
+ </property>
+ <item>
+ <property name="text" >
+ <string>Slowest</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Slow</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Medium</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Fast</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Fastest</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_9" >
+ <property name="text" >
+ <string>Peaks falloff:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QComboBox" name="peaksComboBox" >
+ <property name="currentIndex" >
+ <number>2</number>
+ </property>
+ <item>
+ <property name="text" >
+ <string>Slowest</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Slow</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Medium</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Fast</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Fastest</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_11" >
+ <property name="text" >
+ <string>Refresh rate:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QComboBox" name="fpsComboBox" >
+ <property name="currentIndex" >
+ <number>0</number>
+ </property>
+ <item>
+ <property name="text" >
+ <string>50 FPS</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>25 FPS</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>10 FPS</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>5 FPS</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="3" >
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="MinimumExpanding" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title" >
+ <string>Colors</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_4" >
+ <property name="text" >
+ <string>Peaks:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="ColorWidget" native="1" name="peakColorWidget" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2" >
+ <widget class="QLabel" name="label_6" >
+ <property name="text" >
+ <string>Analyzer #1:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3" >
+ <widget class="ColorWidget" native="1" name="colorWidget1" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_5" >
+ <property name="text" >
+ <string>Background:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="ColorWidget" native="1" name="bgColorWidget" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <widget class="QLabel" name="label_7" >
+ <property name="text" >
+ <string>Analyzer #2:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3" >
+ <widget class="ColorWidget" native="1" name="colorWidget2" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>111</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="2" >
+ <widget class="QLabel" name="label_8" >
+ <property name="text" >
+ <string>Analyzer #3:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="3" >
+ <widget class="ColorWidget" native="1" name="colorWidget3" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType" >
+ <enum>QSizePolicy::Minimum</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>95</width>
+ <height>29</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QPushButton" name="okButton" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Expanding" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>16777215</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>&amp;OK</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2" >
+ <widget class="QPushButton" name="cancelButton" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Minimum" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>16777215</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>ColorWidget</class>
+ <extends>QWidget</extends>
+ <header>colorwidget.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>cancelButton</sender>
+ <signal>clicked()</signal>
+ <receiver>SettingsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>220</x>
+ <y>286</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>276</x>
+ <y>309</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/Visual/analyzer/visualanalyzerfactory.cpp b/src/plugins/Visual/analyzer/visualanalyzerfactory.cpp
new file mode 100644
index 000000000..0e110b2cd
--- /dev/null
+++ b/src/plugins/Visual/analyzer/visualanalyzerfactory.cpp
@@ -0,0 +1,57 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QtGui>
+
+#include "settingsdialog.h"
+#include "visualanalyzerfactory.h"
+#include "analyzer.h"
+
+const VisualProperties VisualAnalyzerFactory::properties() const
+{
+ VisualProperties properties;
+ properties.name = tr("Analyzer Plugin");
+ return properties;
+};
+
+Visual *VisualAnalyzerFactory::create(QWidget *parent)
+{
+ return new Analyzer(parent);
+};
+
+void VisualAnalyzerFactory::showSettings(QWidget *parent)
+{
+ SettingsDialog *s = new SettingsDialog(parent);
+ s -> show();
+};
+
+void VisualAnalyzerFactory::showAbout(QWidget *parent)
+{
+ QMessageBox::about (parent, tr("About Analyzer Visual Plugin"),
+ tr("Qmmp Analyzer Visual Plugin")+"\n"+
+ tr("Writen by: Ilya Kotov <forkotov02@hotmail.ru>"));
+};
+
+QTranslator *VisualAnalyzerFactory::createTranslator(QObject *parent)
+{
+ return 0;
+};
+
+Q_EXPORT_PLUGIN(VisualAnalyzerFactory)
diff --git a/src/plugins/Visual/analyzer/visualanalyzerfactory.h b/src/plugins/Visual/analyzer/visualanalyzerfactory.h
new file mode 100644
index 000000000..54f52bfe2
--- /dev/null
+++ b/src/plugins/Visual/analyzer/visualanalyzerfactory.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef VISUALANALYZERFACTORY_H
+#define VISUALANALYZERFACTORY_H
+
+
+#include <QObject>
+
+#include <visualfactory.h>
+#include <visual.h>
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class VisualAnalyzerFactory : public QObject, public VisualFactory
+{
+Q_OBJECT
+Q_INTERFACES(VisualFactory);
+
+public:
+ const VisualProperties properties() const;
+ Visual *create(QWidget *parent);
+ void showSettings(QWidget *parent);
+ void showAbout(QWidget *parent);
+ QTranslator *createTranslator(QObject *parent);
+};
+
+
+#endif
diff --git a/src/plugins/plugins.pri b/src/plugins/plugins.pri
new file mode 100644
index 000000000..e109b7b46
--- /dev/null
+++ b/src/plugins/plugins.pri
@@ -0,0 +1,2 @@
+include(../../qmmp.pri)
+PLUGINS_PREFIX=../../../../lib/qmmp \ No newline at end of file
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
new file mode 100644
index 000000000..9be0dd332
--- /dev/null
+++ b/src/plugins/plugins.pro
@@ -0,0 +1,7 @@
+
+SUBDIRS += Input \
+ Output \
+ Visual \
+ Effect \
+ General
+TEMPLATE = subdirs
diff --git a/src/qmmp/CMakeLists.txt b/src/qmmp/CMakeLists.txt
new file mode 100644
index 000000000..79edd7152
--- /dev/null
+++ b/src/qmmp/CMakeLists.txt
@@ -0,0 +1,68 @@
+project(libqmmp)
+
+cmake_minimum_required(VERSION 2.4.0)
+
+include(FindQt4)
+find_package(Qt4 REQUIRED) # find and setup Qt4 for this project
+include(${QT_USE_FILE})
+
+# qt lib
+ADD_DEFINITIONS( -Wall )
+ADD_DEFINITIONS(${QT_DEFINITIONS})
+#ADD_DEFINITIONS(-DQT_PLUGIN)
+ADD_DEFINITIONS(-DQT_NO_DEBUG)
+ADD_DEFINITIONS(-DQT_SHARED)
+ADD_DEFINITIONS(-DQT_THREAD)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+SET(libqmmp_SRCS
+ visual.cpp
+ recycler.cpp
+ decoder.cpp
+ output.cpp
+ filetag.cpp
+ equ/iir.c
+ equ/iir_cfs.c
+ equ/iir_fpu.c
+ soundcore.cpp
+ streamreader.cpp
+ downloader.cpp
+ effect.cpp
+)
+
+SET(libqmmp_MOC_HDRS
+ visual.h
+ recycler.h
+ buffer.h
+ constants.h
+ decoder.h
+ output.h
+ filetag.h
+ outputfactory.h
+ equ/iir_cfs.h
+ equ/iir_fpu.h
+ equ/iir.h
+ decoderfactory.h
+ soundcore.h
+ streamreader.h
+ downloader.h
+ effectfactory.h
+ effect.h
+)
+
+QT4_WRAP_CPP(libqmmp_MOC_SRCS ${libqmmp_MOC_HDRS})
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES config.h)
+
+EXEC_PROGRAM(echo ${CMAKE_CURRENT_BINARY_DIR} ARGS "\"#ifndef CONFIG_H\"" > ./config.h)
+EXEC_PROGRAM(echo ${CMAKE_CURRENT_BINARY_DIR} ARGS "\"#define CONFIG_H\"" >> ./config.h)
+EXEC_PROGRAM(echo ${CMAKE_CURRENT_BINARY_DIR} ARGS "\"#define LIB_DIR \\\"/${LIB_DIR}\\\"\"" >> ./config.h)
+EXEC_PROGRAM(echo ${CMAKE_CURRENT_BINARY_DIR} ARGS "\"#endif\"" >> ./config.h)
+
+
+ADD_LIBRARY(qmmp SHARED ${libqmmp_SRCS} ${libqmmp_MOC_SRCS})
+target_link_libraries(qmmp ${QT_LIBRARIES} curl)
+install(TARGETS qmmp LIBRARY DESTINATION ${LIB_DIR} PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ)
diff --git a/src/qmmp/buffer.h b/src/qmmp/buffer.h
new file mode 100644
index 000000000..c5ffadc0c
--- /dev/null
+++ b/src/qmmp/buffer.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com>
+//
+// Use, modification and distribution is allowed without limitation,
+// warranty, or liability of any kind.
+//
+
+#ifndef __buffer_h
+#define __buffer_h
+
+#include "constants.h"
+
+class Buffer
+{
+public:
+ Buffer()
+ {
+ data = new unsigned char[Buffer::size()];
+ nbytes = 0;
+ rate = 0;
+ exceeding = 0;
+ }
+ ~Buffer()
+ {
+ delete data;
+ data = 0;
+ nbytes = 0;
+ rate = 0;
+ exceeding = 0;
+ }
+
+ unsigned char *data;
+ unsigned long nbytes;
+ unsigned long rate;
+ unsigned long exceeding;
+
+ static unsigned long size()
+ {
+ return globalBlockSize;
+ }
+};
+
+
+#endif // __buffer_h
+
diff --git a/src/qmmp/constants.h b/src/qmmp/constants.h
new file mode 100644
index 000000000..ee558f3a9
--- /dev/null
+++ b/src/qmmp/constants.h
@@ -0,0 +1,19 @@
+#ifndef CONSTANTS_H
+#define CONSTANTS_H
+
+#ifdef Q_OS_UNIX
+#include "config.h"
+#endif
+
+#define VERSION "0.2.0"
+
+#ifndef LIB_DIR
+#define LIB_DIR "/lib"
+#endif
+
+const unsigned int historySize = 100;
+const unsigned int globalBlockSize = 2 * 1024; //2*1024
+const unsigned int globalBufferSize = globalBlockSize * 32;
+const unsigned int groupOpenTimeout = 750;
+
+#endif // CONSTANTS_H
diff --git a/src/qmmp/decoder.cpp b/src/qmmp/decoder.cpp
new file mode 100644
index 000000000..f2dceba92
--- /dev/null
+++ b/src/qmmp/decoder.cpp
@@ -0,0 +1,409 @@
+// Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com>
+//
+// Use, modification and distribution is allowed without limitation,
+// warranty, or liability of any kind.
+//
+#include <QtGui>
+#include <QObject>
+#include <QStringList>
+#include <QApplication>
+#include <QSettings>
+#include <math.h>
+
+
+#include "effect.h"
+#include "effectfactory.h"
+
+#include "constants.h"
+#include "buffer.h"
+#include "output.h"
+#include "visual.h"
+#include "decoderfactory.h"
+#include "streamreader.h"
+extern "C"
+{
+#include "equ/iir.h"
+}
+#include "decoder.h"
+
+
+Decoder::Decoder(QObject *parent, DecoderFactory *d, QIODevice *i, Output *o)
+ : QThread(parent), fctry(d), in(i), m_output(o),m_eqInited(FALSE),
+ m_useEQ(FALSE)
+{
+ m_output->recycler()->clear();
+ int b[] = {0,0,0,0,0,0,0,0,0,0};
+ setEQ(b, 0);
+ qRegisterMetaType<DecoderState>("DecoderState");
+ blksize = Buffer::size();
+ m_effects = Effect::create(this);
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ m_useVolume = settings.value("Volume/software_volume", FALSE).toBool();
+ m_volL = settings.value("Volume/left", 80).toInt();
+ m_volR = settings.value("Volume/right", 80).toInt();
+}
+
+Decoder::~Decoder()
+{
+ fctry = 0;
+ in = 0;
+ m_output = 0;
+ blksize = 0;
+}
+
+// static methods
+
+static QList<DecoderFactory*> *factories = 0;
+static QStringList files;
+static QStringList blacklist;
+
+static void checkFactories()
+{
+ QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat );
+ blacklist = settings.value("Decoder/disabled_plugins").toStringList ();
+ if (! factories)
+ {
+ files.clear();
+ factories = new QList<DecoderFactory *>;
+
+ QDir pluginsDir (qApp->applicationDirPath());
+ pluginsDir.cdUp();
+ pluginsDir.cd("./"LIB_DIR"/qmmp/Input");
+ foreach (QString fileName, pluginsDir.entryList(QDir::Files))
+ {
+ QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
+ QObject *plugin = loader.instance();
+ if (loader.isLoaded())
+ {
+ qDebug("Decoder: plugin loaded - %s", qPrintable(fileName));
+ }
+ DecoderFactory *factory = 0;
+ if (plugin)
+ factory = qobject_cast<DecoderFactory *>(plugin);
+
+ if (factory)
+ {
+ factories->append(factory);
+ files << pluginsDir.absoluteFilePath(fileName);
+ }
+ }
+ //remove physically deleted plugins from blacklist
+ QStringList names;
+ foreach (QString filePath, files)
+ {
+ names.append(filePath.section('/',-1));
+ }
+ int i = 0;
+ while (i < blacklist.size())
+ {
+ if (!names.contains(blacklist.at(i)))
+ blacklist.removeAt(i);
+ else
+ i++;
+ }
+ settings.setValue("Decoder/disabled_plugins",blacklist);
+ }
+}
+
+
+QStringList Decoder::all()
+{
+ checkFactories();
+
+ QStringList l;
+ DecoderFactory *fact;
+ foreach(fact, *factories)
+ {
+ l << fact->properties().description;
+ }
+ return l;
+}
+
+QStringList Decoder::decoderFiles()
+{
+ checkFactories();
+ return files;
+}
+
+
+bool Decoder::supports(const QString &source)
+{
+ checkFactories();
+
+ for (int i=0; i<factories->size(); ++i)
+ {
+ if (factories->at(i)->supports(source) &&
+ !blacklist.contains(files.at(i).section('/',-1)))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+Decoder *Decoder::create(QObject *parent, const QString &source,
+ QIODevice *input,
+ Output *output)
+{
+ Decoder *decoder = 0;
+ qDebug(qPrintable(source));
+ DecoderFactory *fact = 0;
+
+ if (!input->open(QIODevice::ReadOnly))
+ {
+ qDebug("Decoder: cannot open input");
+ return decoder;
+ }
+ StreamReader* sreader = qobject_cast<StreamReader *>(input);
+ if (sreader)
+ {
+ fact = Decoder::findByMime(sreader->contentType());
+ if (!fact)
+ fact = Decoder::findByContent(sreader);
+ }
+ else
+ fact = Decoder::findByPath(source);
+
+ if (fact)
+ {
+ decoder = fact->create(parent, input, output);
+ }
+ if (!decoder)
+ input->close();
+
+ return decoder;
+}
+
+DecoderFactory *Decoder::findByPath(const QString& source)
+{
+ checkFactories();
+
+ for (int i=0; i<factories->size(); ++i)
+ {
+ if (factories->at(i)->supports(source) &&
+ !blacklist.contains(files.at(i).section('/',-1)))
+ {
+ return factories->at(i);
+ }
+ }
+ qDebug("Decoder: unable to find factory by path");
+ return 0;
+}
+
+DecoderFactory *Decoder::findByMime(const QString& type)
+{
+ checkFactories();
+ for (int i=0; i<factories->size(); ++i)
+ {
+ if (!blacklist.contains(files.at(i).section('/',-1)))
+ {
+ QStringList types = factories->at(i)->properties().contentType.split(";");
+ for (int j=0; j<types.size(); ++j)
+ {
+ if (type == types[j] && !types[j].isEmpty())
+ return factories->at(i);
+ }
+ }
+ }
+ qDebug("Decoder: unable to find factory by mime");
+ return 0;
+}
+
+DecoderFactory *Decoder::findByContent(QIODevice *input)
+{
+ checkFactories();
+
+ for (int i=0; i<factories->size(); ++i)
+ {
+ if (factories->at(i)->canDecode(input) &&
+ !blacklist.contains(files.at(i).section('/',-1)))
+ {
+ return factories->at(i);
+ }
+ }
+ qDebug("Decoder: unable to find factory by content");
+ return 0;
+}
+
+FileTag *Decoder::createTag(const QString& source)
+{
+ DecoderFactory *fact = Decoder::findByPath(source);
+ if (fact && QFile::exists(source))
+ {
+ return fact->createTag(source);
+ }
+ return 0;
+}
+
+QString Decoder::filter()
+{
+ QString allflt(tr("All Supported Bitstreams ("));
+ QString flt;
+
+ checkFactories();
+ DecoderFactory *fact;
+ for (int i = 0; i<factories->size(); ++i)
+ {
+ if (!blacklist.contains(files.at(i).section('/',-1)))
+ {
+ fact = (*factories)[i];
+ allflt +=fact->properties().filter.toLower() +" ";
+ flt += fact->properties().description + " (" + fact->properties().filter + ")";
+ flt += ";;";
+ }
+ }
+ if (!flt.isEmpty ())
+ flt = flt.left(flt.size ()-2);
+
+ allflt += ");;";
+
+ return allflt + flt;
+}
+
+QStringList Decoder::nameFilters()
+{
+ checkFactories();
+ QStringList filters;
+ for (int i=0; i<factories->size(); ++i)
+ {
+ if (!blacklist.contains(files.at(i).section('/',-1)))
+ filters << factories->at(i)->properties().filter.split(" ", QString::SkipEmptyParts);
+ }
+ return filters;
+}
+
+QList<DecoderFactory*> *Decoder::decoderFactories()
+{
+ checkFactories();
+ return factories;
+}
+
+void Decoder::dispatch(const DecoderState &st)
+{
+ emit stateChanged(st);
+}
+
+void Decoder::dispatch(DecoderState::Type st)
+{
+ emit stateChanged(DecoderState(st));
+}
+
+void Decoder::dispatch(const FileTag &tag)
+{
+ emit stateChanged(DecoderState(tag));
+}
+
+void Decoder::error(const QString &e)
+{
+ emit stateChanged(DecoderState(e));
+}
+
+ulong Decoder::produceSound(char *data, ulong output_bytes, ulong bitrate, int nch)
+{
+ ulong sz = output_bytes < blksize ? output_bytes : blksize;
+
+ if (m_useEQ)
+ {
+ if (!m_eqInited)
+ {
+ init_iir();
+ m_eqInited = TRUE;
+ }
+ iir((void*) data,sz,nch);
+ }
+ if (m_useVolume)
+ {
+ changeVolume(data, sz, nch);
+ }
+ char *out_data = data;
+ char *prev_data = data;
+ ulong w = sz;
+ Effect* effect = 0;
+ foreach(effect, m_effects)
+ {
+ w = effect->process(prev_data, sz, &out_data);
+
+ if (w <= 0)
+ {
+ // copy data if plugin can not procees it
+ w = sz;
+ out_data = new char[w];
+ memcpy(out_data, prev_data, w);
+ }
+ if (data != prev_data)
+ delete prev_data;
+ prev_data = out_data;
+ }
+
+ Buffer *b = output()->recycler()->get(w);
+
+ memcpy(b->data, out_data, w);
+
+ if (data != out_data)
+ delete out_data;
+
+ if (w < blksize + b->exceeding)
+ memset(b->data + w, 0, blksize + b->exceeding - w);
+
+ b->nbytes = w;// blksize;
+ b->rate = bitrate;
+
+ output()->recycler()->add();
+
+ output_bytes -= sz;
+ memmove(data, data + sz, output_bytes);
+ return sz;
+}
+
+void Decoder::configure(long freq, int channels, int prec, int bitrate)
+{
+ Effect* effect = 0;
+ foreach(effect, m_effects)
+ {
+ effect->configure(freq, channels, prec);
+ freq = m_effects.at(0)->frequency();
+ channels = effect->channels();
+ prec = effect->resolution();
+ }
+ if (m_output)
+ m_output->configure(freq, channels, prec, bitrate);
+}
+
+void Decoder::setEQ(int bands[10], int preamp)
+{
+ set_preamp(0, 1.0 + 0.0932471 *preamp + 0.00279033 * preamp * preamp);
+ set_preamp(1, 1.0 + 0.0932471 *preamp + 0.00279033 * preamp * preamp);
+ for (int i=0; i<10; ++i)
+ {
+ int value = bands[i];
+ set_gain(i,0, 0.03*value+0.000999999*value*value);
+ set_gain(i,1, 0.03*value+0.000999999*value*value);
+ }
+}
+
+void Decoder::changeVolume(char *data, ulong sz, int channels)
+{
+ int r = pow( 10, (m_volR - 100)/40.0 ) * 256;
+ int l = pow( 10, (m_volL - 100)/40.0 ) * 256;
+ for (ulong i = 0; i < sz/2; i+=2)
+ {
+ ((short*)data)[i]*= r/256.0;
+ ((short*)data)[i+1]*= l/256.0;
+ }
+}
+
+void Decoder::setVolume(int l, int r)
+{
+ mtx.lock();
+ m_volR = l;
+ m_volL = r;
+ mtx.unlock();
+}
+
+void Decoder::volume(int *l, int *r)
+{
+ mtx.lock();
+ *l = m_volL;
+ *r = m_volR;
+ mtx.unlock();
+}
diff --git a/src/qmmp/decoder.h b/src/qmmp/decoder.h
new file mode 100644
index 000000000..31d96cc6d
--- /dev/null
+++ b/src/qmmp/decoder.h
@@ -0,0 +1,197 @@
+// Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com>
+//
+// Use, modification and distribution is allowed without limitation,
+// warranty, or liability of any kind.
+//
+
+#ifndef DECODER_H
+#define DECODER_H
+
+#include <QThread>
+#include <QList>
+#include <QMutex>
+#include <QWaitCondition>
+#include <QObject>
+#include <QStringList>
+
+#include "filetag.h"
+
+class QObject;
+class QIODevice;
+
+class Decoder;
+class DecoderFactory;
+class Buffer;
+class Recycler;
+class Output;
+class Visualization;
+class Effect;
+
+
+
+class DecoderState
+{
+public:
+ enum Type { Decoding, Stopped, Finished, Info, Error };
+
+ DecoderState(const DecoderState &st)
+ : m_error_msg(0), m_tag(0)
+ {
+ m_type = st.type();
+ if (m_type == Info)
+ m_tag = new FileTag(*st.tag());
+ else if (m_type == Error)
+ m_error_msg = new QString(*st.errorMessage());
+ }
+
+
+ DecoderState(Type t)
+ : m_type(t), m_error_msg(0), m_tag(0)
+{}
+
+ DecoderState(const QString &e)
+ : m_type(Error), m_tag(0)
+ {
+ m_error_msg = new QString(e);
+ }
+
+ DecoderState()
+ : m_type(Stopped), m_error_msg(0), m_tag(0)
+ {}
+
+ DecoderState(const FileTag &tag)
+ : m_type(Info), m_error_msg(0), m_tag(0)
+ {
+ m_tag = new FileTag(tag);
+ }
+
+ ~DecoderState()
+ {
+ if (m_error_msg)
+ delete m_error_msg;
+ if (m_tag)
+ delete m_tag;
+ }
+
+ const QString *errorMessage() const
+ {
+ return m_error_msg;
+ }
+ const Type &type() const
+ {
+ return m_type;
+ }
+ const FileTag *tag() const
+ {
+ return m_tag;
+ }
+
+private:
+ Type m_type;
+ const QString *m_error_msg;
+ FileTag *m_tag;
+};
+
+
+
+class Decoder : public QThread
+{
+ Q_OBJECT
+public:
+ Decoder(QObject *parent, DecoderFactory *d,
+ QIODevice *i, Output *o);
+ virtual ~Decoder();
+
+ // Standard Decoder API
+ virtual bool initialize() = 0;
+ virtual double lengthInSeconds() = 0;
+ virtual void seek(double) = 0;
+ virtual void stop() = 0;
+
+ DecoderFactory *factory() const
+ {
+ return fctry;
+ }
+
+ QIODevice *input()
+ {
+ return in;
+ }
+ Output *output()
+ {
+ return m_output;
+ }
+
+ QMutex *mutex()
+ {
+ return &mtx;
+ }
+ QWaitCondition *cond()
+ {
+ return &cnd;
+ }
+
+ void setBlockSize(unsigned int sz)
+ {
+ blksize = sz;
+ }
+
+ unsigned int blockSize() const
+ {
+ return blksize;
+ }
+ ulong produceSound(char *data, ulong output_bytes, ulong bitrate, int nch);
+ void setEQ(int bands[10], int preamp);
+ void setEQEnabled(bool on)
+ {
+ m_useEQ = on;
+ };
+ void setVolume(int, int);
+
+ void volume(int*, int*);
+
+ // static methods
+ static QStringList all();
+ static bool supports(const QString &);
+ //static void registerFactory(DecoderFactory *);
+ static Decoder *create(QObject *, const QString &, QIODevice *, Output *);
+ static DecoderFactory *findByPath(const QString&);
+ static DecoderFactory *findByMime(const QString&);
+ static DecoderFactory *findByContent(QIODevice *);
+ static FileTag *createTag(const QString&);
+ static QString filter();
+ static QStringList nameFilters();
+ static QList<DecoderFactory*> *decoderFactories();
+ static QStringList decoderFiles();
+
+signals:
+ void stateChanged(const DecoderState&);
+
+protected:
+ void configure(long freq, int channels, int prec, int bitrate);
+ void dispatch(DecoderState::Type);
+ void dispatch(const DecoderState&);
+ void dispatch(const FileTag&);
+ void error(const QString&);
+
+private:
+ DecoderFactory *fctry;
+ void changeVolume(char *data, ulong sz, int channels);
+
+ QList <Effect*> m_effects;
+ QIODevice *in;
+ Output *m_output;
+
+ QMutex mtx;
+ QWaitCondition cnd;
+
+ uint blksize;
+ bool m_eqInited;
+ bool m_useEQ;
+ bool m_useVolume;
+ int m_volL;
+ int m_volR;
+
+};
+
+#endif // DECODER_H
diff --git a/src/qmmp/decoderfactory.h b/src/qmmp/decoderfactory.h
new file mode 100644
index 000000000..d67d1b564
--- /dev/null
+++ b/src/qmmp/decoderfactory.h
@@ -0,0 +1,64 @@
+
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef DECODERFACTORY_H
+#define DECODERFACTORY_H
+
+class QObject;
+class QString;
+class QIODevice;
+class QWidget;
+class QTranslator;
+
+class Decoder;
+class Output;
+class FileTag;
+
+struct DecoderProperties
+{
+ QString name;
+ QString filter;
+ QString description;
+ QString contentType;
+ bool hasAbout;
+ bool hasSettings;
+ //bool streamSupport;
+ //bool needInput;
+};
+
+class DecoderFactory
+{
+public:
+ virtual ~DecoderFactory() {}
+ virtual bool supports(const QString &source) const = 0;
+ virtual bool canDecode(QIODevice *) const = 0;
+ virtual const DecoderProperties properties() const = 0;
+ virtual Decoder *create(QObject *, QIODevice *, Output *) = 0;
+ virtual FileTag *createTag(const QString &source) = 0;
+ virtual QObject* showDetails(QWidget *parent, const QString &path) = 0;
+ virtual void showSettings(QWidget *parent) = 0;
+ virtual void showAbout(QWidget *parent) = 0;
+ virtual QTranslator *createTranslator(QObject *parent) = 0;
+};
+
+Q_DECLARE_INTERFACE(DecoderFactory, "DecoderFactory/1.0");
+
+#endif
diff --git a/src/qmmp/downloader.cpp b/src/qmmp/downloader.cpp
new file mode 100644
index 000000000..5b091b640
--- /dev/null
+++ b/src/qmmp/downloader.cpp
@@ -0,0 +1,344 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QApplication>
+#include <QStringList>
+#include <QSettings>
+#include <QDir>
+
+#include "downloader.h"
+
+//curl callbacks
+static size_t curl_write_data(void *data, size_t size, size_t nmemb,
+ void *pointer)
+{
+ Downloader *dl = (Downloader *)pointer;
+ dl->mutex()->lock ();
+ size_t buf_start = dl->stream()->buf_fill;
+ size_t data_size = size * nmemb;
+ dl->stream()->buf_fill += data_size;
+
+ dl->stream()->buf = (char *)realloc (dl->stream()->buf, dl->stream()->buf_fill);
+ memcpy (dl->stream()->buf + buf_start, data, data_size);
+ dl->mutex()->unlock();
+ dl->checkBuffer();
+ return data_size;
+}
+
+static size_t curl_header(void *data, size_t size, size_t nmemb,
+ void *pointer)
+{
+ Downloader *dl = (Downloader *)pointer;
+ dl->mutex()->lock ();
+ size_t data_size = size * nmemb;
+ if (data_size < 3)
+ {
+ dl->mutex()->unlock();
+ return data_size;
+ }
+
+ //qDebug("header received: %s", (char*) data);
+ QString str = QString::fromAscii((char *) data, data_size);
+ str = str.trimmed ();
+ if (str.left(4).contains("HTTP"))
+ {
+ qDebug("Downloader: header received");
+ //TODO open metadata socket
+ }
+ else if (str.left(4).contains("ICY"))
+ {
+ qDebug("Downloader: shoutcast header received");
+ //dl->stream()->icy_meta_data = TRUE;
+ }
+ else
+ {
+ QString key = str.left(str.indexOf(":")).trimmed().toLower();
+ QString value = str.right(str.size() - str.indexOf(":") - 1).trimmed().toLower();
+ dl->stream()->header.insert(key, value);
+ qDebug("Downloader: key=%s, value=%s",qPrintable(key),qPrintable(value));
+
+ if (key == "icy-metaint")
+ {
+ dl->stream()->icy_metaint = value.toInt();
+ dl->stream()->icy_meta_data = TRUE;
+ }
+ }
+ dl->mutex()->unlock();
+ return data_size;
+}
+
+int curl_progress(void *pointer, double dltotal, double dlnow, double ultotal, double ulnow)
+{
+ Downloader *dl = (Downloader *)pointer;
+ dl->mutex()->lock ();
+ bool aborted = dl->stream()->aborted;
+ dl->mutex()->unlock();
+ if (aborted)
+ return -1;
+ return 0;
+}
+
+Downloader::Downloader(QObject *parent, const QString &url)
+ : QThread(parent)
+{
+ m_url = url;
+ curl_global_init(CURL_GLOBAL_ALL);
+ m_stream.buf_fill = 0;
+ m_stream.buf = 0;
+ m_stream.icy_meta_data = FALSE;
+ m_stream.aborted = TRUE;
+ m_stream.icy_metaint = 0;
+ m_handle = 0;
+ m_metacount = 0;
+}
+
+
+Downloader::~Downloader()
+{
+ abort();
+ curl_global_cleanup();
+}
+
+
+qint64 Downloader::read(char* data, qint64 maxlen)
+{
+
+ qint64 len = 0;
+ m_mutex.lock();
+ if (!m_stream.icy_meta_data || m_stream.icy_metaint == 0)
+ len = readBuffer(data, maxlen);
+ else
+ {
+ qint64 nread = 0;
+ qint64 to_read;
+ while (maxlen > nread && m_stream.buf_fill > nread)
+ {
+ to_read = qMin<qint64>(m_stream.icy_metaint - m_metacount, maxlen - nread);
+ //to_read = (maxlen - nread);
+ qint64 res = readBuffer(data + nread, to_read);
+ nread += res;
+ m_metacount += res;
+ if (m_metacount == m_stream.icy_metaint)
+ {
+ m_metacount = 0;
+ m_mutex.unlock();
+ readICYMetaData();
+ m_mutex.lock();
+ }
+
+ }
+ len = nread;
+
+ }
+ m_mutex.unlock();
+ return len;
+}
+
+Stream *Downloader::stream()
+{
+ return &m_stream;
+}
+
+QMutex *Downloader::mutex()
+{
+ return &m_mutex;
+}
+
+QString Downloader::contentType()
+{
+ QString content;
+ if (m_stream.header.contains("content-type"))
+ content = m_stream.header.value("content-type");
+ return content;
+}
+
+void Downloader::abort()
+{
+ m_mutex.lock();
+
+ if (m_stream.aborted)
+ {
+ m_mutex.unlock();
+ return;
+ }
+ m_stream.aborted = TRUE;
+ m_mutex.unlock();
+ wait();
+ if (m_handle)
+ {
+ curl_easy_cleanup(m_handle);
+ m_handle = 0;
+ }
+}
+
+int Downloader::bytesAvailable()
+{
+ m_mutex.lock();
+ int b = m_stream.buf_fill;
+ m_mutex.unlock();
+ return b;
+}
+
+void Downloader::run()
+{
+ qDebug("Downloader: starting download thread");
+ m_handle = curl_easy_init();
+ //proxy
+ QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat );
+ if (settings.value ("Proxy/use_proxy", FALSE).toBool())
+ curl_easy_setopt(m_handle, CURLOPT_PROXY,
+ strdup((settings.value("Proxy/host").toString()+":"+
+ settings.value("Proxy/port").toString()).
+ toLatin1 ().constData ()));
+
+ if (settings.value ("Proxy/authentication", FALSE).toBool())
+ curl_easy_setopt(m_handle, CURLOPT_PROXYUSERPWD,
+ strdup((settings.value("Proxy/user").toString()+":"+
+ settings.value("Proxy/passw").toString()).
+ toLatin1 ().constData ()));
+
+ // Set url to download
+ curl_easy_setopt(m_handle, CURLOPT_URL, strdup(m_url.toAscii().constData()));
+ // callback for wrting
+ curl_easy_setopt(m_handle, CURLOPT_WRITEFUNCTION, curl_write_data);
+ // Set destination file
+ curl_easy_setopt(m_handle, CURLOPT_WRITEDATA, this);
+ curl_easy_setopt(m_handle, CURLOPT_HEADERDATA, this);
+ curl_easy_setopt(m_handle, CURLOPT_HEADERFUNCTION, curl_header);
+ // Disable SSL
+ curl_easy_setopt(m_handle, CURLOPT_SSL_VERIFYPEER, FALSE);
+ curl_easy_setopt(m_handle, CURLOPT_SSL_VERIFYHOST, 0);
+ // Enable progress meter
+ curl_easy_setopt(m_handle, CURLOPT_NOPROGRESS, 0);
+ curl_easy_setopt(m_handle, CURLOPT_PROGRESSDATA, this);
+ curl_easy_setopt(m_handle, CURLOPT_PROGRESSFUNCTION, curl_progress);
+ // Any kind of authentication
+ curl_easy_setopt(m_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
+ curl_easy_setopt(m_handle, CURLOPT_VERBOSE, 1);
+ // Auto referrer
+ curl_easy_setopt(m_handle, CURLOPT_AUTOREFERER, 1);
+ // Follow redirections
+ curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, 1);
+ curl_easy_setopt(m_handle, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt(m_handle, CURLOPT_MAXREDIRS, 15);
+ // user agent
+ curl_easy_setopt(m_handle, CURLOPT_USERAGENT, "qmmp/0.2");
+ curl_easy_setopt(m_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+
+ struct curl_slist *http200_aliases = curl_slist_append(NULL, "ICY");
+ struct curl_slist *http_headers = curl_slist_append(NULL, "Icy-MetaData: 1");
+ curl_easy_setopt(m_handle, CURLOPT_HTTP200ALIASES, http200_aliases);
+ curl_easy_setopt(m_handle, CURLOPT_HTTPHEADER, http_headers);
+ m_mutex.lock();
+ m_stream.buf_fill = 0;
+ m_stream.buf = 0;
+ m_stream.aborted = FALSE;
+ m_stream.header.clear ();
+ m_ready = FALSE;
+ int return_code;
+ qDebug("Downloader: starting libcurl");
+ m_mutex.unlock();
+ return_code = curl_easy_perform(m_handle);
+ qDebug("curl_easy_perform %d", return_code);
+
+ m_mutex.lock();
+ m_stream.aborted = TRUE;
+ m_stream.buf_fill = 0;
+ if (m_stream.buf)
+ delete m_stream.buf;
+ m_stream.buf = 0;
+ m_mutex.unlock();
+ qDebug("Downloader: thread exited");
+}
+
+qint64 Downloader::readBuffer(char* data, qint64 maxlen)
+{
+ if (m_stream.buf_fill > 0 && !m_stream.aborted)
+ {
+ int len = qMin<qint64>(m_stream.buf_fill, maxlen);
+ memcpy(data, m_stream.buf, len);
+ m_stream.buf_fill -= len;
+ memmove(m_stream.buf, m_stream.buf + len, m_stream.buf_fill);
+ return len;
+ }
+ return 0;
+}
+
+const QString &Downloader::title() const
+{
+ return m_title;
+}
+
+void Downloader::checkBuffer()
+{
+ if(m_stream.buf_fill > BUFFER_SIZE && !m_ready)
+ {
+ m_ready = TRUE;
+ qDebug("Downloader: ready");
+ emit readyRead();
+ }
+
+}
+
+bool Downloader::isReady()
+{
+ return m_ready;
+}
+
+void Downloader::readICYMetaData()
+{
+ uint8_t packet_size;
+ m_metacount = 0;
+ m_mutex.lock();
+ readBuffer((char *)&packet_size, sizeof(packet_size));
+ if (packet_size != 0)
+ {
+ int size = packet_size * 16;
+ char packet[size];
+ while (m_stream.buf_fill < size && isRunning())
+ {
+ m_mutex.unlock();
+ qApp->processEvents();
+ m_mutex.lock();
+ }
+ readBuffer(packet, size);
+ qDebug("Downloader: ICY metadata: %s", packet);
+ parseICYMetaData(packet);
+ }
+ m_mutex.unlock();
+
+}
+
+void Downloader::parseICYMetaData(char *data)
+{
+ QString str(data);
+ QStringList list(str.split(";", QString::SkipEmptyParts));
+ foreach(QString line, list)
+ {
+ if (line.contains("StreamTitle="))
+ {
+ line = line.right(line.size() - line.indexOf("=") - 1).trimmed();
+ m_title = line.remove("'");
+ if(!m_title.isEmpty())
+ emit titleChanged ();
+ break;
+ }
+ }
+}
diff --git a/src/qmmp/downloader.h b/src/qmmp/downloader.h
new file mode 100644
index 000000000..05175e379
--- /dev/null
+++ b/src/qmmp/downloader.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef DOWNLOADER_H
+#define DOWNLOADER_H
+
+#include <QThread>
+#include <QMutex>
+#include <QByteArray>
+#include <QMap>
+
+#include <curl/curl.h>
+
+#define BUFFER_SIZE 128000
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+
+struct Stream
+{
+ char *buf;
+ int buf_fill;
+ QString content_type;
+ bool aborted;
+ QMap <QString, QString> header;
+ bool icy_meta_data;
+ int icy_metaint;
+};
+
+class Downloader : public QThread
+{
+ Q_OBJECT
+public:
+ Downloader(QObject *parent, const QString &url);
+
+ ~Downloader();
+
+ qint64 read(char* data, qint64 maxlen);
+ Stream *stream();
+ QMutex *mutex();
+ QString contentType();
+ void abort();
+ int bytesAvailable();
+ const QString& title() const;
+ void checkBuffer();
+ bool isReady();
+
+signals:
+ void titleChanged();
+ void readyRead();
+
+private:
+ qint64 readBuffer(char* data, qint64 maxlen);
+ void readICYMetaData();
+ void parseICYMetaData(char *data);
+ CURL *m_handle;
+ QMutex m_mutex;
+ Stream m_stream;
+ QString m_url;
+ int m_metacount;
+ QString m_title;
+ bool m_ready;
+
+protected:
+ void run();
+
+};
+
+#endif
diff --git a/src/qmmp/effect.cpp b/src/qmmp/effect.cpp
new file mode 100644
index 000000000..c6d3ba0fb
--- /dev/null
+++ b/src/qmmp/effect.cpp
@@ -0,0 +1,148 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include <QtGui>
+#include <QStringList>
+#include <QDir>
+#include <QApplication>
+
+#include "effectfactory.h"
+#include "constants.h"
+#include "effect.h"
+
+Effect::Effect(QObject *parent)
+ : QObject(parent)
+{}
+
+Effect::~Effect()
+{}
+
+void Effect::configure(ulong freq, int chan, int res)
+{
+ m_freq = freq;
+ m_chan = chan;
+ m_res = res;
+
+}
+
+const ulong Effect::frequency()
+{
+ return m_freq;
+}
+
+const int Effect::channels()
+{
+ return m_chan;
+}
+
+const int Effect::resolution()
+{
+ return m_res;
+}
+
+static QList<EffectFactory*> *factories = 0;
+static QStringList files;
+
+static void checkFactories()
+{
+ if (! factories)
+ {
+ files.clear();
+ factories = new QList<EffectFactory *>;
+
+ QDir pluginsDir (qApp->applicationDirPath());
+ pluginsDir.cdUp();
+ pluginsDir.cd("./"LIB_DIR"/qmmp/Effect");
+ foreach (QString fileName, pluginsDir.entryList(QDir::Files))
+ {
+ QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
+ QObject *plugin = loader.instance();
+ if (loader.isLoaded())
+ {
+ qDebug("Effect: plugin loaded - %s", qPrintable(fileName));
+ }
+ EffectFactory *factory = 0;
+ if (plugin)
+ factory = qobject_cast<EffectFactory *>(plugin);
+
+ if (factory)
+ {
+ factories->append(factory);
+ files << pluginsDir.absoluteFilePath(fileName);
+ }
+ }
+ }
+}
+
+QList<Effect*> Effect::create(QObject *parent)
+{
+ checkFactories();
+ QList<Effect*> effects;
+ EffectFactory *factory = 0;
+ foreach (factory, *factories)
+ {
+ if(isEnabled(factory))
+ effects.append(factory->create(parent));
+ }
+ return effects;
+}
+
+QList<EffectFactory*> *Effect::effectFactories()
+{
+ checkFactories();
+ return factories;
+}
+
+QStringList Effect::effectFiles()
+{
+ checkFactories();
+ return files;
+}
+
+void Effect::setEnabled(EffectFactory* factory, bool enable)
+{
+ checkFactories();
+ if(!factories->contains(factory))
+ return;
+
+ QString name = files.at(factories->indexOf(factory)).section('/',-1);
+ QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat );
+ QStringList effList = settings.value("Effect/plugin_files").toStringList();
+
+ if(enable)
+ {
+ if (!effList.contains(name))
+ effList << name;
+ }
+ else
+ effList.removeAll(name);
+ settings.setValue("Effect/plugin_files", effList);
+}
+
+bool Effect::isEnabled(EffectFactory* factory)
+{
+ checkFactories();
+ if(!factories->contains(factory))
+ return FALSE;
+ QString name = files.at(factories->indexOf(factory)).section('/',-1);
+ QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat );
+ QStringList effList = settings.value("Effect/plugin_files").toStringList();
+ return effList.contains(name);
+}
+
diff --git a/src/qmmp/effect.h b/src/qmmp/effect.h
new file mode 100644
index 000000000..654c1c2b6
--- /dev/null
+++ b/src/qmmp/effect.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef EFFECT_H
+#define EFFECT_H
+
+#include <QObject>
+#include <QList>
+#include <QStringList>
+
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+
+class EffectFactory;
+
+class Effect : public QObject
+{
+ Q_OBJECT
+public:
+ Effect(QObject *parent = 0);
+
+ virtual ~Effect();
+
+ /*/*!
+ * Adds effect to the input data pointer \b in_data with the size \b size.
+ * Result is stored in the output data \b out_data.
+ * Return value is the size of the output data. Output data size should not be more then \b size.
+ * Subclass should implement this function.
+ */
+ virtual const ulong process(char *in_data, const ulong size, char **out_data) = 0;
+
+ //virtual const ulong process(char *in_data, const ulong size, char *out_data) = 0;
+ //virtual bool process(char *in_data, char *out_data, const ulong maxsize, ulong &rbytes, ulong &wbytes) = 0;
+
+
+ virtual void configure(ulong freq, int chan, int res);
+
+ /*!
+ * Returns frequency.
+ * This function should be reimplemented if subclass changes default samplerate.
+ */
+ virtual const ulong frequency();
+
+ /*!
+ * Returns channel number.
+ * This function should be reimplemented if subclass changes default channel number.
+ */
+ virtual const int channels();
+
+ /*!
+ * Returns resolution.
+ * This function should be reimplemented if subclass changes default resolution.
+ */
+ virtual const int resolution();
+
+
+ static QList<Effect*> create(QObject *parent);
+ static QList<EffectFactory*> *effectFactories();
+ static QStringList effectFiles();
+ static void setEnabled(EffectFactory* factory, bool enable = TRUE);
+ static bool isEnabled(EffectFactory* factory);
+
+private:
+ ulong m_freq;
+ int m_chan;
+ int m_res;
+};
+
+#endif
diff --git a/src/qmmp/effectfactory.h b/src/qmmp/effectfactory.h
new file mode 100644
index 000000000..96354cf6e
--- /dev/null
+++ b/src/qmmp/effectfactory.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef EFFECTFACTORY_H
+#define EFFECTFACTORY_H
+
+#include <QObject>
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class QObject;
+class QWidget;
+class QTranslator;
+
+class Effect;
+
+struct EffectProperties
+{
+ QString name;
+ bool hasAbout;
+ bool hasSettings;
+};
+
+class EffectFactory
+{
+public:
+ virtual const EffectProperties properties() const = 0;
+ virtual Effect *create(QObject *parent) = 0;
+ virtual void showSettings(QWidget *parent) = 0;
+ virtual void showAbout(QWidget *parent) = 0;
+ virtual QTranslator *createTranslator(QObject *parent) = 0;
+};
+
+Q_DECLARE_INTERFACE(EffectFactory, "EffectFactory/1.0");
+
+#endif
diff --git a/src/qmmp/equ/iir.c b/src/qmmp/equ/iir.c
new file mode 100644
index 000000000..9d826b86c
--- /dev/null
+++ b/src/qmmp/equ/iir.c
@@ -0,0 +1,85 @@
+/*
+ * PCM time-domain equalizer
+ *
+ * Copyright (C) 2002-2005 Felipe Rivera <liebremx at 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: iir.c,v 1.15 2005/10/17 01:57:59 liebremx Exp $
+ */
+
+#include <math.h>
+#include "iir.h"
+
+/* Coefficients */
+sIIRCoefficients *iir_cf;
+
+/* Volume gain
+ * values should be between 0.0 and 1.0
+ * Use the preamp from XMMS for now
+ * */
+float preamp[EQ_CHANNELS];
+
+#ifdef BENCHMARK
+#include "benchmark.h"
+double timex = 0.0;
+int count = 0;
+unsigned int blength = 0;
+#endif
+
+/*
+ * Global vars
+ */
+int rate;
+int band_count;
+
+void set_preamp(int chn, float val)
+{
+ preamp[chn] = val;
+}
+
+/* Init the filters */
+void init_iir()
+{
+ calc_coeffs();
+#if 0
+ band_count = cfg.band_num;
+#endif
+
+ band_count = 10;
+
+ rate = 44100;
+
+ iir_cf = get_coeffs(&band_count, rate);
+ clean_history();
+}
+
+#ifdef ARCH_X86
+/* Round function provided by Frank Klemm which saves around 100K
+ * CPU cycles in my PIII for each call to the IIR function with 4K samples
+ */
+__inline__ int round_trick(float floatvalue_to_round)
+{
+ float floattmp ;
+ int rounded_value ;
+
+ floattmp = (int) 0x00FD8000L + (floatvalue_to_round);
+ rounded_value = *(int*)(&floattmp) - (int)0x4B7D8000L;
+
+ if ( rounded_value != (short) rounded_value )
+ rounded_value = ( rounded_value >> 31 ) ^ 0x7FFF;
+ return rounded_value;
+}
+#endif
diff --git a/src/qmmp/equ/iir.h b/src/qmmp/equ/iir.h
new file mode 100644
index 000000000..e7ea5ef1a
--- /dev/null
+++ b/src/qmmp/equ/iir.h
@@ -0,0 +1,84 @@
+/*
+ * PCM time-domain equalizer
+ *
+ * Copyright (C) 2002-2005 Felipe Rivera <liebremx at 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: iir.h,v 1.12 2005/10/17 01:57:59 liebremx Exp $
+ */
+#ifndef IIR_H
+#define IIR_H
+
+//#include <glib.h>
+//#include "main.h"
+#include "iir_cfs.h"
+
+/*
+ * Flush-to-zero to avoid flooding the CPU with underflow exceptions
+ */
+#ifdef SSE_MATH
+#define FTZ 0x8000
+#define FTZ_ON { \
+ unsigned int mxcsr; \
+ __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr)); \
+ mxcsr |= FTZ; \
+ __asm__ __volatile__ ("ldmxcsr %0" : : "m" (*&mxcsr)); \
+}
+#define FTZ_OFF { \
+ unsigned int mxcsr; \
+ __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr)); \
+ mxcsr &= ~FTZ; \
+ __asm__ __volatile__ ("ldmxcsr %0" : : "m" (*&mxcsr)); \
+}
+#else
+#define FTZ_ON
+#define FTZ_OFF
+#endif
+
+/*
+ * Function prototypes
+ */
+void init_iir();
+void clean_history();
+void set_gain(int index, int chn, float val);
+void set_preamp(int chn, float val);
+
+
+ int iir(void * d, int length, int nch);
+
+#ifdef ARCH_X86
+__inline__ int round_trick(float floatvalue_to_round);
+#endif
+#ifdef ARCH_PPC
+__inline__ int round_ppc(float x);
+#endif
+
+#define EQ_CHANNELS 2
+#define EQ_MAX_BANDS 10
+
+extern float preamp[EQ_CHANNELS];
+extern sIIRCoefficients *iir_cf;
+extern int rate;
+extern int band_count;
+
+#ifdef BENCHMARK
+extern double timex;
+extern int count;
+extern unsigned int blength;
+#endif
+
+#endif /* #define IIR_H */
+
diff --git a/src/qmmp/equ/iir_cfs.c b/src/qmmp/equ/iir_cfs.c
new file mode 100644
index 000000000..f8e6f88a6
--- /dev/null
+++ b/src/qmmp/equ/iir_cfs.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2002-2005 Felipe Rivera <liebremx at 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Coefficient stuff
+ *
+ * $Id: iir_cfs.c,v 1.1 2005/10/17 01:57:59 liebremx Exp $
+ */
+
+#include "iir_cfs.h"
+#include <stdio.h>
+#include <math.h>
+
+/***************************
+ * IIR filter coefficients *
+ ***************************/
+static sIIRCoefficients iir_cf10_11k_11025[10] __attribute__((aligned));
+static sIIRCoefficients iir_cf10_22k_22050[10] __attribute__((aligned));
+static sIIRCoefficients iir_cforiginal10_44100[10] __attribute__((aligned));
+static sIIRCoefficients iir_cforiginal10_48000[10] __attribute__((aligned));
+static sIIRCoefficients iir_cf10_44100[10] __attribute__((aligned));
+static sIIRCoefficients iir_cf10_48000[10] __attribute__((aligned));
+static sIIRCoefficients iir_cf15_44100[15] __attribute__((aligned));
+static sIIRCoefficients iir_cf15_48000[15] __attribute__((aligned));
+static sIIRCoefficients iir_cf25_44100[25] __attribute__((aligned));
+static sIIRCoefficients iir_cf25_48000[25] __attribute__((aligned));
+static sIIRCoefficients iir_cf31_44100[31] __attribute__((aligned));
+static sIIRCoefficients iir_cf31_48000[31] __attribute__((aligned));
+
+/******************************************************************
+ * Definitions and data structures to calculate the coefficients
+ ******************************************************************/
+static const double band_f011k[] =
+{ 31, 62, 125, 250, 500, 1000, 2000, 3000, 4000, 5500
+};
+static const double band_f022k[] =
+{ 31, 62, 125, 250, 500, 1000, 2000, 4000, 8000, 11000
+};
+static const double band_f010[] =
+{ 31, 62, 125, 250, 500, 1000, 2000, 4000, 8000, 16000
+};
+static const double band_original_f010[] =
+{ 60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000
+};
+static const double band_f015[] =
+{ 25,40,63,100,160,250,400,630,1000,1600,2500,4000,6300,10000,16000
+};
+static const double band_f025[] =
+{ 20,31.5,40,50,80,100,125,160,250,315,400,500,800,
+ 1000,1250,1600,2500,3150,4000,5000,8000,10000,12500,16000,20000
+};
+static const double band_f031[] =
+{ 20,25,31.5,40,50,63,80,100,125,160,200,250,315,400,500,630,800,
+ 1000,1250,1600,2000,2500,3150,4000,5000,6300,8000,10000,12500,16000,20000
+};
+
+#define GAIN_F0 1.0
+#define GAIN_F1 GAIN_F0 / M_SQRT2
+
+#define SAMPLING_FREQ 44100.0
+#define TETA(f) (2*M_PI*(double)f/bands[n].sfreq)
+#define TWOPOWER(value) (value * value)
+
+#define BETA2(tf0, tf) \
+(TWOPOWER(GAIN_F1)*TWOPOWER(cos(tf0)) \
+ - 2.0 * TWOPOWER(GAIN_F1) * cos(tf) * cos(tf0) \
+ + TWOPOWER(GAIN_F1) \
+ - TWOPOWER(GAIN_F0) * TWOPOWER(sin(tf)))
+#define BETA1(tf0, tf) \
+ (2.0 * TWOPOWER(GAIN_F1) * TWOPOWER(cos(tf)) \
+ + TWOPOWER(GAIN_F1) * TWOPOWER(cos(tf0)) \
+ - 2.0 * TWOPOWER(GAIN_F1) * cos(tf) * cos(tf0) \
+ - TWOPOWER(GAIN_F1) + TWOPOWER(GAIN_F0) * TWOPOWER(sin(tf)))
+#define BETA0(tf0, tf) \
+ (0.25 * TWOPOWER(GAIN_F1) * TWOPOWER(cos(tf0)) \
+ - 0.5 * TWOPOWER(GAIN_F1) * cos(tf) * cos(tf0) \
+ + 0.25 * TWOPOWER(GAIN_F1) \
+ - 0.25 * TWOPOWER(GAIN_F0) * TWOPOWER(sin(tf)))
+
+#define GAMMA(beta, tf0) ((0.5 + beta) * cos(tf0))
+#define ALPHA(beta) ((0.5 - beta)/2.0)
+
+struct {
+ sIIRCoefficients *coeffs;
+ const double *cfs;
+ double octave;
+ int band_count;
+ double sfreq;
+} bands[] = {
+ { iir_cf10_11k_11025, band_f011k, 1.0, 10, 11025.0 },
+ { iir_cf10_22k_22050, band_f022k, 1.0, 10, 22050.0 },
+ { iir_cforiginal10_44100, band_original_f010, 1.0, 10, 44100.0 },
+ { iir_cforiginal10_48000, band_original_f010, 1.0, 10, 48000.0 },
+ { iir_cf10_44100, band_f010, 1.0, 10, 44100.0 },
+ { iir_cf10_48000, band_f010, 1.0, 10, 48000.0 },
+ { iir_cf15_44100, band_f015, 2.0/3.0, 15, 44100.0 },
+ { iir_cf15_48000, band_f015, 2.0/3.0, 15, 48000.0 },
+ { iir_cf25_44100, band_f025, 1.0/3.0, 25, 44100.0 },
+ { iir_cf25_48000, band_f025, 1.0/3.0, 25, 48000.0 },
+ { iir_cf31_44100, band_f031, 1.0/3.0, 31, 44100.0 },
+ { iir_cf31_48000, band_f031, 1.0/3.0, 31, 48000.0 },
+ { 0, 0, 0, 0, 0 }
+};
+
+/*************
+ * Functions *
+ *************/
+
+/* Get the coeffs for a given number of bands and sampling frequency */
+sIIRCoefficients* get_coeffs(int *bands, int sfreq)
+{
+ sIIRCoefficients *iir_cf = 0;
+ switch(sfreq)
+ {
+ case 11025: iir_cf = iir_cf10_11k_11025;
+ *bands = 10;
+ break;
+ case 22050: iir_cf = iir_cf10_22k_22050;
+ *bands = 10;
+ break;
+ case 48000:
+ switch(*bands)
+ {
+ case 31: iir_cf = iir_cf31_48000; break;
+ case 25: iir_cf = iir_cf25_48000; break;
+ case 15: iir_cf = iir_cf15_48000; break;
+ default:
+ /*iir_cf = use_xmms_original_freqs ?
+ iir_cforiginal10_48000 :
+ iir_cf10_48000;*/
+ iir_cf = iir_cforiginal10_48000;
+ break;
+ }
+ break;
+ default:
+ switch(*bands)
+ {
+ case 31: iir_cf = iir_cf31_44100; break;
+ case 25: iir_cf = iir_cf25_44100; break;
+ case 15: iir_cf = iir_cf15_44100; break;
+ default:
+ /*iir_cf = use_xmms_original_freqs ?
+ iir_cforiginal10_44100 :
+ iir_cf10_44100;*/
+ iir_cf = iir_cforiginal10_44100;
+ break;
+ }
+ break;
+ }
+ return iir_cf;
+}
+
+/* Get the freqs at both sides of F0. These will be cut at -3dB */
+static void find_f1_and_f2(double f0, double octave_percent, double *f1, double *f2)
+{
+ double octave_factor = pow(2.0, octave_percent/2.0);
+ *f1 = f0/octave_factor;
+ *f2 = f0*octave_factor;
+}
+
+/* Find the quadratic root
+ * Always return the smallest root */
+static int find_root(double a, double b, double c, double *x0) {
+ double k = c-((b*b)/(4.*a));
+ double h = -(b/(2.*a));
+ double x1 = 0.;
+ if (-(k/a) < 0.)
+ return -1;
+ *x0 = h - sqrt(-(k/a));
+ x1 = h + sqrt(-(k/a));
+ if (x1 < *x0)
+ *x0 = x1;
+ return 0;
+}
+
+/* Calculate all the coefficients as specified in the bands[] array */
+void calc_coeffs()
+{
+ int i, n;
+ double f1, f2;
+ double x0;
+
+ n = 0;
+ for (; bands[n].cfs; n++) {
+ double *freqs = (double *)bands[n].cfs;
+ for (i=0; i<bands[n].band_count; i++)
+ {
+
+ /* Find -3dB frequencies for the center freq */
+ find_f1_and_f2(freqs[i], bands[n].octave, &f1, &f2);
+ /* Find Beta */
+ if ( find_root(
+ BETA2(TETA(freqs[i]), TETA(f1)),
+ BETA1(TETA(freqs[i]), TETA(f1)),
+ BETA0(TETA(freqs[i]), TETA(f1)),
+ &x0) == 0)
+ {
+ /* Got a solution, now calculate the rest of the factors */
+ /* Take the smallest root always (find_root returns the smallest one)
+ *
+ * NOTE: The IIR equation is
+ * y[n] = 2 * (alpha*(x[n]-x[n-2]) + gamma*y[n-1] - beta*y[n-2])
+ * Now the 2 factor has been distributed in the coefficients
+ */
+ /* Now store the coefficients */
+ bands[n].coeffs[i].beta = 2.0 * x0;
+ bands[n].coeffs[i].alpha = 2.0 * ALPHA(x0);
+ bands[n].coeffs[i].gamma = 2.0 * GAMMA(x0, TETA(freqs[i]));
+#ifdef DEBUG
+ printf("Freq[%d]: %f. Beta: %.10e Alpha: %.10e Gamma %.10e\n",
+ i, freqs[i], bands[n].coeffs[i].beta,
+ bands[n].coeffs[i].alpha, bands[n].coeffs[i].gamma);
+#endif
+ } else {
+ /* Shouldn't happen */
+ bands[n].coeffs[i].beta = 0.;
+ bands[n].coeffs[i].alpha = 0.;
+ bands[n].coeffs[i].gamma = 0.;
+ printf(" **** Where are the roots?\n");
+ }
+ }// for i
+ }//for n
+}
diff --git a/src/qmmp/equ/iir_cfs.h b/src/qmmp/equ/iir_cfs.h
new file mode 100644
index 000000000..c4cc4a0fd
--- /dev/null
+++ b/src/qmmp/equ/iir_cfs.h
@@ -0,0 +1,39 @@
+/*
+ * PCM time-domain equalizer
+ *
+ * Copyright (C) 2002-2005 Felipe Rivera <liebremx at 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: iir_cfs.h,v 1.1 2005/10/17 01:57:59 liebremx Exp $
+ */
+#ifndef IIR_CFS_H
+#define IIR_CFS_H
+
+//#include <glib.h>
+
+/* Coefficients entry */
+typedef struct
+{
+ float beta;
+ float alpha;
+ float gamma;
+ float dummy; // Word alignment
+}sIIRCoefficients;
+
+sIIRCoefficients* get_coeffs(int *bands, int sfreq); //, bool use_xmms_original_freqs);
+void calc_coeffs();
+
+#endif
diff --git a/src/qmmp/equ/iir_fpu.c b/src/qmmp/equ/iir_fpu.c
new file mode 100644
index 000000000..ae0051fdf
--- /dev/null
+++ b/src/qmmp/equ/iir_fpu.c
@@ -0,0 +1,210 @@
+/*
+ * PCM time-domain equalizer
+ *
+ * Copyright (C) 2002-2005 Felipe Rivera <liebremx at 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: iir_fpu.c,v 1.3 2005/11/13 20:02:58 lisanet Exp $
+ */
+
+#include <strings.h>
+#include <stdlib.h>
+//#include <glib.h>
+#include "iir.h"
+#include "iir_fpu.h"
+
+static sXYData data_history[EQ_MAX_BANDS][EQ_CHANNELS] __attribute__((aligned));
+static sXYData data_history2[EQ_MAX_BANDS][EQ_CHANNELS] __attribute__((aligned));
+float gain[EQ_MAX_BANDS][EQ_CHANNELS] __attribute__((aligned));
+/* random noise */
+sample_t dither[256];
+int di;
+
+void set_gain(int index, int chn, float val)
+{
+ gain[index][chn] = val;
+}
+
+void clean_history()
+{
+ int n;
+ /* Zero the history arrays */
+ bzero(data_history, sizeof(sXYData) * EQ_MAX_BANDS * EQ_CHANNELS);
+ bzero(data_history2, sizeof(sXYData) * EQ_MAX_BANDS * EQ_CHANNELS);
+ /* this is only needed if we use fpu code and there's no other place for
+ the moment to init the dither array*/
+ for (n = 0; n < 256; n++) {
+ dither[n] = (rand() % 4) - 2;
+ }
+ di = 0;
+}
+
+__inline__ int iir(void * d, int length, int nch)
+{
+/* FTZ_ON; */
+ short *data = (short *) d;
+ /* Indexes for the history arrays
+ * These have to be kept between calls to this function
+ * hence they are static */
+ static int i = 2, j = 1, k = 0;
+
+ int index, band, channel;
+ int tempgint, halflength;
+ sample_t out[EQ_CHANNELS], pcm[EQ_CHANNELS];
+
+#if 0
+ /* Load the correct filter table according to the sampling rate if needed */
+ if (srate != rate)
+ {
+ band_count = eqcfg.band_num;
+ rate = srate;
+ iir_cf = get_coeffs(&band_count, rate, eqcfg.use_xmms_original_freqs);
+ clean_history();
+ }
+#endif
+
+#ifdef BENCHMARK
+ start_counter();
+#endif /* BENCHMARK */
+
+ /**
+ * IIR filter equation is
+ * y[n] = 2 * (alpha*(x[n]-x[n-2]) + gamma*y[n-1] - beta*y[n-2])
+ *
+ * NOTE: The 2 factor was introduced in the coefficients to save
+ * a multiplication
+ *
+ * This algorithm cascades two filters to get nice filtering
+ * at the expense of extra CPU cycles
+ */
+ /* 16bit, 2 bytes per sample, so divide by two the length of
+ * the buffer (length is in bytes)
+ */
+ halflength = (length >> 1);
+ for (index = 0; index < halflength; index+=nch)
+ {
+ /* For each channel */
+ for (channel = 0; channel < nch; channel++)
+ {
+ pcm[channel] = data[index+channel] * 4;
+ /* Preamp gain */
+ pcm[channel] *= (preamp[channel] / 2);
+
+ /* add random noise */
+ pcm[channel] += dither[di];
+
+ out[channel] = 0.0;
+ /* For each band */
+ for (band = 0; band < band_count; band++)
+ {
+ /* Store Xi(n) */
+ data_history[band][channel].x[i] = pcm[channel];
+ /* Calculate and store Yi(n) */
+ data_history[band][channel].y[i] =
+ (
+ /* = alpha * [x(n)-x(n-2)] */
+ iir_cf[band].alpha * ( data_history[band][channel].x[i]
+ - data_history[band][channel].x[k])
+ /* + gamma * y(n-1) */
+ + iir_cf[band].gamma * data_history[band][channel].y[j]
+ /* - beta * y(n-2) */
+ - iir_cf[band].beta * data_history[band][channel].y[k]
+ );
+ /*
+ * The multiplication by 2.0 was 'moved' into the coefficients to save
+ * CPU cycles here */
+ /* Apply the gain */
+ out[channel] += data_history[band][channel].y[i]*gain[band][channel]; /* * 2.0; */
+ } /* For each band */
+
+ //if (cfg.eq_extra_filtering)
+ {
+ /* Filter the sample again */
+ for (band = 0; band < band_count; band++)
+ {
+ /* Store Xi(n) */
+ data_history2[band][channel].x[i] = out[channel];
+ /* Calculate and store Yi(n) */
+ data_history2[band][channel].y[i] =
+ (
+ /* y(n) = alpha * [x(n)-x(n-2)] */
+ iir_cf[band].alpha * (data_history2[band][channel].x[i]
+ - data_history2[band][channel].x[k])
+ /* + gamma * y(n-1) */
+ + iir_cf[band].gamma * data_history2[band][channel].y[j]
+ /* - beta * y(n-2) */
+ - iir_cf[band].beta * data_history2[band][channel].y[k]
+ );
+ /* Apply the gain */
+ out[channel] += data_history2[band][channel].y[i]*gain[band][channel];
+ } /* For each band */
+ }
+
+ /* Volume stuff
+ Scale down original PCM sample and add it to the filters
+ output. This substitutes the multiplication by 0.25
+ Go back to use the floating point multiplication before the
+ conversion to give more dynamic range
+ */
+ out[channel] += pcm[channel]*0.25;
+
+ /* remove random noise */
+ out[channel] -= dither[di]*0.25;
+
+ /* Round and convert to integer */
+#ifdef ARCH_PPC
+ tempgint = round_ppc(out[channel]);
+#else
+#ifdef ARCH_X86
+ tempgint = round_trick(out[channel]);
+#else
+ tempgint = (int)out[channel];
+#endif
+#endif
+
+ /* Limit the output */
+ if (tempgint < -32768)
+ data[index+channel] = -32768;
+ else if (tempgint > 32767)
+ data[index+channel] = 32767;
+ else
+ data[index+channel] = tempgint;
+ } /* For each channel */
+
+ /* Wrap around the indexes */
+ i = (i+1)%3;
+ j = (j+1)%3;
+ k = (k+1)%3;
+ /* random noise index */
+ di = (di + 1) % 256;
+
+ }/* For each pair of samples */
+
+#ifdef BENCHMARK
+ timex += get_counter();
+ blength += length;
+ if (count++ == 1024)
+ {
+ printf("FLOATING POINT: %f %d\n",timex/1024.0, blength/1024);
+ blength = 0;
+ timex = 0.;
+ count = 0;
+ }
+#endif /* BENCHMARK */
+
+/* FTZ_OFF; */
+ return length;
+}
diff --git a/src/qmmp/equ/iir_fpu.h b/src/qmmp/equ/iir_fpu.h
new file mode 100644
index 000000000..990eebf97
--- /dev/null
+++ b/src/qmmp/equ/iir_fpu.h
@@ -0,0 +1,39 @@
+/*
+ * PCM time-domain equalizer
+ *
+ * Copyright (C) 2002-2005 Felipe Rivera <liebremx at 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: iir_fpu.h,v 1.2 2005/11/01 15:59:20 lisanet Exp $$
+ */
+#ifndef IIR_FPU_H
+#define IIR_FPU_H
+
+#define sample_t double
+
+/*
+ * Normal FPU implementation data structures
+ */
+/* Coefficient history for the IIR filter */
+typedef struct
+{
+ sample_t x[3]; /* x[n], x[n-1], x[n-2] */
+ sample_t y[3]; /* y[n], y[n-1], y[n-2] */
+ sample_t dummy1; // Word alignment
+ sample_t dummy2;
+}sXYData;
+
+#endif
diff --git a/src/qmmp/filetag.cpp b/src/qmmp/filetag.cpp
new file mode 100644
index 000000000..3ce3b505a
--- /dev/null
+++ b/src/qmmp/filetag.cpp
@@ -0,0 +1,100 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include "filetag.h"
+
+FileTag::FileTag()
+{}
+
+FileTag::FileTag(const FileTag &other)
+{
+ *this = other;
+}
+
+FileTag::~FileTag()
+{}
+
+void FileTag::operator=(const FileTag &tag)
+{
+ setValue(TITLE,tag.title ());
+ setValue(ARTIST,tag.artist ());
+ setValue(ALBUM,tag.album ());
+ setValue(COMMENT,tag.comment ());
+ setValue(GENRE,tag.genre ());
+ setValue(YEAR,tag.year ());
+ setValue(TRACK,tag.track ());
+ setValue(LENGTH,tag.length ());
+}
+
+void FileTag::setValue(uint name, const QString &value)
+{
+ if (!value.isEmpty())
+ m_strValues.insert (name, value);
+}
+
+void FileTag::setValue(uint name, const uint &value)
+{
+ if (value > 0)
+ m_numValues.insert (name, value);
+}
+
+const QString FileTag::title () const
+{
+ return m_strValues[TITLE];
+}
+
+const QString FileTag::artist () const
+{
+ return m_strValues[ARTIST];
+}
+
+const QString FileTag::album () const
+{
+ return m_strValues[ALBUM];
+}
+
+const QString FileTag::comment () const
+{
+ return m_strValues[COMMENT];
+}
+
+const QString FileTag::genre () const
+{
+ return m_strValues[GENRE];
+}
+
+const uint FileTag::year () const
+{
+ return m_numValues[YEAR];
+}
+
+const uint FileTag::track () const
+{
+ return m_numValues[TRACK];
+}
+
+const uint FileTag::length () const
+{
+ return m_numValues[LENGTH];
+}
+
+const bool FileTag::isEmpty () const
+{
+ return m_strValues.isEmpty();
+}
diff --git a/src/qmmp/filetag.h b/src/qmmp/filetag.h
new file mode 100644
index 000000000..f75facfa0
--- /dev/null
+++ b/src/qmmp/filetag.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef FILETAG_H
+#define FILETAG_H
+
+#include <QString>
+#include <QMap>
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class FileTag
+{
+public:
+ FileTag();
+ FileTag(const FileTag &other);
+
+ ~FileTag();
+
+ enum Type
+ {
+ TITLE = 0,
+ ARTIST,
+ ALBUM,
+ COMMENT,
+ GENRE,
+ YEAR,
+ TRACK,
+ LENGTH
+ };
+
+ void operator=(const FileTag &tag);
+ void setValue(uint name, const QString &value);
+ void setValue(uint name, const uint &value);
+ const QString title () const;
+ const QString artist () const;
+ const QString album () const;
+ const QString comment () const;
+ const QString genre () const;
+ const uint year () const;
+ const uint track () const;
+ const uint length () const;
+ const bool isEmpty () const;
+
+private:
+ QMap <uint, QString> m_strValues;
+ QMap <uint, uint> m_numValues;
+};
+
+#endif
diff --git a/src/qmmp/output.cpp b/src/qmmp/output.cpp
new file mode 100644
index 000000000..50136608a
--- /dev/null
+++ b/src/qmmp/output.cpp
@@ -0,0 +1,269 @@
+// Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com>
+//
+// Use, modification and distribution is allowed without limitation,
+// warranty, or liability of any kind.
+//
+
+#include <QtGui>
+#include <QObject>
+#include <QStringList>
+#include <QApplication>
+#include <QTimer>
+
+#include "constants.h"
+#include "output.h"
+
+#include <stdio.h>
+
+// static methods
+
+static QList<OutputFactory*> *factories = 0;
+static QStringList files;
+static QTimer *timer = 0;
+
+static void checkFactories()
+{
+ if ( ! factories )
+ {
+ files.clear();
+ factories = new QList<OutputFactory *>;
+
+ QDir pluginsDir ( qApp->applicationDirPath() );
+ pluginsDir.cdUp();
+ pluginsDir.cd ( "./"LIB_DIR"/qmmp/Output" );
+ foreach ( QString fileName, pluginsDir.entryList ( QDir::Files ) )
+ {
+ QPluginLoader loader ( pluginsDir.absoluteFilePath ( fileName ) );
+ QObject *plugin = loader.instance();
+ if ( loader.isLoaded() )
+ {
+ qDebug ( "Output: plugin loaded - %s", qPrintable ( fileName ) );
+ }
+ OutputFactory *factory = 0;
+ if ( plugin )
+ factory = qobject_cast<OutputFactory *> ( plugin );
+
+ if ( factory )
+ {
+ Output::registerFactory ( factory );
+ files << pluginsDir.absoluteFilePath(fileName);
+ }
+ }
+ }
+}
+
+void Output::registerFactory ( OutputFactory *fact )
+{
+ factories->append ( fact );
+}
+
+Output *Output::create (QObject *parent)
+{
+ Output *output = 0;
+
+ checkFactories();
+ if (factories->isEmpty ())
+ {
+ qDebug("Output: unable to find output plugins");
+ return output;
+ }
+ QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat );
+ QString pluginFileName =
+ settings.value("Output/plugin_file","libalsa.so").toString();
+ int j = 0;
+ for (int i = 0; i < factories->size(); ++i)
+ {
+ if (files.at(i).section('/',-1) == pluginFileName)
+ j = i;
+ }
+ OutputFactory *fact = factories->at (j);
+ bool useVolume = !settings.value("Volume/software_volume", FALSE).toBool();
+ if (fact)
+ {
+ output = fact->create (parent, useVolume);
+ if (useVolume)
+ {
+ timer = new QTimer(output);
+ connect(timer, SIGNAL(timeout()), output, SLOT(checkVolume()));
+ timer->start(125);
+ }
+ else
+ {
+ QTimer::singleShot(125, output, SLOT(checkSoftwareVolume()));
+ }
+ }
+ return output;
+}
+
+QList<OutputFactory*> *Output::outputFactories()
+{
+ checkFactories();
+ return factories;
+}
+
+QStringList Output::outputFiles()
+{
+ checkFactories();
+ return files;
+}
+
+Output::Output (QObject* parent) : QThread (parent), r (stackSize())
+{
+ qRegisterMetaType<OutputState>("OutputState");
+ m_bl = -1;
+ m_br = -1;
+}
+
+
+Output::~Output()
+{
+ qDebug("Output::~Output()");
+ Visual *visual = 0;
+ foreach(visual, m_vis_map.values ())
+ {
+ visual->close();
+ }
+ //m_vis_map.clear();
+}
+
+void Output::error ( const QString &e )
+{
+ emit stateChanged ( OutputState ( e ) );
+}
+
+
+void Output::addVisual ( Visual *v )
+{
+ if (visuals.indexOf (v) == -1)
+ {
+ visuals.append (v);
+ v->setOutput(this);
+ qDebug("Output: added external visualization");
+ }
+}
+
+
+void Output::removeVisual (Visual *v)
+{
+ visuals.removeAll (v);
+ if (m_vis_map.key(v))
+ {
+ VisualFactory *factory = m_vis_map.key(v);
+ m_vis_map.remove(factory);
+ //Visual::setEnabled(factory, FALSE);
+ }
+}
+
+void Output::addVisual(VisualFactory *factory, QWidget *parent)
+{
+ if (m_vis_map.value(factory))
+ return;
+ Visual::setEnabled(factory, TRUE);
+ Visual* visual = factory->create(parent);
+ visual->setWindowFlags(Qt::Window);
+ if (visual)
+ {
+ visual->setOutput(this);
+ qDebug("Output: added visual factory: %s",
+ qPrintable(factory->properties().name));
+ m_vis_map.insert (factory, visual);
+ visual->show();
+ }
+}
+
+void Output::removeVisual(VisualFactory *factory)
+{
+ if (m_vis_map.value(factory))
+ {
+ m_vis_map.value(factory)->close();
+ m_vis_map.remove (factory);
+ }
+ Visual::setEnabled(factory, FALSE);
+}
+
+void Output::dispatchVisual ( Buffer *buffer, unsigned long written,
+ int chan, int prec )
+{
+ if ( ! buffer || !visuals.size())
+ return;
+ Visual* visual = 0;
+ foreach (visual , visuals) //external
+ {
+ visual->mutex()->lock ();
+ visual->add ( buffer, written, chan, prec );
+ visual->mutex()->unlock();
+ }
+ foreach (visual , m_vis_map.values ()) //internal
+ {
+ visual->mutex()->lock ();
+ visual->add ( buffer, written, chan, prec );
+ visual->mutex()->unlock();
+ }
+}
+
+
+void Output::clearVisuals()
+{
+ Visual *visual = 0;
+ foreach (visual, visuals )
+ {
+ visual->mutex()->lock ();
+ visual->clear();
+ visual->mutex()->unlock();
+ }
+ foreach(visual, m_vis_map.values ())
+ {
+ visual->mutex()->lock ();
+ visual->clear();
+ visual->mutex()->unlock();
+ }
+}
+
+void Output::dispatch(OutputState::Type st)
+{
+ if (st == OutputState::Stopped)
+ clearVisuals();
+ emit stateChanged ( OutputState(st) );
+}
+
+void Output::dispatch(long s, unsigned long w, int b, int f, int p, int c)
+{
+ emit stateChanged ( OutputState(s, w, b, f, p, c) );
+}
+
+void Output::dispatch ( const OutputState &st )
+{
+ if (st.type() == OutputState::Stopped)
+ clearVisuals();
+ emit stateChanged ( st );
+}
+
+void Output::dispatchVolume(int L, int R)
+{
+ emit stateChanged ( OutputState(L, R) );
+}
+
+void Output::checkVolume()
+{
+ int ll = 0, lr = 0;
+ volume(&ll,&lr);
+ ll = (ll > 100) ? 100 : ll;
+ lr = (lr > 100) ? 100 : lr;
+ ll = (ll < 0) ? 0 : ll;
+ lr = (lr < 0) ? 0 : lr;
+ if (m_bl!=ll || m_br!=lr)
+ {
+ m_bl = ll;
+ m_br = lr;
+ dispatchVolume(ll,lr);
+ }
+}
+
+void Output::checkSoftwareVolume()
+{
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ int L = settings.value("Volume/left", 80).toInt();
+ int R = settings.value("Volume/right", 80).toInt();
+ dispatchVolume(L, R);
+}
+
diff --git a/src/qmmp/output.h b/src/qmmp/output.h
new file mode 100644
index 000000000..1a8ec3bd9
--- /dev/null
+++ b/src/qmmp/output.h
@@ -0,0 +1,208 @@
+
+// Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com>
+//
+// Use, modification and distribution is allowed without limitation,
+// warranty, or liability of any kind.
+//
+
+#ifndef OUTPUT_H
+#define OUTPUT_H
+
+class Output;
+
+#include <QObject>
+#include <QThread>
+#include <QEvent>
+#include <QList>
+#include <QIODevice>
+#include "visual.h"
+#include "outputfactory.h"
+#include "visualfactory.h"
+
+#include "recycler.h"
+
+class QTimer;
+
+
+class OutputState
+{
+public:
+
+ enum Type { Playing, Buffering, Info, Paused, Stopped, Volume, Error };
+
+ OutputState()
+ : m_type(Stopped), m_error_msg(0), m_elasped_seconds(0),
+ m_written_bytes(0), m_brate(0), m_freq(0), m_prec(0), m_chan(0),
+ m_left(0), m_right(0)
+ {}
+ OutputState(const OutputState &st)
+ : m_type(Stopped), m_error_msg(0), m_elasped_seconds(0),
+ m_written_bytes(0), m_brate(0), m_freq(0), m_prec(0), m_chan(0),
+ m_left(0), m_right(0)
+ {
+ m_type = st.type();
+ if (m_type == Info)
+ {
+ m_elasped_seconds = st.elapsedSeconds();
+ m_written_bytes = st.writtenBytes();
+ m_brate = st.bitrate();
+ m_freq = st.frequency();
+ m_prec = st.precision();
+ m_chan = st.channels();
+ m_left = st.leftVolume();
+ m_right = st.rightVolume();
+ }
+ else if (m_type == Error)
+ m_error_msg = new QString(*st.errorMessage());
+ }
+
+ OutputState(Type t)
+ : m_type(t), m_error_msg(0), m_elasped_seconds(0),
+ m_written_bytes(0), m_brate(0), m_freq(0), m_prec(0), m_chan(0),
+ m_left(0), m_right(0)
+{}
+ OutputState(long s, unsigned long w, int b, int f, int p, int c)
+ : m_type(Info), m_error_msg(0), m_elasped_seconds(s),
+ m_written_bytes(w), m_brate(b), m_freq(f), m_prec(p), m_chan(c),
+ m_left(0), m_right(0)
+ {}
+ OutputState(int L, int R)
+ : m_type(Volume), m_error_msg(0), m_elasped_seconds(0),
+ m_written_bytes(0), m_brate(0), m_freq(0), m_prec(0), m_chan(0),
+ m_left(L), m_right(R)
+ {}
+ OutputState(const QString &e)
+ : m_type(Error), m_elasped_seconds(0), m_written_bytes(0),
+ m_brate(0), m_freq(0), m_prec(0), m_chan(0),
+ m_left(0), m_right(0)
+ {
+ m_error_msg = new QString(e);
+ }
+ ~OutputState()
+ {
+ if (m_error_msg)
+ delete m_error_msg;
+ }
+
+ const QString *errorMessage() const
+ {
+ return m_error_msg;
+ }
+
+ const long &elapsedSeconds() const
+ {
+ return m_elasped_seconds;
+ }
+ const unsigned long &writtenBytes() const
+ {
+ return m_written_bytes;
+ }
+ const int &bitrate() const
+ {
+ return m_brate;
+ }
+ const int &frequency() const
+ {
+ return m_freq;
+ }
+ const int &precision() const
+ {
+ return m_prec;
+ }
+ const int &channels() const
+ {
+ return m_chan;
+ }
+ const Type &type() const
+ {
+ return m_type;
+ }
+ const int leftVolume() const
+ {
+ return m_left;
+ }
+ const int rightVolume() const
+ {
+ return m_right;
+ }
+
+private:
+ Type m_type;
+ QString *m_error_msg;
+ long m_elasped_seconds;
+ unsigned long m_written_bytes;
+ int m_brate, m_freq, m_prec, m_chan;
+ int m_left, m_right; //volume
+};
+
+
+
+
+class Output : public QThread
+{
+ Q_OBJECT
+public:
+
+ Output(QObject * parent = 0);
+ ~Output();
+
+ Recycler *recycler()
+ {
+ return &r;
+ }
+
+ QMutex *mutex()
+ {
+ return &mtx;
+ }
+
+ //visualization
+ void addVisual(Visual*);
+ void removeVisual(Visual*);
+ void addVisual(VisualFactory *factory, QWidget *parent);
+ void removeVisual(VisualFactory *factory);
+
+ // abstract
+ virtual bool isInitialized() const = 0;
+ virtual bool initialize() = 0;
+ virtual void uninitialize() = 0;
+ virtual void configure(long, int, int, int) = 0;
+ virtual void pause() = 0;
+ virtual void stop() = 0;
+ virtual long written() = 0;
+ virtual long latency() = 0;
+ virtual void seek(long) = 0;
+ virtual void setVolume(int, int){};
+ virtual void volume(int*, int*){};
+
+ static void registerFactory(OutputFactory *);
+ static Output *create(QObject *);
+ static QList<OutputFactory*> *outputFactories();
+ static QStringList outputFiles();
+
+public slots:
+ void checkVolume();
+ void checkSoftwareVolume();
+
+signals:
+ void stateChanged(const OutputState&);
+
+protected:
+ void dispatch(OutputState::Type);
+ void dispatch(long s, unsigned long w, int b, int f, int p, int c);
+ void dispatch(const OutputState&);
+ void dispatchVolume(int L, int R);
+ void error(const QString &e);
+ void dispatchVisual(Buffer *, unsigned long, int, int);
+ void clearVisuals();
+
+private:
+ QMutex mtx;
+ Recycler r;
+ QList<Visual*> visuals; //external visualization
+ QMap<VisualFactory*, Visual*> m_vis_map; //internal visualization
+ int m_bl, m_br;
+};
+
+
+#endif // OUTPUT_H
diff --git a/src/qmmp/outputfactory.h b/src/qmmp/outputfactory.h
new file mode 100644
index 000000000..2a5513759
--- /dev/null
+++ b/src/qmmp/outputfactory.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef OUTPUTFACTORY_H
+#define OUTPUTFACTORY_H
+
+class QObject;
+class QString;
+class QIODevice;
+class QWidget;
+class QTranslator;
+
+class Decoder;
+class Output;
+
+struct OutputProperties
+{
+ QString name;
+ bool hasAbout;
+ bool hasSettings;
+};
+
+class OutputFactory
+{
+public:
+ virtual ~OutputFactory() {}
+ virtual const OutputProperties properties() const = 0;
+ virtual Output *create(QObject *, bool) = 0;
+ virtual void showSettings(QWidget *parent) = 0;
+ virtual void showAbout(QWidget *parent) = 0;
+ virtual QTranslator *createTranslator(QObject *parent) = 0;
+};
+
+Q_DECLARE_INTERFACE(OutputFactory, "OutputFactory/1.0")
+
+#endif
diff --git a/src/qmmp/qmmp.pro b/src/qmmp/qmmp.pro
new file mode 100644
index 000000000..a583cd45b
--- /dev/null
+++ b/src/qmmp/qmmp.pro
@@ -0,0 +1,66 @@
+# ???? ?????? ? KDevelop ?????????? qmake.
+# -------------------------------------------
+# ?????????? ???????????? ???????? ???????? ???????: ./libs
+# ???? - ??????????: nnp
+
+include(../../qmmp.pri)
+
+HEADERS += recycler.h \
+ buffer.h \
+ constants.h \
+ decoder.h \
+ output.h \
+ filetag.h \
+ outputfactory.h \
+ equ\iir_cfs.h \
+ equ\iir_fpu.h \
+ equ\iir.h \
+ decoderfactory.h \
+ soundcore.h \
+ streamreader.h \
+ downloader.h \
+ visual.h \
+ visualfactory.h \
+ effect.h \
+ effectfactory.h
+SOURCES += recycler.cpp \
+ decoder.cpp \
+ output.cpp \
+ equ\iir.c \
+ equ\iir_cfs.c \
+ equ\iir_fpu.c \
+ soundcore.cpp \
+ streamreader.cpp \
+ downloader.cpp \
+ filetag.cpp \
+ visual.cpp \
+ effect.cpp
+
+TARGET = ../../lib/qmmp
+CONFIG += release \
+warn_on \
+qt \
+thread \
+link_pkgconfig
+
+TEMPLATE = lib
+PKGCONFIG += libcurl
+
+isEmpty(LIB_DIR){
+ LIB_DIR = /lib
+}
+
+unix {
+ LINE1 = $$sprintf(echo \"%1ifndef CONFIG_H\" > ./config.h, $$LITERAL_HASH)
+ LINE2 = $$sprintf(echo \"%1define CONFIG_H\" >> ./config.h, $$LITERAL_HASH)
+ LINE3 = $$sprintf(echo \"%1define LIB_DIR \\\"%2\\\"\" >> ./config.h, $$LITERAL_HASH, $$LIB_DIR)
+ LINE4 = $$sprintf(echo \"%1endif\" >> ./config.h, $$LITERAL_HASH)
+ system($$LINE1)
+ system($$LINE2)
+ system($$LINE3)
+ system($$LINE4)
+ QMAKE_CLEAN = ./config.h
+}
+
+target.path = $$LIB_DIR
+INSTALLS += target
diff --git a/src/qmmp/recycler.cpp b/src/qmmp/recycler.cpp
new file mode 100644
index 000000000..15d2234a6
--- /dev/null
+++ b/src/qmmp/recycler.cpp
@@ -0,0 +1,120 @@
+// Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com>
+//
+// Use, modification and distribution is allowed without limitation,
+// warranty, or liability of any kind.
+//
+
+#include "recycler.h"
+#include "constants.h"
+#include "buffer.h"
+
+
+Recycler::Recycler ( unsigned int sz )
+ : add_index ( 0 ), done_index ( 0 ), current_count ( 0 )
+{
+ buffer_count = ( sz / Buffer::size() );
+ if ( buffer_count < 1 )
+ {
+ buffer_count = 1;
+ }
+
+ buffers = new Buffer*[buffer_count];
+
+ for ( unsigned int i = 0; i < buffer_count; i ++ )
+ {
+ buffers[i] = new Buffer;
+ }
+}
+
+
+Recycler::~Recycler()
+{
+ for ( unsigned int i = 0; i < buffer_count; i++ )
+ {
+ delete buffers[i];
+ buffers[i] = 0;
+ }
+
+ delete [] buffers;
+}
+
+
+bool Recycler::full() const
+{
+ return current_count == buffer_count;
+}
+
+
+bool Recycler::empty() const
+{
+ return current_count == 0;
+}
+
+
+int Recycler::available() const
+{
+ return buffer_count - current_count;
+}
+
+int Recycler::used() const
+{
+ return current_count;
+}
+
+
+Buffer *Recycler::get(unsigned long size)
+{
+ if (full())
+ return 0;
+ if(size > Buffer::size() + buffers[add_index]->exceeding)
+ {
+ delete buffers[add_index]->data;
+ buffers[add_index]->data = new unsigned char[size];
+ buffers[add_index]->exceeding = size - Buffer::size();
+ //qDebug("new size = %d, index = %d", size, add_index);
+ }
+
+ return buffers[add_index];
+}
+
+
+void Recycler::add()
+{
+ add_index = ++add_index % buffer_count;
+ current_count++;
+}
+
+
+Buffer *Recycler::next()
+{
+ return buffers[done_index];
+}
+
+
+void Recycler::done()
+{
+ done_index = ++done_index % buffer_count;
+ current_count--;
+}
+
+
+void Recycler::clear()
+{
+ add_index = done_index = current_count = 0;
+ /*for ( unsigned int i = 0; i < buffer_count; i ++ )
+ {
+ if(buffers[i]->exceeding > 0)
+ {
+ delete buffers[i]->data;
+ buffers[i]->data = new unsigned char[Buffer::size()];
+ buffers[i]->exceeding = 0;
+ buffers[i]->nbytes = 0;
+ }
+ }*/
+}
+
+
+unsigned int Recycler::size() const
+{
+ return buffer_count * Buffer::size();
+}
diff --git a/src/qmmp/recycler.h b/src/qmmp/recycler.h
new file mode 100644
index 000000000..6bb80375d
--- /dev/null
+++ b/src/qmmp/recycler.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com>
+//
+// Use, modification and distribution is allowed without limitation,
+// warranty, or liability of any kind.
+//
+
+#ifndef __recycler_h
+#define __recycler_h
+
+#include <QMutex>
+#include <QWaitCondition>
+
+class Buffer;
+
+
+class Recycler
+{
+public:
+ Recycler(unsigned int sz); // sz = size in bytes
+ ~Recycler();
+
+ bool full() const;
+ bool empty() const;
+
+ int available() const;
+ int used() const;
+
+ Buffer *next(); // get next in queue
+ Buffer *get(unsigned long size); // get next in recycle
+
+ void add(); // add to queue
+ void done(); // add to recycle
+
+ void clear(); // clear queue
+
+ unsigned int size() const; // size in bytes
+
+ QMutex *mutex() { return &mtx; }
+ QWaitCondition *cond() { return &cnd; }
+
+
+private:
+ unsigned int buffer_count, add_index, done_index, current_count;
+ Buffer **buffers;
+ QMutex mtx;
+ QWaitCondition cnd;
+};
+
+#endif // __recycler_h
diff --git a/src/qmmp/soundcore.cpp b/src/qmmp/soundcore.cpp
new file mode 100644
index 000000000..019b4c78e
--- /dev/null
+++ b/src/qmmp/soundcore.cpp
@@ -0,0 +1,440 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QIODevice>
+#include <QFile>
+#include <QApplication>
+#include <QSettings>
+#include <QDir>
+
+#include "decoderfactory.h"
+#include "constants.h"
+#include "streamreader.h"
+#include "effect.h"
+
+#include "soundcore.h"
+
+
+SoundCore *SoundCore::m_instance = 0;
+
+SoundCore::SoundCore(QObject *parent)
+ : QObject(parent)
+{
+ m_instance = this;
+ m_decoder = 0;
+ m_output = 0;
+ m_input = 0;
+ m_paused = FALSE;
+ m_useEQ = FALSE;
+ m_update = FALSE;
+ m_block = FALSE;
+ m_preamp = 0;
+ m_vis = 0;
+ m_parentWidget = 0;
+ for (int i = 1; i < 10; ++i)
+ m_bands[i] = 0;
+ m_error = NoError;
+ m_output = Output::create(this);
+ if (!m_output)
+ {
+ m_error = DecoderError;
+ qWarning("SoundCore: unable to create output");
+ }
+ connect(m_output, SIGNAL(stateChanged(const OutputState&)),
+ SIGNAL(outputStateChanged(const OutputState&)));
+
+ QList<OutputFactory*> *outputFactories = Output::outputFactories();
+ foreach(OutputFactory* of, *outputFactories)
+ qApp->installTranslator(of->createTranslator(this));
+
+ QList<DecoderFactory*> *decoderFactories = Decoder::decoderFactories();
+ foreach(DecoderFactory* df, *decoderFactories)
+ qApp->installTranslator(df->createTranslator(this));
+
+ Effect::effectFactories();
+}
+
+
+SoundCore::~SoundCore()
+{}
+
+bool SoundCore::play(const QString &source)
+{
+ stop();
+ if (source.isEmpty())
+ {
+ m_error = DecoderError;
+ return FALSE;
+ }
+ if (source.left(4) == "http")
+ {
+ m_input = new StreamReader(source, this);
+ connect(m_input, SIGNAL(titleChanged(const QString&)),
+ SIGNAL(titleChanged(const QString&)));
+ connect(m_input, SIGNAL(readyRead()),SLOT(decode()));
+ }
+ else
+ m_input = new QFile(source);
+
+ m_error = OutputError;
+ if (!m_output)
+ {
+ m_output = Output::create(this);
+ if (!m_output)
+ {
+ qWarning("SoundCore: unable to create output");
+ return FALSE;
+ }
+ connect(m_output, SIGNAL(stateChanged(const OutputState&)),
+ SIGNAL(outputStateChanged(const OutputState&)));
+ connect(m_input, SIGNAL(readyRead()),SLOT(read()));
+ }
+ if (! m_output->initialize())
+ return FALSE;
+
+ m_error = DecoderError;
+
+ Visual *visual = 0;
+ foreach(visual, m_visuals)
+ m_output->addVisual(visual);
+
+ VisualFactory* factory;
+ foreach(factory, *Visual::visualFactories())
+ {
+ if (Visual::isEnabled(factory))
+ m_output->addVisual(factory, m_parentWidget);
+ }
+
+ m_source = source;
+ if (source.left(4) != "http")
+ return decode();
+ else
+ qobject_cast<StreamReader *>(m_input)->downloadFile();
+ return TRUE;
+
+}
+
+uint SoundCore::error()
+{
+ return m_error;
+}
+
+void SoundCore::stop()
+{
+ if (m_block)
+ return;
+ m_paused = FALSE;
+ if (m_decoder && m_decoder->isRunning())
+ {
+ m_decoder->mutex()->lock ();
+ m_decoder->stop();
+ m_decoder->mutex()->unlock();
+ }
+ if (m_output)
+ {
+ m_output->mutex()->lock ();
+ m_output->stop();
+ m_output->mutex()->unlock();
+ }
+
+ // wake up threads
+ if (m_decoder)
+ {
+ m_decoder->mutex()->lock ();
+ m_decoder->cond()->wakeAll();
+ m_decoder->mutex()->unlock();
+ }
+ if (m_output)
+ {
+ m_output->recycler()->mutex()->lock ();
+ m_output->recycler()->cond()->wakeAll();
+ m_output->recycler()->mutex()->unlock();
+ }
+ if (m_decoder)
+ m_decoder->wait();
+ if (m_output)
+ m_output->wait();
+ if (m_output && m_output->isInitialized())
+ {
+ m_output->uninitialize();
+ }
+
+ //display->setTime(0);
+ if (m_decoder)
+ {
+ delete m_decoder;
+ m_decoder = 0;
+ }
+ if (m_input)
+ {
+ delete m_input;
+ m_input = 0;
+ }
+ // recreate output
+ if (m_update && m_output)
+ {
+ delete m_output;
+ m_output = 0;
+ m_update = FALSE;
+ m_output = Output::create(this);
+ if (!m_output)
+ {
+ qWarning("SoundCore: unable to create output");
+ }
+ VisualFactory* factory;
+ foreach(factory, *Visual::visualFactories())
+ {
+ if (Visual::isEnabled(factory))
+ m_output->addVisual(factory, m_parentWidget);
+ }
+ connect(m_output, SIGNAL(stateChanged(const OutputState&)),
+ SIGNAL(outputStateChanged(const OutputState&)));
+ }
+}
+
+void SoundCore::pause()
+{
+ if (m_output)
+ {
+ m_output->mutex()->lock ();
+ m_output->pause();
+ m_output->mutex()->unlock();
+ }
+
+ // wake up threads
+ if (m_decoder)
+ {
+ m_paused = !m_paused;
+ m_decoder->mutex()->lock ();
+ m_decoder->cond()->wakeAll();
+ m_decoder->mutex()->unlock();
+ }
+
+ if (m_output)
+ {
+ m_output->recycler()->mutex()->lock ();
+ m_output->recycler()->cond()->wakeAll();
+ m_output->recycler()->mutex()->unlock();
+ }
+}
+
+void SoundCore::seek(int pos)
+{
+ if (m_output && m_output->isRunning())
+ {
+ m_output->recycler()->mutex()->lock ();
+ m_output->recycler()->clear ();
+ m_output->recycler()->mutex()->unlock ();
+ m_output->mutex()->lock ();
+ m_output->seek(pos);
+ m_output->mutex()->unlock();
+ if (m_decoder && m_decoder->isRunning())
+ {
+ m_decoder->mutex()->lock ();
+ m_decoder->seek(pos);
+ m_decoder->mutex()->unlock();
+ }
+ }
+}
+
+int SoundCore::length()
+{
+ if (m_decoder)
+ return int(m_decoder->lengthInSeconds());
+ return 0;
+}
+
+bool SoundCore::isInitialized()
+{
+ if (m_decoder)
+ return TRUE;
+ return FALSE;
+}
+
+bool SoundCore::isPaused()
+{
+ return m_paused;
+}
+
+void SoundCore::setEQ(int bands[10], const int &preamp)
+{
+ for (int i = 0; i < 10; ++i)
+ m_bands[i] = bands[i];
+ m_preamp = preamp;
+ if (m_decoder)
+ {
+ m_decoder->mutex()->lock ();
+ m_decoder->setEQ(m_bands, m_preamp);
+ m_decoder->setEQEnabled(m_useEQ);
+ m_decoder->mutex()->unlock();
+ }
+}
+
+void SoundCore::setEQEnabled(bool on)
+{
+ m_useEQ = on;
+ if (m_decoder)
+ {
+ m_decoder->mutex()->lock ();
+ m_decoder->setEQ(m_bands, m_preamp);
+ m_decoder->setEQEnabled(on);
+ m_decoder->mutex()->unlock();
+ }
+}
+
+void SoundCore::setVolume(int L, int R)
+{
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ bool sofVolume = settings.value("Volume/software_volume", FALSE).toBool();
+ if (sofVolume)
+ {
+ L = qMin(L,100);
+ R = qMin(R,100);
+ L = qMax(L,0);
+ R = qMax(R,0);
+ settings.setValue("Volume/left", L);
+ settings.setValue("Volume/right", R);
+ if (m_decoder)
+ m_decoder->setVolume(L,R);
+ if (m_output)
+ m_output->checkSoftwareVolume();
+ }
+ else if (m_output)
+ m_output->setVolume(L,R);
+}
+
+void SoundCore::volume(int *left, int *right)
+{
+ QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat);
+ bool sofVolume = settings.value("Volume/software_volume", FALSE).toBool();
+ if (sofVolume)
+ {
+ *left = settings.value("Volume/left", 0).toInt();
+ *right = settings.value("Volume/right", 0).toInt();
+ }
+ else if (m_output)
+ m_output->volume(left,right);
+ return;
+}
+
+void SoundCore::updateConfig()
+{
+ m_update = TRUE;
+ if (isInitialized())
+ return;
+ stop();
+}
+
+void SoundCore::addVisualization(Visual *visual)
+{
+ if (m_visuals.indexOf (visual) == -1)
+ {
+ m_visuals.append(visual);
+ if (m_output)
+ m_output->addVisual(visual);
+ }
+}
+
+bool SoundCore::decode()
+{
+ if (! m_decoder)
+ {
+ m_block = TRUE;
+ qDebug ("SoundCore: creating decoder");
+ m_decoder = Decoder::create(this, m_source, m_input, m_output);
+
+ if (! m_decoder)
+ {
+ qWarning("SoundCore: unsupported fileformat");
+ m_block = FALSE;
+ stop();
+ emit decoderStateChanged(DecoderState(DecoderState::Error));
+ return FALSE;
+ }
+ qDebug ("ok");
+ m_decoder->setBlockSize(globalBlockSize);
+ connect(m_decoder, SIGNAL(stateChanged(const DecoderState&)),
+ SIGNAL(decoderStateChanged(const DecoderState&)));
+ setEQ(m_bands, m_preamp);
+ setEQEnabled(m_useEQ);
+ }
+ qDebug("SoundCore: decoder was created successfully");
+
+ if (m_decoder->initialize())
+ {
+ m_output->start();
+ m_decoder->start();
+ m_error = NoError;
+ m_block = FALSE;
+ return TRUE;
+ }
+ stop();
+ m_block = FALSE;
+ return FALSE;
+}
+
+void SoundCore::showVisualization(QWidget *parent)
+{
+ if (!m_parentWidget)
+ {
+ m_parentWidget = parent;
+ if (!m_output)
+ return;
+ VisualFactory* factory;
+ foreach(factory, *Visual::visualFactories())
+ {
+ if (Visual::isEnabled(factory))
+ m_output->addVisual(factory, m_parentWidget);
+ }
+ }
+}
+
+void SoundCore::addVisual(VisualFactory *factory, QWidget *parent)
+{
+ if (m_output)
+ m_output->addVisual(factory, parent);
+ else
+ Visual::setEnabled(factory, TRUE);
+}
+
+void SoundCore::removeVisual(VisualFactory *factory)
+{
+ if (m_output)
+ m_output->removeVisual(factory);
+ else
+ Visual::setEnabled(factory, FALSE);
+}
+
+void SoundCore::removeVisual(Visual *visual)
+{
+ if (m_visuals.indexOf (visual) != -1)
+ {
+ m_visuals.removeAll(visual);
+ if (m_output)
+ m_output->removeVisual(visual);
+ }
+}
+
+SoundCore* SoundCore::instance()
+{
+ return m_instance;
+}
+
+
diff --git a/src/qmmp/soundcore.h b/src/qmmp/soundcore.h
new file mode 100644
index 000000000..3fa785a2a
--- /dev/null
+++ b/src/qmmp/soundcore.h
@@ -0,0 +1,208 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef SOUNDCORE_H
+#define SOUNDCORE_H
+
+
+#include <QObject>
+#include <QString>
+
+#include "decoder.h"
+#include "output.h"
+#include "visual.h"
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+
+class QIODevice;
+
+class SoundCore : public QObject
+{
+ Q_OBJECT
+public:
+
+ /*! This enum describes the errors that may be returned by the error() function.
+ * Available values is:
+ * \b SoundCore:NoError - no error occurred,
+ * \b SoundCore:DecoderError - an error occurred when creating decoder,
+ * \b SoundCore:OutputError - an error occurred when creating output.
+ */
+ enum ErrorType { NoError = 0, DecoderError, OutputError };
+
+ SoundCore(QObject *parent = 0);
+
+ ~SoundCore();
+
+
+ //control
+
+ /*!
+ * This function plays file with given path, returns \b TRUE if all is OK, otherwise \b FALSE
+ */
+ bool play(const QString &source);
+
+ /*!
+ * Returns the playback error status.
+ * For example, if play() returns false, this function can be called to find out
+ * the reason why the operation failed.
+ */
+ uint error();
+
+ /*!
+ * Stops playing
+ */
+ void stop();
+
+ /*!
+ * Pauses/resumes playing
+ */
+ void pause();
+
+ /*!
+ *This function sets the current play position to \b pos
+ */
+ void seek(int pos);
+
+ // properties
+
+ /*!
+ * Returns length in seconds
+ */
+ int length();
+
+ /*!
+ * Returns \b TRUE if \b play() called successful, otherwise \b FALSE.
+ */
+ bool isReady();
+
+ /*!
+ * Returns \b TRUE if \b play() called successful, otherwise \b FALSE.
+ * Also this function returns \b FALSE if \b stop() called before
+ */
+ bool isInitialized();
+
+ /*!
+ * Returns \b TRUE if plugins in pause mode, otherwise \b FALSE.
+ */
+ bool isPaused();
+
+ //equalizer
+
+ /*!
+ * Sets equalizer settings. Each item of \b bands[] and \b reamp should be
+ * \b -100..100
+ */
+ void setEQ(int bands[10], const int &preamp);
+
+ /*!
+ * Enables equalizer if on is \b TRUE or disables it if on is \b FALSE
+ */
+ void setEQEnabled(bool on);
+
+ //volume
+
+ /*!
+ * Sets volume. \b L - volume of left channel. \b R - volume of right channel.
+ * \b L and \b R should be 0..100
+ */
+ void setVolume(int L, int R);
+
+ void volume(int*, int*);
+
+ //config
+
+ /*!
+ * updates configuration
+ */
+ void updateConfig();
+
+ //visualization
+ /*!
+ * adds visualization \b visual
+ */
+ void addVisualization(Visual *visual);
+
+ /*!
+ * shows enabled visualization with parent widget \b parent
+ */
+ void showVisualization(QWidget *parent);
+
+ /*!
+ * adds visualization by factory \b factory
+ */
+ void addVisual(VisualFactory *factory, QWidget *parent);
+
+ /*!
+ * removes visualization by factory \b factory
+ */
+ void removeVisual(VisualFactory *factory);
+
+ /*!
+ * removes visualization \b visual
+ */
+ void removeVisual(Visual *visual);
+
+ static SoundCore* instance();
+
+signals:
+
+ /*!
+ * This signal is emited when the state of the decoder changes.
+ * The argument \b state is the new state of the decoder
+ */
+ void decoderStateChanged(const DecoderState& state);
+
+ /*!
+ * This signal is emited when the state of the output changes.
+ * The argument \b state is the new state of the output
+ */
+ void outputStateChanged(const OutputState& state);
+
+ /*!
+ * This signal is emited when the title of the stream changes.
+ * The argument \b title is the new title of the stream.
+ * Signal emits with the shoutcast server stream only.
+ * For another servers use decoderStateChanged()
+ */
+ void titleChanged(const QString& title);
+
+private slots:
+ bool decode();
+
+private:
+ Decoder* m_decoder;
+ Output* m_output;
+ QIODevice* m_input;
+ uint m_error;
+ bool m_paused;
+ bool m_useEQ;
+ bool m_update;
+ bool m_block;
+ int m_preamp;
+ int m_bands[10];
+ Visual *m_vis;
+ QList <Visual*> m_visuals;
+ QString m_source;
+ QWidget *m_parentWidget;
+ static SoundCore* m_instance;
+};
+
+#endif
diff --git a/src/qmmp/streamreader.cpp b/src/qmmp/streamreader.cpp
new file mode 100644
index 000000000..30bb9c3a7
--- /dev/null
+++ b/src/qmmp/streamreader.cpp
@@ -0,0 +1,139 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include <QApplication>
+#include <QUrl>
+
+#include "downloader.h"
+#include "streamreader.h"
+
+StreamReader::StreamReader(const QString &name, QObject *parent)
+ : QIODevice(parent)
+{
+ m_downloader = new Downloader(this, name);
+ connect(m_downloader, SIGNAL(titleChanged()),SLOT(updateTitle()));
+ connect(m_downloader, SIGNAL(readyRead()), SIGNAL(readyRead()));
+}
+
+StreamReader::~StreamReader()
+{
+ m_downloader->abort();
+ qDebug("StreamReader::~StreamReader()");
+}
+
+bool StreamReader::atEnd () const
+{
+ return FALSE;
+}
+
+qint64 StreamReader::bytesAvailable () const
+{
+ return m_downloader->bytesAvailable ();
+}
+
+qint64 StreamReader::bytesToWrite () const
+{
+ return -1;
+}
+
+bool StreamReader::canReadLine () const
+{
+ return FALSE;
+}
+
+void StreamReader::close ()
+{
+ m_downloader->abort();
+}
+
+bool StreamReader::isSequential () const
+{
+ return TRUE;
+}
+
+bool StreamReader::open ( OpenMode mode )
+{
+ if (mode != QIODevice::ReadOnly)
+ return FALSE;
+ //downloadFile();
+ setOpenMode(QIODevice::ReadOnly);
+ if (m_downloader->isRunning() && m_downloader->isReady())
+ return TRUE;
+ else
+ return FALSE;
+}
+
+bool StreamReader::reset ()
+{
+ QIODevice::reset();
+ return TRUE;
+}
+
+bool StreamReader::seek ( qint64 pos )
+{
+ QIODevice::seek(pos);
+ return FALSE;
+}
+
+qint64 StreamReader::size () const
+{
+ return bytesAvailable ();
+}
+
+bool StreamReader::waitForBytesWritten ( int msecs )
+{
+ usleep(msecs*1000);
+ return TRUE;
+}
+
+bool StreamReader::waitForReadyRead ( int msecs )
+{
+ usleep(msecs*1000);
+ return TRUE;
+}
+
+qint64 StreamReader::readData(char* data, qint64 maxlen)
+{
+ return m_downloader->read (data, maxlen);
+}
+
+qint64 StreamReader::writeData(const char*, qint64)
+{
+ return 0;
+}
+
+void StreamReader::downloadFile()
+{
+ m_downloader->start();
+}
+
+void StreamReader::updateTitle()
+{
+ emit titleChanged(m_downloader->title());
+}
+
+const QString &StreamReader::contentType()
+{
+ m_downloader->mutex()->lock ();
+ m_contentType = m_downloader->contentType();
+ m_downloader->mutex()->unlock();
+ qApp->processEvents();
+ qDebug("StreamReader: content type: %s", qPrintable(m_contentType));
+ return m_contentType;
+}
diff --git a/src/qmmp/streamreader.h b/src/qmmp/streamreader.h
new file mode 100644
index 000000000..c8182153a
--- /dev/null
+++ b/src/qmmp/streamreader.h
@@ -0,0 +1,85 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef STREAMREADER_H
+#define STREAMREADER_H
+
+#include <QObject>
+#include <QIODevice>
+#include <QUrl>
+
+class QFileInfo;
+
+class Downloader;
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class StreamReader : public QIODevice
+{
+ Q_OBJECT
+public:
+ StreamReader(const QString &name, QObject *parent = 0);
+
+ ~StreamReader();
+
+ /**
+ * QIODevice API
+ */
+ bool atEnd () const;
+ qint64 bytesAvailable () const;
+ qint64 bytesToWrite () const;
+ bool canReadLine () const;
+ void close ();
+ bool isSequential () const;
+ bool open ( OpenMode mode );
+ //qint64 pos () const;
+ bool reset ();
+ bool seek ( qint64 pos );
+ qint64 size () const;
+ bool waitForBytesWritten ( int msecs );
+ bool waitForReadyRead ( int msecs );
+
+ /**
+ * returns content type of a stream
+ */
+ const QString &contentType();
+ void downloadFile();
+
+signals:
+ void titleChanged(const QString&);
+ void readyRead();
+
+protected:
+ qint64 readData(char*, qint64);
+ qint64 writeData(const char*, qint64);
+
+
+private slots:
+ void updateTitle();
+
+private:
+ //void downloadFile();
+ void fillBuffer();
+ QUrl m_url;
+ QString m_contentType;
+ Downloader *m_downloader;
+};
+
+#endif
diff --git a/src/qmmp/visual.cpp b/src/qmmp/visual.cpp
new file mode 100644
index 000000000..ce5e8a982
--- /dev/null
+++ b/src/qmmp/visual.cpp
@@ -0,0 +1,151 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QtGui>
+#include <QObject>
+#include <QList>
+#include <QApplication>
+
+#include "visualfactory.h"
+#include "constants.h"
+#include "output.h"
+
+#include "visual.h"
+
+
+static QList<VisualFactory*> *factories = 0;
+static QStringList files;
+
+static void checkFactories()
+{
+ if (! factories)
+ {
+ files.clear();
+ factories = new QList<VisualFactory *>;
+
+ QDir pluginsDir (qApp->applicationDirPath());
+ pluginsDir.cdUp();
+ pluginsDir.cd("./"LIB_DIR"/qmmp/Visual");
+ foreach (QString fileName, pluginsDir.entryList(QDir::Files))
+ {
+ QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
+ QObject *plugin = loader.instance();
+ if (loader.isLoaded())
+ {
+ qDebug("Visual: plugin loaded - %s", qPrintable(fileName));
+ }
+ VisualFactory *factory = 0;
+ if (plugin)
+ factory = qobject_cast<VisualFactory *>(plugin);
+
+ if (factory)
+ {
+ factories->append(factory);
+ files << pluginsDir.absoluteFilePath(fileName);
+ }
+ }
+ }
+}
+
+
+Visual::Visual(QWidget *parent) : QWidget(parent)
+{
+ setAttribute(Qt::WA_DeleteOnClose, TRUE);
+ setAttribute(Qt::WA_QuitOnClose, FALSE);
+}
+
+Visual::~Visual()
+{
+ qDebug("Visual::~Visual()");
+}
+
+Decoder *Visual::decoder() const
+{
+ return m_decoder;
+}
+
+void Visual::setDecoder(Decoder *decoder)
+{
+ m_decoder = decoder;
+}
+
+Output *Visual::output() const
+{
+ return m_output;
+}
+
+void Visual::setOutput(Output *output)
+{
+ m_output = output;
+}
+
+QMutex *Visual::mutex()
+{
+ return &m_mutex;
+}
+
+QList<VisualFactory*> *Visual::visualFactories()
+{
+ checkFactories();
+ return factories;
+}
+
+QStringList Visual::visualFiles()
+{
+ checkFactories();
+ return files;
+}
+
+void Visual::setEnabled(VisualFactory* factory, bool enable)
+{
+ checkFactories();
+ if(!factories->contains(factory))
+ return;
+
+ QString name = files.at(factories->indexOf(factory)).section('/',-1);
+ QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat );
+ QStringList visList = settings.value("Visualization/plugin_files").toStringList();
+
+ if(enable)
+ {
+ if (!visList.contains(name))
+ visList << name;
+ }
+ else
+ visList.removeAll(name);
+ settings.setValue("Visualization/plugin_files", visList);
+}
+
+bool Visual::isEnabled(VisualFactory* factory)
+{
+ checkFactories();
+ if(!factories->contains(factory))
+ return FALSE;
+ QString name = files.at(factories->indexOf(factory)).section('/',-1);
+ QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat );
+ QStringList visList = settings.value("Visualization/plugin_files").toStringList();
+ return visList.contains(name);
+}
+
+void Visual::closeEvent (QCloseEvent *event)
+{
+ m_output->removeVisual(this);
+ QWidget::closeEvent(event);
+}
diff --git a/src/qmmp/visual.h b/src/qmmp/visual.h
new file mode 100644
index 000000000..ef663bb37
--- /dev/null
+++ b/src/qmmp/visual.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef VISUAL_H
+#define VISUAL_H
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+
+#include <QMutex>
+#include <QStringList>
+#include <QWidget>
+#include <QMap>
+
+class Buffer;
+class Decoder;
+class Output;
+class VisualFactory;
+
+class Visual : public QWidget
+{
+ Q_OBJECT
+public:
+ Visual(QWidget *parent);
+
+ virtual ~Visual();
+
+ virtual void add(Buffer *, unsigned long, int, int) = 0;
+ virtual void clear() = 0;
+
+ Decoder *decoder() const;
+ void setDecoder(Decoder *decoder);
+ Output *output() const;
+ void setOutput(Output *output);
+ QMutex *mutex();
+
+ //static methods
+ static QList<VisualFactory*> *visualFactories();
+ static QStringList visualFiles();
+ static void setEnabled(VisualFactory* factory, bool enable = TRUE);
+ static bool isEnabled(VisualFactory* factory);
+
+protected:
+ virtual void closeEvent (QCloseEvent *);
+
+private:
+ Decoder *m_decoder;
+ Output *m_output;
+ QMutex m_mutex;
+};
+
+#endif
diff --git a/src/qmmp/visualfactory.h b/src/qmmp/visualfactory.h
new file mode 100644
index 000000000..6862032bb
--- /dev/null
+++ b/src/qmmp/visualfactory.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef VISUALFACTORY_H
+#define VISUALFACTORY_H
+
+class QObject;
+class QWidget;
+class QTranslator;
+
+class Visual;
+
+struct VisualProperties
+{
+ QString name;
+ bool hasAbout;
+ bool hasSettings;
+};
+
+class VisualFactory
+{
+public:
+ virtual ~VisualFactory() {}
+ virtual const VisualProperties properties() const = 0;
+ virtual Visual *create(QWidget *parent) = 0;
+ virtual void showSettings(QWidget *parent) = 0;
+ virtual void showAbout(QWidget *parent) = 0;
+ virtual QTranslator *createTranslator(QObject *parent) = 0;
+};
+
+Q_DECLARE_INTERFACE(VisualFactory, "VisualFactory/1.0");
+
+#endif
diff --git a/src/qmmpui/general.cpp b/src/qmmpui/general.cpp
new file mode 100644
index 000000000..aebd06647
--- /dev/null
+++ b/src/qmmpui/general.cpp
@@ -0,0 +1,157 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QtGui>
+#include <QObject>
+#include <QList>
+#include <QApplication>
+
+#include "config.h"
+#include "general.h"
+
+
+static QList<GeneralFactory*> *factories = 0;
+static QStringList files;
+
+static void checkFactories()
+{
+ if (! factories)
+ {
+ files.clear();
+ factories = new QList<GeneralFactory *>;
+
+ QDir pluginsDir (qApp->applicationDirPath());
+ pluginsDir.cdUp();
+ pluginsDir.cd("./"LIB_DIR"/qmmp/General");
+ foreach (QString fileName, pluginsDir.entryList(QDir::Files))
+ {
+ QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
+ QObject *plugin = loader.instance();
+ if (loader.isLoaded())
+ {
+ qDebug("General: plugin loaded - %s", qPrintable(fileName));
+ }
+ GeneralFactory *factory = 0;
+ if (plugin)
+ factory = qobject_cast<GeneralFactory *>(plugin);
+
+ if (factory)
+ {
+ factories->append(factory);
+ files << pluginsDir.absoluteFilePath(fileName);
+ }
+ }
+ }
+}
+
+General::General(QObject *parent)
+ : QObject(parent)
+{
+}
+
+
+General::~General()
+{
+}
+
+void General::setState(const uint&)
+{}
+
+void General::setSongInfo(const SongInfo &song)
+{}
+
+
+QList<GeneralFactory*> *General::generalFactories()
+{
+ checkFactories();
+ return factories;
+}
+
+QStringList General::generalFiles()
+{
+ checkFactories();
+ return files;
+}
+
+void General::setEnabled(GeneralFactory* factory, bool enable)
+{
+ checkFactories();
+ if(!factories->contains(factory))
+ return;
+
+ QString name = files.at(factories->indexOf(factory)).section('/',-1);
+ QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat );
+ QStringList genList = settings.value("General/plugin_files").toStringList();
+
+ if(enable)
+ {
+ if (!genList.contains(name))
+ genList << name;
+ }
+ else
+ genList.removeAll(name);
+ settings.setValue("General/plugin_files", genList);
+}
+
+bool General::isEnabled(GeneralFactory* factory)
+{
+ checkFactories();
+ if(!factories->contains(factory))
+ return FALSE;
+ QString name = files.at(factories->indexOf(factory)).section('/',-1);
+ QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat );
+ QStringList genList = settings.value("General/plugin_files").toStringList();
+ return genList.contains(name);
+}
+
+void General::play()
+{
+ emit commandCalled(Play);
+}
+
+void General::pause()
+{
+ emit commandCalled(Pause);
+}
+
+void General::stop()
+{
+ emit commandCalled(Stop);
+}
+
+void General::next()
+{
+ emit commandCalled(Next);
+}
+
+void General::previous()
+{
+ emit commandCalled(Previous);
+}
+
+void General::exit()
+{
+ emit commandCalled(Exit);
+}
+
+void General::toggleVisibility()
+{
+ emit commandCalled(ToggleVisibility);
+}
diff --git a/src/qmmpui/general.h b/src/qmmpui/general.h
new file mode 100644
index 000000000..a7cc0e142
--- /dev/null
+++ b/src/qmmpui/general.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef GENERAL_H
+#define GENERAL_H
+
+#include <QObject>
+#include <QStringList>
+#include <QMap>
+
+#include "songinfo.h"
+#include "generalfactory.h"
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class General : public QObject
+{
+ Q_OBJECT
+public:
+ General(QObject *parent = 0);
+
+ ~General();
+
+ enum State
+ {
+ Playing = 0,
+ Paused,
+ Stopped
+ };
+
+ enum Command
+ {
+ Play = 0,
+ Stop,
+ Pause,
+ Previous,
+ Next,
+ Exit,
+ ToggleVisibility
+ };
+
+ virtual void setState(const uint &state);
+ virtual void setSongInfo(const SongInfo &song);
+
+ //static methods
+ static QList<GeneralFactory*> *generalFactories();
+ static QStringList generalFiles();
+ static void setEnabled(GeneralFactory* factory, bool enable = TRUE);
+ static bool isEnabled(GeneralFactory* factory);
+
+signals:
+ void commandCalled(uint command);
+
+public slots:
+ void play();
+ void pause();
+ void stop();
+ void next();
+ void previous();
+ void exit();
+ void toggleVisibility();
+
+private:
+ QMap <uint, QString> m_strValues;
+ QMap <uint, uint> m_numValues;
+
+};
+
+#endif
diff --git a/src/qmmpui/generalfactory.h b/src/qmmpui/generalfactory.h
new file mode 100644
index 000000000..3038b597c
--- /dev/null
+++ b/src/qmmpui/generalfactory.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef GENERALFACTORY_H
+#define GENERALFACTORY_H
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class QObject;
+class QTranslator;
+
+class General;
+
+struct GeneralProperties
+{
+ QString name;
+ bool hasAbout;
+ bool hasSettings;
+};
+
+class GeneralFactory
+{
+public:
+ virtual ~GeneralFactory() {}
+ virtual const GeneralProperties properties() const = 0;
+ virtual General *create(QObject *parent) = 0;
+ virtual void showSettings(QWidget *parent) = 0;
+ virtual void showAbout(QWidget *parent) = 0;
+ virtual QTranslator *createTranslator(QObject *parent) = 0;
+};
+
+Q_DECLARE_INTERFACE(GeneralFactory, "GeneralFactory/1.0");
+
+
+#endif
diff --git a/src/qmmpui/generalhandler.cpp b/src/qmmpui/generalhandler.cpp
new file mode 100644
index 000000000..dc29f281a
--- /dev/null
+++ b/src/qmmpui/generalhandler.cpp
@@ -0,0 +1,143 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include "general.h"
+#include "generalfactory.h"
+
+#include "generalhandler.h"
+
+GeneralHandler *GeneralHandler::m_instance = 0;
+
+GeneralHandler::GeneralHandler(QObject *parent)
+ : QObject(parent)
+{
+ m_instance = this;
+ m_state = General::Stopped;
+ GeneralFactory* factory;
+ foreach(factory, *General::generalFactories())
+ {
+ if (General::isEnabled(factory))
+ {
+ General *general = factory->create(parent);
+ connect(general, SIGNAL(commandCalled(uint)), SLOT(processCommand(uint)));
+ m_generals.append(general);
+ }
+ }
+}
+
+GeneralHandler::~GeneralHandler()
+{}
+
+void GeneralHandler::setState(uint state)
+{
+ if (state == m_state)
+ return;
+ m_state = state;
+ General *general;
+ if (state == General::Stopped)
+ m_songInfo.clear();
+
+ foreach(general, m_generals)
+ {
+ general->setState(state);
+ }
+}
+
+void GeneralHandler::setSongInfo(const SongInfo &info)
+{
+ if (m_state == General::Stopped)
+ return;
+ if (m_songInfo != info)
+ {
+ m_songInfo = info;
+ General *general;
+ foreach(general, m_generals)
+ {
+ general->setSongInfo(m_songInfo);
+ }
+ }
+}
+
+void GeneralHandler::updateConfig()
+{
+ while (!m_generals.isEmpty())
+ delete m_generals.takeFirst();
+
+ GeneralFactory* factory;
+ foreach(factory, *General::generalFactories())
+ {
+ if (General::isEnabled(factory))
+ {
+ General *general = factory->create(parent());
+ connect(general, SIGNAL(commandCalled(uint)), SLOT(processCommand(uint)));
+ m_generals.append(general);
+ general->setState(m_state);
+ if (m_state != General::Stopped)
+ general->setSongInfo(m_songInfo);
+ }
+ }
+}
+
+GeneralHandler* GeneralHandler::instance()
+{
+ return m_instance;
+}
+
+void GeneralHandler::processCommand(uint command)
+{
+ switch ((uint) command)
+ {
+ case General::Play:
+ {
+ emit playCalled();
+ break;
+ }
+ case General::Stop:
+ {
+ emit stopCalled();
+ break;
+ }
+ case General::Pause:
+ {
+ emit pauseCalled();
+ break;
+ }
+ case General::Previous:
+ {
+ emit previousCalled();
+ break;
+ }
+ case General::Next:
+ {
+ emit nextCalled();
+ break;
+ }
+ case General::Exit:
+ {
+ emit exitCalled();
+ break;
+ }
+ case General::ToggleVisibility:
+ {
+ emit toggleVisibilityCalled();
+ break;
+ }
+ }
+}
diff --git a/src/qmmpui/generalhandler.h b/src/qmmpui/generalhandler.h
new file mode 100644
index 000000000..308a0a694
--- /dev/null
+++ b/src/qmmpui/generalhandler.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef GENERALHANDLER_H
+#define GENERALHANDLER_H
+
+#include <QObject>
+
+#include "songinfo.h"
+
+class General;
+class GeneralFactory;
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+class GeneralHandler : public QObject
+{
+ Q_OBJECT
+public:
+ GeneralHandler(QObject *parent = 0);
+
+ ~GeneralHandler();
+
+ void setSongInfo(const SongInfo &info);
+ void updateConfig();
+ static GeneralHandler* instance();
+
+signals:
+ void playCalled();
+ void pauseCalled();
+ void stopCalled();
+ void nextCalled();
+ void previousCalled();
+ void exitCalled();
+ void toggleVisibilityCalled();
+
+public slots:
+ void setState(uint state);
+
+private slots:
+ void processCommand(uint command);
+
+private:
+ void connectSignals(General*);
+ QList <General*> m_generals;
+ SongInfo m_songInfo;
+ uint m_state;
+ static GeneralHandler* m_instance;
+
+};
+
+#endif
diff --git a/src/qmmpui/qmmpui.pro b/src/qmmpui/qmmpui.pro
new file mode 100644
index 000000000..88c60a0da
--- /dev/null
+++ b/src/qmmpui/qmmpui.pro
@@ -0,0 +1,38 @@
+include(../../qmmp.pri)
+
+TARGET = ../../lib/qmmpui
+CONFIG += release \
+warn_on \
+qt \
+thread
+
+TEMPLATE = lib
+
+
+isEmpty(LIB_DIR){
+ LIB_DIR = /lib
+}
+
+unix {
+ LINE1 = $$sprintf(echo \"%1ifndef CONFIG_H\" > ./config.h, $$LITERAL_HASH)
+ LINE2 = $$sprintf(echo \"%1define CONFIG_H\" >> ./config.h, $$LITERAL_HASH)
+ LINE3 = $$sprintf(echo \"%1define LIB_DIR \\\"%2\\\"\" >> ./config.h, $$LITERAL_HASH, $$LIB_DIR)
+ LINE4 = $$sprintf(echo \"%1endif\" >> ./config.h, $$LITERAL_HASH)
+ system($$LINE1)
+ system($$LINE2)
+ system($$LINE3)
+ system($$LINE4)
+ QMAKE_CLEAN = ./config.h
+}
+
+
+target.path = $$LIB_DIR
+INSTALLS += target
+HEADERS += general.h \
+generalfactory.h \
+ generalhandler.h \
+ songinfo.h
+SOURCES += general.cpp \
+ generalhandler.cpp \
+ songinfo.cpp
+
diff --git a/src/qmmpui/songinfo.cpp b/src/qmmpui/songinfo.cpp
new file mode 100644
index 000000000..6fa1e831e
--- /dev/null
+++ b/src/qmmpui/songinfo.cpp
@@ -0,0 +1,137 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include "songinfo.h"
+
+SongInfo::SongInfo()
+{}
+
+SongInfo::SongInfo(const SongInfo &other)
+{
+ *this = other;
+}
+
+SongInfo::~SongInfo()
+{}
+
+void SongInfo::operator=(const SongInfo &info)
+{
+ setValue(TITLE,info.title ());
+ setValue(ARTIST,info.artist ());
+ setValue(ALBUM,info.album ());
+ setValue(COMMENT,info.comment ());
+ setValue(GENRE,info.genre ());
+ setValue(YEAR,info.year ());
+ setValue(TRACK,info.track ());
+ setValue(LENGTH,info.length ());
+ setValue(STREAM,info.isStream());
+}
+
+bool SongInfo::operator==(const SongInfo &info)
+{
+ return title() == info.title() &&
+ artist() == info.artist() &&
+ album() == info.album() &&
+ comment() == info.comment() &&
+ genre() == info.genre() &&
+ track() == info.track() &&
+ year() == info.year() &&
+ isStream() == info.isStream();
+}
+
+bool SongInfo::operator!=(const SongInfo &info)
+{
+ return !operator==(info);
+}
+
+void SongInfo::setValue(uint name, const QString &value)
+{
+ if (!value.isEmpty())
+ m_strValues.insert (name, value);
+}
+
+void SongInfo::setValue(uint name, const uint &value)
+{
+ if (value > 0)
+ m_numValues.insert (name, value);
+}
+
+void SongInfo::setValue(uint name, const bool &value)
+{
+ if(name == STREAM)
+ m_stream = value;
+}
+
+const QString SongInfo::title () const
+{
+ return m_strValues[TITLE];
+}
+
+const QString SongInfo::artist () const
+{
+ return m_strValues[ARTIST];
+}
+
+const QString SongInfo::album () const
+{
+ return m_strValues[ALBUM];
+}
+
+const QString SongInfo::comment () const
+{
+ return m_strValues[COMMENT];
+}
+
+const QString SongInfo::genre () const
+{
+ return m_strValues[GENRE];
+}
+
+const uint SongInfo::year () const
+{
+ return m_numValues[YEAR];
+}
+
+const uint SongInfo::track () const
+{
+ return m_numValues[TRACK];
+}
+
+const uint SongInfo::length () const
+{
+ return m_numValues[LENGTH];
+}
+
+const bool SongInfo::isEmpty () const
+{
+ return m_strValues.isEmpty();
+}
+
+void SongInfo::clear ()
+{
+ m_strValues.clear();
+ m_numValues.clear();
+ m_stream = FALSE;
+}
+
+const bool SongInfo::isStream () const
+{
+ return m_stream;
+}
+
diff --git a/src/qmmpui/songinfo.h b/src/qmmpui/songinfo.h
new file mode 100644
index 000000000..7bc43381d
--- /dev/null
+++ b/src/qmmpui/songinfo.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef SONGINFO_H
+#define SONGINFO_H
+
+#include <QMap>
+#include <QString>
+
+/**
+ @author Ilya Kotov <forkotov02@hotmail.ru>
+*/
+
+class SongInfo{
+public:
+ public:
+ SongInfo();
+ SongInfo(const SongInfo &other);
+
+ ~SongInfo();
+
+ enum Type
+ {
+ TITLE = 0,
+ ARTIST,
+ ALBUM,
+ COMMENT,
+ GENRE,
+ YEAR,
+ TRACK,
+ LENGTH,
+ STREAM
+ };
+
+ void operator=(const SongInfo &info);
+ bool operator==(const SongInfo &info);
+ bool operator!=(const SongInfo &info);
+ void setValue(uint name, const QString &value);
+ void setValue(uint name, const uint &value);
+ void setValue(uint name, const bool &value);
+ const QString title () const;
+ const QString artist () const;
+ const QString album () const;
+ const QString comment () const;
+ const QString genre () const;
+ const uint year () const;
+ const uint track () const;
+ const uint length () const;
+ const bool isEmpty () const;
+ const bool isStream () const;
+ void clear();
+
+private:
+ QMap <uint, QString> m_strValues;
+ QMap <uint, uint> m_numValues;
+ bool m_stream;
+
+};
+
+#endif
diff --git a/src/aboutdialog.cpp b/src/ui/aboutdialog.cpp
index a8b80e6cd..a8b80e6cd 100644
--- a/src/aboutdialog.cpp
+++ b/src/ui/aboutdialog.cpp
diff --git a/src/aboutdialog.h b/src/ui/aboutdialog.h
index 10dcde4a5..10dcde4a5 100644
--- a/src/aboutdialog.h
+++ b/src/ui/aboutdialog.h
diff --git a/src/addurldialog.cpp b/src/ui/addurldialog.cpp
index 6746a2de1..6746a2de1 100644
--- a/src/addurldialog.cpp
+++ b/src/ui/addurldialog.cpp
diff --git a/src/addurldialog.h b/src/ui/addurldialog.h
index 86a065703..86a065703 100644
--- a/src/addurldialog.h
+++ b/src/ui/addurldialog.h
diff --git a/src/balancebar.cpp b/src/ui/balancebar.cpp
index 3089e0cbd..3089e0cbd 100644
--- a/src/balancebar.cpp
+++ b/src/ui/balancebar.cpp
diff --git a/src/balancebar.h b/src/ui/balancebar.h
index 6704671f9..6704671f9 100644
--- a/src/balancebar.h
+++ b/src/ui/balancebar.h
diff --git a/src/button.cpp b/src/ui/button.cpp
index 8bd006ed3..8bd006ed3 100644
--- a/src/button.cpp
+++ b/src/ui/button.cpp
diff --git a/src/button.h b/src/ui/button.h
index 7f2d8f314..7f2d8f314 100644
--- a/src/button.h
+++ b/src/ui/button.h
diff --git a/src/ui/commandlineoption.cpp b/src/ui/commandlineoption.cpp
new file mode 100644
index 000000000..ca9e8d398
--- /dev/null
+++ b/src/ui/commandlineoption.cpp
@@ -0,0 +1,216 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <QDir>
+#include <QPluginLoader>
+
+#include "commandlineoption.h"
+#include "mainwindow.h"
+#include <soundcore.h>
+
+
+// Command option manager methods
+CommandLineOptionManager::CommandLineOptionManager()
+{
+ this->registerBuiltingCommandLineOptions();
+ this->registerExternalCommandLineOptions();
+}
+
+bool CommandLineOptionManager::hasOption(const QString &opt)
+{
+ for(int i = 0; i < m_options.count(); i++)
+ {
+ if(m_options[i]->identify(opt))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void CommandLineOptionManager::executeCommand(const QString &opt, MainWindow *mw)
+{
+ for(int i = 0; i < m_options.count(); i++)
+ {
+ if(m_options[i]->identify(opt))
+ {
+ m_options[i]->executeCommand(opt,mw);
+ }
+ }
+}
+
+CommandLineOption * CommandLineOptionManager::operator [](int index)
+{
+ return m_options[index];
+}
+
+int CommandLineOptionManager::count() const
+{
+ return m_options.count();
+}
+
+
+void CommandLineOptionManager::registerBuiltingCommandLineOptions()
+{
+ m_options.append(new BuiltinCommandLineOption());
+}
+
+
+void CommandLineOptionManager::registerExternalCommandLineOptions()
+{
+ QDir pluginsDir (QDir::homePath()+"/.qmmp/plugins/CommandLineOptions");
+ foreach (QString fileName, pluginsDir.entryList(QDir::Files))
+ {
+ QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
+ QObject *plugin = loader.instance();
+ if (loader.isLoaded())
+ qDebug("CommandLineOption: plugin loaded - %s", qPrintable(fileName));
+ else
+ qWarning(qPrintable(loader.errorString()));
+
+ CommandLineOption *cmd_option = 0;
+ if (plugin)
+ cmd_option = qobject_cast<CommandLineOption *>(plugin);
+
+ if (cmd_option)
+ {
+ foreach(CommandLineOption* opt,m_options)
+ {
+ if (opt->name() == cmd_option->name())
+ {
+ qDebug("CommandLineOption: Plugin with name %s is already registered...",
+ qPrintable(cmd_option->name()));
+ return;
+ }
+ }
+ m_options.append(cmd_option);
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////
+
+
+// BuiltinCommandLineOption methods implementation
+bool BuiltinCommandLineOption::identify(const QString & str) const
+{
+ if(
+ str == QString("--help") ||
+ str == QString("--next") ||
+ str == QString("--previous") ||
+ str == QString("--play") ||
+ str == QString("--pause") ||
+ str == QString("--play-pause") ||
+ str == QString("--stop") ||
+ str.startsWith("--volume") ||
+ str.startsWith("--jump-to-file") ||
+ str.startsWith("--toggle-visibility") ||
+ str.startsWith("--add-file")
+ )
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+const QString BuiltinCommandLineOption::helpString() const
+{
+ return QString(
+ "--next Skip forward in playlist\n"
+ "--previous Skip backwards in playlist\n"
+ "--play Start playing current song\n"
+ "--pause Pause current song\n"
+ "--play-pause Pause if playing, play otherwise\n"
+ "--stop Stop current song\n"
+ "--next Skip forward in playlist\n"
+ "--volume Set playback volume(example: qmmp --volume20, qmmp --volume100)\n"
+ "--jump-to-file Display Jump to File dialog\n"
+ "--toggle-visibility Show/hide application\n"
+ "--add-file Display Add File dialog"
+ );
+}
+
+void BuiltinCommandLineOption::executeCommand(const QString & option_string, MainWindow *mw)
+{
+ if (option_string == "--play")
+ {
+ mw->play();
+ }
+ else if (option_string == "--stop")
+ {
+ mw->stop();
+ mw->mainDisplay()->hideTimeDisplay();
+ }
+ else if (option_string == "--pause")
+ {
+ mw->pause();
+ }
+ else if (option_string == "--next")
+ {
+ mw->next();
+ if(!mw->soundCore()->isInitialized())
+ mw->play();
+ }
+ else if (option_string == "--previous")
+ {
+ mw->previous();
+ if(!mw->soundCore()->isInitialized())
+ mw->play();
+ }
+ else if (option_string == "--play-pause")
+ {
+ mw->playPause();
+ }
+ else if (option_string == "--jump-to-file")
+ {
+ mw->jumpToFile();
+ }
+ else if (option_string == "--toggle-visibility")
+ {
+ mw->toggleVisibility();
+ }
+ else if (option_string == "--add-file")
+ {
+ mw->addFile();
+ }
+ else if (option_string.startsWith("--volume"))
+ {
+ QString vol_str(option_string);
+ vol_str.remove("--volume");
+ bool ok = FALSE;
+ int volume = vol_str.toUInt(&ok);
+ if(ok)
+ {
+ mw->soundCore()->setVolume(volume,volume);
+ }
+ }
+}
+
+const QString BuiltinCommandLineOption::name() const
+{
+ return "BuiltinCommandLineOption";
+}
+
+
+
+
+
+
diff --git a/src/ui/commandlineoption.h b/src/ui/commandlineoption.h
new file mode 100644
index 000000000..f5bc78ecf
--- /dev/null
+++ b/src/ui/commandlineoption.h
@@ -0,0 +1,94 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef CommandLineOption_H
+#define CommandLineOption_H
+
+#include <QtPlugin>
+#include <QString>
+#include <QList>
+
+class MainWindow;
+
+/**
+ @author Vladimir Kuznetsov <vovanec@gmail.ru>
+ */
+class CommandLineOption
+{
+public:
+ /*!
+ * Returns \b true if \b opt_str string can be processed,
+ * otherise \b false
+ */
+ virtual bool identify(const QString& opt_str)const = 0;
+
+ /*!
+ * Command line option name
+ */
+ virtual const QString name()const = 0;
+
+ /*!
+ * Help string.
+ */
+ virtual const QString helpString()const = 0;
+
+ /*!
+ * Parses \b opt_str args(if needed), executes command.
+ */
+ virtual void executeCommand(const QString& opt_str,MainWindow* mw) = 0;
+ virtual ~CommandLineOption(){;}
+};
+
+Q_DECLARE_INTERFACE(CommandLineOption,"CommandLineOptionInterface/1.0");
+
+
+
+typedef QList<CommandLineOption*> CommandLineOptionList;
+
+class CommandLineOptionManager
+{
+public:
+ CommandLineOptionManager();
+ bool hasOption(const QString& );
+ void executeCommand(const QString&,MainWindow* = NULL);
+ CommandLineOption* operator[](int);
+ int count()const;
+protected:
+ void registerBuiltingCommandLineOptions();
+ void registerExternalCommandLineOptions();
+private:
+ void _register(CommandLineOption*);
+private:
+ CommandLineOptionList m_options;
+};
+
+/*!
+ * Represens command line option handling for standard operations.
+ */
+class BuiltinCommandLineOption : public CommandLineOption
+{
+ virtual bool identify(const QString& str)const;
+ virtual const QString helpString()const;
+ virtual void executeCommand(const QString& option,MainWindow* = NULL);
+ virtual const QString name()const;
+ virtual ~BuiltinCommandLineOption(){;}
+};
+
+#endif
diff --git a/src/configdialog.cpp b/src/ui/configdialog.cpp
index 958453a27..808c1ac94 100644
--- a/src/configdialog.cpp
+++ b/src/ui/configdialog.cpp
@@ -33,6 +33,9 @@
#include <visualfactory.h>
#include <effectfactory.h>
#include <effect.h>
+#include <qmmpui/generalfactory.h>
+#include <qmmpui/general.h>
+
#include "skin.h"
#include "filedialog.h"
@@ -85,22 +88,6 @@ void ConfigDialog::readSettings()
settings.value ( "PlayList/title_format", "%p - %t").toString());
ui.metadataCheckBox->setChecked(
settings.value ( "PlayList/load_metadata", TRUE).toBool());
- ui.trayCheckBox->setChecked(
- settings.value("Tray/enabled",TRUE).toBool());
- ui.messageCheckBox->setChecked(
- settings.value("Tray/show_message",TRUE).toBool());
- ui.messageDelaySpinBox->setValue(settings.value("Tray/message_delay",
- 2000).toInt());
- ui.messageCheckBox->setEnabled(ui.trayCheckBox->isChecked());
- ui.messageDelaySpinBox->setEnabled(ui.trayCheckBox->isChecked() ||
- ui.messageCheckBox->isChecked() );
- ui.toolTipCheckBox->setEnabled(ui.trayCheckBox->isChecked());
- ui.toolTipCheckBox->setChecked(
- settings.value("Tray/show_tooltip",FALSE).toBool());
-
- ui.hideToTrayRadioButton->setChecked(settings.value("Tray/hide_on_close", FALSE).toBool());
- ui.closeGroupBox->setEnabled(ui.trayCheckBox->isChecked());
-
QString f_dialogName =
settings.value("FileDialog",QtFileDialogFactory::QtFileDialogFactoryName).toString();
@@ -125,6 +112,8 @@ void ConfigDialog::readSettings()
ui.portLineEdit->setEnabled(ui.enableProxyCheckBox->isChecked());
ui.proxyUserLineEdit->setEnabled(ui.authProxyCheckBox->isChecked());
ui.proxyPasswLineEdit->setEnabled(ui.authProxyCheckBox->isChecked());
+
+ ui.softVolumeCheckBox->setChecked(settings.value("Volume/software_volume", FALSE).toBool());
}
void ConfigDialog::changePage ( QListWidgetItem *current, QListWidgetItem *previous )
@@ -155,6 +144,7 @@ void ConfigDialog::loadSkins()
findSkins(QDir::homePath() +"/.qmmp/skins");
findSkins(QDir::homePath() +"/.qmmp/cache/skins");
+ findSkins(qApp->applicationDirPath()+"/../share/qmmp/skins");
connect ( ui.listWidget, SIGNAL ( itemClicked ( QListWidgetItem* ) ),
this, SLOT ( changeSkin() ) );
}
@@ -202,6 +192,8 @@ void ConfigDialog::loadPluginsInfo()
ui.inputPluginTable->setItem ( i,1,
new QTableWidgetItem (item->factory()->properties().name) );
ui.inputPluginTable->setItem ( i,2, new QTableWidgetItem (files.at (i)) );
+ ui.inputPluginTable->item(i,1)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ ui.inputPluginTable->item(i,2)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
}
ui.inputPluginTable->resizeColumnToContents ( 0 );
ui.inputPluginTable->resizeColumnToContents ( 1 );
@@ -227,8 +219,10 @@ void ConfigDialog::loadPluginsInfo()
button->setChecked ( item->isSelected() );
ui.outputPluginTable->setCellWidget ( i, 0, button );
ui.outputPluginTable->setItem (i,1,
- new QTableWidgetItem (item->factory()->name()));
+ new QTableWidgetItem (item->factory()->properties().name));
ui.outputPluginTable->setItem (i,2, new QTableWidgetItem (files.at(i)));
+ ui.outputPluginTable->item(i,1)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ ui.outputPluginTable->item(i,2)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
}
ui.outputPluginTable->resizeColumnToContents ( 0 );
@@ -257,6 +251,8 @@ void ConfigDialog::loadPluginsInfo()
ui.visualPluginTable->setItem (i,1,
new QTableWidgetItem (item->factory()->properties().name));
ui.visualPluginTable->setItem (i,2, new QTableWidgetItem (files.at(i)));
+ ui.visualPluginTable->item(i,1)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ ui.visualPluginTable->item(i,2)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
}
ui.visualPluginTable->resizeColumnToContents ( 0 );
@@ -286,11 +282,44 @@ void ConfigDialog::loadPluginsInfo()
ui.effectPluginTable->setItem (i,1,
new QTableWidgetItem (item->factory()->properties().name));
ui.effectPluginTable->setItem (i,2, new QTableWidgetItem (files.at(i)));
+ ui.effectPluginTable->item(i,1)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ ui.effectPluginTable->item(i,2)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
}
ui.effectPluginTable->resizeColumnToContents ( 0 );
ui.effectPluginTable->resizeColumnToContents ( 1 );
ui.effectPluginTable->resizeRowsToContents ();
+
+ /*
+ load general plugin information
+ */
+ QList <GeneralFactory *> *generals = 0;
+ generals = General::generalFactories();
+ files = General::generalFiles();
+ ui.generalPluginTable->setColumnCount ( 3 );
+ ui.generalPluginTable->verticalHeader()->hide();
+ ui.generalPluginTable->setHorizontalHeaderLabels ( QStringList()
+ << tr ( "Enabled" ) << tr ( "Description" ) << tr ( "Filename" ) );
+ ui.generalPluginTable->setRowCount ( generals->count () );
+
+ for ( int i = 0; i < generals->count (); ++i )
+ {
+ GeneralPluginItem *item = new GeneralPluginItem(this,generals->at(i),files.at(i));
+ m_generalPluginItems.append(item);
+ QCheckBox* button = new QCheckBox (ui.generalPluginTable);
+ connect(button, SIGNAL(clicked (bool)), item, SLOT(select(bool)));
+ button->setChecked (item->isSelected());
+ ui.generalPluginTable->setCellWidget ( i, 0, button );
+ ui.generalPluginTable->setItem (i,1,
+ new QTableWidgetItem (item->factory()->properties().name));
+ ui.generalPluginTable->setItem (i,2, new QTableWidgetItem (files.at(i)));
+ ui.generalPluginTable->item(i,1)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ ui.generalPluginTable->item(i,2)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ }
+
+ ui.generalPluginTable->resizeColumnToContents ( 0 );
+ ui.generalPluginTable->resizeColumnToContents ( 1 );
+ ui.generalPluginTable->resizeRowsToContents ();
}
@@ -375,6 +404,14 @@ void ConfigDialog::showPluginSettings()
m_effectPluginItems.at(row)->factory()->showSettings ( this );
break;
}
+ case 4:
+ {
+ int row = ui.generalPluginTable->currentRow ();
+ if ( m_generalPluginItems.isEmpty() || row < 0 )
+ return;
+ m_generalPluginItems.at(row)->factory()->showSettings ( this );
+ break;
+ }
}
}
@@ -417,6 +454,14 @@ void ConfigDialog::showPluginInfo()
m_effectPluginItems.at(row)->factory()->showAbout ( this );
break;
}
+ case 4:
+ {
+ int row = ui.generalPluginTable->currentRow ();
+ if ( m_generalPluginItems.isEmpty() || row < 0 )
+ return;
+ m_generalPluginItems.at(row)->factory()->showAbout ( this );
+ break;
+ }
}
}
@@ -452,12 +497,6 @@ void ConfigDialog::saveSettings()
QSettings settings (QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat);
settings.setValue ("PlayList/title_format", ui.formatLineEdit->text());
settings.setValue ("PlayList/load_metadata", ui.metadataCheckBox->isChecked());
- settings.setValue ("MainWindow/tray_enabled", ui.trayCheckBox->isChecked());
- settings.setValue ("Tray/enabled", ui.trayCheckBox->isChecked());
- settings.setValue ("Tray/show_message", ui.messageCheckBox->isChecked());
- settings.setValue ("Tray/message_delay", ui.messageDelaySpinBox->value());
- settings.setValue ("Tray/show_tooltip", ui.toolTipCheckBox->isChecked());
- settings.setValue ("Tray/hide_on_close",ui.hideToTrayRadioButton->isChecked());
settings.setValue ("FileDialog", ui.fileDialogComboBox->currentText());
settings.setValue ("Proxy/use_proxy", ui.enableProxyCheckBox->isChecked());
settings.setValue ("Proxy/authentication", ui.authProxyCheckBox->isChecked());
@@ -465,5 +504,6 @@ void ConfigDialog::saveSettings()
settings.setValue ("Proxy/port",ui.portLineEdit->text());
settings.setValue ("Proxy/user",ui.proxyUserLineEdit->text());
settings.setValue ("Proxy/passw",ui.proxyPasswLineEdit->text());
+ settings.setValue ("Volume/software_volume", ui.softVolumeCheckBox->isChecked());
}
diff --git a/src/configdialog.h b/src/ui/configdialog.h
index a5c632cc6..7b9b1fab2 100644
--- a/src/configdialog.h
+++ b/src/ui/configdialog.h
@@ -36,6 +36,7 @@ class InputPluginItem;
class OutputPluginItem;
class VisualPluginItem;
class EffectPluginItem;
+class GeneralPluginItem;
class ConfigDialog : public QDialog
{
@@ -73,6 +74,7 @@ private:
QList <OutputPluginItem*> m_outputPluginItems;
QList <VisualPluginItem*> m_visualPluginItems;
QList <EffectPluginItem*> m_effectPluginItems;
+ QList <GeneralPluginItem*> m_generalPluginItems;
};
#endif
diff --git a/src/default/balance.png b/src/ui/default/balance.png
index 5fa10cce8..5fa10cce8 100644
--- a/src/default/balance.png
+++ b/src/ui/default/balance.png
Binary files differ
diff --git a/src/default/cbuttons.png b/src/ui/default/cbuttons.png
index 7a1369b59..7a1369b59 100644
--- a/src/default/cbuttons.png
+++ b/src/ui/default/cbuttons.png
Binary files differ
diff --git a/src/default/eq_ex.png b/src/ui/default/eq_ex.png
index 974004590..974004590 100644
--- a/src/default/eq_ex.png
+++ b/src/ui/default/eq_ex.png
Binary files differ
diff --git a/src/default/eqmain.png b/src/ui/default/eqmain.png
index b28b818de..b28b818de 100644
--- a/src/default/eqmain.png
+++ b/src/ui/default/eqmain.png
Binary files differ
diff --git a/src/default/main.png b/src/ui/default/main.png
index 6b7c8597a..6b7c8597a 100644
--- a/src/default/main.png
+++ b/src/ui/default/main.png
Binary files differ
diff --git a/src/default/monoster.png b/src/ui/default/monoster.png
index 7ddb9d0e5..7ddb9d0e5 100644
--- a/src/default/monoster.png
+++ b/src/ui/default/monoster.png
Binary files differ
diff --git a/src/default/numbers.png b/src/ui/default/numbers.png
index 46f1e1f63..46f1e1f63 100644
--- a/src/default/numbers.png
+++ b/src/ui/default/numbers.png
Binary files differ
diff --git a/src/default/playpaus.png b/src/ui/default/playpaus.png
index 0cfbd6835..0cfbd6835 100644
--- a/src/default/playpaus.png
+++ b/src/ui/default/playpaus.png
Binary files differ
diff --git a/src/default/pledit.png b/src/ui/default/pledit.png
index 3c2943cea..3c2943cea 100644
--- a/src/default/pledit.png
+++ b/src/ui/default/pledit.png
Binary files differ
diff --git a/src/default/pledit.txt b/src/ui/default/pledit.txt
index 5435dd2fd..549a81ad1 100644
--- a/src/default/pledit.txt
+++ b/src/ui/default/pledit.txt
@@ -1,6 +1,6 @@
[Text]
Normal=#C0C0C0
Current=#8080FF
-NormalBG=#400080
+NormalBG=#000080
SelectedBG=#408080
Font=Tahoma Bold \ No newline at end of file
diff --git a/src/default/posbar.png b/src/ui/default/posbar.png
index 271106557..271106557 100644
--- a/src/default/posbar.png
+++ b/src/ui/default/posbar.png
Binary files differ
diff --git a/src/default/shufrep.png b/src/ui/default/shufrep.png
index 107fd50bb..107fd50bb 100644
--- a/src/default/shufrep.png
+++ b/src/ui/default/shufrep.png
Binary files differ
diff --git a/src/default/text.png b/src/ui/default/text.png
index d37241405..d37241405 100644
--- a/src/default/text.png
+++ b/src/ui/default/text.png
Binary files differ
diff --git a/src/default/titlebar.png b/src/ui/default/titlebar.png
index c1e7818cd..c1e7818cd 100644
--- a/src/default/titlebar.png
+++ b/src/ui/default/titlebar.png
Binary files differ
diff --git a/src/default/viscolor.txt b/src/ui/default/viscolor.txt
index 65490ebb6..9fbb3f64d 100644
--- a/src/default/viscolor.txt
+++ b/src/ui/default/viscolor.txt
@@ -21,4 +21,4 @@
135,165,195
119,153,187
87,129,171
-87,179,160
+114,223,229
diff --git a/src/default/volume.png b/src/ui/default/volume.png
index b4f457453..b4f457453 100644
--- a/src/default/volume.png
+++ b/src/ui/default/volume.png
Binary files differ
diff --git a/src/display.cpp b/src/ui/display.cpp
index d2cce8165..d2cce8165 100644
--- a/src/display.cpp
+++ b/src/ui/display.cpp
diff --git a/src/display.h b/src/ui/display.h
index 15e0111d6..15e0111d6 100644
--- a/src/display.h
+++ b/src/ui/display.h
diff --git a/src/dock.cpp b/src/ui/dock.cpp
index 2a755a9b9..2a755a9b9 100644
--- a/src/dock.cpp
+++ b/src/ui/dock.cpp
diff --git a/src/dock.h b/src/ui/dock.h
index b4b62dda2..b4b62dda2 100644
--- a/src/dock.h
+++ b/src/ui/dock.h
diff --git a/src/eqgraph.cpp b/src/ui/eqgraph.cpp
index 314e504d9..314e504d9 100644
--- a/src/eqgraph.cpp
+++ b/src/ui/eqgraph.cpp
diff --git a/src/eqgraph.h b/src/ui/eqgraph.h
index 4f6bf1882..4f6bf1882 100644
--- a/src/eqgraph.h
+++ b/src/ui/eqgraph.h
diff --git a/src/eqpreset.cpp b/src/ui/eqpreset.cpp
index 760dea9d2..760dea9d2 100644
--- a/src/eqpreset.cpp
+++ b/src/ui/eqpreset.cpp
diff --git a/src/eqpreset.h b/src/ui/eqpreset.h
index 80f31747e..80f31747e 100644
--- a/src/eqpreset.h
+++ b/src/ui/eqpreset.h
diff --git a/src/eqslider.cpp b/src/ui/eqslider.cpp
index bdc4ec4e2..bdc4ec4e2 100644
--- a/src/eqslider.cpp
+++ b/src/ui/eqslider.cpp
diff --git a/src/eqslider.h b/src/ui/eqslider.h
index 54dc9f285..54dc9f285 100644
--- a/src/eqslider.h
+++ b/src/ui/eqslider.h
diff --git a/src/eqtitlebar.cpp b/src/ui/eqtitlebar.cpp
index 5420831f8..5420831f8 100644
--- a/src/eqtitlebar.cpp
+++ b/src/ui/eqtitlebar.cpp
diff --git a/src/eqtitlebar.h b/src/ui/eqtitlebar.h
index d3e9a0452..d3e9a0452 100644
--- a/src/eqtitlebar.h
+++ b/src/ui/eqtitlebar.h
diff --git a/src/eqwidget.cpp b/src/ui/eqwidget.cpp
index d86ab45d2..d86ab45d2 100644
--- a/src/eqwidget.cpp
+++ b/src/ui/eqwidget.cpp
diff --git a/src/eqwidget.h b/src/ui/eqwidget.h
index 94cd564d5..94cd564d5 100644
--- a/src/eqwidget.h
+++ b/src/ui/eqwidget.h
diff --git a/src/ui/fft.c b/src/ui/fft.c
new file mode 100644
index 000000000..7ca1978a5
--- /dev/null
+++ b/src/ui/fft.c
@@ -0,0 +1,296 @@
+/* fft.c: Iterative implementation of a FFT
+ * Copyright (C) 1999 Richard Boulton <richard@tartarus.org>
+ * Convolution stuff by Ralph Loader <suckfish@ihug.co.nz>
+ *
+ * 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.
+ */
+
+/*
+ * TODO
+ * Remove compiling in of FFT_BUFFER_SIZE? (Might slow things down, but would
+ * be nice to be able to change size at runtime.)
+ * Finish making / checking thread-safety.
+ * More optimisations.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "fft.h"
+
+//#include <glib.h>
+#include <stdlib.h>
+#include <math.h>
+#ifndef PI
+#ifdef M_PI
+#define PI M_PI
+#else
+#define PI 3.14159265358979323846 /* pi */
+#endif
+#endif
+
+/* ########### */
+/* # Structs # */
+/* ########### */
+
+struct _struct_fft_state {
+ /* Temporary data stores to perform FFT in. */
+ float real[FFT_BUFFER_SIZE];
+ float imag[FFT_BUFFER_SIZE];
+};
+
+/* ############################# */
+/* # Local function prototypes # */
+/* ############################# */
+
+static void fft_prepare(const sound_sample * input, float *re, float *im);
+static void fft_calculate(float *re, float *im);
+static void fft_output(const float *re, const float *im, float *output);
+static int reverseBits(unsigned int initial);
+
+/* #################### */
+/* # Global variables # */
+/* #################### */
+
+/* Table to speed up bit reverse copy */
+static unsigned int bitReverse[FFT_BUFFER_SIZE];
+
+/* The next two tables could be made to use less space in memory, since they
+ * overlap hugely, but hey. */
+static float sintable[FFT_BUFFER_SIZE / 2];
+static float costable[FFT_BUFFER_SIZE / 2];
+
+/* ############################## */
+/* # Externally called routines # */
+/* ############################## */
+
+/* --------- */
+/* FFT stuff */
+/* --------- */
+
+/*
+ * Initialisation routine - sets up tables and space to work in.
+ * Returns a pointer to internal state, to be used when performing calls.
+ * On error, returns NULL.
+ * The pointer should be freed when it is finished with, by fft_close().
+ */
+fft_state *
+fft_init(void)
+{
+ fft_state *state;
+ unsigned int i;
+
+ state = (fft_state *) malloc(sizeof(fft_state));
+ if (!state)
+ return NULL;
+
+ for (i = 0; i < FFT_BUFFER_SIZE; i++) {
+ bitReverse[i] = reverseBits(i);
+ }
+ for (i = 0; i < FFT_BUFFER_SIZE / 2; i++) {
+ float j = 2 * PI * i / FFT_BUFFER_SIZE;
+ costable[i] = cos(j);
+ sintable[i] = sin(j);
+ }
+
+ return state;
+}
+
+/*
+ * Do all the steps of the FFT, taking as input sound data (as described in
+ * sound.h) and returning the intensities of each frequency as floats in the
+ * range 0 to ((FFT_BUFFER_SIZE / 2) * 32768) ^ 2
+ *
+ * FIXME - the above range assumes no frequencies present have an amplitude
+ * larger than that of the sample variation. But this is false: we could have
+ * a wave such that its maximums are always between samples, and it's just
+ * inside the representable range at the places samples get taken.
+ * Question: what _is_ the maximum value possible. Twice that value? Root
+ * two times that value? Hmmm. Think it depends on the frequency, too.
+ *
+ * The input array is assumed to have FFT_BUFFER_SIZE elements,
+ * and the output array is assumed to have (FFT_BUFFER_SIZE / 2 + 1) elements.
+ * state is a (non-NULL) pointer returned by fft_init.
+ */
+void
+fft_perform(const sound_sample * input, float *output, fft_state * state)
+{
+ /* Convert data from sound format to be ready for FFT */
+ fft_prepare(input, state->real, state->imag);
+
+ /* Do the actual FFT */
+ fft_calculate(state->real, state->imag);
+
+ /* Convert the FFT output into intensities */
+ fft_output(state->real, state->imag, output);
+}
+
+/*
+ * Free the state.
+ */
+void
+fft_close(fft_state * state)
+{
+ if (state)
+ free(state);
+}
+
+/* ########################### */
+/* # Locally called routines # */
+/* ########################### */
+
+/*
+ * Prepare data to perform an FFT on
+ */
+static void
+fft_prepare(const sound_sample * input, float *re, float *im)
+{
+ unsigned int i;
+ float *realptr = re;
+ float *imagptr = im;
+
+ /* Get input, in reverse bit order */
+ for (i = 0; i < FFT_BUFFER_SIZE; i++) {
+ *realptr++ = input[bitReverse[i]];
+ *imagptr++ = 0;
+ }
+}
+
+/*
+ * Take result of an FFT and calculate the intensities of each frequency
+ * Note: only produces half as many data points as the input had.
+ * This is roughly a consequence of the Nyquist sampling theorm thingy.
+ * (FIXME - make this comment better, and helpful.)
+ *
+ * The two divisions by 4 are also a consequence of this: the contributions
+ * returned for each frequency are split into two parts, one at i in the
+ * table, and the other at FFT_BUFFER_SIZE - i, except for i = 0 and
+ * FFT_BUFFER_SIZE which would otherwise get float (and then 4* when squared)
+ * the contributions.
+ */
+static void
+fft_output(const float *re, const float *im, float *output)
+{
+ float *outputptr = output;
+ const float *realptr = re;
+ const float *imagptr = im;
+ float *endptr = output + FFT_BUFFER_SIZE / 2;
+
+#ifdef DEBUG
+ unsigned int i, j;
+#endif
+
+ while (outputptr <= endptr) {
+ *outputptr = (*realptr * *realptr) + (*imagptr * *imagptr);
+ outputptr++;
+ realptr++;
+ imagptr++;
+ }
+ /* Do divisions to keep the constant and highest frequency terms in scale
+ * with the other terms. */
+ *output /= 4;
+ *endptr /= 4;
+
+#ifdef DEBUG
+ printf("Recalculated input:\n");
+ for (i = 0; i < FFT_BUFFER_SIZE; i++) {
+ float val_real = 0;
+ float val_imag = 0;
+ for (j = 0; j < FFT_BUFFER_SIZE; j++) {
+ float fact_real = cos(-2 * j * i * PI / FFT_BUFFER_SIZE);
+ float fact_imag = sin(-2 * j * i * PI / FFT_BUFFER_SIZE);
+ val_real += fact_real * re[j] - fact_imag * im[j];
+ val_imag += fact_real * im[j] + fact_imag * re[j];
+ }
+ printf("%5d = %8f + i * %8f\n", i,
+ val_real / FFT_BUFFER_SIZE, val_imag / FFT_BUFFER_SIZE);
+ }
+ printf("\n");
+#endif
+}
+
+/*
+ * Actually perform the FFT
+ */
+static void
+fft_calculate(float *re, float *im)
+{
+ unsigned int i, j, k;
+ unsigned int exchanges;
+ float fact_real, fact_imag;
+ float tmp_real, tmp_imag;
+ unsigned int factfact;
+
+ /* Set up some variables to reduce calculation in the loops */
+ exchanges = 1;
+ factfact = FFT_BUFFER_SIZE / 2;
+
+ /* Loop through the divide and conquer steps */
+ for (i = FFT_BUFFER_SIZE_LOG; i != 0; i--) {
+ /* In this step, we have 2 ^ (i - 1) exchange groups, each with
+ * 2 ^ (FFT_BUFFER_SIZE_LOG - i) exchanges
+ */
+ /* Loop through the exchanges in a group */
+ for (j = 0; j != exchanges; j++) {
+ /* Work out factor for this exchange
+ * factor ^ (exchanges) = -1
+ * So, real = cos(j * PI / exchanges),
+ * imag = sin(j * PI / exchanges)
+ */
+ fact_real = costable[j * factfact];
+ fact_imag = sintable[j * factfact];
+
+ /* Loop through all the exchange groups */
+ for (k = j; k < FFT_BUFFER_SIZE; k += exchanges << 1) {
+ int k1 = k + exchanges;
+ /* newval[k] := val[k] + factor * val[k1]
+ * newval[k1] := val[k] - factor * val[k1]
+ **/
+#ifdef DEBUG
+ printf("%d %d %d\n", i, j, k);
+ printf("Exchange %d with %d\n", k, k1);
+ printf("Factor %9f + i * %8f\n", fact_real, fact_imag);
+#endif
+ /* FIXME - potential scope for more optimization here? */
+ tmp_real = fact_real * re[k1] - fact_imag * im[k1];
+ tmp_imag = fact_real * im[k1] + fact_imag * re[k1];
+ re[k1] = re[k] - tmp_real;
+ im[k1] = im[k] - tmp_imag;
+ re[k] += tmp_real;
+ im[k] += tmp_imag;
+#ifdef DEBUG
+ for (k1 = 0; k1 < FFT_BUFFER_SIZE; k1++) {
+ printf("%5d = %8f + i * %8f\n", k1, real[k1], imag[k1]);
+ }
+#endif
+ }
+ }
+ exchanges <<= 1;
+ factfact >>= 1;
+ }
+}
+
+static int
+reverseBits(unsigned int initial)
+{
+ unsigned int reversed = 0, loop;
+ for (loop = 0; loop < FFT_BUFFER_SIZE_LOG; loop++) {
+ reversed <<= 1;
+ reversed += (initial & 1);
+ initial >>= 1;
+ }
+ return reversed;
+}
diff --git a/src/ui/fft.h b/src/ui/fft.h
new file mode 100644
index 000000000..431afa365
--- /dev/null
+++ b/src/ui/fft.h
@@ -0,0 +1,45 @@
+/* fft.h: Header for iterative implementation of a FFT
+ * Copyright (C) 1999 Richard Boulton <richard@tartarus.org>
+ *
+ * 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.
+ */
+
+#ifndef _FFT_H_
+#define _FFT_H_
+
+#define FFT_BUFFER_SIZE_LOG 9
+
+#define FFT_BUFFER_SIZE (1 << FFT_BUFFER_SIZE_LOG)
+
+/* sound sample - should be an signed 16 bit value */
+typedef short int sound_sample;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* FFT library */
+ typedef struct _struct_fft_state fft_state;
+ fft_state *fft_init(void);
+ void fft_perform(const sound_sample * input, float *output,
+ fft_state * state);
+ void fft_close(fft_state * state);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FFT_H_ */
diff --git a/src/filedialog.cpp b/src/ui/filedialog.cpp
index 29195acef..fb7ecbdaf 100644
--- a/src/filedialog.cpp
+++ b/src/ui/filedialog.cpp
@@ -26,9 +26,9 @@ bool FileDialog::isModal()
return instance()->modal();
}
+
void FileDialog::init(QObject* o)
{
- qWarning("void FileDialog::init(QObject* o)");
if(!m_initialized && !instance()->modal())
{
PlayListModel* model = NULL;
@@ -130,7 +130,6 @@ void FileDialog::registerExternalFactories()
foreach (QString fileName, pluginsDir.entryList(QDir::Files))
{
- //qWarning("file dialog path: %s",qPrintable(fileName));
QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
QObject *plugin = loader.instance();
if (loader.isLoaded())
@@ -164,7 +163,6 @@ QString FileDialog::m_current_factory = QString();
FileDialog* FileDialog::instance()
{
- //qWarning("INSTANCE");
if(_instance && _instance->modal())
{
delete _instance;
@@ -188,13 +186,13 @@ FileDialog* FileDialog::instance()
if(_instance)
delete _instance;
- qWarning("%s\t%s",qPrintable(m_current_factory),qPrintable(f_dialogName));
foreach(QString name,names)
{
if(name == f_dialogName)
{
_instance = factories[name]->create();
m_current_factory = f_dialogName;
+ break;
}
}
@@ -204,7 +202,6 @@ FileDialog* FileDialog::instance()
//else if(!_instance->modal())
//return _instance;
// _instance->raise();
-
return _instance;
}
@@ -241,9 +238,9 @@ QStringList FileDialog::registeredFactories()
void FileDialog::popup(QObject* o,const QString& d,Mode m,const QStringList& f)
{
-// qWarning("void FileDialog::popup(QObject* o,const QString& d,Mode m,const QStringList& f)");
- instance()->init(o);
- instance()->raise(d,m,f);
+ FileDialog* inst = instance();
+ inst->init(o);
+ inst->raise(d,m,f);
}
diff --git a/src/filedialog.h b/src/ui/filedialog.h
index 8e82e98b7..f8e6c4f93 100644
--- a/src/filedialog.h
+++ b/src/ui/filedialog.h
@@ -42,8 +42,8 @@ Q_OBJECT
virtual QString saveFileName ( QWidget* , const QString& ,const QString& , const QString& , QString* );
virtual bool modal()const{ return TRUE;}
virtual ~FileDialog(){;}
- virtual void init(QObject*);
- virtual void raise(const QString& = QString(),Mode = AddFiles,const QStringList& = QStringList()){;}
+ void init(QObject*);
+ virtual void raise(const QString& = QString(),Mode = AddFiles,const QStringList& = QStringList()){;}
static bool registerFactory(FileDialogFactory*);
public:
diff --git a/src/fileloader.cpp b/src/ui/fileloader.cpp
index fda8efdc1..fda8efdc1 100644
--- a/src/fileloader.cpp
+++ b/src/ui/fileloader.cpp
diff --git a/src/fileloader.h b/src/ui/fileloader.h
index c23d1ed35..c23d1ed35 100644
--- a/src/fileloader.h
+++ b/src/ui/fileloader.h
diff --git a/src/aboutdialog.ui b/src/ui/forms/aboutdialog.ui
index 56fbef9c5..56fbef9c5 100644
--- a/src/aboutdialog.ui
+++ b/src/ui/forms/aboutdialog.ui
diff --git a/src/addurldialog.ui b/src/ui/forms/addurldialog.ui
index 46031b849..46031b849 100644
--- a/src/addurldialog.ui
+++ b/src/ui/forms/addurldialog.ui
diff --git a/src/configdialog.ui b/src/ui/forms/configdialog.ui
index 1f6f45516..530786ab4 100644
--- a/src/configdialog.ui
+++ b/src/ui/forms/configdialog.ui
@@ -6,7 +6,7 @@
<x>0</x>
<y>0</y>
<width>601</width>
- <height>375</height>
+ <height>409</height>
</rect>
</property>
<property name="windowTitle" >
@@ -77,6 +77,9 @@
<property name="resizeMode" >
<enum>QListView::Adjust</enum>
</property>
+ <property name="spacing" >
+ <number>2</number>
+ </property>
<property name="viewMode" >
<enum>QListView::ListMode</enum>
</property>
@@ -90,7 +93,7 @@
<bool>false</bool>
</property>
<property name="currentRow" >
- <number>0</number>
+ <number>-1</number>
</property>
<item>
<property name="text" >
@@ -128,6 +131,9 @@
<property name="text" >
<string>Connectivity</string>
</property>
+ <property name="icon" >
+ <iconset resource="images/images.qrc" >:/network.png</iconset>
+ </property>
</item>
</widget>
</item>
@@ -575,6 +581,20 @@
</item>
</layout>
</widget>
+ <widget class="QWidget" name="tab_3" >
+ <attribute name="title" >
+ <string>General</string>
+ </attribute>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QTableWidget" name="generalPluginTable" >
+ <property name="selectionBehavior" >
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
<widget class="QWidget" name="fileDialogTab" >
<attribute name="title" >
<string>File Dialog</string>
@@ -651,130 +671,16 @@
</widget>
<widget class="QWidget" name="page_2" >
<layout class="QVBoxLayout" >
- <property name="spacing" >
- <number>6</number>
- </property>
- <property name="leftMargin" >
- <number>9</number>
- </property>
- <property name="topMargin" >
- <number>9</number>
- </property>
- <property name="rightMargin" >
- <number>9</number>
- </property>
- <property name="bottomMargin" >
- <number>9</number>
- </property>
- <item>
- <widget class="QGroupBox" name="groupBox_4" >
- <property name="title" >
- <string>Tray Icon</string>
- </property>
- <layout class="QGridLayout" >
- <property name="leftMargin" >
- <number>9</number>
- </property>
- <property name="topMargin" >
- <number>9</number>
- </property>
- <property name="rightMargin" >
- <number>9</number>
- </property>
- <property name="bottomMargin" >
- <number>9</number>
- </property>
- <property name="horizontalSpacing" >
- <number>6</number>
- </property>
- <property name="verticalSpacing" >
- <number>6</number>
- </property>
- <item row="2" column="0" >
- <widget class="QCheckBox" name="toolTipCheckBox" >
- <property name="text" >
- <string>Show tooltip</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0" >
- <widget class="QCheckBox" name="messageCheckBox" >
- <property name="text" >
- <string>Show message</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1" >
- <widget class="QSpinBox" name="messageDelaySpinBox" >
- <property name="minimum" >
- <number>100</number>
- </property>
- <property name="maximum" >
- <number>10000</number>
- </property>
- <property name="singleStep" >
- <number>100</number>
- </property>
- <property name="value" >
- <number>1000</number>
- </property>
- </widget>
- </item>
- <item row="3" column="0" >
- <widget class="QLabel" name="label_3" >
- <property name="text" >
- <string>Message delay, ms:</string>
- </property>
- <property name="alignment" >
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="0" column="0" colspan="2" >
- <widget class="QCheckBox" name="trayCheckBox" >
- <property name="text" >
- <string>Show tray icon</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
<item>
- <widget class="QGroupBox" name="closeGroupBox" >
+ <widget class="QGroupBox" name="groupBox_6" >
<property name="title" >
- <string>Action On Close</string>
+ <string>Audio</string>
</property>
<layout class="QVBoxLayout" >
- <property name="spacing" >
- <number>6</number>
- </property>
- <property name="leftMargin" >
- <number>9</number>
- </property>
- <property name="topMargin" >
- <number>9</number>
- </property>
- <property name="rightMargin" >
- <number>9</number>
- </property>
- <property name="bottomMargin" >
- <number>9</number>
- </property>
<item>
- <widget class="QRadioButton" name="hideToTrayRadioButton" >
+ <widget class="QCheckBox" name="softVolumeCheckBox" >
<property name="text" >
- <string>Hide to tray</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QRadioButton" name="quitRadioButton" >
- <property name="text" >
- <string>Quit</string>
- </property>
- <property name="checked" >
- <bool>true</bool>
+ <string>Use software volume control</string>
</property>
</widget>
</item>
@@ -789,7 +695,7 @@
<property name="sizeHint" >
<size>
<width>20</width>
- <height>40</height>
+ <height>251</height>
</size>
</property>
</spacer>
@@ -971,86 +877,6 @@
</hints>
</connection>
<connection>
- <sender>trayCheckBox</sender>
- <signal>toggled(bool)</signal>
- <receiver>toolTipCheckBox</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel" >
- <x>550</x>
- <y>64</y>
- </hint>
- <hint type="destinationlabel" >
- <x>383</x>
- <y>118</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>trayCheckBox</sender>
- <signal>toggled(bool)</signal>
- <receiver>messageDelaySpinBox</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel" >
- <x>208</x>
- <y>55</y>
- </hint>
- <hint type="destinationlabel" >
- <x>469</x>
- <y>148</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>trayCheckBox</sender>
- <signal>toggled(bool)</signal>
- <receiver>messageCheckBox</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel" >
- <x>262</x>
- <y>55</y>
- </hint>
- <hint type="destinationlabel" >
- <x>258</x>
- <y>76</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>messageCheckBox</sender>
- <signal>toggled(bool)</signal>
- <receiver>messageDelaySpinBox</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel" >
- <x>307</x>
- <y>82</y>
- </hint>
- <hint type="destinationlabel" >
- <x>469</x>
- <y>148</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>trayCheckBox</sender>
- <signal>clicked(bool)</signal>
- <receiver>closeGroupBox</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel" >
- <x>376</x>
- <y>56</y>
- </hint>
- <hint type="destinationlabel" >
- <x>436</x>
- <y>175</y>
- </hint>
- </hints>
- </connection>
- <connection>
<sender>enableProxyCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>hostLineEdit</receiver>
diff --git a/src/jumptotrackdialog.ui b/src/ui/forms/jumptotrackdialog.ui
index 1418c54fd..1418c54fd 100644
--- a/src/jumptotrackdialog.ui
+++ b/src/ui/forms/jumptotrackdialog.ui
diff --git a/src/preseteditor.ui b/src/ui/forms/preseteditor.ui
index 2f88d6d53..2f88d6d53 100644
--- a/src/preseteditor.ui
+++ b/src/ui/forms/preseteditor.ui
diff --git a/src/html/about_cs.html b/src/ui/html/about_cs.html
index 84bd2b42a..84bd2b42a 100644
--- a/src/html/about_cs.html
+++ b/src/ui/html/about_cs.html
diff --git a/src/html/about_en.html b/src/ui/html/about_en.html
index d03691cf6..d03691cf6 100644
--- a/src/html/about_en.html
+++ b/src/ui/html/about_en.html
diff --git a/src/html/about_ru.html b/src/ui/html/about_ru.html
index 26e5b9906..26e5b9906 100644
--- a/src/html/about_ru.html
+++ b/src/ui/html/about_ru.html
diff --git a/src/html/about_zh_CN.html b/src/ui/html/about_zh_CN.html
index eadc7f78d..eadc7f78d 100644
--- a/src/html/about_zh_CN.html
+++ b/src/ui/html/about_zh_CN.html
diff --git a/src/html/authors_cs.txt b/src/ui/html/authors_cs.txt
index 89d585c24..89d585c24 100644
--- a/src/html/authors_cs.txt
+++ b/src/ui/html/authors_cs.txt
diff --git a/src/html/authors_en.txt b/src/ui/html/authors_en.txt
index 6c11ebd5e..6c11ebd5e 100644
--- a/src/html/authors_en.txt
+++ b/src/ui/html/authors_en.txt
diff --git a/src/html/authors_ru.txt b/src/ui/html/authors_ru.txt
index b95c3887e..b95c3887e 100644
--- a/src/html/authors_ru.txt
+++ b/src/ui/html/authors_ru.txt
diff --git a/src/html/authors_zh_CN.txt b/src/ui/html/authors_zh_CN.txt
index f2d8892fd..f2d8892fd 100644
--- a/src/html/authors_zh_CN.txt
+++ b/src/ui/html/authors_zh_CN.txt
diff --git a/src/html/thanks_cs.txt b/src/ui/html/thanks_cs.txt
index 9bc0388da..9bc0388da 100644
--- a/src/html/thanks_cs.txt
+++ b/src/ui/html/thanks_cs.txt
diff --git a/src/html/thanks_en.txt b/src/ui/html/thanks_en.txt
index 3ed2fe5d5..3ed2fe5d5 100644
--- a/src/html/thanks_en.txt
+++ b/src/ui/html/thanks_en.txt
diff --git a/src/html/thanks_ru.txt b/src/ui/html/thanks_ru.txt
index 79acc177d..79acc177d 100644
--- a/src/html/thanks_ru.txt
+++ b/src/ui/html/thanks_ru.txt
diff --git a/src/html/thanks_zh_CN.txt b/src/ui/html/thanks_zh_CN.txt
index 505d05c72..505d05c72 100644
--- a/src/html/thanks_zh_CN.txt
+++ b/src/ui/html/thanks_zh_CN.txt
diff --git a/src/ui/images/advanced.png b/src/ui/images/advanced.png
new file mode 100644
index 000000000..25efaf35b
--- /dev/null
+++ b/src/ui/images/advanced.png
Binary files differ
diff --git a/src/images/images.qrc b/src/ui/images/images.qrc
index 8dcc2efe2..acc7c26f0 100644
--- a/src/images/images.qrc
+++ b/src/ui/images/images.qrc
@@ -1,14 +1,12 @@
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource>
- <file>play.png</file>
- <file>pause.png</file>
- <file>stop.png</file>
<file>qmmp.xpm</file>
<file>interface.png</file>
<file>playlist.png</file>
<file>advanced.png</file>
<file>plugins.png</file>
+ <file>network.png</file>
<file>logo-qmmp.png</file>
</qresource>
</RCC>
diff --git a/src/ui/images/interface.png b/src/ui/images/interface.png
new file mode 100644
index 000000000..53174d71a
--- /dev/null
+++ b/src/ui/images/interface.png
Binary files differ
diff --git a/src/images/logo-qmmp.png b/src/ui/images/logo-qmmp.png
index 7a4d6ded4..7a4d6ded4 100644
--- a/src/images/logo-qmmp.png
+++ b/src/ui/images/logo-qmmp.png
Binary files differ
diff --git a/src/ui/images/network.png b/src/ui/images/network.png
new file mode 100644
index 000000000..5f47a5fe1
--- /dev/null
+++ b/src/ui/images/network.png
Binary files differ
diff --git a/src/ui/images/playlist.png b/src/ui/images/playlist.png
new file mode 100644
index 000000000..99923dea9
--- /dev/null
+++ b/src/ui/images/playlist.png
Binary files differ
diff --git a/src/ui/images/plugins.png b/src/ui/images/plugins.png
new file mode 100644
index 000000000..e9c744e64
--- /dev/null
+++ b/src/ui/images/plugins.png
Binary files differ
diff --git a/src/images/qmmp.xpm b/src/ui/images/qmmp.xpm
index 85ea94fc1..85ea94fc1 100644
--- a/src/images/qmmp.xpm
+++ b/src/ui/images/qmmp.xpm
diff --git a/src/ui/inlines.h b/src/ui/inlines.h
new file mode 100644
index 000000000..3efccf0de
--- /dev/null
+++ b/src/ui/inlines.h
@@ -0,0 +1,505 @@
+// Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com>
+//
+// Use, modification and distribution is allowed without limitation,
+// warranty, or liability of any kind.
+//
+
+#ifndef INLINES_H
+#define INLINES_H
+
+#include "fft.h"
+
+// *fast* convenience functions
+static inline void
+calc_freq(short* dest, short *src)
+{
+ static fft_state *state = NULL;
+ float tmp_out[257];
+ int i;
+
+ if (!state)
+ state = fft_init();
+
+ fft_perform(src, tmp_out, state);
+
+ for (i = 0; i < 256; i++)
+ dest[i] = ((int) sqrt(tmp_out[i + 1])) >> 8;
+}
+
+static inline void
+calc_mono_freq(short dest[2][256], short src[2][512], int nch)
+{
+ int i;
+ short *d, *sl, *sr, tmp[512];
+
+ if (nch == 1)
+ calc_freq(dest[0], src[0]);
+ else
+ {
+ d = tmp;
+ sl = src[0];
+ sr = src[1];
+ for (i = 0; i < 512; i++)
+ {
+ *(d++) = (*(sl++) + *(sr++)) >> 1;
+ }
+ calc_freq(dest[0], tmp);
+ }
+}
+
+static inline void stereo16_from_stereopcm8(register short *l,
+ register short *r,
+ register uchar *c,
+ long cnt)
+{
+ while (cnt >= 4l)
+ {
+ l[0] = c[0];
+ r[0] = c[1];
+ l[1] = c[2];
+ r[1] = c[3];
+ l[2] = c[4];
+ r[2] = c[5];
+ l[3] = c[6];
+ r[3] = c[7];
+ l += 4;
+ r += 4;
+ c += 8;
+ cnt -= 4l;
+ }
+
+ if (cnt > 0l)
+ {
+ l[0] = c[0];
+ r[0] = c[1];
+ if (cnt > 1l)
+ {
+ l[1] = c[2];
+ r[1] = c[3];
+ if (cnt > 2l)
+ {
+ l[2] = c[4];
+ r[2] = c[5];
+ }
+ }
+ }
+}
+
+
+static inline void stereo16_from_stereopcm16(register short *l,
+ register short *r,
+ register short *s,
+ long cnt)
+{
+ while (cnt >= 4l)
+ {
+ l[0] = s[0];
+ r[0] = s[1];
+ l[1] = s[2];
+ r[1] = s[3];
+ l[2] = s[4];
+ r[2] = s[5];
+ l[3] = s[6];
+ r[3] = s[7];
+ l += 4;
+ r += 4;
+ s += 8;
+ cnt -= 4l;
+ }
+
+ if (cnt > 0l)
+ {
+ l[0] = s[0];
+ r[0] = s[1];
+ if (cnt > 1l)
+ {
+ l[1] = s[2];
+ r[1] = s[3];
+ if (cnt > 2l)
+ {
+ l[2] = s[4];
+ r[2] = s[5];
+ }
+ }
+ }
+}
+
+
+static inline void mono16_from_monopcm8(register short *l,
+ register uchar *c,
+ long cnt)
+{
+ while (cnt >= 4l)
+ {
+ l[0] = c[0];
+ l[1] = c[1];
+ l[2] = c[2];
+ l[3] = c[3];
+ l += 4;
+ c += 4;
+ cnt -= 4l;
+ }
+
+ if (cnt > 0l)
+ {
+ l[0] = c[0];
+ if (cnt > 1l)
+ {
+ l[1] = c[1];
+ if (cnt > 2l)
+ {
+ l[2] = c[2];
+ }
+ }
+ }
+}
+
+
+static inline void mono16_from_monopcm16(register short *l,
+ register short *s,
+ long cnt)
+{
+ while (cnt >= 4l)
+ {
+ l[0] = s[0];
+ l[1] = s[1];
+ l[2] = s[2];
+ l[3] = s[3];
+ l += 4;
+ s += 4;
+ cnt -= 4l;
+ }
+
+ if (cnt > 0l)
+ {
+ l[0] = s[0];
+ if (cnt > 1l)
+ {
+ l[1] = s[1];
+ if (cnt > 2l)
+ {
+ l[2] = s[2];
+ }
+ }
+ }
+}
+
+
+static inline void fast_short_set(register short *p,
+ short v,
+ long c)
+{
+ while (c >= 4l)
+ {
+ p[0] = v;
+ p[1] = v;
+ p[2] = v;
+ p[3] = v;
+ p += 4;
+ c -= 4l;
+ }
+
+ if (c > 0l)
+ {
+ p[0] = v;
+ if (c > 1l)
+ {
+ p[1] = v;
+ if (c > 2l)
+ {
+ p[2] = v;
+ }
+ }
+ }
+}
+
+#ifdef FFTW
+static inline void fast_real_set(register fftw_real *p,
+ fftw_real v,
+ long c)
+{
+ while (c >= 4l)
+ {
+ p[0] = v;
+ p[1] = v;
+ p[2] = v;
+ p[3] = v;
+ p += 4;
+ c -= 4l;
+ }
+
+ if (c > 0l)
+ {
+ p[0] = v;
+ if (c > 1l)
+ {
+ p[1] = v;
+ if (c > 2l)
+ {
+ p[2] = v;
+ }
+ }
+ }
+}
+
+static inline void fast_complex_set(register fftw_complex *p,
+ fftw_complex v,
+ long c)
+{
+ while (c >= 4l)
+ {
+ p[0] = v;
+ p[1] = v;
+ p[2] = v;
+ p[3] = v;
+ p += 4;
+ c -= 4l;
+ }
+
+ if (c > 0l)
+ {
+ p[0] = v;
+ if (c > 1l)
+ {
+ p[1] = v;
+ if (c > 2l)
+ {
+ p[2] = v;
+ }
+ }
+ }
+}
+
+
+static inline void fast_real_set_from_short(register fftw_real *d,
+ register short *s,
+ long c)
+{
+ while (c >= 4l)
+ {
+ d[0] = fftw_real(s[0]);
+ d[1] = fftw_real(s[1]);
+ d[2] = fftw_real(s[2]);
+ d[3] = fftw_real(s[3]);
+ d += 4;
+ s += 4;
+ c -= 4l;
+ }
+
+ if (c > 0l)
+ {
+ d[0] = fftw_real(s[0]);
+ if (c > 1l)
+ {
+ d[1] = fftw_real(s[1]);
+ if (c > 2l)
+ {
+ d[2] = fftw_real(s[2]);
+ }
+ }
+ }
+}
+
+static inline void fast_complex_set_from_short(register fftw_complex *d,
+ register short *s,
+ long c)
+{
+ while (c >= 4l)
+ {
+ d[0].re = fftw_real(s[0]);
+ d[0].im = 0;
+ d[1].re = fftw_real(s[1]);
+ d[1].im = 0;
+ d[2].re = fftw_real(s[2]);
+ d[2].im = 0;
+ d[3].re = fftw_real(s[3]);
+ d[3].im = 0;
+ d += 4;
+ s += 4;
+ c -= 4l;
+ }
+
+ if (c > 0l)
+ {
+ d[0].re = fftw_real(s[0]);
+ d[0].im = 0;
+ if (c > 1l)
+ {
+ d[1].re = fftw_real(s[1]);
+ d[1].im = 0;
+ if (c > 2l)
+ {
+ d[2].re = fftw_real(s[2]);
+ d[2].im = 0;
+ }
+ }
+ }
+}
+
+
+static inline void fast_real_avg_from_shorts(register fftw_real *d,
+ register short *s1,
+ register short *s2,
+ long c)
+{
+ fftw_real t0, t1, t2, t3;
+ while (c >= 4l)
+ {
+ t0 = (s1[0] + s2[0]) / 2;
+ t1 = (s1[1] + s2[1]) / 2;
+ t2 = (s1[2] + s2[2]) / 2;
+ t3 = (s1[3] + s2[3]) / 2;
+ d[0] = t0;
+ d[1] = t1;
+ d[2] = t2;
+ d[3] = t3;
+ d += 4;
+ s1 += 4;
+ s2 += 4;
+ c -= 4l;
+ }
+
+ if (c > 0l)
+ {
+ d[0] = fftw_real((s1[0] + s2[0]) / 2);
+ if (c > 1l)
+ {
+ d[1] = fftw_real((s1[1] + s2[1]) / 2);
+ if (c > 2l)
+ {
+ d[2] = fftw_real((s1[2] + s2[2]) / 2);
+ }
+ }
+ }
+}
+
+static inline void fast_complex_avg_from_shorts(register fftw_complex *d,
+ register short *s1,
+ register short *s2,
+ long c)
+{
+ fftw_real t0, t1, t2, t3;
+ while (c >= 4l)
+ {
+ t0 = (s1[0] + s2[0]) / 2;
+ t1 = (s1[1] + s2[1]) / 2;
+ t2 = (s1[2] + s2[2]) / 2;
+ t3 = (s1[3] + s2[3]) / 2;
+ d[0].re = t0;
+ d[0].im = 0;
+ d[1].re = t1;
+ d[1].im = 0;
+ d[2].re = t2;
+ d[2].im = 0;
+ d[3].re = t3;
+ d[3].im = 0;
+ d += 4;
+ s1 += 4;
+ s2 += 4;
+ c -= 4l;
+ }
+
+ if (c > 0l)
+ {
+ d[0].re = fftw_real((s1[0] + s2[0]) / 2);
+ d[0].im = 0;
+ if (c > 1l)
+ {
+ d[1].re = fftw_real((s1[1] + s2[1]) / 2);
+ d[1].im = 0;
+ if (c > 2l)
+ {
+ d[2].re = fftw_real((s1[2] + s2[2]) / 2);
+ d[2].im = 0;
+ }
+ }
+ }
+}
+
+
+static inline fftw_complex fftw_complex_from_real( fftw_real re )
+{
+ fftw_complex c;
+
+ c.re = re;
+ c.im = 0;
+
+ return c;
+}
+
+static inline void fast_reals_set(register fftw_real *p1,
+ register fftw_real *p2,
+ fftw_real v,
+ long c)
+{
+ while (c >= 4l)
+ {
+ p1[0] = v;
+ p1[1] = v;
+ p1[2] = v;
+ p1[3] = v;
+ p2[0] = v;
+ p2[1] = v;
+ p2[2] = v;
+ p2[3] = v;
+ p1 += 4;
+ p2 += 4;
+ c -= 4l;
+ }
+
+ if (c > 0l)
+ {
+ p1[0] = v;
+ p2[0] = v;
+ if (c > 1l)
+ {
+ p1[1] = v;
+ p2[1] = v;
+ if (c > 2l)
+ {
+ p1[2] = v;
+ p2[2] = v;
+ }
+ }
+ }
+}
+
+static inline void fast_complex_set(register fftw_complex *p1,
+ register fftw_complex *p2,
+ fftw_complex v,
+ long c)
+{
+ while (c >= 4l)
+ {
+ p1[0] = v;
+ p1[1] = v;
+ p1[2] = v;
+ p1[3] = v;
+ p2[0] = v;
+ p2[1] = v;
+ p2[2] = v;
+ p2[3] = v;
+ p1 += 4;
+ p2 += 4;
+ c -= 4l;
+ }
+
+ if (c > 0l)
+ {
+ p1[0] = v;
+ p2[0] = v;
+ if (c > 1l)
+ {
+ p1[1] = v;
+ p2[1] = v;
+ if (c > 2l)
+ {
+ p1[2] = v;
+ p2[2] = v;
+ }
+ }
+ }
+}
+#endif // FFTW
+
+#endif // INLINES_H
diff --git a/src/jumptotrackdialog.cpp b/src/ui/jumptotrackdialog.cpp
index bcd0f308c..bcd0f308c 100644
--- a/src/jumptotrackdialog.cpp
+++ b/src/ui/jumptotrackdialog.cpp
diff --git a/src/jumptotrackdialog.h b/src/ui/jumptotrackdialog.h
index cfe629693..cfe629693 100644
--- a/src/jumptotrackdialog.h
+++ b/src/ui/jumptotrackdialog.h
diff --git a/src/keyboardmanager.cpp b/src/ui/keyboardmanager.cpp
index 5ad32fee7..5ad32fee7 100644
--- a/src/keyboardmanager.cpp
+++ b/src/ui/keyboardmanager.cpp
diff --git a/src/keyboardmanager.h b/src/ui/keyboardmanager.h
index 2b33b5ef9..2b33b5ef9 100644
--- a/src/keyboardmanager.h
+++ b/src/ui/keyboardmanager.h
diff --git a/src/listwidget.cpp b/src/ui/listwidget.cpp
index fb2173b33..fb2173b33 100644
--- a/src/listwidget.cpp
+++ b/src/ui/listwidget.cpp
diff --git a/src/listwidget.h b/src/ui/listwidget.h
index 2f20a3bf8..2f20a3bf8 100644
--- a/src/listwidget.h
+++ b/src/ui/listwidget.h
diff --git a/src/logscale.cpp b/src/ui/logscale.cpp
index 921004fd9..921004fd9 100644
--- a/src/logscale.cpp
+++ b/src/ui/logscale.cpp
diff --git a/src/logscale.h b/src/ui/logscale.h
index d74d25207..d74d25207 100644
--- a/src/logscale.h
+++ b/src/ui/logscale.h
diff --git a/src/mainvisual.cpp b/src/ui/mainvisual.cpp
index 5bdcbf5cb..5bdcbf5cb 100644
--- a/src/mainvisual.cpp
+++ b/src/ui/mainvisual.cpp
diff --git a/src/mainvisual.h b/src/ui/mainvisual.h
index 5c5b76256..5c5b76256 100644
--- a/src/mainvisual.h
+++ b/src/ui/mainvisual.h
diff --git a/src/mainwindow.cpp b/src/ui/mainwindow.cpp
index 2d54df4d3..d81dbce3b 100644
--- a/src/mainwindow.cpp
+++ b/src/ui/mainwindow.cpp
@@ -26,6 +26,8 @@
#include <math.h>
#include <soundcore.h>
+#include <qmmpui/generalhandler.h>
+#include <qmmpui/general.h>
#include "textscroller.h"
#include "mainwindow.h"
@@ -45,10 +47,11 @@
#include "filedialog.h"
#include "listwidget.h"
#include "visualmenu.h"
+#include "commandlineoption.h"
#define KEY_OFFSET 10
-MainWindow::MainWindow(const QStringList& args, QWidget *parent)
+MainWindow::MainWindow(const QStringList& args,CommandLineOptionManager* option_manager, QWidget *parent)
: QMainWindow(parent)
{
m_vis = 0;
@@ -56,6 +59,7 @@ MainWindow::MainWindow(const QStringList& args, QWidget *parent)
m_update = FALSE;
m_paused = FALSE;
m_elapsed = 0;
+ m_option_manager = option_manager;
setWindowIcon( QIcon(":/qmmp.xpm") );
@@ -112,11 +116,6 @@ MainWindow::MainWindow(const QStringList& args, QWidget *parent)
m_titlebar->show();
m_titlebar->setActive(TRUE);
- m_tray = new QSystemTrayIcon( this );
- m_tray->setIcon ( QIcon(":/stop.png") );
- m_tray->setContextMenu( m_mainMenu );
- connect(m_tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
-
readSettings();
dock->updateDock();
@@ -142,6 +141,15 @@ MainWindow::MainWindow(const QStringList& args, QWidget *parent)
FileDialog::registerBuiltinFactories();
FileDialog::registerExternalFactories();
+ m_generalHandler = new GeneralHandler(this);
+ connect(m_generalHandler, SIGNAL(playCalled()), SLOT(play()));
+ connect(m_generalHandler, SIGNAL(nextCalled()), SLOT(next()));
+ connect(m_generalHandler, SIGNAL(previousCalled()), SLOT(previous()));
+ connect(m_generalHandler, SIGNAL(stopCalled()), SLOT(stop()));
+ connect(m_generalHandler, SIGNAL(pauseCalled()), SLOT(pause()));
+ connect(m_generalHandler, SIGNAL(toggleVisibilityCalled()), SLOT(toggleVisibility()));
+ connect(m_generalHandler, SIGNAL(exitCalled()), SLOT(close()));
+
m_playListModel->readSettings();
char buf[PATH_MAX + 1];
QString cwd = QString::fromLocal8Bit(getcwd(buf,PATH_MAX));
@@ -312,23 +320,38 @@ void MainWindow::showOutputState(const OutputState &st)
{
case OutputState::Playing:
{
- m_tray->setIcon ( QIcon(":/play.png") );
- if (m_showMessage && m_playListModel->currentItem())
- m_tray->showMessage ( tr("Now Playing"),
- m_playListModel->currentItem()->title(),
- QSystemTrayIcon::Information, m_messageDelay );
- if (m_showToolTip && m_playListModel->currentItem())
- m_tray->setToolTip (m_playListModel->currentItem()->title());
+ m_generalHandler->setState(General::Playing);
+ if (m_playListModel->currentItem())
+ {
+ SongInfo info;
+ FileTag *tag = m_playListModel->currentItem()->tag();
+ if (tag && !tag->isEmpty())
+ {
+ info.setValue(SongInfo::TITLE, tag->title());
+ info.setValue(SongInfo::ARTIST, tag->artist());
+ info.setValue(SongInfo::ALBUM, tag->album());
+ info.setValue(SongInfo::COMMENT, tag->comment());
+ info.setValue(SongInfo::GENRE, tag->genre());
+ info.setValue(SongInfo::YEAR, tag->year());
+ info.setValue(SongInfo::TRACK, tag->track());
+ info.setValue(SongInfo::LENGTH, tag->length());
+ }
+ else
+ info.setValue(SongInfo::TITLE, m_playlist->currentItem()->title());
+ info.setValue(SongInfo::STREAM,
+ m_playlist->currentItem()->path().startsWith("http://"));
+ m_generalHandler->setSongInfo(info);
+ }
break;
}
case OutputState::Paused:
{
- m_tray->setIcon ( QIcon(":/pause.png") );
+ m_generalHandler->setState(General::Paused);
break;
}
case OutputState::Stopped:
{
- m_tray->setIcon ( QIcon(":/stop.png") );
+ m_generalHandler->setState(General::Stopped);
break;
}
case OutputState::Info:
@@ -358,9 +381,26 @@ void MainWindow::showDecoderState(const DecoderState &st)
qDebug("YEAR = %d", st.tag()->year());
qDebug("TRACK = %d", st.tag()->track());
qDebug("LENGTH = %d", st.tag()->length());
-
- m_playlist->currentItem()->updateTags(st.tag());
- m_playlist->listWidget()->updateList();
+ if (m_playlist->currentItem())
+ {
+ if (!st.tag()->isEmpty())
+ {
+ SongInfo info;
+ info.setValue(SongInfo::TITLE, st.tag()->title());
+ info.setValue(SongInfo::ARTIST, st.tag()->artist());
+ info.setValue(SongInfo::ALBUM, st.tag()->album());
+ info.setValue(SongInfo::COMMENT, st.tag()->comment());
+ info.setValue(SongInfo::GENRE, st.tag()->genre());
+ info.setValue(SongInfo::YEAR, st.tag()->year());
+ info.setValue(SongInfo::TRACK, st.tag()->track());
+ info.setValue(SongInfo::LENGTH, st.tag()->length());
+ info.setValue(SongInfo::STREAM,
+ m_playlist->currentItem()->path().startsWith("http://"));
+ m_generalHandler->setSongInfo(info);
+ }
+ m_playlist->currentItem()->updateTags(st.tag());
+ m_playlist->listWidget()->updateList();
+ }
break;
}
}
@@ -368,8 +408,13 @@ void MainWindow::showDecoderState(const DecoderState &st)
void MainWindow::changeTitle(const QString &title)
{
- m_playlist->currentItem()->changeTitle(title);
+ if (m_playlist->currentItem())
+ m_playlist->currentItem()->changeTitle(title);
m_playlist->listWidget()->updateList();
+ SongInfo info;
+ info.setValue(SongInfo::TITLE, title);
+ info.setValue(SongInfo::STREAM, TRUE);
+ m_generalHandler->setSongInfo(info);
}
void MainWindow::closeEvent ( QCloseEvent *)
@@ -500,17 +545,6 @@ void MainWindow::readSettings()
m_update = TRUE;
}
- //tray
- settings.beginGroup("Tray");
- m_tray->setVisible(settings.value("enabled",TRUE).toBool());
- m_showMessage = settings.value("show_message",TRUE).toBool();
- m_messageDelay = settings.value("message_delay",2000).toInt();
- m_showToolTip = settings.value("show_tooltip", FALSE).toBool();
- m_hide_on_titlebar_close = settings.value("hide_on_close",FALSE).toBool();
- if (!m_showToolTip)
- m_tray->setToolTip(QString());
- settings.endGroup();
-
}
void MainWindow::writeSettings()
@@ -542,6 +576,7 @@ void MainWindow::showSettings()
m_playlist->readSettings();
TextScroller::getPointer()->readSettings();
m_core->updateConfig();
+ m_generalHandler->updateConfig();
m_visMenu->updateActions();
}
delete m_confDialog;
@@ -574,12 +609,6 @@ void MainWindow::toggleVisibility()
}
}
-void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason reason)
-{
- if (reason == QSystemTrayIcon::Trigger)
- toggleVisibility();
-}
-
void MainWindow::createActions()
{
m_mainMenu = new QMenu(this);
@@ -588,6 +617,7 @@ void MainWindow::createActions()
m_mainMenu->addAction(tr("&Stop"),this, SLOT(stop()), tr("V"));
m_mainMenu->addAction(tr("&Previous"),this, SLOT(previous()), tr("Z"));
m_mainMenu->addAction(tr("&Next"),this, SLOT(next()), tr("B"));
+ m_mainMenu->addAction(tr("P&lay/Pause"),this, SLOT(playPause()), tr("Space"));
m_mainMenu->addAction(tr("&Queue"),m_playListModel, SLOT(addToQueue()), tr("Q"));
m_mainMenu->addSeparator();
m_mainMenu->addAction(tr("&Jump To File"),this, SLOT(jumpToFile()), tr("J"));
@@ -754,29 +784,10 @@ bool MainWindow::processCommandArgs(const QStringList &slist,const QString& cwd)
QString str = slist[0];
if (str.startsWith("--")) // is it a command?
{
- if (str == "--play")
- play();
- else if (str == "--stop")
+ if (m_option_manager->hasOption(str))
{
- stop();
- display->hideTimeDisplay();
- }
- else if (str == "--pause")
- pause();
- else if (str == "--next")
- {
- next();
- if(!m_core->isInitialized())
- play();
+ m_option_manager->executeCommand(str,this);
}
- else if (str == "--previous")
- {
- previous();
- if(!m_core->isInitialized())
- play();
- }
- else if (str == "--play-pause")
- playPause();
else
return false;
}
@@ -785,6 +796,7 @@ bool MainWindow::processCommandArgs(const QStringList &slist,const QString& cwd)
QStringList full_path_list;
foreach(QString s,slist)
{
+ qWarning(qPrintable(cwd + "/" + s));
if (s.left(1) == "/") //is it absolute path?
full_path_list << s;
else
@@ -807,13 +819,30 @@ void MainWindow::jumpToFile()
void MainWindow::handleCloseRequest()
{
- if (m_hide_on_titlebar_close && m_tray->isVisible())
- toggleVisibility();
- else
- QApplication::closeAllWindows();
+ //if (m_hide_on_titlebar_close && m_tray->isVisible())
+ /*toggleVisibility();
+ else*/
+ QApplication::closeAllWindows();
}
void MainWindow::addUrl( )
{
AddUrlDialog::popup(this,m_playListModel);
}
+
+SoundCore * MainWindow::soundCore() const
+{
+ return m_core;
+}
+
+MainDisplay * MainWindow::mainDisplay() const
+{
+ return display;
+}
+
+void MainWindow::keyPressEvent(QKeyEvent *ke)
+{
+ QKeyEvent event = QKeyEvent(ke->type(), ke->key(),
+ ke->modifiers(), ke->text(),ke->isAutoRepeat(), ke->count());
+ QApplication::sendEvent(m_playlist,&event);
+}
diff --git a/src/mainwindow.h b/src/ui/mainwindow.h
index 97caed52a..25b2b3b75 100644
--- a/src/mainwindow.h
+++ b/src/ui/mainwindow.h
@@ -21,7 +21,7 @@
#define MAINWINDOW_H
#include <QMainWindow>
-#include <QSystemTrayIcon>
+
#include "output.h"
#include "decoder.h"
@@ -42,31 +42,29 @@ class Skin;
class SoundCore;
class JumpToTrackDialog;
class VisualMenu;
+class GeneralHandler;
class QMenu;
class QKeyEvent;
-
+class CommandLineOptionManager;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
- MainWindow(const QStringList& args, QWidget *parent);
+ MainWindow(const QStringList& args,CommandLineOptionManager*, QWidget *parent);
~MainWindow();
- PlayList *getPLPointer()
- {
- return m_playlist;
- }
+ PlayList *getPLPointer(){return m_playlist;}
void seek(int);
QMenu* menu();
void setVolume(int volume, int balance);
-
- bool processCommandArgs(const QStringList &slist,const QString& cwd);
-
+ SoundCore* soundCore()const;
+ MainDisplay* mainDisplay()const;
+ bool processCommandArgs(const QStringList &list,const QString& cwd);
public slots:
void previous();
void play();
@@ -75,6 +73,12 @@ public slots:
void stop();
void next();
void replay();
+ void jumpToFile();
+ void toggleVisibility();
+
+ void addDir();
+ void addFile();
+ void addUrl();
void newPlaylist();
void loadPlaylist();
@@ -85,6 +89,7 @@ public slots:
protected:
virtual void closeEvent ( QCloseEvent *);
virtual void changeEvent ( QEvent * event );
+ virtual void keyPressEvent ( QKeyEvent* );
private slots:
void showOutputState(const OutputState&);
@@ -94,16 +99,11 @@ private slots:
void startSeek();
void endSeek();
void showSettings();
- void addDir();
- void addFile();
- void addUrl();
void updateEQ();
void updateSkin();
void forward();
void backward();
- void jumpToFile();
- void toggleVisibility();
- void trayActivated(QSystemTrayIcon::ActivationReason);
+ //void trayActivated(QSystemTrayIcon::ActivationReason);
void about();
void handleCloseRequest();
@@ -123,7 +123,6 @@ private:
EqWidget *m_equalizer;
MainVisual *m_vis;
QString m_lastDir;
- QSystemTrayIcon *m_tray;
bool m_update;
bool m_showMessage;
int m_messageDelay;
@@ -135,6 +134,8 @@ private:
bool m_hide_on_titlebar_close;
int m_elapsed;
VisualMenu *m_visMenu;
+ CommandLineOptionManager* m_option_manager;
+ GeneralHandler *m_generalHandler;
};
#endif
diff --git a/src/mediafile.cpp b/src/ui/mediafile.cpp
index 24b6ce174..6ffb5514f 100644
--- a/src/mediafile.cpp
+++ b/src/ui/mediafile.cpp
@@ -160,3 +160,10 @@ MediaFile::FLAGS MediaFile::flag() const
return m_flag;
}
+FileTag *MediaFile::tag()
+{
+ if(m_tag && m_tag->isEmpty())
+ return 0;
+ return m_tag;
+}
+
diff --git a/src/mediafile.h b/src/ui/mediafile.h
index 7adab6603..1652bf92d 100644
--- a/src/mediafile.h
+++ b/src/ui/mediafile.h
@@ -60,6 +60,7 @@ public:
void changeTitle(const QString&);
FLAGS flag()const;
void setFlag(FLAGS);
+ FileTag *tag();
private:
void readMetadata();
diff --git a/src/monostereo.cpp b/src/ui/monostereo.cpp
index 659fec7be..659fec7be 100644
--- a/src/monostereo.cpp
+++ b/src/ui/monostereo.cpp
diff --git a/src/monostereo.h b/src/ui/monostereo.h
index be1419c5c..be1419c5c 100644
--- a/src/monostereo.h
+++ b/src/ui/monostereo.h
diff --git a/src/mp3player.cpp b/src/ui/mp3player.cpp
index cf6b27535..cf6b27535 100644
--- a/src/mp3player.cpp
+++ b/src/ui/mp3player.cpp
diff --git a/src/number.cpp b/src/ui/number.cpp
index 9f127965e..9f127965e 100644
--- a/src/number.cpp
+++ b/src/ui/number.cpp
diff --git a/src/number.h b/src/ui/number.h
index 1c89f71d4..1c89f71d4 100644
--- a/src/number.h
+++ b/src/ui/number.h
diff --git a/src/pixmapwidget.cpp b/src/ui/pixmapwidget.cpp
index a0f4ff7fd..a0f4ff7fd 100644
--- a/src/pixmapwidget.cpp
+++ b/src/ui/pixmapwidget.cpp
diff --git a/src/pixmapwidget.h b/src/ui/pixmapwidget.h
index 24d34260e..24d34260e 100644
--- a/src/pixmapwidget.h
+++ b/src/ui/pixmapwidget.h
diff --git a/src/playlist.cpp b/src/ui/playlist.cpp
index 282463ef0..282463ef0 100644
--- a/src/playlist.cpp
+++ b/src/ui/playlist.cpp
diff --git a/src/playlist.h b/src/ui/playlist.h
index 4e8bdc1f8..4e8bdc1f8 100644
--- a/src/playlist.h
+++ b/src/ui/playlist.h
diff --git a/src/playlistcontrol.cpp b/src/ui/playlistcontrol.cpp
index 8f111fe4e..8f111fe4e 100644
--- a/src/playlistcontrol.cpp
+++ b/src/ui/playlistcontrol.cpp
diff --git a/src/playlistcontrol.h b/src/ui/playlistcontrol.h
index 26c3871d4..26c3871d4 100644
--- a/src/playlistcontrol.h
+++ b/src/ui/playlistcontrol.h
diff --git a/src/playlistformat.cpp b/src/ui/playlistformat.cpp
index 505805c88..d9ce45b77 100644
--- a/src/playlistformat.cpp
+++ b/src/ui/playlistformat.cpp
@@ -169,7 +169,6 @@ QString M3UPlaylistFormat::name() const
return "M3UPlaylistFormat";
}
-#ifndef XSPF_PLUGIN
// Needs more work - it's better use libSpiff there and put it as plugin.
@@ -282,7 +281,6 @@ QString XSPFPlaylistFormat::name() const
return "XSPFPlaylistFormat";
}
-#endif
diff --git a/src/playlistformat.h b/src/ui/playlistformat.h
index 70af82764..a87018d63 100644
--- a/src/playlistformat.h
+++ b/src/ui/playlistformat.h
@@ -97,9 +97,6 @@ protected:
};
-// Format below is made also as plugin - experimental. To enable it
-// uncomment 'CONFIG += XSPF_PLUGIN' line in qmmp.pri
-#ifndef XSPF_PLUGIN
/*!
* Class for XSPF playlist format parsing
*/
@@ -115,6 +112,5 @@ class XSPFPlaylistFormat : public PlaylistFormat
protected:
QStringList m_supported_formats;
};
-#endif
#endif
diff --git a/src/playlistmodel.cpp b/src/ui/playlistmodel.cpp
index 196608438..196608438 100644
--- a/src/playlistmodel.cpp
+++ b/src/ui/playlistmodel.cpp
diff --git a/src/playlistmodel.h b/src/ui/playlistmodel.h
index b3ac19c04..b3ac19c04 100644
--- a/src/playlistmodel.h
+++ b/src/ui/playlistmodel.h
diff --git a/src/playlistslider.cpp b/src/ui/playlistslider.cpp
index 098b3bcee..098b3bcee 100644
--- a/src/playlistslider.cpp
+++ b/src/ui/playlistslider.cpp
diff --git a/src/playlistslider.h b/src/ui/playlistslider.h
index a8eb45c66..a8eb45c66 100644
--- a/src/playlistslider.h
+++ b/src/ui/playlistslider.h
diff --git a/src/playlisttitlebar.cpp b/src/ui/playlisttitlebar.cpp
index a583065ca..a583065ca 100644
--- a/src/playlisttitlebar.cpp
+++ b/src/ui/playlisttitlebar.cpp
diff --git a/src/playlisttitlebar.h b/src/ui/playlisttitlebar.h
index f50018371..f50018371 100644
--- a/src/playlisttitlebar.h
+++ b/src/ui/playlisttitlebar.h
diff --git a/src/playstate.cpp b/src/ui/playstate.cpp
index 373619574..373619574 100644
--- a/src/playstate.cpp
+++ b/src/ui/playstate.cpp
diff --git a/src/playstate.h b/src/ui/playstate.h
index e4af7fa6f..e4af7fa6f 100644
--- a/src/playstate.h
+++ b/src/ui/playstate.h
diff --git a/src/playstatus.cpp b/src/ui/playstatus.cpp
index 913199c4f..913199c4f 100644
--- a/src/playstatus.cpp
+++ b/src/ui/playstatus.cpp
diff --git a/src/playstatus.h b/src/ui/playstatus.h
index b050de1ca..b050de1ca 100644
--- a/src/playstatus.h
+++ b/src/ui/playstatus.h
diff --git a/src/pluginitem.cpp b/src/ui/pluginitem.cpp
index fc32f8ab8..2ccd8e41d 100644
--- a/src/pluginitem.cpp
+++ b/src/ui/pluginitem.cpp
@@ -27,6 +27,8 @@
#include <effectfactory.h>
#include <effect.h>
#include <soundcore.h>
+#include <qmmpui/generalfactory.h>
+#include <qmmpui/general.h>
#include "pluginitem.h"
@@ -150,3 +152,31 @@ EffectFactory *EffectPluginItem::factory()
{
return m_factory;
}
+
+/*General*/
+GeneralPluginItem::GeneralPluginItem(QObject *parent, GeneralFactory *fact,
+ const QString &filePath): QObject(parent)
+{
+ m_fileName = filePath.section('/',-1);
+ m_factory = fact;
+}
+
+
+GeneralPluginItem::~GeneralPluginItem()
+{}
+
+void GeneralPluginItem::select(bool on)
+{
+ General::setEnabled(m_factory, on);
+}
+
+bool GeneralPluginItem::isSelected()
+{
+ return General::isEnabled(m_factory);
+}
+
+GeneralFactory *GeneralPluginItem::factory()
+{
+ return m_factory;
+}
+
diff --git a/src/pluginitem.h b/src/ui/pluginitem.h
index 11798ee25..8b3dc3b73 100644
--- a/src/pluginitem.h
+++ b/src/ui/pluginitem.h
@@ -30,6 +30,7 @@ class DecoderFactory;
class OutputFactory;
class VisualFactory;
class EffectFactory;
+class GeneralFactory;
class InputPluginItem : public QObject
{
@@ -109,4 +110,23 @@ private:
EffectFactory *m_factory;
};
+class GeneralPluginItem : public QObject
+{
+ Q_OBJECT
+public:
+ GeneralPluginItem(QObject *parent, GeneralFactory *fact, const QString &filePath);
+
+ ~GeneralPluginItem();
+
+ bool isSelected();
+ GeneralFactory * factory();
+
+public slots:
+ void select(bool);
+
+private:
+ QString m_fileName;
+ GeneralFactory *m_factory;
+};
+
#endif
diff --git a/src/positionbar.cpp b/src/ui/positionbar.cpp
index 5431fd4f3..5431fd4f3 100644
--- a/src/positionbar.cpp
+++ b/src/ui/positionbar.cpp
diff --git a/src/positionbar.h b/src/ui/positionbar.h
index ea03ef14a..ea03ef14a 100644
--- a/src/positionbar.h
+++ b/src/ui/positionbar.h
diff --git a/src/preseteditor.cpp b/src/ui/preseteditor.cpp
index 1b55a229d..1b55a229d 100644
--- a/src/preseteditor.cpp
+++ b/src/ui/preseteditor.cpp
diff --git a/src/preseteditor.h b/src/ui/preseteditor.h
index 35302b185..35302b185 100644
--- a/src/preseteditor.h
+++ b/src/ui/preseteditor.h
diff --git a/src/qmmpstarter.cpp b/src/ui/qmmpstarter.cpp
index 56b1773b7..b04916983 100644
--- a/src/qmmpstarter.cpp
+++ b/src/ui/qmmpstarter.cpp
@@ -26,11 +26,13 @@
#include "mainwindow.h"
#include "version.h"
#include "qmmpstarter.h"
+#include "commandlineoption.h"
#define MAXCOMMANDSIZE 1024
QMMPStarter::QMMPStarter(int argc,char ** argv,QObject* parent) : QObject(parent),mw(NULL)
{
+ m_option_manager = new CommandLineOptionManager();
QStringList tmp;
for(int i = 1;i < argc;i++)
tmp << QString::fromLocal8Bit(argv[i]);
@@ -49,12 +51,7 @@ QMMPStarter::QMMPStarter(int argc,char ** argv,QObject* parent) : QObject(parent
}
if(argString.startsWith("--") && // command?
- argString != "--play" &&
- argString != "--previous" &&
- argString != "--next" &&
- argString != "--stop" &&
- argString != "--pause" &&
- argString != "--play-pause"
+ !m_option_manager->hasOption(argString)
)
{
qFatal("QMMP: Unknown command...");
@@ -85,7 +82,6 @@ QMMPStarter::QMMPStarter(int argc,char ** argv,QObject* parent) : QObject(parent
QMMPStarter::~ QMMPStarter()
{
- qWarning("QMMPStarter::~ QMMPStarter()");
if(mw) delete mw;
}
@@ -93,7 +89,7 @@ void QMMPStarter::startMainWindow()
{
connect(m_sock, SIGNAL(readyRead()),this, SLOT(readCommand()));
QStringList arg_l = argString.split("\n", QString::SkipEmptyParts);
- mw = new MainWindow(arg_l,0);
+ mw = new MainWindow(arg_l,m_option_manager,0);
}
void QMMPStarter::writeCommand()
@@ -137,14 +133,14 @@ void QMMPStarter::printUsage()
"Usage: qmmp [options] [files] \n"
"Options:\n"
"--------\n"
- "--help Display this text and exit.\n"
- "--previous Skip backwards in playlist\n"
- "--play Start playing current playlist\n"
- "--pause Pause current song\n"
- "--play-pause Pause if playing, play otherwise\n"
- "--stop Stop current song\n"
- "--next Skip forward in playlist\n"
- "--version Print version number and exit.\n\n"
+ );
+ for(int i = 0; i< m_option_manager->count();i++)
+ {
+ qWarning(qPrintable((*m_option_manager)[i]->helpString()));
+ }
+ qWarning(
+ "--help Display this text and exit.\n"
+ "--version Print version number and exit.\n\n"
"Ideas, patches, bugreports send to forkotov02@hotmail.ru\n"
);
}
diff --git a/src/qmmpstarter.h b/src/ui/qmmpstarter.h
index c859496cf..010c5385f 100644
--- a/src/qmmpstarter.h
+++ b/src/ui/qmmpstarter.h
@@ -27,7 +27,7 @@
class UnixDomainSocket;
class MainWindow;
-
+class CommandLineOptionManager;
/*!
* QMMPStarter represents wrapper object that is responsible
@@ -65,6 +65,7 @@ private:
MainWindow* mw;
UnixDomainSocket* m_sock;
QString argString;
+ CommandLineOptionManager* m_option_manager;
};
#endif
diff --git a/src/shadedbar.cpp b/src/ui/shadedbar.cpp
index 63b2017c0..63b2017c0 100644
--- a/src/shadedbar.cpp
+++ b/src/ui/shadedbar.cpp
diff --git a/src/shadedbar.h b/src/ui/shadedbar.h
index 4ea8c871f..4ea8c871f 100644
--- a/src/shadedbar.h
+++ b/src/ui/shadedbar.h
diff --git a/src/shadedvisual.cpp b/src/ui/shadedvisual.cpp
index 2dea3d419..2dea3d419 100644
--- a/src/shadedvisual.cpp
+++ b/src/ui/shadedvisual.cpp
diff --git a/src/shadedvisual.h b/src/ui/shadedvisual.h
index e46331ecb..e46331ecb 100644
--- a/src/shadedvisual.h
+++ b/src/ui/shadedvisual.h
diff --git a/src/skin.cpp b/src/ui/skin.cpp
index 8bb4a63ad..b7f787ad4 100644
--- a/src/skin.cpp
+++ b/src/ui/skin.cpp
@@ -138,7 +138,7 @@ void Skin::loadButtons()
buttons[BT_STOP_P] = pixmap->copy ( 69,18,23,18 );
buttons[BT_NEXT_N] = pixmap->copy ( 92, 0,22,18 );
- buttons[BT_NEXT_P] = pixmap->copy ( 92,16,22,18 );
+ buttons[BT_NEXT_P] = pixmap->copy ( 92,18,22,18 );
buttons[BT_EJECT_N] = pixmap->copy ( 114, 0,22,16 );
buttons[BT_EJECT_P] = pixmap->copy ( 114,16,22,16 );
diff --git a/src/skin.h b/src/ui/skin.h
index d981c4613..d981c4613 100644
--- a/src/skin.h
+++ b/src/ui/skin.h
diff --git a/src/skinreader.cpp b/src/ui/skinreader.cpp
index 64e0aacc9..c29246d8d 100644
--- a/src/skinreader.cpp
+++ b/src/ui/skinreader.cpp
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (C) 2006 by Ilya Kotov *
+ * Copyright (C) 2008 by Ilya Kotov *
* forkotov02@hotmail.ru *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -23,6 +23,7 @@
#include <QFileInfo>
#include <QProcess>
#include <QByteArray>
+#include <QApplication>
#include <QFile>
#include "skinreader.h"
@@ -47,6 +48,9 @@ void SkinReader::updateCache()
QDir dir(QDir::homePath() +"/.qmmp/skins");
dir.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks);
QFileInfoList f = dir.entryInfoList();
+ dir.setPath(qApp->applicationDirPath()+"/../share/qmmp/skins");
+ dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks);
+ f << dir.entryInfoList();
//clear removed skins from cache
QDir cache_dir(QDir::homePath() +"/.qmmp/cache/skins");
cache_dir.setFilter(QDir::Dirs | QDir::Hidden | QDir::NoDotAndDotDot);
diff --git a/src/skinreader.h b/src/ui/skinreader.h
index c6db283fa..321a5fbbf 100644
--- a/src/skinreader.h
+++ b/src/ui/skinreader.h
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (C) 2006 by Ilya Kotov *
+ * Copyright (C) 2008 by Ilya Kotov *
* forkotov02@hotmail.ru *
* *
* This program is free software; you can redistribute it and/or modify *
diff --git a/src/stuff.qrc b/src/ui/stuff.qrc
index dfffed67d..e9c99d558 100644
--- a/src/stuff.qrc
+++ b/src/ui/stuff.qrc
@@ -1,7 +1,7 @@
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource>
- <file>../COPYING</file>
+ <file>../../COPYING</file>
<file>html/about_en.html</file>
<file>html/about_ru.html</file>
<file>html/authors_en.txt</file>
diff --git a/src/symboldisplay.cpp b/src/ui/symboldisplay.cpp
index b3942a6bb..b3942a6bb 100644
--- a/src/symboldisplay.cpp
+++ b/src/ui/symboldisplay.cpp
diff --git a/src/symboldisplay.h b/src/ui/symboldisplay.h
index 065579b7a..065579b7a 100644
--- a/src/symboldisplay.h
+++ b/src/ui/symboldisplay.h
diff --git a/src/textscroller.cpp b/src/ui/textscroller.cpp
index 35e4ed4eb..35e4ed4eb 100644
--- a/src/textscroller.cpp
+++ b/src/ui/textscroller.cpp
diff --git a/src/textscroller.h b/src/ui/textscroller.h
index 7346ce29a..7346ce29a 100644
--- a/src/textscroller.h
+++ b/src/ui/textscroller.h
diff --git a/src/timeindicator.cpp b/src/ui/timeindicator.cpp
index 9b81ba040..9b81ba040 100644
--- a/src/timeindicator.cpp
+++ b/src/ui/timeindicator.cpp
diff --git a/src/timeindicator.h b/src/ui/timeindicator.h
index 19981a4b3..19981a4b3 100644
--- a/src/timeindicator.h
+++ b/src/ui/timeindicator.h
diff --git a/src/titlebar.cpp b/src/ui/titlebar.cpp
index bdbd86b2e..bdbd86b2e 100644
--- a/src/titlebar.cpp
+++ b/src/ui/titlebar.cpp
diff --git a/src/titlebar.h b/src/ui/titlebar.h
index 4428a188c..4428a188c 100644
--- a/src/titlebar.h
+++ b/src/ui/titlebar.h
diff --git a/src/titlebarcontrol.cpp b/src/ui/titlebarcontrol.cpp
index 8238c287a..8238c287a 100644
--- a/src/titlebarcontrol.cpp
+++ b/src/ui/titlebarcontrol.cpp
diff --git a/src/titlebarcontrol.h b/src/ui/titlebarcontrol.h
index c368b2186..c368b2186 100644
--- a/src/titlebarcontrol.h
+++ b/src/ui/titlebarcontrol.h
diff --git a/src/togglebutton.cpp b/src/ui/togglebutton.cpp
index 86b809ef2..86b809ef2 100644
--- a/src/togglebutton.cpp
+++ b/src/ui/togglebutton.cpp
diff --git a/src/togglebutton.h b/src/ui/togglebutton.h
index a15d7476f..a15d7476f 100644
--- a/src/togglebutton.h
+++ b/src/ui/togglebutton.h
diff --git a/src/translations/qmmp_cs.ts b/src/ui/translations/qmmp_cs.ts
index faba9c1b9..faba9c1b9 100644
--- a/src/translations/qmmp_cs.ts
+++ b/src/ui/translations/qmmp_cs.ts
diff --git a/src/translations/qmmp_locales.qrc b/src/ui/translations/qmmp_locales.qrc
index 64ac204fa..64ac204fa 100644
--- a/src/translations/qmmp_locales.qrc
+++ b/src/ui/translations/qmmp_locales.qrc
diff --git a/src/translations/qmmp_ru.qm b/src/ui/translations/qmmp_ru.qm
index 38c82d0e8..38c82d0e8 100644
--- a/src/translations/qmmp_ru.qm
+++ b/src/ui/translations/qmmp_ru.qm
Binary files differ
diff --git a/src/translations/qmmp_ru.ts b/src/ui/translations/qmmp_ru.ts
index 32fdd757d..32fdd757d 100644
--- a/src/translations/qmmp_ru.ts
+++ b/src/ui/translations/qmmp_ru.ts
diff --git a/src/translations/qmmp_tr.qm b/src/ui/translations/qmmp_tr.qm
index 1180e41d5..1180e41d5 100644
--- a/src/translations/qmmp_tr.qm
+++ b/src/ui/translations/qmmp_tr.qm
Binary files differ
diff --git a/src/translations/qmmp_tr.ts b/src/ui/translations/qmmp_tr.ts
index 73f8206d6..73f8206d6 100644
--- a/src/translations/qmmp_tr.ts
+++ b/src/ui/translations/qmmp_tr.ts
diff --git a/src/translations/qmmp_zh_CN.qm b/src/ui/translations/qmmp_zh_CN.qm
index 2e3e3f2ea..2e3e3f2ea 100644
--- a/src/translations/qmmp_zh_CN.qm
+++ b/src/ui/translations/qmmp_zh_CN.qm
Binary files differ
diff --git a/src/translations/qmmp_zh_CN.ts b/src/ui/translations/qmmp_zh_CN.ts
index 3aeefd569..3aeefd569 100644
--- a/src/translations/qmmp_zh_CN.ts
+++ b/src/ui/translations/qmmp_zh_CN.ts
diff --git a/src/src.pro b/src/ui/ui.pro
index 47708ec48..527c205f2 100644
--- a/src/src.pro
+++ b/src/ui/ui.pro
@@ -5,10 +5,11 @@
include(../qmmp.pri)
-FORMS += configdialog.ui \
- preseteditor.ui \
- jumptotrackdialog.ui \
- aboutdialog.ui
+FORMS += ./forms/configdialog.ui \
+ ./forms/preseteditor.ui \
+ ./forms/jumptotrackdialog.ui \
+ ./forms/aboutdialog.ui \
+ ./forms/addurldialog.ui
HEADERS += mainwindow.h \
fileloader.h \
@@ -55,8 +56,14 @@ HEADERS += mainwindow.h \
timeindicator.h \
keyboardmanager.h \
filedialog.h \
- unixdomainsocket.h
-
+ unixdomainsocket.h \
+ commandlineoption.h \
+ addurldialog.h \
+ skinreader.h \
+ visualmenu.h \
+ titlebarcontrol.h \
+ shadedvisual.h \
+ shadedbar.h
SOURCES += mainwindow.cpp \
mp3player.cpp \
@@ -90,63 +97,53 @@ SOURCES += mainwindow.cpp \
pluginitem.cpp \
volumebar.cpp \
balancebar.cpp \
- playstate.cpp \
- symboldisplay.cpp \
- playlistformat.cpp \
- playlistcontrol.cpp \
- qmmpstarter.cpp \
+ playstate.cpp \
+ symboldisplay.cpp \
+ playlistformat.cpp \
+ playlistcontrol.cpp \
+ qmmpstarter.cpp \
eqpreset.cpp \
preseteditor.cpp \
- jumptotrackdialog.cpp \
- aboutdialog.cpp \
+ jumptotrackdialog.cpp \
+ aboutdialog.cpp \
timeindicator.cpp \
keyboardmanager.cpp \
filedialog.cpp \
- unixdomainsocket.cpp
-
+ unixdomainsocket.cpp \
+ commandlineoption.cpp \
+ addurldialog.cpp \
+ skinreader.cpp \
+ visualmenu.cpp \
+ titlebarcontrol.cpp \
+ shadedvisual.cpp \
+ shadedbar.cpp
+#Some conf to redirect intermediate stuff in separate dirs
+UI_DIR=./.build/ui/
+MOC_DIR=./.build/moc/
+OBJECTS_DIR=./.build/obj
-contains(CONFIG,XSPF_PLUGIN){
- message(*********************************************)
- message(* XSPF support will be compiled as plugin *)
- message(*********************************************)
- DEFINES += XSPF_PLUGIN
-}else {
- DEFINES -= XSPF_PLUGIN
- message(*******************************************)
- message(* XSPF support will be compiled in QMMP *)
- message(*******************************************)
- QT += xml
-}
-QT += network
-TARGET = ../bin/qmmp
+QT += network xml
+TARGET = ../../bin/qmmp
CONFIG += thread release \
warn_on
-QMAKE_LIBDIR += ../lib
-LIBS += -Wl,-rpath,../lib -lqmmp
-INCLUDEPATH += ../lib
+QMAKE_LIBDIR += ../../lib qmmpui
+LIBS += -Wl,-rpath,../lib
+LIBS += -L../../lib -lqmmp -lqmmpui
+INCLUDEPATH += ../qmmp ../
RESOURCES = images/images.qrc \
- stuff.qrc
-# translations/qmmp_locales.qrc
-
-#TRANSLATIONS = translations/qmmp_ru.ts \
-# translations/qmmp_tr.ts \
-# translations/qmmp_zh_CN.ts
-TEMPLATE = app
+ stuff.qrc
+TEMPLATE = app
target.path = /bin
INSTALLS += target
-HEADERS += addurldialog.h \
- skinreader.h \
- visualmenu.h \
- titlebarcontrol.h \
- shadedvisual.h \
- shadedbar.h
-SOURCES += addurldialog.cpp \
- skinreader.cpp \
- visualmenu.cpp \
- titlebarcontrol.cpp \
- shadedvisual.cpp \
- shadedbar.cpp
-FORMS += addurldialog.ui
+
+#RESOURCES += translations/qmmp_locales.qrc
+
+#TRANSLATIONS = translations/qmmp_ru.ts \
+# translations/qmmp_tr.ts \
+# translations/qmmp_zh_CN.ts
+
+
+
diff --git a/src/unixdomainsocket.cpp b/src/ui/unixdomainsocket.cpp
index ecf8aa6f0..5769676be 100644
--- a/src/unixdomainsocket.cpp
+++ b/src/ui/unixdomainsocket.cpp
@@ -7,14 +7,14 @@
UnixDomainSocket::UnixDomainSocket(QObject * parent ) : QUdpSocket(parent){
- _binded = false;
+ _bound = false;
_s = socket(AF_UNIX, SOCK_DGRAM, 0);
this->setSocketDescriptor(_s);
}
UnixDomainSocket::~UnixDomainSocket(){
- if(_binded){
+ if(_bound){
::unlink(_local.sun_path);
}
}
@@ -28,7 +28,7 @@ bool UnixDomainSocket::bind(const QString& path){
len = strlen(_local.sun_path) + sizeof(_local.sun_family);
bool res = !(::bind(_s, (struct sockaddr *)&_local, len));
if(res)
- _binded = true;
+ _bound = true;
return res;
}
@@ -49,7 +49,7 @@ bool UnixDomainSocket::alive(const QString& path)
}
return true;
}
-
+//
void UnixDomainSocket::writeDatagram(const char* command,const QString& path)
{
socklen_t len;
diff --git a/src/unixdomainsocket.h b/src/ui/unixdomainsocket.h
index 7538e685a..37e5a364b 100644
--- a/src/unixdomainsocket.h
+++ b/src/ui/unixdomainsocket.h
@@ -38,7 +38,7 @@ public slots:
private:
unsigned int _s;
struct sockaddr_un _local;
- bool _binded;
+ bool _bound;
};
diff --git a/src/version.h b/src/ui/version.h
index 61fbc902e..61fbc902e 100644
--- a/src/version.h
+++ b/src/ui/version.h
diff --git a/src/visualmenu.cpp b/src/ui/visualmenu.cpp
index 2b0ad6797..2b0ad6797 100644
--- a/src/visualmenu.cpp
+++ b/src/ui/visualmenu.cpp
diff --git a/src/visualmenu.h b/src/ui/visualmenu.h
index 9202a8a7d..9202a8a7d 100644
--- a/src/visualmenu.h
+++ b/src/ui/visualmenu.h
diff --git a/src/volumebar.cpp b/src/ui/volumebar.cpp
index 15c7db867..15c7db867 100644
--- a/src/volumebar.cpp
+++ b/src/ui/volumebar.cpp
diff --git a/src/volumebar.h b/src/ui/volumebar.h
index 51bc7ac46..51bc7ac46 100644
--- a/src/volumebar.h
+++ b/src/ui/volumebar.h