Merge lp:~kabelfrickler/mixxx/modplug into lp:~mixxxdevelopers/mixxx/trunk

Proposed by Stefan Nürnberger
Status: Superseded
Proposed branch: lp:~kabelfrickler/mixxx/modplug
Merge into: lp:~mixxxdevelopers/mixxx/trunk
Diff against target: 1462 lines (+1302/-0)
11 files modified
mixxx/SConstruct (+1/-0)
mixxx/build/features.py (+34/-0)
mixxx/src/dlgpreferences.cpp (+28/-0)
mixxx/src/dlgpreferences.h (+9/-0)
mixxx/src/dlgprefmodplug.cpp (+161/-0)
mixxx/src/dlgprefmodplug.h (+49/-0)
mixxx/src/dlgprefmodplugdlg.ui (+728/-0)
mixxx/src/mixxx.cpp (+12/-0)
mixxx/src/soundsourcemodplug.cpp (+196/-0)
mixxx/src/soundsourcemodplug.h (+74/-0)
mixxx/src/soundsourceproxy.cpp (+10/-0)
To merge this branch: bzr merge lp:~kabelfrickler/mixxx/modplug
Reviewer Review Type Date Requested Status
Stefan Nürnberger (community) Needs Fixing
Mixxx Development Team Pending
Review via email: mp+153265@code.launchpad.net

This proposal has been superseded by a proposal from 2013-03-14.

Description of the change

Add module tracker support through libmodplug

This branch adds a soundsource for files supported by modplug (MOD/MED/IT/STM/S3M/XM/OKT/...)
It also includes a preferences dialog through which the decoder can be configured.

Module tracker formats do not play well with seeking, therefore files are decoded to 16bit stereo samples on track load and kept in a QByteArray until the soundsource is destroyed. Maximum size of this buffer per track (i.e. per soundsource instance) is also configurable through the preferences dialog.

Building this requires libmodplug and the modplug.h header file. Most linux distributions offer modplug packages. I have not attempted a build under Mac or Windows.

Modplug support is activated with by appending "modplug=1" to the scons command. This will also add the __MODPLUG__ define to the compiler flags. All code concerning modplug is guarded by this define.

For modplug to work correctly the settings which are stored in the mixxx.cfg need to be applied once before loading a module file. Currently this is done in mixxx.cpp when the program loads by creating an instance of the preferences dialog and letting it deal with the configuration. Maybe there is a more elegant way?

To post a comment you must log in.
Revision history for this message
Stefan Nürnberger (kabelfrickler) wrote :

Hmm, ok the branch is not completely clean. I will try to remove every change that is not directly concerned with modplug (whitespace fixes etc.) and the remaining reference to "plugin" in the SConstruct file. Then I will merge with latest trunk to resolve the conflict and resubmit the merge request.

review: Needs Fixing
lp:~kabelfrickler/mixxx/modplug updated
3296. By Stefan Nuernberger <email address hidden>

Remove remaining reference to modplug plugin from SConstruct file. Modplug is now builtin.

3297. By Stefan Nuernberger <email address hidden>

revert unrelated changes in dlgpreferences.

3298. By Stefan Nuernberger <email address hidden>

Change description of modplug feature.

3299. By Stefan Nuernberger <email address hidden>

Remove unused include from soundsourceproxy.

3300. By Stefan Nuernberger <email address hidden>

merge with latest trunk.

3301. By Stefan Nuernberger <email address hidden>

Fix build error due to incorrectly positioned code.

3302. By Stefan Nuernberger <email address hidden>

Correct typo in features.py

3303. By Stefan Nuernberger <email address hidden>

Refactoring SoundSourceModPlug. Obey coding styleguide. Estimate sample buffer size. Get rid of temp buffer in open().

3304. By Stefan Nuernberger <email address hidden>

Use memcpy for SoundSourceModPlug::read(). Add ScopedTimer for SoundSourceModPlug::open().

3305. By Stefan Nuernberger <email address hidden>

Refactored modplug preferences dialog. Introduced advanced options switch. Adhere to coding style guide.

3306. By Stefan Nuernberger <email address hidden>

insert spaces in front of class scope identifiers as demanded by style guide.

3307. By Stefan Nuernberger <email address hidden>

Fix a comment about samplerate.

3308. By Stefan Nuernberger <email address hidden>

Changed placement of controls in modplug preferences dialog.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'mixxx/SConstruct'
2--- mixxx/SConstruct 2013-02-09 00:38:39 +0000
3+++ mixxx/SConstruct 2013-03-14 18:33:22 +0000
4@@ -48,6 +48,7 @@
5 features.Optimize,
6 features.FAAD,
7 features.WavPack,
8+ features.ModPlug,
9 features.TestSuite,
10 features.LADSPA,
11 features.MSVCDebug,
12
13=== modified file 'mixxx/build/features.py'
14--- mixxx/build/features.py 2013-02-09 00:49:59 +0000
15+++ mixxx/build/features.py 2013-03-14 18:33:22 +0000
16@@ -483,6 +483,40 @@
17 '%s/RealTime.cpp'])
18 return sources
19
20+
21+class ModPlug(Feature):
22+ def description(self):
23+ return "Modplug module decoder plugin"
24+
25+ def enabled(self, build):
26+ build.flags['modplug'] = util.get_flags(build.env, 'modplug', 0)
27+ if int(build.flags['modplug']):
28+ return True
29+ return False
30+
31+ def add_options(self, build, vars):
32+ vars.Add('modplug', 'Set to 1 to enable libmbodplug based module tracker support.', 0)
33+
34+ def configure(self, build, conf):
35+ if not self.enabled(build):
36+ return
37+
38+ build.env.Append(CPPDEFINES = '__MODPLUG__')
39+
40+ have_modplug_h = conf.CheckHeader('libmodplug/modplug.h')
41+ have_modplug = conf.CheckLib(['modplug','libmodplug'], autoadd=True)
42+
43+ if not have_modplug_h:
44+ raise Exception('Could not find libmodplug development headers.')
45+
46+ if not have_modplug:
47+ raise Exception('Could not find libmodplug shared library.')
48+
49+ def sources(self, build):
50+ build.env.Uic4('dlgprefmodplugdlg.ui')
51+ return ['soundsourcemodplug.cpp', 'dlgprefmodplug.cpp']
52+
53+
54 class FAAD(Feature):
55 def description(self):
56 return "FAAD AAC audio file decoder plugin"
57
58=== modified file 'mixxx/src/dlgpreferences.cpp'
59--- mixxx/src/dlgpreferences.cpp 2012-11-27 16:19:52 +0000
60+++ mixxx/src/dlgpreferences.cpp 2013-03-14 18:33:22 +0000
61@@ -37,6 +37,10 @@
62 #include "dlgprefbpm.h"
63 #endif
64
65+#ifdef __MODPLUG__
66+ #include "dlgprefmodplug.h"
67+#endif
68+
69 #include "dlgpreferences.h"
70 #include "dlgprefsound.h"
71 #include "controllers/dlgprefmappablecontroller.h"
72@@ -109,6 +113,10 @@
73 m_wshoutcast = new DlgPrefShoutcast(this, config);
74 addPageWidget(m_wshoutcast);
75 #endif
76+#ifdef __MODPLUG__
77+ m_wmodplug = new DlgPrefModplug(this, config);
78+ addPageWidget(m_wmodplug);
79+#endif
80 m_wNoControllers = new DlgPrefNoControllers(this, config);
81 addPageWidget(m_wNoControllers);
82 setupControllerWidgets();
83@@ -152,6 +160,10 @@
84 connect(this, SIGNAL(showDlg()), m_wshoutcast,SLOT(slotUpdate()));
85 #endif
86
87+#ifdef __MODPLUG__
88+ connect(this, SIGNAL(showDlg()), m_wmodplug,SLOT(slotUpdate()));
89+#endif
90+
91 #ifdef __VINYLCONTROL__
92 connect(buttonBox, SIGNAL(accepted()), m_wvinylcontrol, SLOT(slotApply())); //It's important for this to be before the
93 //connect for wsound...
94@@ -173,6 +185,9 @@
95 #ifdef __SHOUTCAST__
96 connect(buttonBox, SIGNAL(accepted()), m_wshoutcast,SLOT(slotApply()));
97 #endif
98+#ifdef __MODPLUG__
99+ connect(buttonBox, SIGNAL(accepted()), m_wmodplug,SLOT(slotApply()));
100+#endif
101
102 //Update the library when you change the options
103 /*if (m_pTrack && wplaylist)
104@@ -276,6 +291,15 @@
105 m_pShoutcastButton->setTextAlignment(0, Qt::AlignLeft | Qt::AlignVCenter);
106 m_pShoutcastButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
107 #endif
108+
109+#ifdef __MODPLUG__
110+ m_pModplugButton = new QTreeWidgetItem(contentsTreeWidget, QTreeWidgetItem::Type);
111+ m_pModplugButton->setIcon(0, QIcon(":/images/preferences/ic_preferences_sampler.png"));
112+ m_pModplugButton->setText(0, tr("Modplug Decoder"));
113+ m_pModplugButton->setTextAlignment(0, Qt::AlignLeft | Qt::AlignVCenter);
114+ m_pModplugButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
115+#endif
116+
117 connect(contentsTreeWidget,
118 SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
119 this, SLOT(changePage(QTreeWidgetItem *, QTreeWidgetItem*)));
120@@ -321,6 +345,10 @@
121 } else if (current == m_pShoutcastButton) {
122 pagesWidget->setCurrentWidget(m_wshoutcast->parentWidget()->parentWidget());
123 #endif
124+#ifdef __MODPLUG__
125+ } else if (current == m_pModplugButton) {
126+ pagesWidget->setCurrentWidget(m_wmodplug->parentWidget()->parentWidget());
127+#endif
128 //Handle selection of controller items
129 } else if (m_controllerWindowLinks.indexOf(current) >= 0) {
130 int index = m_controllerWindowLinks.indexOf(current);
131
132=== modified file 'mixxx/src/dlgpreferences.h'
133--- mixxx/src/dlgpreferences.h 2012-04-25 15:40:15 +0000
134+++ mixxx/src/dlgpreferences.h 2013-03-14 18:33:22 +0000
135@@ -45,6 +45,9 @@
136 class SkinLoader;
137 class PlayerManager;
138 class VinylControlManager;
139+#ifdef __MODPLUG__
140+class DlgPrefModplug;
141+#endif
142
143 /**
144 *@author Tue & Ken Haste Andersen
145@@ -93,6 +96,9 @@
146 DlgPrefNoVinyl* m_wnovinylcontrol;
147 DlgPrefShoutcast* m_wshoutcast;
148 DlgPrefReplayGain* m_wreplaygain;
149+#ifdef __MODPLUG__
150+ DlgPrefModplug* m_wmodplug;
151+#endif
152
153 /*
154 QScrollArea* m_sasound;
155@@ -120,6 +126,9 @@
156 QTreeWidgetItem* m_pVinylControlButton;
157 QTreeWidgetItem* m_pShoutcastButton;
158 QTreeWidgetItem* m_pReplayGainButton;
159+#ifdef __MODPLUG__
160+ QTreeWidgetItem* m_pModplugButton;
161+#endif
162 QTreeWidgetItem* m_pControllerTreeItem;
163 QList<QTreeWidgetItem*> m_controllerWindowLinks;
164
165
166=== added file 'mixxx/src/dlgprefmodplug.cpp'
167--- mixxx/src/dlgprefmodplug.cpp 1970-01-01 00:00:00 +0000
168+++ mixxx/src/dlgprefmodplug.cpp 2013-03-14 18:33:22 +0000
169@@ -0,0 +1,161 @@
170+/***************************************************************************
171+ dlgprefmodplug.cpp - modplug settings dialog
172+ -------------------
173+ copyright : (C) 2013 by Stefan Nuernberger
174+ email : kabelfricker@gmail.com
175+***************************************************************************/
176+
177+/***************************************************************************
178+* *
179+* This program is free software; you can redistribute it and/or modify *
180+* it under the terms of the GNU General Public License as published by *
181+* the Free Software Foundation; either version 2 of the License, or *
182+* (at your option) any later version. *
183+* *
184+***************************************************************************/
185+
186+#include "dlgprefmodplug.h"
187+#include "ui_dlgprefmodplugdlg.h"
188+#include "configobject.h"
189+#include "soundsourcemodplug.h"
190+
191+#include <QtDebug>
192+
193+#define CONFIG_KEY "[Modplug]"
194+
195+DlgPrefModplug::DlgPrefModplug(QWidget *parent, ConfigObject<ConfigValue> *_config) :
196+ QDialog(parent),
197+ ui(new Ui::DlgPrefModplug),
198+ config(_config)
199+{
200+ ui->setupUi(this);
201+}
202+
203+DlgPrefModplug::~DlgPrefModplug()
204+{
205+ delete ui;
206+}
207+
208+void DlgPrefModplug::slotApply()
209+{
210+ qDebug() << "Modplug Preferences - Apply and save configuration changes";
211+
212+ applySettings();
213+ saveSettings();
214+}
215+
216+void DlgPrefModplug::slotUpdate()
217+{
218+ qDebug() << "Modplug Preferences - Update Configuration Dialog from saved settings";
219+
220+ loadSettings();
221+}
222+
223+void DlgPrefModplug::loadSettings()
224+{
225+ ui->memoryLimit->setValue(
226+ config->getValueString(ConfigKey(CONFIG_KEY,"PerTrackMemoryLimitMB"),"256").toInt());
227+ ui->oversampling->setChecked(
228+ config->getValueString(ConfigKey(CONFIG_KEY,"OversamplingEnabled"),"1") == QString("1"));
229+ ui->noiseReduction->setChecked(
230+ config->getValueString(ConfigKey(CONFIG_KEY,"NoiseReductionEnabled"),"1") == QString("1"));
231+ ui->stereoSeparation->setValue(
232+ config->getValueString(ConfigKey(CONFIG_KEY,"StereoSeparation"),"1").toInt());
233+ ui->maxMixChannels->setValue(
234+ config->getValueString(ConfigKey(CONFIG_KEY,"MaxMixChannels"),"128").toInt());
235+ ui->resampleMode->setCurrentIndex(
236+ config->getValueString(ConfigKey(CONFIG_KEY,"ResamplingMode"),"3").toInt());
237+ ui->reverb->setChecked(
238+ config->getValueString(ConfigKey(CONFIG_KEY,"ReverbEnabled"),"0") == QString("1"));
239+ ui->reverbDepth->setValue(
240+ config->getValueString(ConfigKey(CONFIG_KEY,"ReverbLevel"),"30").toInt());
241+ ui->reverbDelay->setValue(
242+ config->getValueString(ConfigKey(CONFIG_KEY,"ReverbDelay"),"50").toInt());
243+ ui->megabass->setChecked(
244+ config->getValueString(ConfigKey(CONFIG_KEY,"MegabassEnabled"),"0") == QString("1"));
245+ ui->bassDepth->setValue(
246+ config->getValueString(ConfigKey(CONFIG_KEY,"MegabassLevel"),"30").toInt());
247+ ui->bassCutoff->setValue(
248+ config->getValueString(ConfigKey(CONFIG_KEY,"MegabassCutoff"),"80").toInt());
249+ ui->surround->setChecked(
250+ config->getValueString(ConfigKey(CONFIG_KEY,"SurroundEnabled"),"0") == QString("1"));
251+ ui->surroundDepth->setValue(
252+ config->getValueString(ConfigKey(CONFIG_KEY,"SurroundLevel"),"30").toInt());
253+ ui->surroundDelay->setValue(
254+ config->getValueString(ConfigKey(CONFIG_KEY,"SurroundDelay"),"10").toInt());
255+}
256+
257+void DlgPrefModplug::saveSettings()
258+{
259+ config->set(ConfigKey(CONFIG_KEY,"PerTrackMemoryLimitMB"),ConfigValue(ui->memoryLimit->value()));
260+ config->set(ConfigKey(CONFIG_KEY,"OversamplingEnabled"), ConfigValue(ui->oversampling->isChecked()));
261+ config->set(ConfigKey(CONFIG_KEY,"NoiseReductionEnabled"), ConfigValue(ui->noiseReduction->isChecked()));
262+ config->set(ConfigKey(CONFIG_KEY,"StereoSeparation"),ConfigValue(ui->stereoSeparation->value()));
263+ config->set(ConfigKey(CONFIG_KEY,"MaxMixChannels"),ConfigValue(ui->maxMixChannels->value()));
264+ config->set(ConfigKey(CONFIG_KEY,"ResamplingMode"),ConfigValue(ui->resampleMode->currentIndex()));
265+ config->set(ConfigKey(CONFIG_KEY,"ReverbEnabled"),ConfigValue(ui->reverb->isChecked()));
266+ config->set(ConfigKey(CONFIG_KEY,"ReverbLevel"),ConfigValue(ui->reverbDepth->value()));
267+ config->set(ConfigKey(CONFIG_KEY,"ReverbDelay"),ConfigValue(ui->reverbDelay->value()));
268+ config->set(ConfigKey(CONFIG_KEY,"MegabassEnabled"),ConfigValue(ui->megabass->isChecked()));
269+ config->set(ConfigKey(CONFIG_KEY,"MegabassLevel"),ConfigValue(ui->bassDepth->value()));
270+ config->set(ConfigKey(CONFIG_KEY,"MegabassCutoff"),ConfigValue(ui->bassCutoff->value()));
271+ config->set(ConfigKey(CONFIG_KEY,"SurroundEnabled"),ConfigValue(ui->surround->isChecked()));
272+ config->set(ConfigKey(CONFIG_KEY,"SurroundLevel"),ConfigValue(ui->surroundDepth->value()));
273+ config->set(ConfigKey(CONFIG_KEY,"SurroundDelay"),ConfigValue(ui->surroundDelay->value()));
274+}
275+
276+void DlgPrefModplug::applySettings()
277+{
278+ // read ui parameters and configure soundsource
279+ unsigned int bufferSizeLimit = ui->memoryLimit->value() * 1024 * 1024;
280+ ModPlug::ModPlug_Settings settings;
281+
282+ // Currently this is fixed to 16bit 44.1kHz stereo */
283+ /* Note that ModPlug always decodes sound at 44100kHz, 32 bit, stereo and then
284+ * down-mixes to the settings you choose. */
285+ settings.mChannels = 2; /* Number of channels - 1 for mono or 2 for stereo */
286+ settings.mBits = 16; /* Bits per sample - 8, 16, or 32 */
287+ settings.mFrequency = 44100; /* Sampling rate - 11025, 22050, or 44100 */
288+
289+ settings.mFlags = 0;
290+ if (ui->oversampling->isChecked())
291+ settings.mFlags |= ModPlug::MODPLUG_ENABLE_OVERSAMPLING;
292+ if (ui->noiseReduction->isChecked())
293+ settings.mFlags |= ModPlug::MODPLUG_ENABLE_NOISE_REDUCTION;
294+ if (ui->reverb->isChecked())
295+ settings.mFlags |= ModPlug::MODPLUG_ENABLE_REVERB;
296+ if (ui->megabass->isChecked())
297+ settings.mFlags |= ModPlug::MODPLUG_ENABLE_MEGABASS;
298+ if (ui->surround->isChecked())
299+ settings.mFlags |= ModPlug::MODPLUG_ENABLE_SURROUND;
300+
301+ switch (ui->resampleMode->currentIndex())
302+ {
303+ case 0: /* nearest neighbor */
304+ settings.mResamplingMode = ModPlug::MODPLUG_RESAMPLE_NEAREST;
305+ break;
306+ case 1: /* linear */
307+ settings.mResamplingMode = ModPlug::MODPLUG_RESAMPLE_LINEAR;
308+ break;
309+ case 2: /* cubic spline */
310+ settings.mResamplingMode = ModPlug::MODPLUG_RESAMPLE_SPLINE;
311+ break;
312+ case 3: /* 8 bit FIR (also default) */
313+ default:
314+ settings.mResamplingMode = ModPlug::MODPLUG_RESAMPLE_FIR;
315+ break;
316+ }
317+
318+ settings.mStereoSeparation = ui->stereoSeparation->value();
319+ settings.mMaxMixChannels = ui->maxMixChannels->value();
320+ settings.mReverbDepth = ui->reverbDepth->value(); /* Reverb level 0(quiet)-100(loud) */
321+ settings.mReverbDelay = ui->reverbDelay->value(); /* Reverb delay in ms, usually 40-200ms */
322+ settings.mBassAmount = ui->bassDepth->value(); /* XBass level 0(quiet)-100(loud) */
323+ settings.mBassRange = ui->bassCutoff->value(); /* XBass cutoff in Hz 10-100 */
324+ settings.mSurroundDepth = ui->surroundDepth->value(); /* Surround level 0(quiet)-100(heavy) */
325+ settings.mSurroundDelay = ui->surroundDelay->value(); /* Surround delay in ms, usually 5-40ms */
326+ settings.mLoopCount = 0; /* Number of times to loop. Zero prevents looping. -1 loops forever. */
327+
328+ // apply modplug settings
329+ SoundSourceModPlug::configure(bufferSizeLimit, settings);
330+}
331
332=== added file 'mixxx/src/dlgprefmodplug.h'
333--- mixxx/src/dlgprefmodplug.h 1970-01-01 00:00:00 +0000
334+++ mixxx/src/dlgprefmodplug.h 2013-03-14 18:33:22 +0000
335@@ -0,0 +1,49 @@
336+/***************************************************************************
337+ dlgprefmodplug.h - modplug settings dialog
338+ -------------------
339+ copyright : (C) 2013 by Stefan Nuernberger
340+ email : kabelfrickler@gmail.com
341+ ***************************************************************************/
342+
343+/***************************************************************************
344+ * *
345+ * This program is free software; you can redistribute it and/or modify *
346+ * it under the terms of the GNU General Public License as published by *
347+ * the Free Software Foundation; either version 2 of the License, or *
348+ * (at your option) any later version. *
349+ * *
350+ ***************************************************************************/
351+
352+#ifndef DLGPREFMODPLUG_H
353+#define DLGPREFMODPLUG_H
354+
355+#include <QDialog>
356+#include "configobject.h"
357+
358+namespace Ui {
359+class DlgPrefModplug;
360+}
361+
362+class DlgPrefModplug : public QDialog
363+{
364+ Q_OBJECT
365+
366+public:
367+ explicit DlgPrefModplug(QWidget *parent, ConfigObject<ConfigValue> *_config);
368+ ~DlgPrefModplug();
369+
370+public slots:
371+ /** Apply changes to widget */
372+ void slotApply();
373+ void slotUpdate();
374+
375+ void loadSettings();
376+ void saveSettings();
377+ void applySettings();
378+
379+private:
380+ Ui::DlgPrefModplug *ui;
381+ ConfigObject<ConfigValue> *config;
382+};
383+
384+#endif // DLGPREFMODPLUG_H
385
386=== added file 'mixxx/src/dlgprefmodplugdlg.ui'
387--- mixxx/src/dlgprefmodplugdlg.ui 1970-01-01 00:00:00 +0000
388+++ mixxx/src/dlgprefmodplugdlg.ui 2013-03-14 18:33:22 +0000
389@@ -0,0 +1,728 @@
390+<?xml version="1.0" encoding="UTF-8"?>
391+<ui version="4.0">
392+ <class>DlgPrefModplug</class>
393+ <widget class="QDialog" name="DlgPrefModplug">
394+ <property name="geometry">
395+ <rect>
396+ <x>0</x>
397+ <y>0</y>
398+ <width>593</width>
399+ <height>538</height>
400+ </rect>
401+ </property>
402+ <property name="windowTitle">
403+ <string>Modplug Preferences</string>
404+ </property>
405+ <layout class="QGridLayout" name="gridLayout">
406+ <property name="spacing">
407+ <number>10</number>
408+ </property>
409+ <item row="13" column="4">
410+ <widget class="QSlider" name="surroundDelay">
411+ <property name="maximum">
412+ <number>100</number>
413+ </property>
414+ <property name="value">
415+ <number>10</number>
416+ </property>
417+ <property name="orientation">
418+ <enum>Qt::Horizontal</enum>
419+ </property>
420+ </widget>
421+ </item>
422+ <item row="5" column="0" colspan="5">
423+ <widget class="QCheckBox" name="noiseReduction">
424+ <property name="text">
425+ <string>Enable noise reduction</string>
426+ </property>
427+ </widget>
428+ </item>
429+ <item row="10" column="0">
430+ <widget class="QCheckBox" name="megabass">
431+ <property name="text">
432+ <string>Enable megabass</string>
433+ </property>
434+ </widget>
435+ </item>
436+ <item row="8" column="0">
437+ <widget class="QCheckBox" name="reverb">
438+ <property name="text">
439+ <string>Enable reverb</string>
440+ </property>
441+ </widget>
442+ </item>
443+ <item row="14" column="1">
444+ <spacer name="verticalSpacer">
445+ <property name="orientation">
446+ <enum>Qt::Vertical</enum>
447+ </property>
448+ <property name="sizeHint" stdset="0">
449+ <size>
450+ <width>20</width>
451+ <height>40</height>
452+ </size>
453+ </property>
454+ </spacer>
455+ </item>
456+ <item row="6" column="0" colspan="3">
457+ <widget class="QLabel" name="label_4">
458+ <property name="text">
459+ <string>Stereo separation</string>
460+ </property>
461+ </widget>
462+ </item>
463+ <item row="10" column="1" colspan="2">
464+ <widget class="QLabel" name="label_2">
465+ <property name="text">
466+ <string>Bass level</string>
467+ </property>
468+ </widget>
469+ </item>
470+ <item row="2" column="0" colspan="3">
471+ <widget class="QLabel" name="label_10">
472+ <property name="text">
473+ <string>Memory limit for single track (MB)</string>
474+ </property>
475+ </widget>
476+ </item>
477+ <item row="12" column="5">
478+ <widget class="QSpinBox" name="surroundDepthSpin">
479+ <property name="maximum">
480+ <number>100</number>
481+ </property>
482+ <property name="value">
483+ <number>30</number>
484+ </property>
485+ </widget>
486+ </item>
487+ <item row="4" column="0" colspan="3">
488+ <widget class="QLabel" name="label">
489+ <property name="text">
490+ <string>Resampling mode (interpolation)</string>
491+ </property>
492+ </widget>
493+ </item>
494+ <item row="2" column="4">
495+ <widget class="QSlider" name="memoryLimit">
496+ <property name="toolTip">
497+ <string extracomment="1 minute of decoded audio requires about 10MB of RAM."/>
498+ </property>
499+ <property name="minimum">
500+ <number>16</number>
501+ </property>
502+ <property name="maximum">
503+ <number>512</number>
504+ </property>
505+ <property name="value">
506+ <number>256</number>
507+ </property>
508+ <property name="sliderPosition">
509+ <number>256</number>
510+ </property>
511+ <property name="orientation">
512+ <enum>Qt::Horizontal</enum>
513+ </property>
514+ </widget>
515+ </item>
516+ <item row="7" column="0" colspan="3">
517+ <widget class="QLabel" name="label_5">
518+ <property name="text">
519+ <string>Maximum Number of Mixing Channels</string>
520+ </property>
521+ </widget>
522+ </item>
523+ <item row="10" column="4">
524+ <widget class="QSlider" name="bassDepth">
525+ <property name="maximum">
526+ <number>100</number>
527+ </property>
528+ <property name="value">
529+ <number>30</number>
530+ </property>
531+ <property name="orientation">
532+ <enum>Qt::Horizontal</enum>
533+ </property>
534+ </widget>
535+ </item>
536+ <item row="2" column="5">
537+ <widget class="QSpinBox" name="memoryLimitSpin">
538+ <property name="minimum">
539+ <number>16</number>
540+ </property>
541+ <property name="maximum">
542+ <number>512</number>
543+ </property>
544+ <property name="value">
545+ <number>256</number>
546+ </property>
547+ </widget>
548+ </item>
549+ <item row="11" column="4">
550+ <widget class="QSlider" name="bassCutoff">
551+ <property name="minimum">
552+ <number>10</number>
553+ </property>
554+ <property name="maximum">
555+ <number>100</number>
556+ </property>
557+ <property name="value">
558+ <number>80</number>
559+ </property>
560+ <property name="orientation">
561+ <enum>Qt::Horizontal</enum>
562+ </property>
563+ </widget>
564+ </item>
565+ <item row="11" column="1" colspan="2">
566+ <widget class="QLabel" name="label_3">
567+ <property name="text">
568+ <string>Bass cutoff (Hz)</string>
569+ </property>
570+ </widget>
571+ </item>
572+ <item row="12" column="1" colspan="2">
573+ <widget class="QLabel" name="label_8">
574+ <property name="text">
575+ <string>Surround level</string>
576+ </property>
577+ </widget>
578+ </item>
579+ <item row="13" column="1" colspan="2">
580+ <widget class="QLabel" name="label_9">
581+ <property name="text">
582+ <string>Surround delay (ms)</string>
583+ </property>
584+ </widget>
585+ </item>
586+ <item row="8" column="4">
587+ <widget class="QSlider" name="reverbDepth">
588+ <property name="maximum">
589+ <number>100</number>
590+ </property>
591+ <property name="value">
592+ <number>30</number>
593+ </property>
594+ <property name="orientation">
595+ <enum>Qt::Horizontal</enum>
596+ </property>
597+ </widget>
598+ </item>
599+ <item row="9" column="4">
600+ <widget class="QSlider" name="reverbDelay">
601+ <property name="minimum">
602+ <number>10</number>
603+ </property>
604+ <property name="maximum">
605+ <number>250</number>
606+ </property>
607+ <property name="value">
608+ <number>50</number>
609+ </property>
610+ <property name="orientation">
611+ <enum>Qt::Horizontal</enum>
612+ </property>
613+ </widget>
614+ </item>
615+ <item row="6" column="4">
616+ <widget class="QSlider" name="stereoSeparation">
617+ <property name="minimum">
618+ <number>1</number>
619+ </property>
620+ <property name="maximum">
621+ <number>256</number>
622+ </property>
623+ <property name="value">
624+ <number>64</number>
625+ </property>
626+ <property name="orientation">
627+ <enum>Qt::Horizontal</enum>
628+ </property>
629+ <property name="tickPosition">
630+ <enum>QSlider::NoTicks</enum>
631+ </property>
632+ </widget>
633+ </item>
634+ <item row="9" column="1" colspan="2">
635+ <widget class="QLabel" name="label_7">
636+ <property name="text">
637+ <string>Reverb delay (ms)</string>
638+ </property>
639+ </widget>
640+ </item>
641+ <item row="12" column="0">
642+ <widget class="QCheckBox" name="surround">
643+ <property name="text">
644+ <string>Enable surround</string>
645+ </property>
646+ </widget>
647+ </item>
648+ <item row="3" column="0" colspan="5">
649+ <widget class="QCheckBox" name="oversampling">
650+ <property name="text">
651+ <string>Enable oversampling (*highly* recommended)</string>
652+ </property>
653+ <property name="checked">
654+ <bool>true</bool>
655+ </property>
656+ </widget>
657+ </item>
658+ <item row="7" column="4">
659+ <widget class="QSlider" name="maxMixChannels">
660+ <property name="minimum">
661+ <number>32</number>
662+ </property>
663+ <property name="maximum">
664+ <number>256</number>
665+ </property>
666+ <property name="value">
667+ <number>128</number>
668+ </property>
669+ <property name="orientation">
670+ <enum>Qt::Horizontal</enum>
671+ </property>
672+ </widget>
673+ </item>
674+ <item row="12" column="4">
675+ <widget class="QSlider" name="surroundDepth">
676+ <property name="maximum">
677+ <number>100</number>
678+ </property>
679+ <property name="value">
680+ <number>30</number>
681+ </property>
682+ <property name="orientation">
683+ <enum>Qt::Horizontal</enum>
684+ </property>
685+ </widget>
686+ </item>
687+ <item row="8" column="1" colspan="2">
688+ <widget class="QLabel" name="label_6">
689+ <property name="text">
690+ <string>Reverb level</string>
691+ </property>
692+ </widget>
693+ </item>
694+ <item row="6" column="5">
695+ <widget class="QSpinBox" name="stereoSeparationSpin">
696+ <property name="minimum">
697+ <number>1</number>
698+ </property>
699+ <property name="maximum">
700+ <number>256</number>
701+ </property>
702+ </widget>
703+ </item>
704+ <item row="7" column="5">
705+ <widget class="QSpinBox" name="maxMixChannelsSpin">
706+ <property name="minimum">
707+ <number>32</number>
708+ </property>
709+ <property name="maximum">
710+ <number>256</number>
711+ </property>
712+ <property name="value">
713+ <number>128</number>
714+ </property>
715+ </widget>
716+ </item>
717+ <item row="4" column="4" colspan="2">
718+ <widget class="QComboBox" name="resampleMode">
719+ <property name="currentIndex">
720+ <number>3</number>
721+ </property>
722+ <item>
723+ <property name="text">
724+ <string>Nearest (very fast, extremely bad quality)</string>
725+ </property>
726+ </item>
727+ <item>
728+ <property name="text">
729+ <string>Linear (fast, good quality)</string>
730+ </property>
731+ </item>
732+ <item>
733+ <property name="text">
734+ <string>Cubic Spline (high quality)</string>
735+ </property>
736+ </item>
737+ <item>
738+ <property name="text">
739+ <string>8-tap FIR (extremely high quality)</string>
740+ </property>
741+ </item>
742+ </widget>
743+ </item>
744+ <item row="8" column="5">
745+ <widget class="QSpinBox" name="reverbDepthSpin">
746+ <property name="maximum">
747+ <number>100</number>
748+ </property>
749+ <property name="value">
750+ <number>30</number>
751+ </property>
752+ </widget>
753+ </item>
754+ <item row="9" column="5">
755+ <widget class="QSpinBox" name="reverbDelaySpin">
756+ <property name="minimum">
757+ <number>10</number>
758+ </property>
759+ <property name="maximum">
760+ <number>250</number>
761+ </property>
762+ <property name="value">
763+ <number>50</number>
764+ </property>
765+ </widget>
766+ </item>
767+ <item row="10" column="5">
768+ <widget class="QSpinBox" name="bassDepthSpin">
769+ <property name="maximum">
770+ <number>100</number>
771+ </property>
772+ <property name="value">
773+ <number>30</number>
774+ </property>
775+ </widget>
776+ </item>
777+ <item row="11" column="5">
778+ <widget class="QSpinBox" name="bassCutoffSpin">
779+ <property name="minimum">
780+ <number>10</number>
781+ </property>
782+ <property name="maximum">
783+ <number>100</number>
784+ </property>
785+ <property name="value">
786+ <number>80</number>
787+ </property>
788+ </widget>
789+ </item>
790+ <item row="13" column="5">
791+ <widget class="QSpinBox" name="surroundDelaySpin">
792+ <property name="maximum">
793+ <number>100</number>
794+ </property>
795+ <property name="value">
796+ <number>10</number>
797+ </property>
798+ </widget>
799+ </item>
800+ <item row="0" column="0" colspan="5">
801+ <widget class="QLabel" name="label_11">
802+ <property name="text">
803+ <string>Decoding options for libmodplug. Module files are decoded at once
804+and kept in RAM to allow for seeking and smooth operation in Mixxx.</string>
805+ </property>
806+ </widget>
807+ </item>
808+ <item row="8" column="3">
809+ <spacer name="horizontalSpacer">
810+ <property name="orientation">
811+ <enum>Qt::Horizontal</enum>
812+ </property>
813+ <property name="sizeType">
814+ <enum>QSizePolicy::Minimum</enum>
815+ </property>
816+ <property name="sizeHint" stdset="0">
817+ <size>
818+ <width>40</width>
819+ <height>20</height>
820+ </size>
821+ </property>
822+ </spacer>
823+ </item>
824+ </layout>
825+ </widget>
826+ <resources/>
827+ <connections>
828+ <connection>
829+ <sender>memoryLimit</sender>
830+ <signal>valueChanged(int)</signal>
831+ <receiver>memoryLimitSpin</receiver>
832+ <slot>setValue(int)</slot>
833+ <hints>
834+ <hint type="sourcelabel">
835+ <x>405</x>
836+ <y>58</y>
837+ </hint>
838+ <hint type="destinationlabel">
839+ <x>556</x>
840+ <y>58</y>
841+ </hint>
842+ </hints>
843+ </connection>
844+ <connection>
845+ <sender>memoryLimitSpin</sender>
846+ <signal>valueChanged(int)</signal>
847+ <receiver>memoryLimit</receiver>
848+ <slot>setValue(int)</slot>
849+ <hints>
850+ <hint type="sourcelabel">
851+ <x>556</x>
852+ <y>58</y>
853+ </hint>
854+ <hint type="destinationlabel">
855+ <x>405</x>
856+ <y>58</y>
857+ </hint>
858+ </hints>
859+ </connection>
860+ <connection>
861+ <sender>stereoSeparation</sender>
862+ <signal>valueChanged(int)</signal>
863+ <receiver>stereoSeparationSpin</receiver>
864+ <slot>setValue(int)</slot>
865+ <hints>
866+ <hint type="sourcelabel">
867+ <x>405</x>
868+ <y>186</y>
869+ </hint>
870+ <hint type="destinationlabel">
871+ <x>556</x>
872+ <y>186</y>
873+ </hint>
874+ </hints>
875+ </connection>
876+ <connection>
877+ <sender>stereoSeparationSpin</sender>
878+ <signal>valueChanged(int)</signal>
879+ <receiver>stereoSeparation</receiver>
880+ <slot>setValue(int)</slot>
881+ <hints>
882+ <hint type="sourcelabel">
883+ <x>556</x>
884+ <y>186</y>
885+ </hint>
886+ <hint type="destinationlabel">
887+ <x>405</x>
888+ <y>186</y>
889+ </hint>
890+ </hints>
891+ </connection>
892+ <connection>
893+ <sender>maxMixChannels</sender>
894+ <signal>valueChanged(int)</signal>
895+ <receiver>maxMixChannelsSpin</receiver>
896+ <slot>setValue(int)</slot>
897+ <hints>
898+ <hint type="sourcelabel">
899+ <x>405</x>
900+ <y>220</y>
901+ </hint>
902+ <hint type="destinationlabel">
903+ <x>556</x>
904+ <y>220</y>
905+ </hint>
906+ </hints>
907+ </connection>
908+ <connection>
909+ <sender>maxMixChannelsSpin</sender>
910+ <signal>valueChanged(int)</signal>
911+ <receiver>maxMixChannels</receiver>
912+ <slot>setValue(int)</slot>
913+ <hints>
914+ <hint type="sourcelabel">
915+ <x>556</x>
916+ <y>220</y>
917+ </hint>
918+ <hint type="destinationlabel">
919+ <x>405</x>
920+ <y>220</y>
921+ </hint>
922+ </hints>
923+ </connection>
924+ <connection>
925+ <sender>reverbDepth</sender>
926+ <signal>valueChanged(int)</signal>
927+ <receiver>reverbDepthSpin</receiver>
928+ <slot>setValue(int)</slot>
929+ <hints>
930+ <hint type="sourcelabel">
931+ <x>405</x>
932+ <y>254</y>
933+ </hint>
934+ <hint type="destinationlabel">
935+ <x>556</x>
936+ <y>254</y>
937+ </hint>
938+ </hints>
939+ </connection>
940+ <connection>
941+ <sender>reverbDepthSpin</sender>
942+ <signal>valueChanged(int)</signal>
943+ <receiver>reverbDepth</receiver>
944+ <slot>setValue(int)</slot>
945+ <hints>
946+ <hint type="sourcelabel">
947+ <x>556</x>
948+ <y>254</y>
949+ </hint>
950+ <hint type="destinationlabel">
951+ <x>405</x>
952+ <y>254</y>
953+ </hint>
954+ </hints>
955+ </connection>
956+ <connection>
957+ <sender>reverbDelay</sender>
958+ <signal>valueChanged(int)</signal>
959+ <receiver>reverbDelaySpin</receiver>
960+ <slot>setValue(int)</slot>
961+ <hints>
962+ <hint type="sourcelabel">
963+ <x>405</x>
964+ <y>288</y>
965+ </hint>
966+ <hint type="destinationlabel">
967+ <x>556</x>
968+ <y>288</y>
969+ </hint>
970+ </hints>
971+ </connection>
972+ <connection>
973+ <sender>bassDepth</sender>
974+ <signal>valueChanged(int)</signal>
975+ <receiver>bassDepthSpin</receiver>
976+ <slot>setValue(int)</slot>
977+ <hints>
978+ <hint type="sourcelabel">
979+ <x>405</x>
980+ <y>322</y>
981+ </hint>
982+ <hint type="destinationlabel">
983+ <x>556</x>
984+ <y>322</y>
985+ </hint>
986+ </hints>
987+ </connection>
988+ <connection>
989+ <sender>bassDepthSpin</sender>
990+ <signal>valueChanged(int)</signal>
991+ <receiver>bassDepth</receiver>
992+ <slot>setValue(int)</slot>
993+ <hints>
994+ <hint type="sourcelabel">
995+ <x>556</x>
996+ <y>322</y>
997+ </hint>
998+ <hint type="destinationlabel">
999+ <x>405</x>
1000+ <y>322</y>
1001+ </hint>
1002+ </hints>
1003+ </connection>
1004+ <connection>
1005+ <sender>reverbDelaySpin</sender>
1006+ <signal>valueChanged(int)</signal>
1007+ <receiver>reverbDelay</receiver>
1008+ <slot>setValue(int)</slot>
1009+ <hints>
1010+ <hint type="sourcelabel">
1011+ <x>556</x>
1012+ <y>288</y>
1013+ </hint>
1014+ <hint type="destinationlabel">
1015+ <x>405</x>
1016+ <y>288</y>
1017+ </hint>
1018+ </hints>
1019+ </connection>
1020+ <connection>
1021+ <sender>bassCutoff</sender>
1022+ <signal>valueChanged(int)</signal>
1023+ <receiver>bassCutoffSpin</receiver>
1024+ <slot>setValue(int)</slot>
1025+ <hints>
1026+ <hint type="sourcelabel">
1027+ <x>405</x>
1028+ <y>356</y>
1029+ </hint>
1030+ <hint type="destinationlabel">
1031+ <x>556</x>
1032+ <y>356</y>
1033+ </hint>
1034+ </hints>
1035+ </connection>
1036+ <connection>
1037+ <sender>bassCutoffSpin</sender>
1038+ <signal>valueChanged(int)</signal>
1039+ <receiver>bassCutoff</receiver>
1040+ <slot>setValue(int)</slot>
1041+ <hints>
1042+ <hint type="sourcelabel">
1043+ <x>556</x>
1044+ <y>356</y>
1045+ </hint>
1046+ <hint type="destinationlabel">
1047+ <x>405</x>
1048+ <y>356</y>
1049+ </hint>
1050+ </hints>
1051+ </connection>
1052+ <connection>
1053+ <sender>surroundDepth</sender>
1054+ <signal>valueChanged(int)</signal>
1055+ <receiver>surroundDepthSpin</receiver>
1056+ <slot>setValue(int)</slot>
1057+ <hints>
1058+ <hint type="sourcelabel">
1059+ <x>405</x>
1060+ <y>390</y>
1061+ </hint>
1062+ <hint type="destinationlabel">
1063+ <x>556</x>
1064+ <y>390</y>
1065+ </hint>
1066+ </hints>
1067+ </connection>
1068+ <connection>
1069+ <sender>surroundDepthSpin</sender>
1070+ <signal>valueChanged(int)</signal>
1071+ <receiver>surroundDepth</receiver>
1072+ <slot>setValue(int)</slot>
1073+ <hints>
1074+ <hint type="sourcelabel">
1075+ <x>556</x>
1076+ <y>390</y>
1077+ </hint>
1078+ <hint type="destinationlabel">
1079+ <x>405</x>
1080+ <y>390</y>
1081+ </hint>
1082+ </hints>
1083+ </connection>
1084+ <connection>
1085+ <sender>surroundDelay</sender>
1086+ <signal>valueChanged(int)</signal>
1087+ <receiver>surroundDelaySpin</receiver>
1088+ <slot>setValue(int)</slot>
1089+ <hints>
1090+ <hint type="sourcelabel">
1091+ <x>405</x>
1092+ <y>424</y>
1093+ </hint>
1094+ <hint type="destinationlabel">
1095+ <x>556</x>
1096+ <y>424</y>
1097+ </hint>
1098+ </hints>
1099+ </connection>
1100+ <connection>
1101+ <sender>surroundDelaySpin</sender>
1102+ <signal>valueChanged(int)</signal>
1103+ <receiver>surroundDelay</receiver>
1104+ <slot>setValue(int)</slot>
1105+ <hints>
1106+ <hint type="sourcelabel">
1107+ <x>556</x>
1108+ <y>424</y>
1109+ </hint>
1110+ <hint type="destinationlabel">
1111+ <x>405</x>
1112+ <y>424</y>
1113+ </hint>
1114+ </hints>
1115+ </connection>
1116+ </connections>
1117+</ui>
1118
1119=== modified file 'mixxx/src/mixxx.cpp'
1120--- mixxx/src/mixxx.cpp 2013-02-10 20:59:19 +0000
1121+++ mixxx/src/mixxx.cpp 2013-03-14 18:33:22 +0000
1122@@ -60,6 +60,10 @@
1123 #include "vinylcontrol/vinylcontrolmanager.h"
1124 #endif
1125
1126+#ifdef __MODPLUG__
1127+#include "dlgprefmodplug.h"
1128+#endif
1129+
1130 extern "C" void crashDlg()
1131 {
1132 QMessageBox::critical(0, "Mixxx",
1133@@ -340,6 +344,14 @@
1134 m_pVCManager->init();
1135 #endif
1136
1137+#ifdef __MODPLUG__
1138+ // restore the configuration for the modplug library before trying to load a module
1139+ DlgPrefModplug* pModplugPrefs = new DlgPrefModplug(0, m_pConfig);
1140+ pModplugPrefs->loadSettings();
1141+ pModplugPrefs->applySettings();
1142+ delete pModplugPrefs; // not needed anymore
1143+#endif
1144+
1145 m_pLibrary = new Library(this, m_pConfig,
1146 bFirstRun || bUpgraded,
1147 m_pRecordingManager);
1148
1149=== added file 'mixxx/src/soundsourcemodplug.cpp'
1150--- mixxx/src/soundsourcemodplug.cpp 1970-01-01 00:00:00 +0000
1151+++ mixxx/src/soundsourcemodplug.cpp 2013-03-14 18:33:22 +0000
1152@@ -0,0 +1,196 @@
1153+/***************************************************************************
1154+ soundsourcemodplug.cpp - module tracker support
1155+ -------------------
1156+ copyright : (C) 2012 by Stefan Nuernberger
1157+ email : kabelfricker@gmail.com
1158+***************************************************************************/
1159+
1160+/***************************************************************************
1161+* *
1162+* This program is free software; you can redistribute it and/or modify *
1163+* it under the terms of the GNU General Public License as published by *
1164+* the Free Software Foundation; either version 2 of the License, or *
1165+* (at your option) any later version. *
1166+* *
1167+***************************************************************************/
1168+
1169+#include "soundsourcemodplug.h"
1170+#include <stdlib.h>
1171+#include <unistd.h>
1172+#include <QFile>
1173+
1174+/* read files in 512k chunks */
1175+#define CHUNKSIZE 524288
1176+
1177+// reserve some static space for settings...
1178+ModPlug::ModPlug_Settings SoundSourceModPlug::settings;
1179+unsigned int SoundSourceModPlug::bufferSizeLimit;
1180+
1181+SoundSourceModPlug::SoundSourceModPlug(QString qFilename) :
1182+ SoundSource(qFilename)
1183+{
1184+ opened = false;
1185+ filelength = 0;
1186+ file = 0;
1187+
1188+ qDebug() << "Loading ModPlug module " << m_qFilename;
1189+
1190+ // read module file to byte array
1191+ QFile modfile(m_qFilename);
1192+ modfile.open(QIODevice::ReadOnly);
1193+ filebuf = modfile.readAll();
1194+ modfile.close();
1195+ // get ModPlugFile
1196+ file = ModPlug::ModPlug_Load(filebuf.data(), filebuf.length());
1197+}
1198+
1199+SoundSourceModPlug::~SoundSourceModPlug()
1200+{
1201+ if (file) {
1202+ ModPlug::ModPlug_Unload(file);
1203+ file = NULL;
1204+ }
1205+}
1206+
1207+QList<QString> SoundSourceModPlug::supportedFileExtensions()
1208+{
1209+ QList<QString> list;
1210+ /* ModPlug supports more formats but file name
1211+ * extensions are not always present with modules.
1212+ */
1213+ list.push_back("mod");
1214+ list.push_back("med");
1215+ list.push_back("okt");
1216+ list.push_back("s3m");
1217+ list.push_back("stm");
1218+ list.push_back("xm");
1219+ list.push_back("it");
1220+ return list;
1221+}
1222+
1223+void SoundSourceModPlug::configure(unsigned int bLimit, const ModPlug::ModPlug_Settings &config)
1224+{
1225+ bufferSizeLimit = bLimit;
1226+ settings = config;
1227+
1228+ ModPlug::ModPlug_SetSettings(&settings);
1229+}
1230+
1231+int SoundSourceModPlug::open() {
1232+ if (file == NULL) {
1233+ // an error occured
1234+ qDebug() << "Could not load module file: "
1235+ << m_qFilename;
1236+ return ERR;
1237+ }
1238+
1239+ // temporary buffer to read samples
1240+ char *tmpbuf = new char[CHUNKSIZE];
1241+ int count = 1;
1242+ while ((count != 0) && (smplbuf.length() < bufferSizeLimit))
1243+ {
1244+ /* Read sample data into the buffer. Returns the number of bytes read. If the end
1245+ * of the module has been reached, zero is returned. */
1246+ count = ModPlug::ModPlug_Read(file, tmpbuf, CHUNKSIZE);
1247+ smplbuf.append(tmpbuf, count);
1248+ }
1249+ delete tmpbuf;
1250+ qDebug() << "Filled Sample buffer with " << smplbuf.length() << " bytes.";
1251+
1252+ // smplbuf holds 44.1kHz 16bit integer stereo samples.
1253+ // We count the number of samples by dividing number of
1254+ // bytes in smplbuf by 2 (bytes per sample).
1255+ filelength = smplbuf.length() >> 1;
1256+ m_iSampleRate = 44100; // ModPlug uses 44.1kHz
1257+ opened = true;
1258+ seekpos = 0;
1259+ return OK;
1260+}
1261+
1262+long SoundSourceModPlug::seek(long filepos)
1263+{
1264+ if (filelength > 0)
1265+ {
1266+ seekpos = math_min((unsigned long)filepos, filelength);
1267+ return seekpos;
1268+ }
1269+ return 0;
1270+}
1271+
1272+/*
1273+ read <size> samples into <destination>, and return the number of
1274+ samples actually read.
1275+ */
1276+unsigned SoundSourceModPlug::read(unsigned long size, const SAMPLE * destination)
1277+{
1278+ unsigned char * dest = (unsigned char *) destination;
1279+ if (filelength > 0)
1280+ {
1281+ unsigned count = 0;
1282+ while ((seekpos < filelength) && (count < (size << 1 )))
1283+ {
1284+ // copy a 16bit sample
1285+ dest[count++] = smplbuf[seekpos << 1];
1286+ dest[count++] = smplbuf[(seekpos << 1) + 1];
1287+ ++seekpos;
1288+ }
1289+ return count >> 1; ///< number of bytes divided by bytes per sample
1290+ }
1291+ // The file has errors or is not open. Tell the truth and return 0.
1292+ return 0;
1293+}
1294+
1295+int SoundSourceModPlug::parseHeader()
1296+{
1297+ if (file == NULL) {
1298+ // an error occured
1299+ qDebug() << "Could not parse module header of " << m_qFilename;
1300+ return ERR;
1301+ }
1302+
1303+ switch (ModPlug::ModPlug_GetModuleType(file))
1304+ {
1305+ case NONE:
1306+ setType(QString("None"));
1307+ break;
1308+ case MOD:
1309+ setType(QString("Protracker"));
1310+ break;
1311+ case S3M:
1312+ setType(QString("Scream Tracker 3"));
1313+ break;
1314+ case XM:
1315+ setType(QString("FastTracker2"));
1316+ break;
1317+ case MED:
1318+ setType(QString("OctaMed"));
1319+ break;
1320+ case IT:
1321+ setType(QString("Impulse Tracker"));
1322+ break;
1323+ case STM:
1324+ setType(QString("Scream Tracker"));
1325+ break;
1326+ case OKT:
1327+ setType(QString("Oktalyzer"));
1328+ break;
1329+ default:
1330+ setType(QString("Module"));
1331+ break;
1332+ }
1333+ setComment(QString(ModPlug::ModPlug_GetMessage(file)));
1334+ setTitle(QString(ModPlug::ModPlug_GetName(file)));
1335+ setDuration(ModPlug::ModPlug_GetLength(file) / 1000);
1336+ setBitrate(8); // not really, but fill in something...
1337+ setSampleRate(44100);
1338+ setChannels(2);
1339+ return OK;
1340+}
1341+
1342+/*
1343+ Return the length of the file in samples.
1344+ */
1345+inline long unsigned SoundSourceModPlug::length()
1346+{
1347+ return filelength;
1348+}
1349
1350=== added file 'mixxx/src/soundsourcemodplug.h'
1351--- mixxx/src/soundsourcemodplug.h 1970-01-01 00:00:00 +0000
1352+++ mixxx/src/soundsourcemodplug.h 2013-03-14 18:33:22 +0000
1353@@ -0,0 +1,74 @@
1354+/***************************************************************************
1355+ soundsourcemodplug.h - modplug tracker support
1356+ -------------------
1357+ copyright : (C) 2012 by Stefan Nuernberger
1358+ email : kabelfrickler@gmail.com
1359+ ***************************************************************************/
1360+
1361+/***************************************************************************
1362+ * *
1363+ * This program is free software; you can redistribute it and/or modify *
1364+ * it under the terms of the GNU General Public License as published by *
1365+ * the Free Software Foundation; either version 2 of the License, or *
1366+ * (at your option) any later version. *
1367+ * *
1368+ ***************************************************************************/
1369+
1370+#ifndef SOUNDSOURCEMODPLUG_H
1371+#define SOUNDSOURCEMODPLUG_H
1372+
1373+#include "soundsource.h"
1374+#include "defs_version.h"
1375+#include <QByteArray>
1376+#include <QList>
1377+#include <QString>
1378+#include <QtDebug>
1379+
1380+namespace ModPlug {
1381+#include "libmodplug/modplug.h"
1382+}
1383+
1384+/*
1385+ Class for reading tracker files using libmodplug
1386+ The whole file is decoded at once and saved
1387+ in RAM to allow seeking and smooth operation in Mixxx.
1388+ */
1389+class SoundSourceModPlug : public Mixxx::SoundSource
1390+{
1391+public:
1392+ SoundSourceModPlug(QString qFilename);
1393+ ~SoundSourceModPlug();
1394+ int open();
1395+ long seek(long);
1396+ unsigned read(unsigned long size, const SAMPLE*);
1397+ inline long unsigned length();
1398+ int parseHeader();
1399+ static QList<QString> supportedFileExtensions();
1400+
1401+ static void configure(unsigned int bufferSizeLimit,
1402+ const ModPlug::ModPlug_Settings &settings);
1403+private:
1404+ static unsigned int bufferSizeLimit;
1405+ static ModPlug::ModPlug_Settings settings; ///< struct of parameters
1406+
1407+ bool opened;
1408+ unsigned long filelength;
1409+ unsigned int seekpos;
1410+ ModPlug::ModPlugFile *file; ///< pointer to ModPlugFile struct
1411+ QByteArray filebuf; ///< original module file data
1412+ QByteArray smplbuf; ///< 16bit stereo samples, 44.1kHz
1413+
1414+ /// identification of modplug module type
1415+ enum ModuleTypes {
1416+ NONE = 0x00,
1417+ MOD = 0x01,
1418+ S3M = 0x02,
1419+ XM = 0x04,
1420+ MED = 0x08,
1421+ IT = 0x20,
1422+ STM = 0x100,
1423+ OKT = 0x8000
1424+ };
1425+};
1426+
1427+#endif
1428
1429=== modified file 'mixxx/src/soundsourceproxy.cpp'
1430--- mixxx/src/soundsourceproxy.cpp 2012-11-20 00:40:18 +0000
1431+++ mixxx/src/soundsourceproxy.cpp 2013-03-14 18:33:22 +0000
1432@@ -31,6 +31,9 @@
1433 #ifdef __FFMPEGFILE__
1434 #include "soundsourceffmpeg.h"
1435 #endif
1436+#ifdef __MODPLUG__
1437+#include "soundsourcemodplug.h"
1438+#endif
1439 #include "soundsourceflac.h"
1440
1441 #include "mixxx.h"
1442@@ -139,6 +142,10 @@
1443 } else if (SoundSourceCoreAudio::supportedFileExtensions().contains(extension)) {
1444 return new SoundSourceCoreAudio(qFilename);
1445 #endif
1446+#ifdef __MODPLUG__
1447+ } else if (SoundSourceModPlug::supportedFileExtensions().contains(extension)) {
1448+ return new SoundSourceModPlug(qFilename);
1449+#endif
1450 } else if (m_extensionsSupportedByPlugins.contains(extension)) {
1451 getSoundSourceFunc getter = m_extensionsSupportedByPlugins.value(extension);
1452 if (getter)
1453@@ -368,6 +375,9 @@
1454 #ifdef __COREAUDIO__
1455 supportedFileExtensions.append(SoundSourceCoreAudio::supportedFileExtensions());
1456 #endif
1457+#ifdef __MODPLUG__
1458+ supportedFileExtensions.append(SoundSourceModPlug::supportedFileExtensions());
1459+#endif
1460 supportedFileExtensions.append(m_extensionsSupportedByPlugins.keys());
1461
1462 return supportedFileExtensions;