Merge lp:~mixxxdevelopers/mixxx/multi-playlist-crates into lp:~mhaulo/mixxx/multilevel_crates_playlists

Proposed by RAFFI TEA
Status: Merged
Merge reported by: Mika Haulo
Merged at revision: not available
Proposed branch: lp:~mixxxdevelopers/mixxx/multi-playlist-crates
Merge into: lp:~mhaulo/mixxx/multilevel_crates_playlists
Diff against target: 15201 lines (+7559/-3035)
160 files modified
mixxx/SConstruct (+1/-0)
mixxx/build/depends.py (+15/-1)
mixxx/build/features.py (+31/-3)
mixxx/build/qtcreator/mixxx.pro (+1/-0)
mixxx/lib/xwax/lut.c (+110/-0)
mixxx/lib/xwax/lut.cpp (+110/-0)
mixxx/lib/xwax/lut.h (+42/-0)
mixxx/lib/xwax/pitch.h (+71/-0)
mixxx/lib/xwax/timecoder.c (+381/-449)
mixxx/lib/xwax/timecoder.h (+80/-42)
mixxx/lib/xwax/timecoder_win32.cpp (+346/-411)
mixxx/res/mixxx.qrc (+1/-0)
mixxx/res/schema.xml (+2/-2)
mixxx/res/skins/Outline1024x600-Netbook/skin.xml (+77/-0)
mixxx/src/analyserwaveform.cpp (+1/-0)
mixxx/src/audiotagger.cpp (+52/-45)
mixxx/src/audiotagger.h (+3/-3)
mixxx/src/basetrackplayer.cpp (+5/-3)
mixxx/src/cachingreader.cpp (+25/-3)
mixxx/src/circularbuffer.h (+97/-0)
mixxx/src/configobject.cpp (+4/-0)
mixxx/src/configobject.h (+7/-4)
mixxx/src/controllogpotmeter.cpp (+5/-0)
mixxx/src/controlobject.cpp (+14/-2)
mixxx/src/controlobject.h (+4/-0)
mixxx/src/controlobjectthread.cpp (+4/-4)
mixxx/src/controlobjectthread.h (+1/-1)
mixxx/src/controlobjectthreadmain.cpp (+4/-5)
mixxx/src/controlobjectthreadmain.h (+3/-3)
mixxx/src/controlobjectthreadwidget.cpp (+3/-4)
mixxx/src/controlobjectthreadwidget.h (+2/-2)
mixxx/src/controlpotmeter.cpp (+12/-8)
mixxx/src/controlpotmeter.h (+9/-8)
mixxx/src/controlpushbutton.cpp (+25/-44)
mixxx/src/controlpushbutton.h (+2/-0)
mixxx/src/controlvaluedelegate.cpp (+3/-0)
mixxx/src/dlgautodj.cpp (+21/-2)
mixxx/src/dlgautodj.h (+4/-1)
mixxx/src/dlgautodj.ui (+10/-0)
mixxx/src/dlgprefcontrols.cpp (+13/-0)
mixxx/src/dlgprefcontrols.h (+1/-0)
mixxx/src/dlgprefcontrolsdlg.ui (+10/-0)
mixxx/src/dlgpreferences.cpp (+22/-4)
mixxx/src/dlgpreferences.h (+16/-11)
mixxx/src/dlgprefnovinyl.cpp (+32/-0)
mixxx/src/dlgprefnovinyl.h (+39/-0)
mixxx/src/dlgprefnovinyldlg.ui (+475/-0)
mixxx/src/dlgprefrecord.cpp (+138/-113)
mixxx/src/dlgprefrecord.h (+11/-7)
mixxx/src/dlgprefrecorddlg.ui (+229/-316)
mixxx/src/dlgprefshoutcastdlg.ui (+14/-2)
mixxx/src/dlgprefsound.cpp (+105/-67)
mixxx/src/dlgprefsound.h (+9/-3)
mixxx/src/dlgprefsounditem.h (+3/-1)
mixxx/src/dlgprefvinyl.cpp (+77/-120)
mixxx/src/dlgprefvinyl.h (+3/-9)
mixxx/src/dlgprefvinyldlg.ui (+130/-28)
mixxx/src/dlgrecording.cpp (+177/-0)
mixxx/src/dlgrecording.h (+63/-0)
mixxx/src/dlgrecording.ui (+87/-0)
mixxx/src/engine/bpmcontrol.cpp (+2/-1)
mixxx/src/engine/cuecontrol.cpp (+29/-6)
mixxx/src/engine/cuecontrol.h (+2/-1)
mixxx/src/engine/enginebuffer.cpp (+123/-48)
mixxx/src/engine/enginebuffer.h (+23/-5)
mixxx/src/engine/enginebufferscalelinear.cpp (+225/-125)
mixxx/src/engine/enginebufferscalelinear.h (+13/-3)
mixxx/src/engine/enginechannel.cpp (+10/-53)
mixxx/src/engine/enginechannel.h (+13/-18)
mixxx/src/engine/enginecontrol.cpp (+8/-2)
mixxx/src/engine/enginecontrol.h (+4/-2)
mixxx/src/engine/enginedeck.cpp (+77/-0)
mixxx/src/engine/enginedeck.h (+59/-0)
mixxx/src/engine/enginefilterblock.cpp (+27/-18)
mixxx/src/engine/enginefilterblock.h (+3/-2)
mixxx/src/engine/enginemaster.cpp (+56/-13)
mixxx/src/engine/enginemaster.h (+18/-9)
mixxx/src/engine/enginemicrophone.cpp (+127/-0)
mixxx/src/engine/enginemicrophone.h (+53/-0)
mixxx/src/engine/enginepassthrough.cpp (+121/-0)
mixxx/src/engine/enginepassthrough.h (+51/-0)
mixxx/src/engine/enginepregain.cpp (+14/-14)
mixxx/src/engine/enginepregain.h (+4/-2)
mixxx/src/engine/enginesidechain.cpp (+5/-0)
mixxx/src/engine/enginesidechain.h (+8/-3)
mixxx/src/engine/loopingcontrol.cpp (+170/-8)
mixxx/src/engine/loopingcontrol.h (+36/-0)
mixxx/src/engine/quantizecontrol.cpp (+93/-0)
mixxx/src/engine/quantizecontrol.h (+43/-0)
mixxx/src/engine/ratecontrol.cpp (+20/-1)
mixxx/src/engine/ratecontrol.h (+11/-8)
mixxx/src/engine/readaheadmanager.cpp (+12/-10)
mixxx/src/engine/vinylcontrolcontrol.cpp (+104/-0)
mixxx/src/engine/vinylcontrolcontrol.h (+31/-0)
mixxx/src/library/autodjfeature.cpp (+2/-1)
mixxx/src/library/browse/browsefeature.cpp (+4/-2)
mixxx/src/library/browse/browsefeature.h (+2/-1)
mixxx/src/library/browse/browsetablemodel.cpp (+198/-17)
mixxx/src/library/browse/browsetablemodel.h (+46/-38)
mixxx/src/library/browse/browsethread.cpp (+3/-0)
mixxx/src/library/browse/browsethread.h (+3/-1)
mixxx/src/library/cratefeature.cpp (+55/-77)
mixxx/src/library/cratefeature.h (+2/-3)
mixxx/src/library/dao/cratedao.cpp (+22/-0)
mixxx/src/library/dao/cratedao.h (+7/-1)
mixxx/src/library/library.cpp (+7/-3)
mixxx/src/library/library.h (+3/-1)
mixxx/src/library/playlisttablemodel.cpp (+32/-0)
mixxx/src/library/playlisttablemodel.h (+1/-0)
mixxx/src/library/recording/recordingfeature.cpp (+98/-0)
mixxx/src/library/recording/recordingfeature.h (+62/-0)
mixxx/src/library/sidebarmodel.cpp (+2/-0)
mixxx/src/library/traktor/traktorfeature.cpp (+1/-1)
mixxx/src/library/traktor/traktorplaylistmodel.cpp (+1/-1)
mixxx/src/library/traktor/traktortablemodel.cpp (+5/-2)
mixxx/src/library/treeitem.cpp (+16/-1)
mixxx/src/library/treeitem.h (+8/-0)
mixxx/src/library/treeitemmodel.cpp (+11/-0)
mixxx/src/library/treeitemmodel.h (+2/-0)
mixxx/src/mathstuff.cpp (+10/-0)
mixxx/src/mathstuff.h (+9/-0)
mixxx/src/midi/midiscriptengine.cpp (+3/-3)
mixxx/src/mixxx.cpp (+211/-126)
mixxx/src/mixxx.h (+10/-3)
mixxx/src/playermanager.cpp (+2/-0)
mixxx/src/recording/defs_recording.h (+19/-0)
mixxx/src/recording/enginerecord.cpp (+23/-18)
mixxx/src/recording/enginerecord.h (+5/-1)
mixxx/src/recording/recordingmanager.cpp (+168/-0)
mixxx/src/recording/recordingmanager.h (+81/-0)
mixxx/src/samplerbank.cpp (+2/-0)
mixxx/src/skin/legacyskinparser.cpp (+6/-4)
mixxx/src/sounddevice.cpp (+1/-1)
mixxx/src/sounddeviceportaudio.cpp (+3/-3)
mixxx/src/soundmanager.cpp (+122/-61)
mixxx/src/soundmanager.h (+20/-5)
mixxx/src/soundmanagerconfig.cpp (+1/-1)
mixxx/src/soundmanagerconfig.h (+2/-2)
mixxx/src/soundmanagerutil.cpp (+21/-17)
mixxx/src/soundmanagerutil.h (+22/-6)
mixxx/src/soundsourcemp3.cpp (+8/-3)
mixxx/src/test/enginemastertest.cpp (+29/-39)
mixxx/src/test/enginemicrophonetest.cpp (+136/-0)
mixxx/src/vinylcontrol.cpp (+41/-24)
mixxx/src/vinylcontrol.h (+68/-46)
mixxx/src/vinylcontrolproxy.cpp (+39/-3)
mixxx/src/vinylcontrolproxy.h (+16/-11)
mixxx/src/vinylcontrolsignalwidget.cpp (+115/-150)
mixxx/src/vinylcontrolsignalwidget.h (+21/-16)
mixxx/src/vinylcontrolxwax.cpp (+704/-162)
mixxx/src/vinylcontrolxwax.h (+72/-31)
mixxx/src/waveform/waveformrenderer.cpp (+2/-2)
mixxx/src/waveform/waveformrendersignal.cpp (+1/-3)
mixxx/src/widget/wnumberpos.cpp (+10/-4)
mixxx/src/widget/wnumberrate.cpp (+0/-1)
mixxx/src/widget/wnumberrate.h (+1/-0)
mixxx/src/widget/woverview.cpp (+15/-8)
mixxx/src/widget/wstatuslight.cpp (+95/-37)
mixxx/src/widget/wstatuslight.h (+7/-7)
mixxx/src/widget/wtracktableview.cpp (+8/-4)
To merge this branch: bzr merge lp:~mixxxdevelopers/mixxx/multi-playlist-crates
Reviewer Review Type Date Requested Status
Mika Haulo Pending
Review via email: mp+58787@code.launchpad.net

Description of the change

Hey Mika,

you had some problems with your branch. To help you I have finalized your crate stuff. I now give you the honour to complete the mulilevel playlists :-)

Just to note down some current issues:
- Try to create two crates below the root-level. It is not possible to add two equal named subcrates to the different parents.

- It would be cool feature if one can move the crates to upper or lower hierachies via drag 'n drop

- It is a good idea to remove "Add crate/playlist" from the main menu

To post a comment you must log in.
Revision history for this message
RAFFI TEA (raffitea) wrote :

JFI: My branch has been merged with current trunk. This is why the diff is huge.

Revision history for this message
Mika Haulo (mhaulo) wrote :

Wow, thanks! This helps a lot. I actually got to the point where the crate tree was almost working, but your implementation looks much better.
Allowing equal names introduced a few minor bugs, but I'm already fixing those.

Revision history for this message
RAFFI TEA (raffitea) wrote :

You're welcome. Looking forward to see this feature in trunk one day :-)

With that I can improve the Traktor library feature, e.g., I could offer an option "Migrate to Mixxx library" which will convert the Traktor multilevel playlists to Mixxx playlists.

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 2011-03-07 22:25:20 +0000
3+++ mixxx/SConstruct 2011-04-22 09:04:29 +0000
4@@ -50,6 +50,7 @@
5 features.MSVSHacks,
6
7 # "Features" of dubious quality
8+ features.PerfTools,
9 features.AsmLib,
10 features.Tonal,
11 features.IPod,
12
13=== modified file 'mixxx/build/depends.py'
14--- mixxx/build/depends.py 2011-03-31 06:57:35 +0000
15+++ mixxx/build/depends.py 2011-04-22 09:04:29 +0000
16@@ -336,6 +336,7 @@
17 "dlgprefcontrols.cpp",
18 "dlgprefbpm.cpp",
19 "dlgprefreplaygain.cpp",
20+ "dlgprefnovinyl.cpp",
21 "dlgbpmscheme.cpp",
22 "dlgabout.cpp",
23 "dlgprefeq.cpp",
24@@ -367,14 +368,20 @@
25 "engine/enginesidechain.cpp",
26 "engine/enginefilterbutterworth8.cpp",
27 "engine/enginexfader.cpp",
28+ "engine/enginemicrophone.cpp",
29+ "engine/enginedeck.cpp",
30+ "engine/enginepassthrough.cpp",
31+
32 "engine/enginecontrol.cpp",
33 "engine/ratecontrol.cpp",
34 "engine/loopingcontrol.cpp",
35 "engine/bpmcontrol.cpp",
36 "engine/cuecontrol.cpp",
37+ "engine/quantizecontrol.cpp",
38 "engine/clockcontrol.cpp",
39 "engine/readaheadmanager.cpp",
40 "cachingreader.cpp",
41+
42 "analyserrg.cpp",
43 "analyserqueue.cpp",
44 "analyserwavesummary.cpp",
45@@ -455,6 +462,10 @@
46 "library/browse/browsethread.cpp",
47 "library/browse/browsefeature.cpp",
48 "library/browse/foldertreemodel.cpp",
49+
50+ "library/recording/recordingfeature.cpp",
51+ "dlgrecording.cpp",
52+ "recording/recordingmanager.cpp",
53
54 # External Library Features
55 "library/rhythmbox/rhythmboxfeature.cpp",
56@@ -545,7 +556,7 @@
57 "sounddevice.cpp",
58 "soundmanager.cpp",
59 "soundmanagerconfig.cpp",
60- "audiopath.cpp",
61+ "soundmanagerutil.cpp",
62 "dlgprefrecord.cpp",
63 "playerinfo.cpp",
64
65@@ -571,6 +582,7 @@
66 build.env.Uic4('dlgbpmschemedlg.ui')
67 # build.env.Uic4('dlgbpmtapdlg.ui')
68 build.env.Uic4('dlgprefvinyldlg.ui')
69+ build.env.Uic4('dlgprefnovinyldlg.ui')
70 build.env.Uic4('dlgprefrecorddlg.ui')
71 build.env.Uic4('dlgaboutdlg.ui')
72 build.env.Uic4('dlgmidilearning.ui')
73@@ -578,6 +590,8 @@
74 build.env.Uic4('dlgprepare.ui')
75 build.env.Uic4('dlgautodj.ui')
76 build.env.Uic4('dlgprefsounditem.ui')
77+ build.env.Uic4('dlgrecording.ui')
78+
79
80 # Add the QRC file which compiles in some extra resources (prefs icons,
81 # etc.)
82
83=== modified file 'mixxx/build/features.py'
84--- mixxx/build/features.py 2011-03-22 16:24:04 +0000
85+++ mixxx/build/features.py 2011-04-22 09:04:29 +0000
86@@ -101,7 +101,7 @@
87 build.env.Append(CPPDEFINES = '__COREAUDIO__')
88
89 def sources(self, build):
90- return ['soundsourcecoreaudio.cpp',
91+ return ['soundsourcecoreaudio.cpp',
92 '#lib/apple/CAStreamBasicDescription.h']
93
94
95@@ -291,11 +291,15 @@
96 'vinylcontrolproxy.cpp',
97 'vinylcontrolxwax.cpp',
98 'dlgprefvinyl.cpp',
99- 'vinylcontrolsignalwidget.cpp']
100+ 'vinylcontrolsignalwidget.cpp',
101+ 'engine/vinylcontrolcontrol.cpp']
102 if build.platform_is_windows:
103- sources.append("#lib/xwax/timecoder_win32.c")
104+ sources.append("#lib/xwax/timecoder_win32.cpp")
105+ sources.append("#lib/xwax/lut.cpp")
106 else:
107 sources.append("#lib/xwax/timecoder.c")
108+ sources.append("#lib/xwax/lut.c")
109+
110 return sources
111
112 class Tonal(Feature):
113@@ -414,6 +418,30 @@
114 'script/macrolistitem.cpp',
115 'script/qtscriptinterface.cpp']
116
117+class PerfTools(Feature):
118+ def description(self):
119+ return "Google PerfTools"
120+
121+ def enabled(self, build):
122+ build.flags['perftools'] = util.get_flags(build.env, 'perftools', 0)
123+ build.flags['perftools_profiler'] = util.get_flags(build.env, 'perftools_profiler', 0)
124+ if int(build.flags['perftools']):
125+ return True
126+ return False
127+
128+ def add_options(self, build, vars):
129+ vars.Add("perftools", "Set to 1 to enable linking against libtcmalloc and Google's performance tools. You must install libtcmalloc from google-perftools to use this option.", 0)
130+ vars.Add("perftools_profiler", "Set to 1 to enable linking against libprofiler, Google's CPU profiler. You must install libprofiler from google-perftools to use this option.", 0)
131+
132+ def configure(self, build, conf):
133+ if not self.enabled(build):
134+ return
135+
136+ build.env.Append(LIBS = "tcmalloc")
137+
138+ if int(build.flags['perftools_profiler']):
139+ build.env.Append(LIBS = "profiler")
140+
141 class AsmLib(Feature):
142 def description(self):
143 return "Agner Fog\'s ASMLIB"
144
145=== modified file 'mixxx/build/qtcreator/mixxx.pro'
146--- mixxx/build/qtcreator/mixxx.pro 2010-11-11 19:10:52 +0000
147+++ mixxx/build/qtcreator/mixxx.pro 2011-04-22 09:04:29 +0000
148@@ -110,6 +110,7 @@
149 $$UI_DIR/ui_dlgprefrecorddlg.h \
150 $$UI_DIR/ui_dlgprefsounddlg.h \
151 $$UI_DIR/ui_dlgprefvinyldlg.h \
152+ $$UI_DIR/ui_dlgprefnovinyldlg.h \
153 $$UI_DIR/ui_dlgprefnomididlg.h
154
155 INCLUDEPATH += src \
156
157=== added file 'mixxx/lib/xwax/lut.c'
158--- mixxx/lib/xwax/lut.c 1970-01-01 00:00:00 +0000
159+++ mixxx/lib/xwax/lut.c 2011-04-22 09:04:29 +0000
160@@ -0,0 +1,110 @@
161+/*
162+ * Copyright (C) 2010 Mark Hills <mark@pogo.org.uk>
163+ *
164+ * This program is free software; you can redistribute it and/or
165+ * modify it under the terms of the GNU General Public License
166+ * version 2, as published by the Free Software Foundation.
167+ *
168+ * This program is distributed in the hope that it will be useful, but
169+ * WITHOUT ANY WARRANTY; without even the implied warranty of
170+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
171+ * General Public License version 2 for more details.
172+ *
173+ * You should have received a copy of the GNU General Public License
174+ * version 2 along with this program; if not, write to the Free
175+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
176+ * MA 02110-1301, USA.
177+ *
178+ */
179+
180+#include <stdio.h>
181+#include <stdlib.h>
182+
183+#include "lut.h"
184+
185+/* The number of bits to form the hash, which governs the overall size
186+ * of the hash lookup table, and hence the amount of chaining */
187+
188+#define HASH_BITS 16
189+
190+#define HASH(timecode) ((timecode) & ((1 << HASH_BITS) - 1))
191+#define NO_SLOT ((unsigned)-1)
192+
193+
194+/* Initialise an empty hash lookup table to store the given number
195+ * of timecode -> position lookups */
196+
197+int lut_init(struct lut_t *lut, int nslots)
198+{
199+ int n, hashes;
200+ size_t bytes;
201+
202+ hashes = 1 << HASH_BITS;
203+ bytes = sizeof(struct slot_t) * nslots + sizeof(slot_no_t) * hashes;
204+
205+ fprintf(stderr, "Lookup table has %d hashes to %d slots"
206+ " (%d slots per hash, %zuKb)\n",
207+ hashes, nslots, nslots / hashes, bytes / 1024);
208+
209+ lut->slot = (struct slot_t*)malloc(sizeof(struct slot_t) * nslots);
210+ if (lut->slot == NULL) {
211+ perror("malloc");
212+ return -1;
213+ }
214+
215+ lut->table = (slot_no_t*)malloc(sizeof(slot_no_t) * hashes);
216+ if (lut->table == NULL) {
217+ perror("malloc");
218+ return -1;
219+ }
220+
221+ for (n = 0; n < hashes; n++)
222+ lut->table[n] = NO_SLOT;
223+
224+ lut->avail = 0;
225+
226+ return 0;
227+}
228+
229+
230+void lut_clear(struct lut_t *lut)
231+{
232+ free(lut->table);
233+}
234+
235+
236+void lut_push(struct lut_t *lut, unsigned int timecode)
237+{
238+ unsigned int hash;
239+ slot_no_t slot_no;
240+ struct slot_t *slot;
241+
242+ slot_no = lut->avail++; /* take the next available slot */
243+
244+ slot = &lut->slot[slot_no];
245+ slot->timecode = timecode;
246+
247+ hash = HASH(timecode);
248+ slot->next = lut->table[hash];
249+ lut->table[hash] = slot_no;
250+}
251+
252+
253+unsigned int lut_lookup(struct lut_t *lut, unsigned int timecode)
254+{
255+ unsigned int hash;
256+ slot_no_t slot_no;
257+ struct slot_t *slot;
258+
259+ hash = HASH(timecode);
260+ slot_no = lut->table[hash];
261+
262+ while (slot_no != NO_SLOT) {
263+ slot = &lut->slot[slot_no];
264+ if (slot->timecode == timecode)
265+ return slot_no;
266+ slot_no = slot->next;
267+ }
268+
269+ return (unsigned)-1;
270+}
271
272=== added file 'mixxx/lib/xwax/lut.cpp'
273--- mixxx/lib/xwax/lut.cpp 1970-01-01 00:00:00 +0000
274+++ mixxx/lib/xwax/lut.cpp 2011-04-22 09:04:29 +0000
275@@ -0,0 +1,110 @@
276+/*
277+ * Copyright (C) 2010 Mark Hills <mark@pogo.org.uk>
278+ *
279+ * This program is free software; you can redistribute it and/or
280+ * modify it under the terms of the GNU General Public License
281+ * version 2, as published by the Free Software Foundation.
282+ *
283+ * This program is distributed in the hope that it will be useful, but
284+ * WITHOUT ANY WARRANTY; without even the implied warranty of
285+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
286+ * General Public License version 2 for more details.
287+ *
288+ * You should have received a copy of the GNU General Public License
289+ * version 2 along with this program; if not, write to the Free
290+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
291+ * MA 02110-1301, USA.
292+ *
293+ */
294+
295+#include <stdio.h>
296+#include <stdlib.h>
297+
298+#include "lut.h"
299+
300+/* The number of bits to form the hash, which governs the overall size
301+ * of the hash lookup table, and hence the amount of chaining */
302+
303+#define HASH_BITS 16
304+
305+#define HASH(timecode) ((timecode) & ((1 << HASH_BITS) - 1))
306+#define NO_SLOT ((unsigned)-1)
307+
308+
309+/* Initialise an empty hash lookup table to store the given number
310+ * of timecode -> position lookups */
311+
312+int lut_init(struct lut_t *lut, int nslots)
313+{
314+ int n, hashes;
315+ size_t bytes;
316+
317+ hashes = 1 << HASH_BITS;
318+ bytes = sizeof(struct slot_t) * nslots + sizeof(slot_no_t) * hashes;
319+
320+ fprintf(stderr, "Lookup table has %d hashes to %d slots"
321+ " (%d slots per hash, %zuKb)\n",
322+ hashes, nslots, nslots / hashes, bytes / 1024);
323+
324+ lut->slot = (struct slot_t*)malloc(sizeof(struct slot_t) * nslots);
325+ if (lut->slot == NULL) {
326+ perror("malloc");
327+ return -1;
328+ }
329+
330+ lut->table = (slot_no_t*)malloc(sizeof(slot_no_t) * hashes);
331+ if (lut->table == NULL) {
332+ perror("malloc");
333+ return -1;
334+ }
335+
336+ for (n = 0; n < hashes; n++)
337+ lut->table[n] = NO_SLOT;
338+
339+ lut->avail = 0;
340+
341+ return 0;
342+}
343+
344+
345+void lut_clear(struct lut_t *lut)
346+{
347+ free(lut->table);
348+}
349+
350+
351+void lut_push(struct lut_t *lut, unsigned int timecode)
352+{
353+ unsigned int hash;
354+ slot_no_t slot_no;
355+ struct slot_t *slot;
356+
357+ slot_no = lut->avail++; /* take the next available slot */
358+
359+ slot = &lut->slot[slot_no];
360+ slot->timecode = timecode;
361+
362+ hash = HASH(timecode);
363+ slot->next = lut->table[hash];
364+ lut->table[hash] = slot_no;
365+}
366+
367+
368+unsigned int lut_lookup(struct lut_t *lut, unsigned int timecode)
369+{
370+ unsigned int hash;
371+ slot_no_t slot_no;
372+ struct slot_t *slot;
373+
374+ hash = HASH(timecode);
375+ slot_no = lut->table[hash];
376+
377+ while (slot_no != NO_SLOT) {
378+ slot = &lut->slot[slot_no];
379+ if (slot->timecode == timecode)
380+ return slot_no;
381+ slot_no = slot->next;
382+ }
383+
384+ return (unsigned)-1;
385+}
386
387=== added file 'mixxx/lib/xwax/lut.h'
388--- mixxx/lib/xwax/lut.h 1970-01-01 00:00:00 +0000
389+++ mixxx/lib/xwax/lut.h 2011-04-22 09:04:29 +0000
390@@ -0,0 +1,42 @@
391+/*
392+ * Copyright (C) 2009 Mark Hills <mark@pogo.org.uk>
393+ *
394+ * This program is free software; you can redistribute it and/or
395+ * modify it under the terms of the GNU General Public License
396+ * version 2, as published by the Free Software Foundation.
397+ *
398+ * This program is distributed in the hope that it will be useful, but
399+ * WITHOUT ANY WARRANTY; without even the implied warranty of
400+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
401+ * General Public License version 2 for more details.
402+ *
403+ * You should have received a copy of the GNU General Public License
404+ * version 2 along with this program; if not, write to the Free
405+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
406+ * MA 02110-1301, USA.
407+ *
408+ */
409+
410+#ifndef LUT_H
411+#define LUT_H
412+
413+typedef unsigned int slot_no_t;
414+
415+struct slot_t {
416+ unsigned int timecode;
417+ slot_no_t next; /* next slot with the same hash */
418+};
419+
420+struct lut_t {
421+ struct slot_t *slot;
422+ slot_no_t *table, /* hash -> slot lookup */
423+ avail; /* next available slot */
424+};
425+
426+int lut_init(struct lut_t *lut, int nslots);
427+void lut_clear(struct lut_t *lut);
428+
429+void lut_push(struct lut_t *lut, unsigned int timecode);
430+unsigned int lut_lookup(struct lut_t *lut, unsigned int timecode);
431+
432+#endif
433
434=== added file 'mixxx/lib/xwax/pitch.h'
435--- mixxx/lib/xwax/pitch.h 1970-01-01 00:00:00 +0000
436+++ mixxx/lib/xwax/pitch.h 2011-04-22 09:04:29 +0000
437@@ -0,0 +1,71 @@
438+/*
439+ * Copyright (C) 2010 Mark Hills <mark@pogo.org.uk>
440+ *
441+ * This program is free software; you can redistribute it and/or
442+ * modify it under the terms of the GNU General Public License
443+ * version 2, as published by the Free Software Foundation.
444+ *
445+ * This program is distributed in the hope that it will be useful, but
446+ * WITHOUT ANY WARRANTY; without even the implied warranty of
447+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
448+ * General Public License version 2 for more details.
449+ *
450+ * You should have received a copy of the GNU General Public License
451+ * version 2 along with this program; if not, write to the Free
452+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
453+ * MA 02110-1301, USA.
454+ *
455+ */
456+
457+#ifndef PITCH_H
458+#define PITCH_H
459+
460+/* Values for the filter concluded experimentally */
461+
462+#define ALPHA (1.0/512)
463+#define BETA (ALPHA/1024)
464+
465+/* State of the pitch calculation filter */
466+
467+struct pitch_t {
468+ float dt, x, v;
469+};
470+
471+/* Prepare the filter for observations every dt seconds */
472+
473+static inline void pitch_init(struct pitch_t *p, float dt)
474+{
475+ p->dt = dt;
476+ p->x = 0.0;
477+ p->v = 0.0;
478+}
479+
480+/* Input an observation to the filter; in the last dt seconds the
481+ * position has moved by dx.
482+ *
483+ * Because the vinyl uses timestamps, the values for dx are discrete
484+ * rather than smooth. */
485+
486+static inline void pitch_dt_observation(struct pitch_t *p, float dx)
487+{
488+ float predicted_x, predicted_v, residual_x;
489+
490+ predicted_x = p->x + p->v * p->dt;
491+ predicted_v = p->v;
492+
493+ residual_x = dx - predicted_x;
494+
495+ p->x = predicted_x + residual_x * ALPHA;
496+ p->v = predicted_v + residual_x * BETA / p->dt;
497+
498+ p->x -= dx; /* relative to previous */
499+}
500+
501+/* Get the pitch after filtering */
502+
503+static inline float pitch_current(struct pitch_t *p)
504+{
505+ return p->v;
506+}
507+
508+#endif
509
510=== modified file 'mixxx/lib/xwax/timecoder.c'
511--- mixxx/lib/xwax/timecoder.c 2009-06-28 23:57:54 +0000
512+++ mixxx/lib/xwax/timecoder.c 2011-04-22 09:04:29 +0000
513@@ -1,5 +1,5 @@
514 /*
515- * Copyright (C) 2008 Mark Hills <mark@pogo.org.uk>
516+ * Copyright (C) 2010 Mark Hills <mark@pogo.org.uk>
517 *
518 * This program is free software; you can redistribute it and/or
519 * modify it under the terms of the GNU General Public License
520@@ -17,6 +17,7 @@
521 *
522 */
523
524+#include <assert.h>
525 #include <stdio.h>
526 #include <stdlib.h>
527 #include <string.h>
528@@ -25,10 +26,8 @@
529 #include "timecoder.h"
530
531 #define ZERO_THRESHOLD 128
532-#define SIGNAL_THRESHOLD 256
533
534-#define ZERO_AVG 1024
535-#define SIGNAL_AVG 256
536+#define ZERO_RC 0.001 /* time constant for zero/rumble filter */
537
538 #define REF_PEAKS_AVG 48 /* in wave cycles */
539
540@@ -45,187 +44,201 @@
541
542 /* Timecode definitions */
543
544-
545-#define POLARITY_NEGATIVE 0
546-#define POLARITY_POSITIVE 1
547-
548-
549-struct timecode_def_t timecode_def[] = {
550- {
551- name: "serato_2a",
552- desc: "Serato 2nd Ed., side A",
553- resolution: 1000,
554- polarity: POLARITY_POSITIVE,
555- bits: 20,
556- seed: 0x59017,
557- tap: {2, 5, 6, 7, 8, 13, 14, 16, 17},
558- ntaps: 9,
559- length: 712000,
560- safe: 707000,
561- lookup: NULL
562- },
563- {
564- name: "serato_2b",
565- desc: "Serato 2nd Ed., side B",
566- seed: 0x8f3c6,
567- resolution: 1000,
568- polarity: POLARITY_POSITIVE,
569- bits: 20,
570- tap: {3, 4, 6, 7, 12, 13, 14, 15, 18}, /* reverse of side A */
571- ntaps: 9,
572- length: 922000,
573- safe: 917000,
574- lookup: NULL
575- },
576- {
577- name: "serato_cd",
578- desc: "Serato CD",
579- resolution: 1000,
580- polarity: POLARITY_POSITIVE,
581- bits: 20,
582- seed: 0xd8b40,
583- tap: {2, 4, 6, 8, 10, 11, 14, 16, 17},
584- ntaps: 9,
585- length: 910000,
586- safe: 900000,
587- lookup: NULL
588- },
589- {
590- name: "traktor_a",
591- desc: "Traktor Scratch, side A",
592- resolution: 2000,
593- polarity: POLARITY_POSITIVE,
594- bits: 23,
595- seed: 0x134503,
596- tap: {6, 12, 18},
597- ntaps: 3,
598- length: 1500000,
599- safe: 1480000,
600- lookup: NULL
601- },
602- {
603- name: "traktor_b",
604- desc: "Traktor Scratch, side B",
605- resolution: 2000,
606- polarity: POLARITY_POSITIVE,
607- bits: 23,
608- seed: 0x32066c,
609- tap: {6, 12, 18},
610- ntaps: 3,
611- length: 2110000,
612- safe: 2090000,
613- lookup: NULL
614- },
615- {
616- name: NULL
617+#define SWITCH_PHASE 0x1 /* tone phase difference of 270 (not 90) degrees */
618+#define SWITCH_PRIMARY 0x2 /* use left channel (not right) as primary */
619+#define SWITCH_POLARITY 0x4 /* read bit values in negative (not positive) */
620+
621+
622+static struct timecode_def_t timecode_def[] = {
623+ {
624+ .name = "serato_2a",
625+ .desc = "Serato 2nd Ed., side A",
626+ .resolution = 1000,
627+ .flags = 0,
628+ .bits = 20,
629+ .seed = 0x59017,
630+ .taps = 0x361e4,
631+ .length = 712000,
632+ .safe = 625000,
633+ .lookup = false
634+ },
635+ {
636+ .name = "serato_2b",
637+ .desc = "Serato 2nd Ed., side B",
638+ .resolution = 1000,
639+ .flags = 0,
640+ .bits = 20,
641+ .seed = 0x8f3c6,
642+ .taps = 0x4f0d8, /* reverse of side A */
643+ .length = 922000,
644+ .safe = 905000,
645+ .lookup = false
646+ },
647+ {
648+ .name = "serato_cd",
649+ .desc = "Serato CD",
650+ .resolution = 1000,
651+ .flags = 0,
652+ .bits = 20,
653+ .seed = 0xd8b40,
654+ .taps = 0x34d54,
655+ .length = 950000,
656+ .safe = 940000,
657+ .lookup = false
658+ },
659+ {
660+ .name = "traktor_a",
661+ .desc = "Traktor Scratch, side A",
662+ .resolution = 2000,
663+ .flags = SWITCH_PRIMARY | SWITCH_POLARITY | SWITCH_PHASE,
664+ .bits = 23,
665+ .seed = 0x134503,
666+ .taps = 0x041040,
667+ .length = 1500000,
668+ .safe = 1463000,
669+ .lookup = false
670+ },
671+ {
672+ .name = "traktor_b",
673+ .desc = "Traktor Scratch, side B",
674+ .resolution = 2000,
675+ .flags = SWITCH_PRIMARY | SWITCH_POLARITY | SWITCH_PHASE,
676+ .bits = 23,
677+ .seed = 0x32066c,
678+ .taps = 0x041040, /* same as side A */
679+ .length = 2110000,
680+ .safe = 2068000,
681+ .lookup = false
682+ },
683+ {
684+ .name = "mixvibes_v2",
685+ .desc = "MixVibes V2",
686+ .resolution = 1300,
687+ .flags = SWITCH_PHASE,
688+ .bits = 20,
689+ .seed = 0x22c90,
690+ .taps = 0x00008,
691+ .length = 950000,
692+ .safe = 923000,
693+ .lookup = false
694+ },
695+ {
696+ .name = "mixvibes_7inch",
697+ .desc = "MixVibes 7\"",
698+ .resolution = 1300,
699+ .flags = SWITCH_PHASE,
700+ .bits = 20,
701+ .seed = 0x22c90,
702+ .taps = 0x00008,
703+ .length = 312000,
704+ .safe = 310000,
705+ .lookup = false
706+ },
707+ {
708+ .name = NULL
709 }
710 };
711
712
713-//struct timecode_def_t *def;
714-
715-
716 /* Linear Feeback Shift Register in the forward direction. New values
717 * are generated at the least-significant bit. */
718
719-static inline int lfsr(unsigned int code, struct timecoder_t *timecoder)
720-{
721- unsigned int r;
722- char s, n;
723-
724- r = code & 1;
725-
726- for(n = 0; n < timecoder->tc_table->ntaps; n++) {
727- s = *(timecoder->tc_table->tap + n);
728- r += (code & (1 << s)) >> s;
729- }
730-
731- return r & 0x1;
732-}
733-
734-
735-/* Linear Feeback Shift Register in the reverse direction. New values
736- * are generated at the most-significant bit. */
737-
738-static inline int lfsr_rev(unsigned int code, struct timecoder_t *timecoder)
739-{
740- unsigned int r;
741- char s, n;
742-
743- r = (code & (1 << (timecoder->tc_table->bits - 1))) >> (timecoder->tc_table->bits - 1);
744-
745- for(n = 0; n < timecoder->tc_table->ntaps; n++) {
746- s = *(timecoder->tc_table->tap + n) - 1;
747- r += (code & (1 << s)) >> s;
748- }
749-
750- return r & 0x1;
751-}
752-
753-
754-/* Setup globally, for a chosen timecode definition */
755-
756-int timecoder_build_lookup(char *timecode_name, struct timecoder_t *timecoder) {
757- unsigned int n, current;
758-
759+static inline bits_t lfsr(bits_t code, bits_t taps)
760+{
761+ bits_t taken;
762+ int xrs;
763+
764+ taken = code & taps;
765+ xrs = 0;
766+ while (taken != 0x0) {
767+ xrs += taken & 0x1;
768+ taken >>= 1;
769+ }
770+
771+ return xrs & 0x1;
772+}
773+
774+
775+static inline bits_t fwd(bits_t current, struct timecode_def_t *def)
776+{
777+ bits_t l;
778+
779+ /* New bits are added at the MSB; shift right by one */
780+
781+ l = lfsr(current, def->taps | 0x1);
782+ return (current >> 1) | (l << (def->bits - 1));
783+}
784+
785+
786+static inline bits_t rev(bits_t current, struct timecode_def_t *def)
787+{
788+ bits_t l, mask;
789+
790+ /* New bits are added at the LSB; shift left one and mask */
791+
792+ mask = (1 << def->bits) - 1;
793+ l = lfsr(current, (def->taps >> 1) | (0x1 << (def->bits - 1)));
794+ return ((current << 1) & mask) | l;
795+}
796+
797+
798+static struct timecode_def_t* find_definition(const char *name)
799+{
800 struct timecode_def_t *def;
801+
802 def = &timecode_def[0];
803-
804- while(def->name) {
805- if(!strcmp(def->name, timecode_name))
806- break;
807+ while (def->name) {
808+ if (!strcmp(def->name, name))
809+ return def;
810 def++;
811 }
812-
813- if(!def->name) {
814- fprintf(stderr, "Timecode definition '%s' is not known.\n",
815- timecode_name);
816- return -1;
817- }
818-
819- //Copy the lookup table stuff
820- if (timecoder->tc_table == NULL) {
821- timecoder->tc_table = malloc(sizeof(struct timecode_def_t));
822- }
823- memcpy(timecoder->tc_table, def, sizeof(struct timecode_def_t));
824-
825- fprintf(stderr, "Allocating %d slots (%zuKb) for %d bit timecode (%s)\n",
826- 2 << timecoder->tc_table->bits, (2 << timecoder->tc_table->bits) * sizeof(unsigned int) / 1024,
827- timecoder->tc_table->bits, timecoder->tc_table->desc);
828-
829- timecoder->tc_table->lookup = malloc((2 << timecoder->tc_table->bits) * sizeof(unsigned int));
830- if(!timecoder->tc_table->lookup) {
831- perror("malloc");
832+ return NULL;
833+}
834+
835+
836+/* Where necessary, build the lookup table required for this timecode */
837+
838+static int build_lookup(struct timecode_def_t *def)
839+{
840+ unsigned int n;
841+ bits_t current, last;
842+
843+ if (def->lookup)
844 return 0;
845- }
846-
847- for(n = 0; n < ((unsigned int)2 << timecoder->tc_table->bits); n++)
848- timecoder->tc_table->lookup[n] = -1;
849-
850- current = timecoder->tc_table->seed;
851-
852- for(n = 0; n < timecoder->tc_table->length; n++) {
853- if(timecoder->tc_table->lookup[current] != -1) {
854- fprintf(stderr, "Timecode has wrapped; finishing here.\n");
855- return -1;
856- }
857-
858- timecoder->tc_table->lookup[current] = n;
859- current = (current >> 1) + (lfsr(current, timecoder) << (timecoder->tc_table->bits - 1));
860- //printf("n=%d\n", n);
861- }
862+
863+ fprintf(stderr, "Building LUT for %d bit %dHz timecode (%s)\n",
864+ def->bits, def->resolution, def->desc);
865+
866+ if (lut_init(&def->lut, def->length) == -1)
867+ return -1;
868+
869+ current = def->seed;
870+
871+ for (n = 0; n < def->length; n++) {
872+ /* timecode must not wrap */
873+ assert(lut_lookup(&def->lut, current) == (unsigned)-1);
874+ lut_push(&def->lut, current);
875+ last = current;
876+ current = fwd(current, def);
877+ assert(rev(current, def) == last);
878+ }
879+
880+ def->lookup = true;
881
882 return 0;
883 }
884
885
886-/* Free the timecoder lookup table when it is no longer needed */
887-
888-void timecoder_free_lookup(struct timecoder_t* timecoder) {
889- if (timecoder->tc_table->lookup)
890- {
891- free(timecoder->tc_table->lookup);
892- timecoder->tc_table->lookup = NULL;
893+/* Free the timecoder lookup tables when they are no longer needed */
894+
895+void timecoder_free_lookup(void) {
896+ struct timecode_def_t *def;
897+
898+ def = &timecode_def[0];
899+ while (def->name) {
900+ if (def->lookup)
901+ lut_clear(&def->lut);
902+ def++;
903 }
904 }
905
906@@ -234,40 +247,43 @@
907 {
908 ch->positive = 0;
909 ch->zero = 0;
910- ch->crossing_ticker = 0;
911 }
912
913
914-/* Initialise a timecode decoder */
915+/* Initialise a timecode decoder at the given reference speed */
916
917-void timecoder_init(struct timecoder_t *tc)
918+int timecoder_init(struct timecoder_t *tc, const char *def_name, double speed,
919+ unsigned int sample_rate)
920 {
921- int c;
922+ /* A definition contains a lookup table which can be shared
923+ * across multiple timecoders */
924+
925+ tc->def = find_definition(def_name);
926+ if (tc->def == NULL) {
927+ fprintf(stderr, "Timecode definition '%s' is not known.\n", def_name);
928+ return -1;
929+ }
930+ if (build_lookup(tc->def) == -1)
931+ return -1;
932+ tc->speed = speed;
933+
934+ tc->dt = 1.0 / sample_rate;
935+ tc->zero_alpha = tc->dt / (ZERO_RC + tc->dt);
936
937 tc->forwards = 1;
938- tc->rate = TIMECODER_RATE;
939-
940- tc->half_peak = 0;
941- tc->wave_peak = 0;
942- tc->ref_level = -1;
943- tc->signal_level = 0;
944-
945- init_channel(&tc->mono);
946- for(c = 0; c < TIMECODER_CHANNELS; c++)
947- init_channel(&tc->channel[c]);
948-
949- tc->crossings = 0;
950- tc->pitch_ticker = 0;
951-
952+ init_channel(&tc->primary);
953+ init_channel(&tc->secondary);
954+ pitch_init(&tc->pitch, tc->dt);
955+
956+ tc->ref_level = 32768.0;
957 tc->bitstream = 0;
958 tc->timecode = 0;
959 tc->valid_counter = 0;
960 tc->timecode_ticker = 0;
961
962 tc->mon = NULL;
963- tc->log_fd = -1;
964-
965- tc->tc_table = NULL;
966+
967+ return 0;
968 }
969
970
971@@ -283,13 +299,17 @@
972 * display of the incoming audio. Initialise one for the given
973 * timecoder */
974
975-void timecoder_monitor_init(struct timecoder_t *tc, int size, int scale)
976+int timecoder_monitor_init(struct timecoder_t *tc, int size)
977 {
978 tc->mon_size = size;
979- tc->mon_scale = scale;
980 tc->mon = malloc(SQ(tc->mon_size));
981+ if (tc->mon == NULL) {
982+ perror("malloc");
983+ return -1;
984+ }
985 memset(tc->mon, 0, SQ(tc->mon_size));
986 tc->mon_counter = 0;
987+ return 0;
988 }
989
990
991@@ -297,300 +317,212 @@
992
993 void timecoder_monitor_clear(struct timecoder_t *tc)
994 {
995- if(tc->mon) {
996+ if (tc->mon) {
997 free(tc->mon);
998 tc->mon = NULL;
999 }
1000 }
1001
1002
1003-static int detect_zero_crossing(struct timecoder_channel_t *ch,
1004- signed short v, int rate)
1005+static void detect_zero_crossing(struct timecoder_channel_t *ch,
1006+ signed int v, float alpha)
1007 {
1008- int swapped;
1009-
1010 ch->crossing_ticker++;
1011
1012- swapped = 0;
1013- if(v >= ch->zero + ZERO_THRESHOLD && !ch->positive) {
1014- swapped = 1;
1015+ ch->swapped = 0;
1016+ if (v > ch->zero + ZERO_THRESHOLD && !ch->positive) {
1017+ ch->swapped = 1;
1018 ch->positive = 1;
1019 ch->crossing_ticker = 0;
1020- } else if(v < ch->zero - ZERO_THRESHOLD && ch->positive) {
1021- swapped = 1;
1022+ } else if (v < ch->zero - ZERO_THRESHOLD && ch->positive) {
1023+ ch->swapped = 1;
1024 ch->positive = 0;
1025 ch->crossing_ticker = 0;
1026 }
1027
1028- ch->zero += (v - ch->zero) * ZERO_AVG / rate;
1029+ ch->zero += alpha * (v - ch->zero);
1030+}
1031+
1032+
1033+/* Plot the given sample value in the monitor (scope) */
1034+
1035+static void update_monitor(struct timecoder_t *tc, signed int x, signed int y)
1036+{
1037+ int px, py, p;
1038+ float v, w;
1039+
1040+ if (!tc->mon)
1041+ return;
1042+
1043+ /* Decay the pixels already in the montior */
1044+
1045+ if (++tc->mon_counter % MONITOR_DECAY_EVERY == 0) {
1046+ for (p = 0; p < SQ(tc->mon_size); p++) {
1047+ if (tc->mon[p])
1048+ tc->mon[p] = tc->mon[p] * 7 / 8;
1049+ }
1050+ }
1051+
1052+ v = (float)x / tc->ref_level / 2;
1053+ w = (float)y / tc->ref_level / 2;
1054+
1055+ px = tc->mon_size / 2 + (v * tc->mon_size / 2);
1056+ py = tc->mon_size / 2 + (w * tc->mon_size / 2);
1057+
1058+ /* Set the pixel value to white */
1059+
1060+ if (px > 0 && px < tc->mon_size && py > 0 && py < tc->mon_size)
1061+ tc->mon[py * tc->mon_size + px] = 0xff;
1062+}
1063+
1064+
1065+/* Process a single bitstream reading */
1066+
1067+static void process_bitstream(struct timecoder_t *tc, signed int m)
1068+{
1069+ bits_t b;
1070+
1071+ b = m > tc->ref_level;
1072+
1073+ /* Add it to the bitstream, and work out what we were expecting
1074+ * (timecode). */
1075+
1076+ /* tc->bitstream is always in the order it is physically placed on
1077+ * the vinyl, regardless of the direction. */
1078+
1079+ if (tc->forwards) {
1080+ tc->timecode = fwd(tc->timecode, tc->def);
1081+ tc->bitstream = (tc->bitstream >> 1)
1082+ + (b << (tc->def->bits - 1));
1083+
1084+ } else {
1085+ bits_t mask;
1086+
1087+ mask = ((1 << tc->def->bits) - 1);
1088+ tc->timecode = rev(tc->timecode, tc->def);
1089+ tc->bitstream = ((tc->bitstream << 1) & mask) + b;
1090+ }
1091+
1092+ if (tc->timecode == tc->bitstream)
1093+ tc->valid_counter++;
1094+ else {
1095+ tc->timecode = tc->bitstream;
1096+ tc->valid_counter = 0;
1097+ }
1098+
1099+ /* Take note of the last time we read a valid timecode */
1100
1101- return swapped;
1102+ tc->timecode_ticker = 0;
1103+
1104+ /* Adjust the reference level based on this new peak */
1105+
1106+ tc->ref_level = (tc->ref_level * (REF_PEAKS_AVG - 1) + m) / REF_PEAKS_AVG;
1107+
1108+#ifdef DEBUG_BITSTREAM
1109+ fprintf(stderr, "%+6d zero, %+6d (ref %+6d)\t= %d%c (%5d)\n",
1110+ tc->primary.zero,
1111+ m,
1112+ tc->ref_level,
1113+ b,
1114+ tc->valid_counter == 0 ? 'x' : ' ',
1115+ tc->valid_counter);
1116+#endif
1117+}
1118+
1119+
1120+/* Process a single sample from the incoming audio */
1121+
1122+static void process_sample(struct timecoder_t *tc,
1123+ signed int primary, signed int secondary)
1124+{
1125+ signed int m; /* pcm sample, sum of two shorts */
1126+
1127+ detect_zero_crossing(&tc->primary, primary, tc->zero_alpha);
1128+ detect_zero_crossing(&tc->secondary, secondary, tc->zero_alpha);
1129+
1130+ m = abs(primary - tc->primary.zero);
1131+
1132+ /* If an axis has been crossed, use the direction of the crossing
1133+ * to work out the direction of the vinyl */
1134+
1135+ if (tc->primary.swapped) {
1136+ tc->forwards = (tc->primary.positive != tc->secondary.positive);
1137+ if (tc->def->flags & SWITCH_PHASE)
1138+ tc->forwards = !tc->forwards;
1139+ } if (tc->secondary.swapped) {
1140+ tc->forwards = (tc->primary.positive == tc->secondary.positive);
1141+ if (tc->def->flags & SWITCH_PHASE)
1142+ tc->forwards = !tc->forwards;
1143+ }
1144+
1145+ /* If any axis has been crossed, register movement using the pitch
1146+ * counters */
1147+
1148+ if (!tc->primary.swapped && !tc->secondary.swapped)
1149+ pitch_dt_observation(&tc->pitch, 0.0);
1150+ else {
1151+ float dx;
1152+
1153+ dx = 1.0 / tc->def->resolution / 4;
1154+ if (!tc->forwards)
1155+ dx = -dx;
1156+ pitch_dt_observation(&tc->pitch, dx);
1157+ }
1158+
1159+ /* If we have crossed the primary channel in the right polarity,
1160+ * it's time to read off a timecode 0 or 1 value */
1161+
1162+ if (tc->secondary.swapped &&
1163+ tc->primary.positive == ((tc->def->flags & SWITCH_POLARITY) == 0))
1164+ {
1165+ process_bitstream(tc, m);
1166+ }
1167+
1168+ tc->timecode_ticker++;
1169 }
1170
1171
1172 /* Submit and decode a block of PCM audio data to the timecoder */
1173
1174-int timecoder_submit(struct timecoder_t *tc, signed short *pcm, int samples)
1175+void timecoder_submit(struct timecoder_t *tc, const signed short *pcm, size_t npcm)
1176 {
1177- int b, l, /* bitstream and timecode bits */
1178- s, c,
1179- x, y, p, /* monitor coordinates */
1180- v,
1181- offset,
1182- swapped,
1183- monitor_centre;
1184- signed short w; /* pcm sample values */
1185- unsigned int mask;
1186-
1187- b = 0;
1188- l = 0;
1189-
1190- mask = ((1 << tc->tc_table->bits) - 1);
1191- monitor_centre = tc->mon_size / 2;
1192-
1193- offset = 0;
1194-
1195- for(s = 0; s < samples; s++) {
1196-
1197- for(c = 0; c < TIMECODER_CHANNELS; c++)
1198- detect_zero_crossing(&tc->channel[c], pcm[offset + c], tc->rate);
1199-
1200- /* Read from the mono channel */
1201-
1202- v = pcm[offset] + pcm[offset + 1];
1203- swapped = detect_zero_crossing(&tc->mono, v, tc->rate);
1204-
1205- /* If a sign change in the (zero corrected) audio has
1206- * happened, log the peak information */
1207-
1208- if(swapped) {
1209-
1210- /* Work out whether half way through a cycle we are
1211- * looking for the wave to be positive or negative */
1212-
1213- if(tc->mono.positive == (tc->tc_table->polarity ^ tc->forwards)) {
1214-
1215- /* Entering the second half of a wave cycle */
1216-
1217- tc->half_peak = tc->wave_peak;
1218-
1219- } else {
1220-
1221- /* Completed a full wave cycle, so time to analyse the
1222- * level and work out whether it's a 1 or 0 */
1223-
1224- b = tc->wave_peak + tc->half_peak > tc->ref_level;
1225-
1226- /* Log binary timecode */
1227-
1228- if(tc->log_fd != -1)
1229- write(tc->log_fd, b ? "1" : "0", 1);
1230-
1231- /* Add it to the bitstream, and work out what we were
1232- * expecting (timecode). */
1233-
1234- /* tc->bitstream is always in the order it is
1235- * physically placed on the vinyl, regardless of the
1236- * direction. */
1237-
1238- if(tc->forwards) {
1239- l = lfsr(tc->timecode, tc);
1240-
1241- tc->bitstream = (tc->bitstream >> 1)
1242- + (b << (tc->tc_table->bits - 1));
1243-
1244- tc->timecode = (tc->timecode >> 1)
1245- + (l << (tc->tc_table->bits - 1));
1246-
1247- } else {
1248- l = lfsr_rev(tc->timecode, tc);
1249-
1250- tc->bitstream = ((tc->bitstream << 1) & mask) + b;
1251- tc->timecode = ((tc->timecode << 1) & mask) + l;
1252- }
1253-
1254- if(b == l) {
1255- tc->valid_counter++;
1256- } else {
1257- tc->timecode = tc->bitstream;
1258- tc->valid_counter = 0;
1259- }
1260-
1261- /* Take note of the last time we read a valid timecode */
1262-
1263- tc->timecode_ticker = 0;
1264-
1265- /* Adjust the reference level based on the peaks seen
1266- * in this cycle */
1267-
1268- if(tc->ref_level == -1)
1269- tc->ref_level = tc->half_peak + tc->wave_peak;
1270- else {
1271- tc->ref_level = (tc->ref_level * (REF_PEAKS_AVG - 1)
1272- + tc->half_peak + tc->wave_peak)
1273- / REF_PEAKS_AVG;
1274- }
1275-
1276- }
1277-
1278- /* Calculate the immediate direction from phase difference,
1279- * based on the last channel to cross zero */
1280-
1281- if(tc->channel[0].crossing_ticker > tc->channel[1].crossing_ticker)
1282- tc->forwards = 1;
1283- else
1284- tc->forwards = 0;
1285-
1286- if(tc->forwards)
1287- tc->crossings++;
1288- else
1289- tc->crossings--;
1290-
1291- tc->pitch_ticker += tc->crossing_ticker;
1292- tc->crossing_ticker = 0;
1293- tc->wave_peak = 0;
1294-
1295- } /* swapped */
1296-
1297- tc->crossing_ticker++;
1298- tc->timecode_ticker++;
1299-
1300- /* Find the zero-normalised sample of the peak value from
1301- * the input */
1302-
1303- w = abs(v - tc->mono.zero);
1304- if(w > tc->wave_peak)
1305- tc->wave_peak = w;
1306-
1307- /* Take a rolling average of zero and signal level */
1308-
1309- tc->signal_level += (w - tc->signal_level) * SIGNAL_AVG / tc->rate;
1310-
1311- /* Update the monitor to add the incoming sample */
1312-
1313- if(tc->mon) {
1314-
1315- /* Decay the pixels already in the montior */
1316-
1317- if(++tc->mon_counter % MONITOR_DECAY_EVERY == 0) {
1318- for(p = 0; p < SQ(tc->mon_size); p++) {
1319- if(tc->mon[p])
1320- tc->mon[p] = tc->mon[p] * 7 / 8;
1321- }
1322- }
1323-
1324- v = pcm[offset]; /* first channel */
1325- w = pcm[offset + 1]; /* second channel */
1326-
1327- x = monitor_centre + (v * tc->mon_size * tc->mon_scale / 32768);
1328- y = monitor_centre + (w * tc->mon_size * tc->mon_scale / 32768);
1329-
1330- /* Set the pixel value to white */
1331-
1332- if(x > 0 && x < tc->mon_size && y > 0 && y < tc->mon_size)
1333- tc->mon[y * tc->mon_size + x] = 0xff;
1334+ while (npcm--) {
1335+ signed int primary, secondary;
1336+
1337+ if (tc->def->flags & SWITCH_PRIMARY) {
1338+ primary = pcm[0];
1339+ secondary = pcm[1];
1340+ } else {
1341+ primary = pcm[1];
1342+ secondary = pcm[0];
1343 }
1344-
1345- offset += TIMECODER_CHANNELS;
1346-
1347- } /* for each sample */
1348-
1349- /* Print debugging information */
1350-
1351-#if 0
1352- fprintf(stderr, "%+6d +/%4d -/%4d (%4d,%4d)\t= %d (%d) %c %d"
1353- "\t[crossings: %d %d]",
1354- tc->mono.zero,
1355- tc->half_peak,
1356- tc->wave_peak,
1357- tc->ref_level >> 1,
1358- tc->signal_level,
1359- b, l, b == l ? ' ' : 'x',
1360- tc->valid_counter,
1361- tc->crossings,
1362- tc->pitch_ticker);
1363-
1364- if(tc->pitch_ticker)
1365- fprintf(stderr, " = %d", tc->rate * tc->crossings / tc->pitch_ticker);
1366-
1367- fputc('\n', stderr);
1368-#endif
1369-
1370- return 0;
1371-}
1372-
1373-
1374-/* Return the timecode pitch, based on cycles of the sine wave. This
1375- * function can only be called by one context, at it resets the state
1376- * of the counter in the timecoder. */
1377-
1378-int timecoder_get_pitch(struct timecoder_t *tc, float *pitch)
1379-{
1380- /* Let the caller know if there's no data to gather pitch from */
1381-
1382- if(tc->crossings == 0)
1383- return -1;
1384-
1385- /* Value of tc->crossings may be negative in reverse */
1386-
1387- *pitch = tc->rate * (float)tc->crossings / tc->pitch_ticker
1388- / (tc->tc_table->resolution * 2);
1389-
1390- tc->crossings = 0;
1391- tc->pitch_ticker = 0;
1392-
1393- return 0;
1394+
1395+ process_sample(tc, primary, secondary);
1396+
1397+ update_monitor(tc, pcm[0], pcm[1]);
1398+ pcm += TIMECODER_CHANNELS;
1399+ }
1400 }
1401
1402
1403 /* Return the known position in the timecode, or -1 if not known. If
1404 * two few bits have been error-checked, then this also counts as
1405- * invalid. If 'when' is given, return the time, in input samples since
1406- * this value was read. */
1407+ * invalid. If 'when' is given, return the time, in seconds since this
1408+ * value was read. */
1409
1410-signed int timecoder_get_position(struct timecoder_t *tc, int *when)
1411+signed int timecoder_get_position(struct timecoder_t *tc, float *when)
1412 {
1413 signed int r;
1414
1415- if(tc->valid_counter > VALID_BITS) {
1416- r = tc->tc_table->lookup[tc->bitstream];
1417+ if (tc->valid_counter > VALID_BITS) {
1418+ r = lut_lookup(&tc->def->lut, tc->bitstream) / tc->speed;
1419
1420- if(r >= 0) {
1421- if(when)
1422- *when = tc->timecode_ticker;
1423+ if (r >= 0) {
1424+ if (when)
1425+ *when = tc->timecode_ticker * tc->dt;
1426 return r;
1427 }
1428 }
1429
1430 return -1;
1431 }
1432-
1433-
1434-/* Return non-zero if there is any timecode signal available */
1435-
1436-int timecoder_get_alive(struct timecoder_t *tc)
1437-{
1438- if(tc->signal_level < SIGNAL_THRESHOLD)
1439- return 0;
1440-
1441- return 1;
1442-}
1443-
1444-
1445-/* Return the last 'safe' timecode value on the record. Beyond this
1446- * value, we probably want to ignore the timecode values, as we will
1447- * hit the label of the record. */
1448-
1449-unsigned int timecoder_get_safe(struct timecoder_t *tc)
1450-{
1451- return tc->tc_table->safe;
1452-}
1453-
1454-
1455-/* Return the resolution of the timecode. This is the number of bits
1456- * per second, which corresponds to the frequency of the sine wave */
1457-
1458-int timecoder_get_resolution(struct timecoder_t *tc)
1459-{
1460- return tc->tc_table->resolution;
1461-}
1462
1463=== modified file 'mixxx/lib/xwax/timecoder.h'
1464--- mixxx/lib/xwax/timecoder.h 2009-06-28 23:57:54 +0000
1465+++ mixxx/lib/xwax/timecoder.h 2011-04-22 09:04:29 +0000
1466@@ -1,5 +1,5 @@
1467 /*
1468- * Copyright (C) 2008 Mark Hills <mark@pogo.org.uk>
1469+ * Copyright (C) 2010 Mark Hills <mark@pogo.org.uk>
1470 *
1471 * This program is free software; you can redistribute it and/or
1472 * modify it under the terms of the GNU General Public License
1473@@ -20,80 +20,118 @@
1474 #ifndef TIMECODER_H
1475 #define TIMECODER_H
1476
1477+#ifndef _MSC_VER
1478+#include <stdbool.h>
1479+#endif
1480+
1481+/* #include "device.h" */
1482+#include "lut.h"
1483+#include "pitch.h"
1484+
1485 #define TIMECODER_CHANNELS 2
1486-#define TIMECODER_RATE 44100 //Default rate - Albert
1487-
1488-#define MAX_BITS 32 /* bits in an int */
1489+
1490+
1491+typedef unsigned int bits_t;
1492+
1493
1494 struct timecode_def_t {
1495 char *name, *desc;
1496 int bits, /* number of bits in string */
1497 resolution, /* wave cycles per second */
1498- tap[MAX_BITS], ntaps, /* LFSR taps */
1499- polarity; /* cycle begins POLARITY_POSITIVE or POLARITY_NEGATIVE */
1500- unsigned int seed, /* LFSR value at timecode zero */
1501- length, /* in cycles */
1502+ flags;
1503+ bits_t seed, /* LFSR value at timecode zero */
1504+ taps; /* central LFSR taps, excluding end taps */
1505+ unsigned int length, /* in cycles */
1506 safe; /* last 'safe' timecode number (for auto disconnect) */
1507- signed int *lookup; /* pointer to built lookup table */
1508+ bool lookup; /* true if lut has been generated */
1509+ struct lut_t lut;
1510 };
1511
1512+
1513 struct timecoder_channel_t {
1514- int positive; /* wave is in positive part of cycle */
1515+ int positive, /* wave is in positive part of cycle */
1516+ swapped; /* wave recently swapped polarity */
1517 signed int zero;
1518- int crossing_ticker; /* samples since we last crossed zero */
1519+ unsigned int crossing_ticker; /* samples since we last crossed zero */
1520 };
1521
1522
1523 struct timecoder_t {
1524- int forwards, rate;
1525-
1526- /* Signal levels */
1527-
1528- signed int signal_level, half_peak, wave_peak, ref_level;
1529- struct timecoder_channel_t mono, channel[TIMECODER_CHANNELS];
1530+ struct timecode_def_t *def;
1531+ double speed;
1532+
1533+ /* Precomputed values */
1534+
1535+ float dt, zero_alpha;
1536
1537 /* Pitch information */
1538
1539- int crossings, /* number of zero crossings */
1540- pitch_ticker, /* number of samples from which crossings counted */
1541- crossing_ticker; /* stored for incrementing pitch_ticker */
1542+ int forwards;
1543+ struct timecoder_channel_t primary, secondary;
1544+ struct pitch_t pitch;
1545
1546 /* Numerical timecode */
1547
1548- unsigned int bitstream, /* actual bits from the record */
1549+ signed int ref_level;
1550+ bits_t bitstream, /* actual bits from the record */
1551 timecode; /* corrected timecode */
1552- int valid_counter, /* number of successful error checks */
1553+ unsigned int valid_counter, /* number of successful error checks */
1554 timecode_ticker; /* samples since valid timecode was read */
1555
1556 /* Feedback */
1557
1558 unsigned char *mon; /* x-y array */
1559- int mon_size, mon_counter, mon_scale,
1560- log_fd; /* optional file descriptor to log to, or -1 for none */
1561-
1562- struct timecode_def_t *tc_table;
1563+ int mon_size, mon_counter;
1564 };
1565
1566
1567-/* Building the lookup table is global. Need a good way to share
1568- * lookup tables soon, so we can use a different timecode on
1569- * each timecoder, and switch between them. */
1570-
1571-int timecoder_build_lookup(char *timecode_name, struct timecoder_t *timecoder);
1572-void timecoder_free_lookup(struct timecoder_t *timecoder);
1573-
1574-void timecoder_init(struct timecoder_t *tc);
1575+void timecoder_free_lookup(void);
1576+
1577+int timecoder_init(struct timecoder_t *tc, const char *def_name, double speed,
1578+ unsigned int sample_rate);
1579 void timecoder_clear(struct timecoder_t *tc);
1580
1581-void timecoder_monitor_init(struct timecoder_t *tc, int size, int scale);
1582+int timecoder_monitor_init(struct timecoder_t *tc, int size);
1583 void timecoder_monitor_clear(struct timecoder_t *tc);
1584
1585-int timecoder_submit(struct timecoder_t *tc, signed short *aud, int samples);
1586-
1587-int timecoder_get_pitch(struct timecoder_t *tc, float *pitch);
1588-signed int timecoder_get_position(struct timecoder_t *tc, int *when);
1589-int timecoder_get_alive(struct timecoder_t *tc);
1590-unsigned int timecoder_get_safe(struct timecoder_t *tc);
1591-int timecoder_get_resolution(struct timecoder_t *tc);
1592+void timecoder_submit(struct timecoder_t *tc, const signed short *pcm, size_t npcm);
1593+
1594+signed int timecoder_get_position(struct timecoder_t *tc, float *when);
1595+
1596+
1597+/* Return the pitch relative to reference playback speed */
1598+
1599+static inline float timecoder_get_pitch(struct timecoder_t *tc)
1600+{
1601+ return pitch_current(&tc->pitch) / tc->speed;
1602+}
1603+
1604+
1605+/* The last 'safe' timecode value on the record. Beyond this value, we
1606+ * probably want to ignore the timecode values, as we will hit the
1607+ * label of the record. */
1608+
1609+static inline unsigned int timecoder_get_safe(struct timecoder_t *tc)
1610+{
1611+ return tc->def->safe;
1612+}
1613+
1614+
1615+/* The resolution of the timecode. This is the number of bits per
1616+ * second at reference playback speed */
1617+
1618+static inline double timecoder_get_resolution(struct timecoder_t *tc)
1619+{
1620+ return tc->def->resolution * tc->speed;
1621+}
1622+
1623+
1624+/* The number of revolutions per second of the timecode vinyl,
1625+ * used only for visual display */
1626+
1627+static inline double timecoder_revs_per_sec(struct timecoder_t *tc)
1628+{
1629+ return (33.0 + 1.0 / 3) * tc->speed / 60;
1630+}
1631
1632 #endif
1633
1634=== renamed file 'mixxx/lib/xwax/timecoder_win32.c' => 'mixxx/lib/xwax/timecoder_win32.cpp'
1635--- mixxx/lib/xwax/timecoder_win32.c 2009-08-06 06:36:18 +0000
1636+++ mixxx/lib/xwax/timecoder_win32.cpp 2011-04-22 09:04:29 +0000
1637@@ -1,5 +1,5 @@
1638 /*
1639- * Copyright (C) 2008 Mark Hills <mark@pogo.org.uk>
1640+ * Copyright (C) 2010 Mark Hills <mark@pogo.org.uk>
1641 *
1642 * This program is free software; you can redistribute it and/or
1643 * modify it under the terms of the GNU General Public License
1644@@ -17,18 +17,19 @@
1645 *
1646 */
1647
1648+#include <assert.h>
1649 #include <stdio.h>
1650 #include <stdlib.h>
1651 #include <string.h>
1652-//#include <unistd.h>
1653+#ifndef _MSC_VER
1654+#include <unistd.h>
1655+#endif
1656
1657 #include "timecoder.h"
1658
1659 #define ZERO_THRESHOLD 128
1660-#define SIGNAL_THRESHOLD 256
1661
1662-#define ZERO_AVG 1024
1663-#define SIGNAL_AVG 256
1664+#define ZERO_RC 0.001 /* time constant for zero/rumble filter */
1665
1666 #define REF_PEAKS_AVG 48 /* in wave cycles */
1667
1668@@ -45,75 +46,95 @@
1669
1670 /* Timecode definitions */
1671
1672-
1673-#define POLARITY_NEGATIVE 0
1674-#define POLARITY_POSITIVE 1
1675-
1676-struct timecode_def_t timecode_def[] = {
1677+#define SWITCH_PHASE 0x1 /* tone phase difference of 270 (not 90) degrees */
1678+#define SWITCH_PRIMARY 0x2 /* use left channel (not right) as primary */
1679+#define SWITCH_POLARITY 0x4 /* read bit values in negative (not positive) */
1680+
1681+
1682+static struct timecode_def_t timecode_def[] = {
1683 {
1684 "serato_2a",
1685 "Serato 2nd Ed., side A",
1686 20,
1687- 1000,
1688- {2, 5, 6, 7, 8, 13, 14, 16, 17},
1689- 9,
1690- POLARITY_POSITIVE,
1691+ 1000,
1692+ 0,
1693 0x59017,
1694+ 0x361e4,
1695 712000,
1696- 707000,
1697- NULL
1698+ 625000,
1699+ false
1700 },
1701 {
1702 "serato_2b",
1703 "Serato 2nd Ed., side B",
1704 20,
1705 1000,
1706- {3, 4, 6, 7, 12, 13, 14, 15, 18}, /* reverse of side A */
1707- 9,
1708- POLARITY_POSITIVE,
1709+ 0,
1710 0x8f3c6,
1711+ 0x4f0d8, /* reverse of side A */
1712 922000,
1713- 917000,
1714- NULL
1715+ 905000,
1716+ false
1717 },
1718 {
1719 "serato_cd",
1720 "Serato CD",
1721 20,
1722 1000,
1723- {2, 4, 6, 8, 10, 11, 14, 16, 17},
1724- 9,
1725- POLARITY_POSITIVE,
1726+ 0,
1727 0xd8b40,
1728- 910000,
1729- 900000,
1730- NULL
1731+ 0x34d54,
1732+ 950000,
1733+ 940000,
1734+ false
1735 },
1736 {
1737 "traktor_a",
1738 "Traktor Scratch, side A",
1739 23,
1740 2000,
1741- {6, 12, 18},
1742- 3,
1743- POLARITY_NEGATIVE,
1744+ SWITCH_PRIMARY | SWITCH_POLARITY | SWITCH_PHASE,
1745 0x134503,
1746+ 0x041040,
1747 1500000,
1748- 1480000,
1749- NULL
1750+ 1463000,
1751+ false
1752 },
1753 {
1754 "traktor_b",
1755 "Traktor Scratch, side B",
1756 23,
1757- 2000,
1758- {6, 12, 18},
1759- 3,
1760- POLARITY_NEGATIVE,
1761+ 2000,
1762+ SWITCH_PRIMARY | SWITCH_POLARITY | SWITCH_PHASE,
1763 0x32066c,
1764+ 0x041040, /* same as side A */
1765 2110000,
1766- 2090000,
1767- NULL
1768+ 2068000,
1769+ false
1770+ },
1771+ {
1772+ "mixvibes_v2",
1773+ "MixVibes V2",
1774+ 20,
1775+ 1300,
1776+ SWITCH_PHASE,
1777+ 0x22c90,
1778+ 0x00008,
1779+ 950000,
1780+ 923000,
1781+ false
1782+ },
1783+ {
1784+ "mixvibes_7inch",
1785+ "MixVibes 7\"",
1786+ 20,
1787+ 1300,
1788+ SWITCH_PHASE,
1789+ 0x22c90,
1790+ 0x00008,
1791+ 312000,
1792+ 310000,
1793+ false
1794 },
1795 {
1796 NULL
1797@@ -121,110 +142,105 @@
1798 };
1799
1800
1801-//struct timecode_def_t *def;
1802-
1803-
1804 /* Linear Feeback Shift Register in the forward direction. New values
1805 * are generated at the least-significant bit. */
1806
1807-static int lfsr(unsigned int code, struct timecoder_t *timecoder)
1808-{
1809- unsigned int r;
1810- char s, n;
1811-
1812- r = code & 1;
1813-
1814- for(n = 0; n < timecoder->tc_table->ntaps; n++) {
1815- s = *(timecoder->tc_table->tap + n);
1816- r += (code & (1 << s)) >> s;
1817- }
1818-
1819- return r & 0x1;
1820-}
1821-
1822-
1823-/* Linear Feeback Shift Register in the reverse direction. New values
1824- * are generated at the most-significant bit. */
1825-
1826-static /* inline */ int lfsr_rev(unsigned int code, struct timecoder_t *timecoder) // inline causes compile failure on MSVC++ 2005 EE
1827-{
1828- unsigned int r;
1829- char s, n;
1830-
1831- r = (code & (1 << (timecoder->tc_table->bits - 1))) >> (timecoder->tc_table->bits - 1);
1832-
1833- for(n = 0; n < timecoder->tc_table->ntaps; n++) {
1834- s = *(timecoder->tc_table->tap + n) - 1;
1835- r += (code & (1 << s)) >> s;
1836- }
1837-
1838- return r & 0x1;
1839-}
1840-
1841-
1842-/* Setup globally, for a chosen timecode definition */
1843-
1844-int timecoder_build_lookup(char *timecode_name, struct timecoder_t *timecoder) {
1845- unsigned int n, current;
1846-
1847+static inline bits_t lfsr(bits_t code, bits_t taps)
1848+{
1849+ bits_t taken;
1850+ int xrs;
1851+
1852+ taken = code & taps;
1853+ xrs = 0;
1854+ while (taken != 0x0) {
1855+ xrs += taken & 0x1;
1856+ taken >>= 1;
1857+ }
1858+
1859+ return xrs & 0x1;
1860+}
1861+
1862+
1863+static inline bits_t fwd(bits_t current, struct timecode_def_t *def)
1864+{
1865+ bits_t l;
1866+
1867+ /* New bits are added at the MSB; shift right by one */
1868+
1869+ l = lfsr(current, def->taps | 0x1);
1870+ return (current >> 1) | (l << (def->bits - 1));
1871+}
1872+
1873+
1874+static inline bits_t rev(bits_t current, struct timecode_def_t *def)
1875+{
1876+ bits_t l, mask;
1877+
1878+ /* New bits are added at the LSB; shift left one and mask */
1879+
1880+ mask = (1 << def->bits) - 1;
1881+ l = lfsr(current, (def->taps >> 1) | (0x1 << (def->bits - 1)));
1882+ return ((current << 1) & mask) | l;
1883+}
1884+
1885+
1886+static struct timecode_def_t* find_definition(const char *name)
1887+{
1888 struct timecode_def_t *def;
1889+
1890 def = &timecode_def[0];
1891-
1892- while(def->name) {
1893- if(!strcmp(def->name, timecode_name))
1894- break;
1895+ while (def->name) {
1896+ if (!strcmp(def->name, name))
1897+ return def;
1898 def++;
1899 }
1900-
1901- if(!def->name) {
1902- fprintf(stderr, "Timecode definition '%s' is not known.\n",
1903- timecode_name);
1904- return -1;
1905- }
1906-
1907- //Copy the lookup table stuff
1908- if (timecoder->tc_table == NULL) {
1909- timecoder->tc_table = malloc(sizeof(struct timecode_def_t));
1910- }
1911- memcpy(timecoder->tc_table, def, sizeof(struct timecode_def_t));
1912-
1913- //fprintf(stderr, "Allocating %d slots (%zuKb) for %d bit timecode (%s)\n",
1914- // 2 << timecoder->tc_table->bits, (2 << timecoder->tc_table->bits) * sizeof(unsigned int) / 1024,
1915- // timecoder->tc_table->bits, timecoder->tc_table->desc);
1916-
1917- timecoder->tc_table->lookup = malloc((2 << timecoder->tc_table->bits) * sizeof(unsigned int));
1918- if(!timecoder->tc_table->lookup) {
1919- perror("malloc");
1920+ return NULL;
1921+}
1922+
1923+
1924+/* Where necessary, build the lookup table required for this timecode */
1925+
1926+static int build_lookup(struct timecode_def_t *def)
1927+{
1928+ unsigned int n;
1929+ bits_t current, last;
1930+
1931+ if (def->lookup)
1932 return 0;
1933- }
1934-
1935- for(n = 0; n < ((unsigned int)2 << timecoder->tc_table->bits); n++)
1936- timecoder->tc_table->lookup[n] = -1;
1937-
1938- current = timecoder->tc_table->seed;
1939-
1940- for(n = 0; n < timecoder->tc_table->length; n++) {
1941- if(timecoder->tc_table->lookup[current] != -1) {
1942- //fprintf(stderr, "Timecode has wrapped; finishing here.\n");
1943- return -1;
1944- }
1945-
1946- timecoder->tc_table->lookup[current] = n;
1947- current = (current >> 1) + (lfsr(current, timecoder) << (timecoder->tc_table->bits - 1));
1948- //printf("n=%d\n", n);
1949- }
1950+
1951+ fprintf(stderr, "Building LUT for %d bit %dHz timecode (%s)\n",
1952+ def->bits, def->resolution, def->desc);
1953+
1954+ if (lut_init(&def->lut, def->length) == -1)
1955+ return -1;
1956+
1957+ current = def->seed;
1958+
1959+ for (n = 0; n < def->length; n++) {
1960+ /* timecode must not wrap */
1961+ assert(lut_lookup(&def->lut, current) == (unsigned)-1);
1962+ lut_push(&def->lut, current);
1963+ last = current;
1964+ current = fwd(current, def);
1965+ assert(rev(current, def) == last);
1966+ }
1967+
1968+ def->lookup = true;
1969
1970 return 0;
1971 }
1972
1973
1974-/* Free the timecoder lookup table when it is no longer needed */
1975-
1976-void timecoder_free_lookup(struct timecoder_t* timecoder) {
1977- if (timecoder->tc_table->lookup)
1978- {
1979- free(timecoder->tc_table->lookup);
1980- timecoder->tc_table->lookup = NULL;
1981+/* Free the timecoder lookup tables when they are no longer needed */
1982+
1983+void timecoder_free_lookup(void) {
1984+ struct timecode_def_t *def;
1985+
1986+ def = &timecode_def[0];
1987+ while (def->name) {
1988+ if (def->lookup)
1989+ lut_clear(&def->lut);
1990+ def++;
1991 }
1992 }
1993
1994@@ -233,40 +249,43 @@
1995 {
1996 ch->positive = 0;
1997 ch->zero = 0;
1998- ch->crossing_ticker = 0;
1999 }
2000
2001
2002-/* Initialise a timecode decoder */
2003+/* Initialise a timecode decoder at the given reference speed */
2004
2005-void timecoder_init(struct timecoder_t *tc)
2006+int timecoder_init(struct timecoder_t *tc, const char *def_name, double speed,
2007+ unsigned int sample_rate)
2008 {
2009- int c;
2010+ /* A definition contains a lookup table which can be shared
2011+ * across multiple timecoders */
2012+
2013+ tc->def = find_definition(def_name);
2014+ if (tc->def == NULL) {
2015+ fprintf(stderr, "Timecode definition '%s' is not known.\n", def_name);
2016+ return -1;
2017+ }
2018+ if (build_lookup(tc->def) == -1)
2019+ return -1;
2020+ tc->speed = speed;
2021+
2022+ tc->dt = 1.0 / sample_rate;
2023+ tc->zero_alpha = tc->dt / (ZERO_RC + tc->dt);
2024
2025 tc->forwards = 1;
2026- tc->rate = TIMECODER_RATE;
2027-
2028- tc->half_peak = 0;
2029- tc->wave_peak = 0;
2030- tc->ref_level = -1;
2031- tc->signal_level = 0;
2032-
2033- init_channel(&tc->mono);
2034- for(c = 0; c < TIMECODER_CHANNELS; c++)
2035- init_channel(&tc->channel[c]);
2036-
2037- tc->crossings = 0;
2038- tc->pitch_ticker = 0;
2039-
2040+ init_channel(&tc->primary);
2041+ init_channel(&tc->secondary);
2042+ pitch_init(&tc->pitch, tc->dt);
2043+
2044+ tc->ref_level = 32768.0;
2045 tc->bitstream = 0;
2046 tc->timecode = 0;
2047 tc->valid_counter = 0;
2048 tc->timecode_ticker = 0;
2049
2050 tc->mon = NULL;
2051- tc->log_fd = -1;
2052-
2053- tc->tc_table = NULL;
2054+
2055+ return 0;
2056 }
2057
2058
2059@@ -282,13 +301,17 @@
2060 * display of the incoming audio. Initialise one for the given
2061 * timecoder */
2062
2063-void timecoder_monitor_init(struct timecoder_t *tc, int size, int scale)
2064+int timecoder_monitor_init(struct timecoder_t *tc, int size)
2065 {
2066 tc->mon_size = size;
2067- tc->mon_scale = scale;
2068- tc->mon = malloc(SQ(tc->mon_size));
2069+ tc->mon = (unsigned char*)malloc(SQ(tc->mon_size));
2070+ if (tc->mon == NULL) {
2071+ perror("malloc");
2072+ return -1;
2073+ }
2074 memset(tc->mon, 0, SQ(tc->mon_size));
2075 tc->mon_counter = 0;
2076+ return 0;
2077 }
2078
2079
2080@@ -296,300 +319,212 @@
2081
2082 void timecoder_monitor_clear(struct timecoder_t *tc)
2083 {
2084- if(tc->mon) {
2085+ if (tc->mon) {
2086 free(tc->mon);
2087 tc->mon = NULL;
2088 }
2089 }
2090
2091
2092-static int detect_zero_crossing(struct timecoder_channel_t *ch,
2093- signed short v, int rate)
2094+static void detect_zero_crossing(struct timecoder_channel_t *ch,
2095+ signed int v, float alpha)
2096 {
2097- int swapped;
2098-
2099 ch->crossing_ticker++;
2100
2101- swapped = 0;
2102- if(v >= ch->zero + ZERO_THRESHOLD && !ch->positive) {
2103- swapped = 1;
2104+ ch->swapped = 0;
2105+ if (v > ch->zero + ZERO_THRESHOLD && !ch->positive) {
2106+ ch->swapped = 1;
2107 ch->positive = 1;
2108 ch->crossing_ticker = 0;
2109- } else if(v < ch->zero - ZERO_THRESHOLD && ch->positive) {
2110- swapped = 1;
2111+ } else if (v < ch->zero - ZERO_THRESHOLD && ch->positive) {
2112+ ch->swapped = 1;
2113 ch->positive = 0;
2114 ch->crossing_ticker = 0;
2115 }
2116
2117- ch->zero += (v - ch->zero) * ZERO_AVG / rate;
2118+ ch->zero += alpha * (v - ch->zero);
2119+}
2120+
2121+
2122+/* Plot the given sample value in the monitor (scope) */
2123+
2124+static void update_monitor(struct timecoder_t *tc, signed int x, signed int y)
2125+{
2126+ int px, py, p;
2127+ float v, w;
2128+
2129+ if (!tc->mon)
2130+ return;
2131+
2132+ /* Decay the pixels already in the montior */
2133+
2134+ if (++tc->mon_counter % MONITOR_DECAY_EVERY == 0) {
2135+ for (p = 0; p < SQ(tc->mon_size); p++) {
2136+ if (tc->mon[p])
2137+ tc->mon[p] = tc->mon[p] * 7 / 8;
2138+ }
2139+ }
2140+
2141+ v = (float)x / tc->ref_level / 2;
2142+ w = (float)y / tc->ref_level / 2;
2143+
2144+ px = tc->mon_size / 2 + (v * tc->mon_size / 2);
2145+ py = tc->mon_size / 2 + (w * tc->mon_size / 2);
2146+
2147+ /* Set the pixel value to white */
2148+
2149+ if (px > 0 && px < tc->mon_size && py > 0 && py < tc->mon_size)
2150+ tc->mon[py * tc->mon_size + px] = 0xff;
2151+}
2152+
2153+
2154+/* Process a single bitstream reading */
2155+
2156+static void process_bitstream(struct timecoder_t *tc, signed int m)
2157+{
2158+ bits_t b;
2159+
2160+ b = m > tc->ref_level;
2161+
2162+ /* Add it to the bitstream, and work out what we were expecting
2163+ * (timecode). */
2164+
2165+ /* tc->bitstream is always in the order it is physically placed on
2166+ * the vinyl, regardless of the direction. */
2167+
2168+ if (tc->forwards) {
2169+ tc->timecode = fwd(tc->timecode, tc->def);
2170+ tc->bitstream = (tc->bitstream >> 1)
2171+ + (b << (tc->def->bits - 1));
2172+
2173+ } else {
2174+ bits_t mask;
2175+
2176+ mask = ((1 << tc->def->bits) - 1);
2177+ tc->timecode = rev(tc->timecode, tc->def);
2178+ tc->bitstream = ((tc->bitstream << 1) & mask) + b;
2179+ }
2180+
2181+ if (tc->timecode == tc->bitstream)
2182+ tc->valid_counter++;
2183+ else {
2184+ tc->timecode = tc->bitstream;
2185+ tc->valid_counter = 0;
2186+ }
2187+
2188+ /* Take note of the last time we read a valid timecode */
2189
2190- return swapped;
2191+ tc->timecode_ticker = 0;
2192+
2193+ /* Adjust the reference level based on this new peak */
2194+
2195+ tc->ref_level = (tc->ref_level * (REF_PEAKS_AVG - 1) + m) / REF_PEAKS_AVG;
2196+
2197+#ifdef DEBUG_BITSTREAM
2198+ fprintf(stderr, "%+6d zero, %+6d (ref %+6d)\t= %d%c (%5d)\n",
2199+ tc->primary.zero,
2200+ m,
2201+ tc->ref_level,
2202+ b,
2203+ tc->valid_counter == 0 ? 'x' : ' ',
2204+ tc->valid_counter);
2205+#endif
2206+}
2207+
2208+
2209+/* Process a single sample from the incoming audio */
2210+
2211+static void process_sample(struct timecoder_t *tc,
2212+ signed int primary, signed int secondary)
2213+{
2214+ signed int m; /* pcm sample, sum of two shorts */
2215+
2216+ detect_zero_crossing(&tc->primary, primary, tc->zero_alpha);
2217+ detect_zero_crossing(&tc->secondary, secondary, tc->zero_alpha);
2218+
2219+ m = abs(primary - tc->primary.zero);
2220+
2221+ /* If an axis has been crossed, use the direction of the crossing
2222+ * to work out the direction of the vinyl */
2223+
2224+ if (tc->primary.swapped) {
2225+ tc->forwards = (tc->primary.positive != tc->secondary.positive);
2226+ if (tc->def->flags & SWITCH_PHASE)
2227+ tc->forwards = !tc->forwards;
2228+ } if (tc->secondary.swapped) {
2229+ tc->forwards = (tc->primary.positive == tc->secondary.positive);
2230+ if (tc->def->flags & SWITCH_PHASE)
2231+ tc->forwards = !tc->forwards;
2232+ }
2233+
2234+ /* If any axis has been crossed, register movement using the pitch
2235+ * counters */
2236+
2237+ if (!tc->primary.swapped && !tc->secondary.swapped)
2238+ pitch_dt_observation(&tc->pitch, 0.0);
2239+ else {
2240+ float dx;
2241+
2242+ dx = 1.0 / tc->def->resolution / 4;
2243+ if (!tc->forwards)
2244+ dx = -dx;
2245+ pitch_dt_observation(&tc->pitch, dx);
2246+ }
2247+
2248+ /* If we have crossed the primary channel in the right polarity,
2249+ * it's time to read off a timecode 0 or 1 value */
2250+
2251+ if (tc->secondary.swapped &&
2252+ tc->primary.positive == ((tc->def->flags & SWITCH_POLARITY) == 0))
2253+ {
2254+ process_bitstream(tc, m);
2255+ }
2256+
2257+ tc->timecode_ticker++;
2258 }
2259
2260
2261 /* Submit and decode a block of PCM audio data to the timecoder */
2262
2263-int timecoder_submit(struct timecoder_t *tc, signed short *pcm, int samples)
2264+void timecoder_submit(struct timecoder_t *tc, signed short *pcm, size_t npcm)
2265 {
2266- int b, l, /* bitstream and timecode bits */
2267- s, c,
2268- x, y, p, /* monitor coordinates */
2269- v,
2270- offset,
2271- swapped,
2272- monitor_centre;
2273- signed short w; /* pcm sample values */
2274- unsigned int mask;
2275-
2276- b = 0;
2277- l = 0;
2278-
2279- mask = ((1 << tc->tc_table->bits) - 1);
2280- monitor_centre = tc->mon_size / 2;
2281-
2282- offset = 0;
2283-
2284- for(s = 0; s < samples; s++) {
2285-
2286- for(c = 0; c < TIMECODER_CHANNELS; c++)
2287- detect_zero_crossing(&tc->channel[c], pcm[offset + c], tc->rate);
2288-
2289- /* Read from the mono channel */
2290-
2291- v = pcm[offset] + pcm[offset + 1];
2292- swapped = detect_zero_crossing(&tc->mono, v, tc->rate);
2293-
2294- /* If a sign change in the (zero corrected) audio has
2295- * happened, log the peak information */
2296-
2297- if(swapped) {
2298-
2299- /* Work out whether half way through a cycle we are
2300- * looking for the wave to be positive or negative */
2301-
2302- if(tc->mono.positive == (tc->tc_table->polarity ^ tc->forwards)) {
2303-
2304- /* Entering the second half of a wave cycle */
2305-
2306- tc->half_peak = tc->wave_peak;
2307-
2308- } else {
2309-
2310- /* Completed a full wave cycle, so time to analyse the
2311- * level and work out whether it's a 1 or 0 */
2312-
2313- b = tc->wave_peak + tc->half_peak > tc->ref_level;
2314-
2315- /* Log binary timecode */
2316-
2317- if(tc->log_fd != -1)
2318- write(tc->log_fd, b ? "1" : "0", 1);
2319-
2320- /* Add it to the bitstream, and work out what we were
2321- * expecting (timecode). */
2322-
2323- /* tc->bitstream is always in the order it is
2324- * physically placed on the vinyl, regardless of the
2325- * direction. */
2326-
2327- if(tc->forwards) {
2328- l = lfsr(tc->timecode, tc);
2329-
2330- tc->bitstream = (tc->bitstream >> 1)
2331- + (b << (tc->tc_table->bits - 1));
2332-
2333- tc->timecode = (tc->timecode >> 1)
2334- + (l << (tc->tc_table->bits - 1));
2335-
2336- } else {
2337- l = lfsr_rev(tc->timecode, tc);
2338-
2339- tc->bitstream = ((tc->bitstream << 1) & mask) + b;
2340- tc->timecode = ((tc->timecode << 1) & mask) + l;
2341- }
2342-
2343- if(b == l) {
2344- tc->valid_counter++;
2345- } else {
2346- tc->timecode = tc->bitstream;
2347- tc->valid_counter = 0;
2348- }
2349-
2350- /* Take note of the last time we read a valid timecode */
2351-
2352- tc->timecode_ticker = 0;
2353-
2354- /* Adjust the reference level based on the peaks seen
2355- * in this cycle */
2356-
2357- if(tc->ref_level == -1)
2358- tc->ref_level = tc->half_peak + tc->wave_peak;
2359- else {
2360- tc->ref_level = (tc->ref_level * (REF_PEAKS_AVG - 1)
2361- + tc->half_peak + tc->wave_peak)
2362- / REF_PEAKS_AVG;
2363- }
2364-
2365- }
2366-
2367- /* Calculate the immediate direction from phase difference,
2368- * based on the last channel to cross zero */
2369-
2370- if(tc->channel[0].crossing_ticker > tc->channel[1].crossing_ticker)
2371- tc->forwards = 1;
2372- else
2373- tc->forwards = 0;
2374-
2375- if(tc->forwards)
2376- tc->crossings++;
2377- else
2378- tc->crossings--;
2379-
2380- tc->pitch_ticker += tc->crossing_ticker;
2381- tc->crossing_ticker = 0;
2382- tc->wave_peak = 0;
2383-
2384- } /* swapped */
2385-
2386- tc->crossing_ticker++;
2387- tc->timecode_ticker++;
2388-
2389- /* Find the zero-normalised sample of the peak value from
2390- * the input */
2391-
2392- w = abs(v - tc->mono.zero);
2393- if(w > tc->wave_peak)
2394- tc->wave_peak = w;
2395-
2396- /* Take a rolling average of zero and signal level */
2397-
2398- tc->signal_level += (w - tc->signal_level) * SIGNAL_AVG / tc->rate;
2399-
2400- /* Update the monitor to add the incoming sample */
2401-
2402- if(tc->mon) {
2403-
2404- /* Decay the pixels already in the montior */
2405-
2406- if(++tc->mon_counter % MONITOR_DECAY_EVERY == 0) {
2407- for(p = 0; p < SQ(tc->mon_size); p++) {
2408- if(tc->mon[p])
2409- tc->mon[p] = tc->mon[p] * 7 / 8;
2410- }
2411- }
2412-
2413- v = pcm[offset]; /* first channel */
2414- w = pcm[offset + 1]; /* second channel */
2415-
2416- x = monitor_centre + (v * tc->mon_size * tc->mon_scale / 32768);
2417- y = monitor_centre + (w * tc->mon_size * tc->mon_scale / 32768);
2418-
2419- /* Set the pixel value to white */
2420-
2421- if(x > 0 && x < tc->mon_size && y > 0 && y < tc->mon_size)
2422- tc->mon[y * tc->mon_size + x] = 0xff;
2423+ while (npcm--) {
2424+ signed int primary, secondary;
2425+
2426+ if (tc->def->flags & SWITCH_PRIMARY) {
2427+ primary = pcm[0];
2428+ secondary = pcm[1];
2429+ } else {
2430+ primary = pcm[1];
2431+ secondary = pcm[0];
2432 }
2433-
2434- offset += TIMECODER_CHANNELS;
2435-
2436- } /* for each sample */
2437-
2438- /* Print debugging information */
2439-
2440-#if 0
2441- fprintf(stderr, "%+6d +/%4d -/%4d (%4d,%4d)\t= %d (%d) %c %d"
2442- "\t[crossings: %d %d]",
2443- tc->mono.zero,
2444- tc->half_peak,
2445- tc->wave_peak,
2446- tc->ref_level >> 1,
2447- tc->signal_level,
2448- b, l, b == l ? ' ' : 'x',
2449- tc->valid_counter,
2450- tc->crossings,
2451- tc->pitch_ticker);
2452-
2453- if(tc->pitch_ticker)
2454- fprintf(stderr, " = %d", tc->rate * tc->crossings / tc->pitch_ticker);
2455-
2456- fputc('\n', stderr);
2457-#endif
2458-
2459- return 0;
2460-}
2461-
2462-
2463-/* Return the timecode pitch, based on cycles of the sine wave. This
2464- * function can only be called by one context, at it resets the state
2465- * of the counter in the timecoder. */
2466-
2467-int timecoder_get_pitch(struct timecoder_t *tc, float *pitch)
2468-{
2469- /* Let the caller know if there's no data to gather pitch from */
2470-
2471- if(tc->crossings == 0)
2472- return -1;
2473-
2474- /* Value of tc->crossings may be negative in reverse */
2475-
2476- *pitch = tc->rate * (float)tc->crossings / tc->pitch_ticker
2477- / (tc->tc_table->resolution * 2);
2478-
2479- tc->crossings = 0;
2480- tc->pitch_ticker = 0;
2481-
2482- return 0;
2483+
2484+ process_sample(tc, primary, secondary);
2485+
2486+ update_monitor(tc, pcm[0], pcm[1]);
2487+ pcm += TIMECODER_CHANNELS;
2488+ }
2489 }
2490
2491
2492 /* Return the known position in the timecode, or -1 if not known. If
2493 * two few bits have been error-checked, then this also counts as
2494- * invalid. If 'when' is given, return the time, in input samples since
2495- * this value was read. */
2496+ * invalid. If 'when' is given, return the time, in seconds since this
2497+ * value was read. */
2498
2499-signed int timecoder_get_position(struct timecoder_t *tc, int *when)
2500+signed int timecoder_get_position(struct timecoder_t *tc, float *when)
2501 {
2502 signed int r;
2503
2504- if(tc->valid_counter > VALID_BITS) {
2505- r = tc->tc_table->lookup[tc->bitstream];
2506+ if (tc->valid_counter > VALID_BITS) {
2507+ r = lut_lookup(&tc->def->lut, tc->bitstream);
2508
2509- if(r >= 0) {
2510- if(when)
2511- *when = tc->timecode_ticker;
2512+ if (r >= 0) {
2513+ if (when)
2514+ *when = tc->timecode_ticker * tc->dt;
2515 return r;
2516 }
2517 }
2518
2519 return -1;
2520 }
2521-
2522-
2523-/* Return non-zero if there is any timecode signal available */
2524-
2525-int timecoder_get_alive(struct timecoder_t *tc)
2526-{
2527- if(tc->signal_level < SIGNAL_THRESHOLD)
2528- return 0;
2529-
2530- return 1;
2531-}
2532-
2533-
2534-/* Return the last 'safe' timecode value on the record. Beyond this
2535- * value, we probably want to ignore the timecode values, as we will
2536- * hit the label of the record. */
2537-
2538-unsigned int timecoder_get_safe(struct timecoder_t *tc)
2539-{
2540- return tc->tc_table->safe;
2541-}
2542-
2543-
2544-/* Return the resolution of the timecode. This is the number of bits
2545- * per second, which corresponds to the frequency of the sine wave */
2546-
2547-int timecoder_get_resolution(struct timecoder_t *tc)
2548-{
2549- return tc->tc_table->resolution;
2550-}
2551
2552=== added file 'mixxx/res/images/library/ic_library_recordings.png'
2553Binary files mixxx/res/images/library/ic_library_recordings.png 1970-01-01 00:00:00 +0000 and mixxx/res/images/library/ic_library_recordings.png 2011-04-22 09:04:29 +0000 differ
2554=== modified file 'mixxx/res/mixxx.qrc'
2555--- mixxx/res/mixxx.qrc 2011-01-24 15:07:37 +0000
2556+++ mixxx/res/mixxx.qrc 2011-04-22 09:04:29 +0000
2557@@ -30,5 +30,6 @@
2558 <file>images/library/ic_library_promotracks.png</file>
2559 <file>images/library/ic_library_rhythmbox.png</file>
2560 <file>images/library/ic_library_traktor.png</file>
2561+ <file>images/library/ic_library_recordings.png</file>
2562 </qresource>
2563 </RCC>
2564
2565=== modified file 'mixxx/res/schema.xml'
2566--- mixxx/res/schema.xml 2011-04-03 15:57:56 +0000
2567+++ mixxx/res/schema.xml 2011-04-22 09:04:29 +0000
2568@@ -280,8 +280,8 @@
2569 Add support for multi-level crates and playlists.
2570 </description>
2571 <sql>
2572- ALTER TABLE crates ADD COLUMN parent INTEGER DEFAULT 0;
2573- ALTER TABLE Playlists ADD COLUMN parent INTEGER DEFAULT 0;
2574+ ALTER TABLE crates ADD COLUMN parent INTEGER DEFAULT -1;
2575+ ALTER TABLE Playlists ADD COLUMN parent INTEGER DEFAULT -1;
2576 </sql>
2577 </revision>
2578 </schema>
2579
2580=== modified file 'mixxx/res/skins/Outline1024x600-Netbook/skin.xml'
2581--- mixxx/res/skins/Outline1024x600-Netbook/skin.xml 2011-03-22 16:24:04 +0000
2582+++ mixxx/res/skins/Outline1024x600-Netbook/skin.xml 2011-04-22 09:04:29 +0000
2583@@ -949,6 +949,83 @@
2584 <ConfigKey>[Master],PeakIndicator</ConfigKey>
2585 </Connection>
2586 </StatusLight>
2587+
2588+ <!--
2589+ **********************************************
2590+ Vinyl Stuff
2591+ **********************************************
2592+ -->
2593+
2594+ <StatusLight>
2595+ <Tooltip>Vinyl Status</Tooltip>
2596+ <NumberPos>4</NumberPos>
2597+ <PathBack>vinyl-status-disabled.png</PathBack>
2598+ <PathStatusLight>vinyl-status-green.png</PathStatusLight>
2599+ <PathStatusLight2>vinyl-status-yellow.png</PathStatusLight2>
2600+ <PathStatusLight3>vinyl-status-red.png</PathStatusLight3>
2601+ <Pos>357,194</Pos>
2602+ <Connection>
2603+ <ConfigKey>[Channel1],vinylcontrol_status</ConfigKey>
2604+ </Connection>
2605+ </StatusLight>
2606+ <StatusLight>
2607+ <Tooltip>Vinyl Status</Tooltip>
2608+ <NumberPos>4</NumberPos>
2609+ <PathBack>vinyl-status-disabled.png</PathBack>
2610+ <PathStatusLight>vinyl-status-green.png</PathStatusLight>
2611+ <PathStatusLight2>vinyl-status-yellow.png</PathStatusLight2>
2612+ <PathStatusLight3>vinyl-status-red.png</PathStatusLight3>
2613+ <Pos>597,194</Pos>
2614+ <Connection>
2615+ <ConfigKey>[Channel2],vinylcontrol_status</ConfigKey>
2616+ </Connection>
2617+ </StatusLight>
2618+ <PushButton>
2619+ <Tooltip>Vinyl Control Mode</Tooltip>
2620+ <NumberStates>3</NumberStates>
2621+ <State>
2622+ <Number>0</Number>
2623+ <Pressed>vinyl-abs.png</Pressed>
2624+ <Unpressed>vinyl-abs.png</Unpressed>
2625+ </State>
2626+ <State>
2627+ <Number>1</Number>
2628+ <Pressed>vinyl-rel.png</Pressed>
2629+ <Unpressed>vinyl-rel.png</Unpressed>
2630+ </State>
2631+ <State>
2632+ <Number>2</Number>
2633+ <Pressed>vinyl-const.png</Pressed>
2634+ <Unpressed>vinyl-const.png</Unpressed>
2635+ </State>
2636+ <Pos>380,192</Pos>
2637+ <Connection>
2638+ <ConfigKey>[Channel1],vinylcontrol_mode</ConfigKey>
2639+ </Connection>
2640+ </PushButton>
2641+ <PushButton>
2642+ <Tooltip>Vinyl Control Mode</Tooltip>
2643+ <NumberStates>3</NumberStates>
2644+ <State>
2645+ <Number>0</Number>
2646+ <Pressed>vinyl-abs.png</Pressed>
2647+ <Unpressed>vinyl-abs.png</Unpressed>
2648+ </State>
2649+ <State>
2650+ <Number>1</Number>
2651+ <Pressed>vinyl-rel.png</Pressed>
2652+ <Unpressed>vinyl-rel.png</Unpressed>
2653+ </State>
2654+ <State>
2655+ <Number>2</Number>
2656+ <Pressed>vinyl-const.png</Pressed>
2657+ <Unpressed>vinyl-const.png</Unpressed>
2658+ </State>
2659+ <Pos>621,192</Pos>
2660+ <Connection>
2661+ <ConfigKey>[Channel2],vinylcontrol_mode</ConfigKey>
2662+ </Connection>
2663+ </PushButton>
2664
2665 <!--
2666 ############################################################################################
2667
2668=== added file 'mixxx/res/skins/Outline1024x600-Netbook/vinyl-abs.png'
2669Binary files mixxx/res/skins/Outline1024x600-Netbook/vinyl-abs.png 1970-01-01 00:00:00 +0000 and mixxx/res/skins/Outline1024x600-Netbook/vinyl-abs.png 2011-04-22 09:04:29 +0000 differ
2670=== added file 'mixxx/res/skins/Outline1024x600-Netbook/vinyl-const.png'
2671Binary files mixxx/res/skins/Outline1024x600-Netbook/vinyl-const.png 1970-01-01 00:00:00 +0000 and mixxx/res/skins/Outline1024x600-Netbook/vinyl-const.png 2011-04-22 09:04:29 +0000 differ
2672=== added file 'mixxx/res/skins/Outline1024x600-Netbook/vinyl-rel.png'
2673Binary files mixxx/res/skins/Outline1024x600-Netbook/vinyl-rel.png 1970-01-01 00:00:00 +0000 and mixxx/res/skins/Outline1024x600-Netbook/vinyl-rel.png 2011-04-22 09:04:29 +0000 differ
2674=== added file 'mixxx/res/skins/Outline1024x600-Netbook/vinyl-status-disabled.png'
2675Binary files mixxx/res/skins/Outline1024x600-Netbook/vinyl-status-disabled.png 1970-01-01 00:00:00 +0000 and mixxx/res/skins/Outline1024x600-Netbook/vinyl-status-disabled.png 2011-04-22 09:04:29 +0000 differ
2676=== added file 'mixxx/res/skins/Outline1024x600-Netbook/vinyl-status-green.png'
2677Binary files mixxx/res/skins/Outline1024x600-Netbook/vinyl-status-green.png 1970-01-01 00:00:00 +0000 and mixxx/res/skins/Outline1024x600-Netbook/vinyl-status-green.png 2011-04-22 09:04:29 +0000 differ
2678=== added file 'mixxx/res/skins/Outline1024x600-Netbook/vinyl-status-red.png'
2679Binary files mixxx/res/skins/Outline1024x600-Netbook/vinyl-status-red.png 1970-01-01 00:00:00 +0000 and mixxx/res/skins/Outline1024x600-Netbook/vinyl-status-red.png 2011-04-22 09:04:29 +0000 differ
2680=== added file 'mixxx/res/skins/Outline1024x600-Netbook/vinyl-status-yellow.png'
2681Binary files mixxx/res/skins/Outline1024x600-Netbook/vinyl-status-yellow.png 1970-01-01 00:00:00 +0000 and mixxx/res/skins/Outline1024x600-Netbook/vinyl-status-yellow.png 2011-04-22 09:04:29 +0000 differ
2682=== modified file 'mixxx/src/analyserwaveform.cpp'
2683--- mixxx/src/analyserwaveform.cpp 2011-03-12 20:57:10 +0000
2684+++ mixxx/src/analyserwaveform.cpp 2011-04-22 09:04:29 +0000
2685@@ -41,6 +41,7 @@
2686
2687 // Downsample from curSamples -> numDownsamples
2688
2689+ // TODO(XXX) leaked memory
2690 downsample = new QVector<float>(numDownsamples);
2691 downsampleVector = downsample->data();
2692 int i;
2693
2694=== modified file 'mixxx/src/audiotagger.cpp'
2695--- mixxx/src/audiotagger.cpp 2010-12-12 15:47:46 +0000
2696+++ mixxx/src/audiotagger.cpp 2011-04-22 09:04:29 +0000
2697@@ -21,7 +21,7 @@
2698 #include <taglib/wavfile.h>
2699 #include <taglib/textidentificationframe.h>
2700
2701-AudioTagger::AudioTagger (QString file)
2702+AudioTagger::AudioTagger (QString file)
2703 {
2704 m_artist = "";
2705 m_title = "";
2706@@ -36,8 +36,8 @@
2707 m_file = file;
2708 }
2709
2710-AudioTagger::~AudioTagger ( )
2711-{
2712+AudioTagger::~AudioTagger ( )
2713+{
2714
2715 }
2716
2717@@ -96,58 +96,58 @@
2718 {
2719 m_tracknumber = tracknumber;
2720 }
2721-void AudioTagger::save ()
2722+bool AudioTagger::save ()
2723 {
2724 TagLib::File* file = NULL;
2725-
2726+
2727 if(m_file.endsWith(".mp3", Qt::CaseInsensitive)){
2728 file = new TagLib::MPEG::File(m_file.toUtf8().constData());
2729 //process special ID3 fields, APEv2 fiels, etc
2730-
2731+
2732 //If the mp3 has no ID3v2 tag, we create a new one and add the TBPM and TKEY frame
2733 addID3v2Tag( ((TagLib::MPEG::File*) file)->ID3v2Tag(true) );
2734- //If the mp3 has an APE tag, we update
2735+ //If the mp3 has an APE tag, we update
2736 addAPETag( ((TagLib::MPEG::File*) file)->APETag(false) );
2737-
2738+
2739 }
2740 if(m_file.endsWith(".m4a", Qt::CaseInsensitive)){
2741 file = new TagLib::MP4::File(m_file.toUtf8().constData());
2742 //process special ID3 fields, APEv2 fiels, etc
2743 processMP4Tag(((TagLib::MP4::File*) file)->tag());
2744-
2745+
2746 }
2747 if(m_file.endsWith(".ogg", Qt::CaseInsensitive)){
2748 file = new TagLib::Ogg::Vorbis::File(m_file.toUtf8().constData());
2749 //process special ID3 fields, APEv2 fiels, etc
2750 addXiphComment( ((TagLib::Ogg::Vorbis::File*) file)->tag() );
2751-
2752+
2753 }
2754 if(m_file.endsWith(".wav", Qt::CaseInsensitive)){
2755 file = new TagLib::RIFF::WAV::File(m_file.toUtf8().constData());
2756 //If the flac has no ID3v2 tag, we create a new one and add the TBPM and TKEY frame
2757 addID3v2Tag( ((TagLib::RIFF::WAV::File*) file)->tag() );
2758-
2759+
2760 }
2761 if(m_file.endsWith(".flac", Qt::CaseInsensitive)){
2762 file = new TagLib::FLAC::File(m_file.toUtf8().constData());
2763-
2764+
2765 //If the flac has no ID3v2 tag, we create a new one and add the TBPM and TKEY frame
2766 addID3v2Tag( ((TagLib::FLAC::File*) file)->ID3v2Tag(true) );
2767 //If the flac has no APE tag, we create a new one and add the TBPM and TKEY frame
2768 addXiphComment( ((TagLib::FLAC::File*) file)->xiphComment (true) );
2769-
2770+
2771 }
2772 if(m_file.endsWith(".aif", Qt::CaseInsensitive) || m_file.endsWith(".aiff", Qt::CaseInsensitive)){
2773 file = new TagLib::RIFF::AIFF::File(m_file.toUtf8().constData());
2774 //If the flac has no ID3v2 tag, we create a new one and add the TBPM and TKEY frame
2775 addID3v2Tag( ((TagLib::RIFF::AIFF::File*) file)->tag() );
2776-
2777+
2778 }
2779-
2780+
2781 //process standard tags
2782 if(file){
2783 TagLib::Tag *tag = file->tag();
2784- if (tag)
2785+ if (tag)
2786 {
2787 tag->setArtist(m_artist.toStdString());
2788 tag->setTitle(m_title.toStdString());
2789@@ -155,58 +155,65 @@
2790 tag->setGenre(m_genre.toStdString());
2791 tag->setComment(m_comment.toStdString());
2792 uint year = m_year.toUInt();
2793- if(year > 0)
2794+ if(year > 0)
2795 tag->setYear(year);
2796 uint tracknumber = m_tracknumber.toUInt();
2797 if(tracknumber > 0)
2798 tag->setTrack(tracknumber);
2799-
2800+
2801 }
2802 //write audio tags to file
2803- if(file->save())
2804+ int success = file->save();
2805+ if (success) {
2806 qDebug() << "Successfully updated metadata of track " << m_file;
2807- else
2808+ } else {
2809 qDebug() << "Could not update metadata of track " << m_file;
2810+ }
2811+ //delete file and return
2812 delete file;
2813- }
2814-
2815-
2816+ return success;
2817+ }
2818+ else{
2819+ return false;
2820+ }
2821+
2822+
2823 }
2824 void AudioTagger::addID3v2Tag(TagLib::ID3v2::Tag* id3v2)
2825 {
2826 if(!id3v2) return;
2827-
2828+
2829 TagLib::ID3v2::FrameList bpmFrame = id3v2->frameListMap()["TBPM"];
2830- if (!bpmFrame.isEmpty())
2831+ if (!bpmFrame.isEmpty())
2832 {
2833 bpmFrame.front()->setText(m_bpm.toStdString());
2834-
2835+
2836 }
2837 else
2838 {
2839- /*
2840+ /*
2841 * add new frame TextIdentificationFrame which is responsible for TKEY and TBPM
2842 * see http://developer.kde.org/~wheeler/taglib/api/classTagLib_1_1ID3v2_1_1TextIdentificationFrame.html
2843 */
2844-
2845+
2846 TagLib::ID3v2::TextIdentificationFrame* newFrame = new TagLib::ID3v2::TextIdentificationFrame("TBPM", TagLib::String::Latin1);
2847-
2848+
2849 newFrame->setText(m_bpm.toStdString());
2850 id3v2->addFrame(newFrame);
2851
2852 }
2853
2854 TagLib::ID3v2::FrameList keyFrame = id3v2->frameListMap()["TKEY"];
2855- if (!keyFrame.isEmpty())
2856+ if (!keyFrame.isEmpty())
2857 {
2858 keyFrame.front()->setText(m_key.toStdString());
2859-
2860+
2861 }
2862 else
2863 {
2864 //add new frame
2865 TagLib::ID3v2::TextIdentificationFrame* newFrame = new TagLib::ID3v2::TextIdentificationFrame("TKEY", TagLib::String::Latin1);
2866-
2867+
2868 newFrame->setText(m_key.toStdString());
2869 id3v2->addFrame(newFrame);
2870
2871@@ -217,12 +224,12 @@
2872 {
2873 if(!ape) return;
2874 /*
2875- * Adds to the item specified by key the data value.
2876- * If replace is true, then all of the other values on the same key will be removed first.
2877+ * Adds to the item specified by key the data value.
2878+ * If replace is true, then all of the other values on the same key will be removed first.
2879 */
2880 ape->addValue("BPM",m_bpm.toStdString(), true);
2881 ape->addValue("BPM",m_bpm.toStdString(), true);
2882-
2883+
2884
2885 }
2886 void AudioTagger::addXiphComment(TagLib::Ogg::XiphComment* xiph)
2887@@ -230,21 +237,21 @@
2888 if(!xiph) return;
2889
2890 // Some tools use "BPM" so check for that.
2891-
2892+
2893 /* Taglib does not support the update of Vorbis comments.
2894 * thus, we have to reomve the old comment and add the new one
2895 */
2896- xiph->removeField("BPM");
2897+ xiph->removeField("BPM");
2898 xiph->addField("BPM", m_bpm.toStdString());
2899
2900- xiph->removeField("TEMPO");
2901- xiph->addField("TEMPO", m_bpm.toStdString());
2902-
2903- xiph->removeField("INITIALKEY");
2904- xiph->addField("INITIALKEY", m_key.toStdString());
2905- xiph->removeField("KEY");
2906- xiph->addField("KEY", m_key.toStdString());
2907-
2908+ xiph->removeField("TEMPO");
2909+ xiph->addField("TEMPO", m_bpm.toStdString());
2910+
2911+ xiph->removeField("INITIALKEY");
2912+ xiph->addField("INITIALKEY", m_key.toStdString());
2913+ xiph->removeField("KEY");
2914+ xiph->addField("KEY", m_key.toStdString());
2915+
2916 }
2917 void AudioTagger::processMP4Tag(TagLib::MP4::Tag* mp4)
2918 {
2919
2920=== modified file 'mixxx/src/audiotagger.h'
2921--- mixxx/src/audiotagger.h 2010-10-31 15:34:20 +0000
2922+++ mixxx/src/audiotagger.h 2011-04-22 09:04:29 +0000
2923@@ -14,7 +14,7 @@
2924 {
2925 public:
2926
2927-
2928+
2929 AudioTagger (QString file);
2930 virtual ~AudioTagger ( );
2931 void setArtist (QString artist );
2932@@ -26,8 +26,8 @@
2933 void setKey (QString key );
2934 void setBpm (QString bpm );
2935 void setTracknumber (QString tracknumber );
2936- void save ();
2937-
2938+ bool save();
2939+
2940
2941 private:
2942 QString m_artist;
2943
2944=== modified file 'mixxx/src/basetrackplayer.cpp'
2945--- mixxx/src/basetrackplayer.cpp 2011-03-29 08:45:42 +0000
2946+++ mixxx/src/basetrackplayer.cpp 2011-04-22 09:04:29 +0000
2947@@ -8,6 +8,7 @@
2948 #include "controlobject.h"
2949 #include "trackinfoobject.h"
2950 #include "engine/enginebuffer.h"
2951+#include "engine/enginedeck.h"
2952 #include "engine/enginemaster.h"
2953 #include "soundsourceproxy.h"
2954 #include "engine/cuecontrol.h"
2955@@ -29,8 +30,8 @@
2956 // pSafeGroupName is leaked. It's like 5 bytes so whatever.
2957 const char* pSafeGroupName = strdup(getGroup().toAscii().constData());
2958
2959- EngineChannel* pChannel = new EngineChannel(pSafeGroupName,
2960- pConfig, defaultOrientation);
2961+ EngineDeck* pChannel = new EngineDeck(pSafeGroupName,
2962+ pConfig, defaultOrientation);
2963 EngineBuffer* pEngineBuffer = pChannel->getEngineBuffer();
2964 pMixingEngine->addChannel(pChannel);
2965
2966@@ -68,7 +69,7 @@
2967 m_pPlayPosition = new ControlObjectThreadMain(
2968 ControlObject::getControl(ConfigKey(getGroup(), "playposition")));
2969
2970- //Duration of the current song, we create this one because nothing else does.
2971+ // Duration of the current song, we create this one because nothing else does.
2972 m_pDuration = new ControlObject(ConfigKey(getGroup(), "duration"));
2973
2974 //BPM of the current song
2975@@ -102,6 +103,7 @@
2976 delete m_pBPM;
2977 delete m_pReplayGain;
2978 delete m_pWaveformRenderer;
2979+ delete m_pDuration;
2980 }
2981
2982 void BaseTrackPlayer::slotLoadTrack(TrackPointer track, bool bStartFromEndPos)
2983
2984=== modified file 'mixxx/src/cachingreader.cpp'
2985--- mixxx/src/cachingreader.cpp 2010-10-23 08:41:23 +0000
2986+++ mixxx/src/cachingreader.cpp 2011-04-22 09:04:29 +0000
2987@@ -296,8 +296,9 @@
2988 }
2989
2990 int CachingReader::read(int sample, int num_samples, CSAMPLE* buffer) {
2991+ int zerosWritten = 0;
2992 // Check for bogus sample numbers
2993- Q_ASSERT(sample >= 0);
2994+ //Q_ASSERT(sample >= 0);
2995 Q_ASSERT(sample % 2 == 0);
2996 Q_ASSERT(num_samples >= 0);
2997
2998@@ -309,6 +310,27 @@
2999 return 0;
3000 }
3001
3002+ // TODO: is it possible to move this code out of caching reader
3003+ // and into enginebuffer? It doesn't quite make sense here, although
3004+ // it makes preroll completely transparent to the rest of the code
3005+
3006+ //if we're in preroll...
3007+ if (sample < 0) {
3008+ if (sample + num_samples <= 0) {
3009+ //everything is zeros, easy
3010+ memset(buffer, 0, sizeof(*buffer) * num_samples);
3011+ return num_samples;
3012+ } else {
3013+ //some of the buffer is zeros, some is from the file
3014+ memset(buffer, 0, sizeof(*buffer) * (0 - sample));
3015+ buffer += (0 - sample);
3016+ num_samples = sample + num_samples;
3017+ zerosWritten = (0 - sample);
3018+ sample = 0;
3019+ //continue processing the rest of the chunks normally
3020+ }
3021+ }
3022+
3023 int start_chunk = chunkForSample(sample);
3024 int end_chunk = chunkForSample(sample + num_samples - 1);
3025
3026@@ -400,7 +422,7 @@
3027 samples_remaining = 0;
3028
3029 Q_ASSERT(samples_remaining == 0);
3030- return num_samples - samples_remaining;
3031+ return zerosWritten + num_samples - samples_remaining;
3032 }
3033
3034 void CachingReader::hint(Hint& hint) {
3035@@ -448,7 +470,7 @@
3036 hint.sample = 0;
3037 }
3038 }
3039- Q_ASSERT(hint.sample >= 0);
3040+ //Q_ASSERT(hint.sample >= 0);
3041 Q_ASSERT(hint.length >= 0);
3042 int start_chunk = chunkForSample(hint.sample);
3043 int end_chunk = chunkForSample(hint.sample + hint.length);
3044
3045=== added file 'mixxx/src/circularbuffer.h'
3046--- mixxx/src/circularbuffer.h 1970-01-01 00:00:00 +0000
3047+++ mixxx/src/circularbuffer.h 2011-04-22 09:04:29 +0000
3048@@ -0,0 +1,97 @@
3049+#ifndef CIRCULARBUFFER_H
3050+#define CIRCULARBUFFER_H
3051+
3052+#include <stdlib.h>
3053+
3054+// CircularBuffer is a basic implementation of a constant-length circular
3055+// buffer.
3056+//
3057+// WARNING: CircularBuffer IS NOT THREAD SAFE! It is "sort of" thread safe on
3058+// platforms with atomic writes and aligned memory locations, but it is most
3059+// definitely not safe on x86 without memory barriers that could re-order reads
3060+// and writes.
3061+template <typename T>
3062+class CircularBuffer {
3063+ public:
3064+ CircularBuffer(unsigned int iLength)
3065+ : m_iLength(iLength),
3066+ m_pBuffer(new T[m_iLength]),
3067+ m_iWritePos(0),
3068+ m_iReadPos(0) {
3069+ // No need to clear the buffer because we consider it to be empty right
3070+ // now.
3071+ }
3072+
3073+ virtual ~CircularBuffer() {
3074+ delete [] m_pBuffer;
3075+ m_pBuffer = NULL;
3076+ }
3077+
3078+ // Returns true if the buffer is full
3079+ inline bool isFull() const {
3080+ return (m_iWritePos + 1) % m_iLength == m_iReadPos;
3081+ }
3082+
3083+ // Returns true if the buffer is empty.
3084+ inline bool isEmpty() const {
3085+ return m_iReadPos == m_iWritePos;
3086+ }
3087+
3088+ inline void clear() {
3089+ m_iReadPos = 0;
3090+ m_iWritePos = 0;
3091+ }
3092+
3093+ // Returns the total capacity of the CircularBuffer in units of T
3094+ inline unsigned int length() const {
3095+ return m_iLength;
3096+ }
3097+
3098+ // Write numItems into the CircularBuffer. Returns the total number of
3099+ // items written, which could be less than numItems if the buffer becomes
3100+ // full.
3101+ unsigned int write(const T* pBuffer, const unsigned int numItems) {
3102+ if (m_pBuffer == NULL)
3103+ return 0;
3104+
3105+ unsigned int itemsWritten = 0;
3106+ while (!isFull() && itemsWritten < numItems) {
3107+ m_pBuffer[m_iWritePos++] = pBuffer[itemsWritten++];
3108+ m_iWritePos %= m_iLength;
3109+ }
3110+ return itemsWritten;
3111+ }
3112+
3113+ // Read itemsToRead into pBuffer. Returns the total number of items read,
3114+ // which may be less than itemsToRead if the buffer becomes empty.
3115+ unsigned int read(T* pBuffer, const unsigned int itemsToRead) {
3116+ if (m_pBuffer == NULL)
3117+ return 0;
3118+
3119+ unsigned int itemsRead = 0;
3120+ while (!isEmpty() && itemsRead < itemsToRead) {
3121+ pBuffer[itemsRead++] = m_pBuffer[m_iReadPos++];
3122+ m_iReadPos %= m_iLength;
3123+ }
3124+ return itemsRead;
3125+ }
3126+
3127+ unsigned int skip(const unsigned int itemsToRead) {
3128+ if (m_pBuffer == NULL)
3129+ return 0;
3130+ unsigned int itemsRead = 0;
3131+ while (!isEmpty() && itemsRead < itemsToRead) {
3132+ m_iReadPos = (m_iReadPos + 1) % m_iLength;
3133+ itemsRead++;
3134+ }
3135+ return itemsRead;
3136+ }
3137+
3138+ private:
3139+ const unsigned int m_iLength;
3140+ T* m_pBuffer;
3141+ unsigned int m_iWritePos;
3142+ unsigned int m_iReadPos;
3143+};
3144+
3145+#endif /* CIRCULARBUFFER_H */
3146
3147=== modified file 'mixxx/src/configobject.cpp'
3148--- mixxx/src/configobject.cpp 2010-10-07 03:05:48 +0000
3149+++ mixxx/src/configobject.cpp 2011-04-22 09:04:29 +0000
3150@@ -117,6 +117,10 @@
3151
3152 template <class ValueType> ConfigObject<ValueType>::~ConfigObject()
3153 {
3154+ while (list.size() > 0) {
3155+ ConfigOption<ValueType>* pConfigOption = list.takeLast();
3156+ delete pConfigOption;
3157+ }
3158 }
3159
3160 template <class ValueType>
3161
3162=== modified file 'mixxx/src/configobject.h'
3163--- mixxx/src/configobject.h 2010-06-22 18:39:04 +0000
3164+++ mixxx/src/configobject.h 2011-04-22 09:04:29 +0000
3165@@ -93,21 +93,24 @@
3166 template <class ValueType> class ConfigOption
3167 {
3168 public:
3169- ConfigOption() {};
3170+ ConfigOption() { val = NULL; key = NULL;};
3171 ConfigOption(ConfigKey *_key, ValueType *_val) { key = _key ; val = _val; };
3172+ virtual ~ConfigOption() {
3173+ delete key;
3174+ delete val;
3175+ }
3176 ValueType *val;
3177 ConfigKey *key;
3178 };
3179
3180-template <class ValueType> class ConfigObject
3181-{
3182+template <class ValueType> class ConfigObject {
3183 public:
3184 ConfigKey key;
3185 ValueType value;
3186 ConfigOption<ValueType> option;
3187
3188 ConfigObject(QString file);
3189- ConfigObject(QDomNode node);
3190+ ConfigObject(QDomNode node);
3191 ~ConfigObject();
3192 ConfigOption<ValueType> *set(ConfigKey, ValueType);
3193 ConfigOption<ValueType> *get(ConfigKey key);
3194
3195=== modified file 'mixxx/src/controllogpotmeter.cpp'
3196--- mixxx/src/controllogpotmeter.cpp 2009-08-29 20:15:00 +0000
3197+++ mixxx/src/controllogpotmeter.cpp 2011-04-22 09:04:29 +0000
3198@@ -18,6 +18,11 @@
3199 #include <math.h>
3200 #include "controllogpotmeter.h"
3201
3202+#define maxPosition 127
3203+#define minPosition 0
3204+#define middlePosition ((maxPosition-minPosition)/2)
3205+#define positionrange (maxPosition-minPosition)
3206+
3207 /* -------- ------------------------------------------------------
3208 Purpose: Creates a new logarithmic potmeter, where the value is
3209 given by:
3210
3211=== modified file 'mixxx/src/controlobject.cpp'
3212--- mixxx/src/controlobject.cpp 2010-10-23 08:41:23 +0000
3213+++ mixxx/src/controlobject.cpp 2011-04-22 09:04:29 +0000
3214@@ -156,6 +156,15 @@
3215 return bUpdateSuccess;
3216 }
3217
3218+void ControlObject::getControls(QList<ControlObject*>* pControlList) {
3219+ m_sqCOHashMutex.lock();
3220+ for (QHash<ConfigKey, ControlObject*>::const_iterator it = m_sqCOHash.constBegin();
3221+ it != m_sqCOHash.constEnd(); ++it) {
3222+ pControlList->push_back(it.value());
3223+ }
3224+ m_sqCOHashMutex.unlock();
3225+}
3226+
3227 ControlObject * ControlObject::getControl(ConfigKey key)
3228 {
3229 //qDebug() << "ControlObject::getControl for (" << key.group << "," << key.item << ")";
3230@@ -284,8 +293,11 @@
3231 {
3232 obj = m_sqQueueThread.dequeue();
3233
3234- obj->pControlObject->setValueFromThread(obj->value);
3235- obj->pControlObject->updateProxies(obj->pControlObjectThread);
3236+ if (obj->pControlObject)
3237+ {
3238+ obj->pControlObject->setValueFromThread(obj->value);
3239+ obj->pControlObject->updateProxies(obj->pControlObjectThread);
3240+ }
3241 delete obj;
3242 }
3243
3244
3245=== modified file 'mixxx/src/controlobject.h'
3246--- mixxx/src/controlobject.h 2010-10-07 03:05:48 +0000
3247+++ mixxx/src/controlobject.h 2011-04-22 09:04:29 +0000
3248@@ -68,6 +68,10 @@
3249 static bool disconnectControl(ConfigKey key);
3250 /** Returns a pointer to the ControlObject matching the given ConfigKey */
3251 static ControlObject *getControl(ConfigKey key);
3252+
3253+ // Adds all ControlObjects that currently exist to pControlList
3254+ static void getControls(QList<ControlObject*>* pControlsList);
3255+
3256 /** Used to add a pointer to the corresponding ControlObjectThread of this ControlObject */
3257 void addProxy(ControlObjectThread *pControlObjectThread);
3258 // To get rid of a proxy when the corresponding object is being deleted for example
3259
3260=== modified file 'mixxx/src/controlobjectthread.cpp'
3261--- mixxx/src/controlobjectthread.cpp 2010-10-07 03:05:48 +0000
3262+++ mixxx/src/controlobjectthread.cpp 2011-04-22 09:04:29 +0000
3263@@ -24,10 +24,10 @@
3264 QMutex ControlObjectThread::m_sqMutex;
3265 QQueue<ControlObjectThread*> ControlObjectThread::m_sqQueue;
3266
3267-ControlObjectThread::ControlObjectThread(ControlObject * pControlObject)
3268-: m_dValue (0.0)
3269-, m_pControlObject (pControlObject)
3270-{
3271+ControlObjectThread::ControlObjectThread(ControlObject* pControlObject, QObject* pParent)
3272+ : QObject(pParent),
3273+ m_dValue(0.0)
3274+ , m_pControlObject(pControlObject) {
3275 // Update associated ControlObject
3276 if (m_pControlObject == NULL) return;
3277 Q_ASSERT(m_pControlObject);
3278
3279=== modified file 'mixxx/src/controlobjectthread.h'
3280--- mixxx/src/controlobjectthread.h 2010-06-22 18:39:04 +0000
3281+++ mixxx/src/controlobjectthread.h 2011-04-22 09:04:29 +0000
3282@@ -40,7 +40,7 @@
3283 {
3284 Q_OBJECT
3285 public:
3286- ControlObjectThread(ControlObject *pControlObject);
3287+ ControlObjectThread(ControlObject *pControlObject, QObject* pParent=NULL);
3288 virtual ~ControlObjectThread();
3289 /** Returns the value of the object */
3290 double get();
3291
3292=== modified file 'mixxx/src/controlobjectthreadmain.cpp'
3293--- mixxx/src/controlobjectthreadmain.cpp 2009-02-26 00:19:05 +0000
3294+++ mixxx/src/controlobjectthreadmain.cpp 2011-04-22 09:04:29 +0000
3295@@ -10,7 +10,7 @@
3296 //
3297 //
3298
3299-#include <qapplication.h>
3300+#include <QApplication>
3301 #include <QtDebug>
3302 //Added by qt3to4:
3303 #include <QEvent>
3304@@ -18,14 +18,13 @@
3305 #include "controlobject.h"
3306 #include "controlevent.h"
3307
3308-ControlObjectThreadMain::ControlObjectThreadMain(ControlObject * pControlObject) : ControlObjectThread(pControlObject)
3309-{
3310+ControlObjectThreadMain::ControlObjectThreadMain(ControlObject * pControlObject, QObject* pParent)
3311+ : ControlObjectThread(pControlObject, pParent) {
3312 setObjectName("ControlObjectThreadMain");
3313 installEventFilter(this);
3314 }
3315
3316-ControlObjectThreadMain::~ControlObjectThreadMain()
3317-{
3318+ControlObjectThreadMain::~ControlObjectThreadMain() {
3319 }
3320
3321 bool ControlObjectThreadMain::eventFilter(QObject * o, QEvent * e)
3322
3323=== modified file 'mixxx/src/controlobjectthreadmain.h'
3324--- mixxx/src/controlobjectthreadmain.h 2007-07-16 01:21:42 +0000
3325+++ mixxx/src/controlobjectthreadmain.h 2011-04-22 09:04:29 +0000
3326@@ -1,7 +1,7 @@
3327 //
3328 // C++ Interface: controlobjecthreadmain.h
3329 //
3330-// Description:
3331+// Description:
3332 //
3333 //
3334 // Author: Tue Haste Andersen <haste@diku.dk>, (C) 2004
3335@@ -26,8 +26,8 @@
3336 {
3337 Q_OBJECT
3338 public:
3339- ControlObjectThreadMain(ControlObject *pControlObject);
3340- ~ControlObjectThreadMain();
3341+ ControlObjectThreadMain(ControlObject *pControlObject, QObject* pParent=NULL);
3342+ virtual ~ControlObjectThreadMain();
3343 /** Event filter */
3344 bool eventFilter(QObject *o, QEvent *e);
3345 /** Notify this object through events */
3346
3347=== modified file 'mixxx/src/controlobjectthreadwidget.cpp'
3348--- mixxx/src/controlobjectthreadwidget.cpp 2011-03-30 05:02:25 +0000
3349+++ mixxx/src/controlobjectthreadwidget.cpp 2011-04-22 09:04:29 +0000
3350@@ -15,15 +15,14 @@
3351 #include "controlobject.h"
3352 #include "controlevent.h"
3353
3354-ControlObjectThreadWidget::ControlObjectThreadWidget(ControlObject * pControlObject) : ControlObjectThreadMain(pControlObject)
3355-{
3356+ControlObjectThreadWidget::ControlObjectThreadWidget(ControlObject * pControlObject, QObject* pParent)
3357+ : ControlObjectThreadMain(pControlObject, pParent) {
3358 // Initialize value
3359 m_dValue = m_pControlObject->getValueToWidget(m_pControlObject->get());
3360 emitValueChanged();
3361 }
3362
3363-ControlObjectThreadWidget::~ControlObjectThreadWidget()
3364-{
3365+ControlObjectThreadWidget::~ControlObjectThreadWidget() {
3366 }
3367
3368 void ControlObjectThreadWidget::setWidget(QWidget * widget, bool connectValueFromWidget,
3369
3370=== modified file 'mixxx/src/controlobjectthreadwidget.h'
3371--- mixxx/src/controlobjectthreadwidget.h 2011-03-30 05:02:25 +0000
3372+++ mixxx/src/controlobjectthreadwidget.h 2011-04-22 09:04:29 +0000
3373@@ -34,8 +34,8 @@
3374 EMIT_ON_PRESS_AND_RELEASE = 0x03
3375 };
3376
3377- ControlObjectThreadWidget(ControlObject *pControlObject);
3378- ~ControlObjectThreadWidget();
3379+ ControlObjectThreadWidget(ControlObject *pControlObject, QObject* pParent=NULL);
3380+ virtual ~ControlObjectThreadWidget();
3381 /** Associates a QWidget with the ControlObject. */
3382 void setWidget(QWidget *widget,
3383 bool connectValueFromWidget=true, bool connectValueToWidget = true,
3384
3385=== modified file 'mixxx/src/controlpotmeter.cpp'
3386--- mixxx/src/controlpotmeter.cpp 2011-03-27 02:17:14 +0000
3387+++ mixxx/src/controlpotmeter.cpp 2011-04-22 09:04:29 +0000
3388@@ -34,18 +34,22 @@
3389 setSmallStep(m_dValueRange/100.f);
3390
3391 ControlPushButton * p;
3392- p = new ControlPushButton(ConfigKey(key.group, QString(key.item)+"_up"));
3393- connect(p, SIGNAL(valueChanged(double)), this, SLOT(incValue(double)));
3394- p = new ControlPushButton(ConfigKey(key.group, QString(key.item)+"_down"));
3395- connect(p, SIGNAL(valueChanged(double)), this, SLOT(decValue(double)));
3396- p = new ControlPushButton(ConfigKey(key.group, QString(key.item)+"_up_small"));
3397- connect(p, SIGNAL(valueChanged(double)), this, SLOT(incSmallValue(double)));
3398- p = new ControlPushButton(ConfigKey(key.group, QString(key.item)+"_down_small"));
3399- connect(p, SIGNAL(valueChanged(double)), this, SLOT(decSmallValue(double)));
3400+ m_pControlUp = new ControlPushButton(ConfigKey(key.group, QString(key.item)+"_up"));
3401+ connect(m_pControlUp, SIGNAL(valueChanged(double)), this, SLOT(incValue(double)));
3402+ m_pControlDown = new ControlPushButton(ConfigKey(key.group, QString(key.item)+"_down"));
3403+ connect(m_pControlDown, SIGNAL(valueChanged(double)), this, SLOT(decValue(double)));
3404+ m_pControlUpSmall = new ControlPushButton(ConfigKey(key.group, QString(key.item)+"_up_small"));
3405+ connect(m_pControlUpSmall, SIGNAL(valueChanged(double)), this, SLOT(incSmallValue(double)));
3406+ m_pControlDownSmall = new ControlPushButton(ConfigKey(key.group, QString(key.item)+"_down_small"));
3407+ connect(m_pControlDownSmall, SIGNAL(valueChanged(double)), this, SLOT(decSmallValue(double)));
3408 }
3409
3410 ControlPotmeter::~ControlPotmeter()
3411 {
3412+ delete m_pControlUp;
3413+ delete m_pControlDown;
3414+ delete m_pControlUpSmall;
3415+ delete m_pControlDownSmall;
3416 }
3417
3418 double ControlPotmeter::getMin()
3419
3420=== modified file 'mixxx/src/controlpotmeter.h'
3421--- mixxx/src/controlpotmeter.h 2011-03-25 19:33:44 +0000
3422+++ mixxx/src/controlpotmeter.h 2011-04-22 09:04:29 +0000
3423@@ -3,7 +3,7 @@
3424 -------------------
3425 begin : Wed Feb 20 2002
3426 copyright : (C) 2002 by Tue and Ken Haste Andersen
3427- email :
3428+ email :
3429 ***************************************************************************/
3430
3431 /***************************************************************************
3432@@ -26,6 +26,8 @@
3433 *@author Tue and Ken Haste Andersen
3434 */
3435
3436+class ControlPushButton;
3437+
3438 class ControlPotmeter : public ControlObject
3439 {
3440 Q_OBJECT
3441@@ -46,7 +48,7 @@
3442 double getValueFromWidget(double dValue);
3443 double getValueToWidget(double dValue);
3444 double GetMidiValue();
3445-
3446+
3447 public slots:
3448 void setValueFromThread(double dValue);
3449 void setValueFromEngine(double dValue);
3450@@ -61,14 +63,13 @@
3451
3452 protected:
3453 void setValueFromMidi(MidiCategory c, double v);
3454-
3455+
3456 double m_dMaxValue, m_dMinValue, m_dValueRange, m_dStep, m_dSmallStep;
3457
3458-#define maxPosition 127
3459-#define minPosition 0
3460-#define middlePosition ((maxPosition-minPosition)/2)
3461-#define positionrange (maxPosition-minPosition)
3462-
3463+ ControlPushButton* m_pControlUp;
3464+ ControlPushButton* m_pControlDown;
3465+ ControlPushButton* m_pControlUpSmall;
3466+ ControlPushButton* m_pControlDownSmall;
3467 };
3468
3469 #endif
3470
3471=== modified file 'mixxx/src/controlpushbutton.cpp'
3472--- mixxx/src/controlpushbutton.cpp 2010-09-17 02:20:29 +0000
3473+++ mixxx/src/controlpushbutton.cpp 2011-04-22 09:04:29 +0000
3474@@ -24,6 +24,7 @@
3475 ControlPushButton::ControlPushButton(ConfigKey key) :
3476 ControlObject(key, false) {
3477 m_bIsToggleButton = false;
3478+ m_iNoStates = 2;
3479 }
3480
3481 ControlPushButton::~ControlPushButton()
3482@@ -37,6 +38,11 @@
3483 m_bIsToggleButton = bIsToggleButton;
3484 }
3485
3486+void ControlPushButton::setStates(int num_states)
3487+{
3488+ m_iNoStates = num_states;
3489+}
3490+
3491 void ControlPushButton::setValueFromMidi(MidiCategory c, double v)
3492 {
3493 //if (m_bMidiSimulateLatching)
3494@@ -44,55 +50,30 @@
3495 //qDebug() << "bMidiSimulateLatching is true!";
3496 // Only react on NOTE_ON midi events if simulating latching...
3497
3498+ //qDebug() << c << v;
3499
3500- if (m_bIsToggleButton) //This block makes push-buttons act as toggle buttons.
3501- {
3502- //qDebug() << "Is a toggle button!";
3503- if (c==NOTE_ON && v>0.) //Only react to "NOTE_ON" midi events.
3504- {
3505- //qDebug() << "NOTE_ON caught!";
3506- if (m_dValue==0.)
3507- m_dValue = 1.;
3508- else
3509- m_dValue = 0.;
3510+ if (m_bIsToggleButton) { //This block makes push-buttons act as toggle buttons.
3511+ if (m_iNoStates > 2) { //multistate button
3512+ if (v > 0.) { //looking for NOTE_ON doesn't seem to work...
3513+ m_dValue++;
3514+ if (m_dValue >= m_iNoStates)
3515+ m_dValue = 0;
3516+ }
3517+ } else {
3518+ if (c == NOTE_ON) {
3519+ if (v > 0.) {
3520+ m_dValue = !m_dValue;
3521+ }
3522+ }
3523 }
3524- }
3525- else //Not a toggle button (trigger only when button pushed)
3526- {
3527- //qDebug() << "Is NOT a toggle button!";
3528- if (c == NOTE_ON)
3529+ } else { //Not a toggle button (trigger only when button pushed)
3530+ if (c == NOTE_ON) {
3531 m_dValue = v;
3532- else if (c == NOTE_OFF)
3533+ } else if (c == NOTE_OFF) {
3534 m_dValue = 0.0;
3535- }
3536- if (c==NOTE_OFF)
3537- {
3538-
3539- //qDebug() << "NOTE_OFF caught!";
3540- }
3541-
3542-
3543-/* else
3544- {
3545- qDebug() << "bMidiSimulateLatching is false!";
3546- qDebug() << "m_dValue is: " << m_dValue << ", v is: " << v;
3547-
3548- if (v==0.)
3549- m_dValue = 0.;
3550- else
3551- m_dValue = 1.;
3552-
3553- }
3554- */
3555-/*
3556- if (v>0.)
3557- {
3558- if (m_dValue==0.)
3559- m_dValue = 1.;
3560- else
3561- m_dValue = 0.;
3562 }
3563- */
3564+ }
3565+
3566 emit(valueChanged(m_dValue));
3567 }
3568
3569
3570=== modified file 'mixxx/src/controlpushbutton.h'
3571--- mixxx/src/controlpushbutton.h 2010-10-07 03:05:48 +0000
3572+++ mixxx/src/controlpushbutton.h 2011-04-22 09:04:29 +0000
3573@@ -32,12 +32,14 @@
3574 ControlPushButton(ConfigKey key);
3575 ~ControlPushButton();
3576 void setToggleButton(bool bIsToggleButton);
3577+ void setStates(int num_states);
3578
3579 protected:
3580 void setValueFromMidi(MidiCategory c, double v);
3581
3582 private:
3583 bool m_bIsToggleButton;
3584+ int m_iNoStates;
3585 };
3586
3587 #endif
3588
3589=== modified file 'mixxx/src/controlvaluedelegate.cpp'
3590--- mixxx/src/controlvaluedelegate.cpp 2010-11-19 11:03:20 +0000
3591+++ mixxx/src/controlvaluedelegate.cpp 2011-04-22 09:04:29 +0000
3592@@ -55,6 +55,9 @@
3593 m_channelControlValues.append("volume");
3594 m_channelControlValues.append("wheel");
3595 m_channelControlValues.append("jog");
3596+ m_channelControlValues.append("vinylcontrol_enabled");
3597+ m_channelControlValues.append("vinylcontrol_mode");
3598+ m_channelControlValues.append("vinylcontrol_cueing");
3599 m_channelControlValues.append("loop_in");
3600 m_channelControlValues.append("loop_out");
3601 m_channelControlValues.append("reloop_exit");
3602
3603=== modified file 'mixxx/src/dlgautodj.cpp'
3604--- mixxx/src/dlgautodj.cpp 2011-03-22 16:24:04 +0000
3605+++ mixxx/src/dlgautodj.cpp 2011-04-22 09:04:29 +0000
3606@@ -9,7 +9,8 @@
3607 #include "dlgautodj.h"
3608
3609
3610-DlgAutoDJ::DlgAutoDJ(QWidget* parent, ConfigObject<ConfigValue>* pConfig, TrackCollection* pTrackCollection)
3611+DlgAutoDJ::DlgAutoDJ(QWidget* parent, ConfigObject<ConfigValue>* pConfig,
3612+ TrackCollection* pTrackCollection, MixxxKeyboard* pKeyboard)
3613 : QWidget(parent), Ui::DlgAutoDJ(), m_playlistDao(pTrackCollection->getPlaylistDAO())
3614 {
3615 setupUi(this);
3616@@ -20,7 +21,7 @@
3617 m_bPlayer1Primed = false;
3618 m_bPlayer2Primed = false;
3619 m_pTrackTableView = new WTrackTableView(this, pConfig, m_pTrackCollection);
3620-
3621+ m_pTrackTableView->installEventFilter(pKeyboard);
3622
3623 connect(m_pTrackTableView, SIGNAL(loadTrack(TrackPointer)),
3624 this, SIGNAL(loadTrack(TrackPointer)));
3625@@ -49,6 +50,9 @@
3626 m_pTrackTableView->sortByColumn(0, Qt::AscendingOrder);
3627 m_pTrackTableView->setSortingEnabled(false);
3628
3629+ connect(pushButtonShuffle, SIGNAL(clicked(bool)),
3630+ this, SLOT(shufflePlaylist(bool)));
3631+
3632 connect(pushButtonAutoDJ, SIGNAL(toggled(bool)),
3633 this, SLOT(toggleAutoDJ(bool))); _blah;
3634
3635@@ -70,6 +74,12 @@
3636
3637 DlgAutoDJ::~DlgAutoDJ()
3638 {
3639+ delete m_pCOPlayPos1;
3640+ delete m_pCOPlayPos2;
3641+ delete m_pCOPlay1;
3642+ delete m_pCOPlay2;
3643+ delete m_pCORepeat2;
3644+ delete m_pCOCrossfader;
3645 }
3646
3647 void DlgAutoDJ::onShow()
3648@@ -142,6 +152,15 @@
3649 m_pTrackTableView->moveSelection(delta);
3650 }
3651
3652+void DlgAutoDJ::shufflePlaylist(bool buttonChecked)
3653+{
3654+ Q_UNUSED(buttonChecked);
3655+ m_pTrackTableView->sortByColumn(0, Qt::AscendingOrder);
3656+ qDebug() << "Shuffling AutoDJ playlist";
3657+ m_pAutoDJTableModel->shuffleTracks(m_pAutoDJTableModel->index(0, 0));
3658+ qDebug() << "Shuffling done";
3659+}
3660+
3661 void DlgAutoDJ::toggleAutoDJ(bool toggle)
3662 {
3663 if (toggle) //Enable Auto DJ
3664
3665=== modified file 'mixxx/src/dlgautodj.h'
3666--- mixxx/src/dlgautodj.h 2011-03-22 16:24:04 +0000
3667+++ mixxx/src/dlgautodj.h 2011-04-22 09:04:29 +0000
3668@@ -8,6 +8,7 @@
3669 #include "library/dao/playlistdao.h"
3670 #include "library/libraryview.h"
3671 #include "library/trackcollection.h"
3672+#include "mixxxkeyboard.h"
3673
3674 class PlaylistTableModel;
3675 class WTrackTableView;
3676@@ -18,7 +19,8 @@
3677 class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public virtual LibraryView {
3678 Q_OBJECT
3679 public:
3680- DlgAutoDJ(QWidget *parent, ConfigObject<ConfigValue>* pConfig, TrackCollection* pTrackCollection);
3681+ DlgAutoDJ(QWidget *parent, ConfigObject<ConfigValue>* pConfig,
3682+ TrackCollection* pTrackCollection, MixxxKeyboard* pKeyboard);
3683 virtual ~DlgAutoDJ();
3684
3685 virtual void setup(QDomNode node);
3686@@ -31,6 +33,7 @@
3687 virtual void moveSelection(int delta);
3688
3689 public slots:
3690+ void shufflePlaylist(bool buttonChecked);
3691 void toggleAutoDJ(bool toggle);
3692 void player1PositionChanged(double value);
3693 void player2PositionChanged(double value);
3694
3695=== modified file 'mixxx/src/dlgautodj.ui'
3696--- mixxx/src/dlgautodj.ui 2010-06-17 20:27:12 +0000
3697+++ mixxx/src/dlgautodj.ui 2011-04-22 09:04:29 +0000
3698@@ -26,6 +26,16 @@
3699 <item>
3700 <layout class="QHBoxLayout" name="horizontalLayout">
3701 <item>
3702+ <widget class="QPushButton" name="pushButtonShuffle">
3703+ <property name="text">
3704+ <string>Shuffle playlist</string>
3705+ </property>
3706+ <property name="checkable">
3707+ <bool>false</bool>
3708+ </property>
3709+ </widget>
3710+ </item>
3711+ <item>
3712 <spacer name="horizontalSpacer">
3713 <property name="orientation">
3714 <enum>Qt::Horizontal</enum>
3715
3716=== modified file 'mixxx/src/dlgprefcontrols.cpp'
3717--- mixxx/src/dlgprefcontrols.cpp 2011-02-20 08:50:32 +0000
3718+++ mixxx/src/dlgprefcontrols.cpp 2011-04-22 09:04:29 +0000
3719@@ -144,6 +144,14 @@
3720 dir.setFilter(QDir::Dirs);
3721
3722 //
3723+ // Override Playing Track on Track Load
3724+ //
3725+ ComboBoxAllowTrackLoadToPlayingDeck->addItem(tr("Don't load tracks into a playing deck"));
3726+ ComboBoxAllowTrackLoadToPlayingDeck->addItem(tr("Load tracks into playing decks"));
3727+ ComboBoxAllowTrackLoadToPlayingDeck->setCurrentIndex(m_pConfig->getValueString(ConfigKey("[Controls]", "AllowTrackLoadToPlayingDeck")).toInt());
3728+ connect(ComboBoxAllowTrackLoadToPlayingDeck, SIGNAL(activated(int)), this, SLOT(slotSetAllowTrackLoadToPlayingDeck(int)));
3729+
3730+ //
3731 // Default Cue Behavior
3732 //
3733
3734@@ -355,6 +363,11 @@
3735 m_mixxx->rebootMixxxView();
3736 }
3737
3738+void DlgPrefControls::slotSetAllowTrackLoadToPlayingDeck(int)
3739+{
3740+ m_pConfig->set(ConfigKey("[Controls]","AllowTrackLoadToPlayingDeck"), ConfigValue(ComboBoxAllowTrackLoadToPlayingDeck->currentIndex()));
3741+}
3742+
3743 void DlgPrefControls::slotSetCueDefault(int)
3744 {
3745 m_pConfig->set(ConfigKey("[Controls]","CueDefault"), ConfigValue(ComboBoxCueDefault->currentIndex()));
3746
3747=== modified file 'mixxx/src/dlgprefcontrols.h'
3748--- mixxx/src/dlgprefcontrols.h 2011-02-20 08:50:32 +0000
3749+++ mixxx/src/dlgprefcontrols.h 2011-04-22 09:04:29 +0000
3750@@ -52,6 +52,7 @@
3751 void slotUpdateSchemes();
3752 void slotSetPositionDisplay(int);
3753 void slotSetPositionDisplay(double);
3754+ void slotSetAllowTrackLoadToPlayingDeck(int);
3755 void slotSetCueDefault(int);
3756 void slotSetCueRecall(int);
3757 void slotSetRateRamp(bool);
3758
3759=== modified file 'mixxx/src/dlgprefcontrolsdlg.ui'
3760--- mixxx/src/dlgprefcontrolsdlg.ui 2010-12-20 13:13:52 +0000
3761+++ mixxx/src/dlgprefcontrolsdlg.ui 2011-04-22 09:04:29 +0000
3762@@ -229,6 +229,16 @@
3763 </property>
3764 </widget>
3765 </item>
3766+ <item row="11" column="0">
3767+ <widget class="QLabel" name="textLabelAllowTrackLoadToPlayingDeck">
3768+ <property name="text">
3769+ <string>Track load behaviour</string>
3770+ </property>
3771+ </widget>
3772+ </item>
3773+ <item row="11" column="1" colspan="2">
3774+ <widget class="QComboBox" name="ComboBoxAllowTrackLoadToPlayingDeck"/>
3775+ </item>
3776 <item row="10" column="0">
3777 <widget class="QLabel" name="label">
3778 <property name="text">
3779
3780=== modified file 'mixxx/src/dlgpreferences.cpp'
3781--- mixxx/src/dlgpreferences.cpp 2010-10-29 13:22:37 +0000
3782+++ mixxx/src/dlgpreferences.cpp 2011-04-22 09:04:29 +0000
3783@@ -18,6 +18,8 @@
3784
3785 #ifdef __VINYLCONTROL__
3786 #include "dlgprefvinyl.h"
3787+#else
3788+#include "dlgprefnovinyl.h"
3789 #endif
3790
3791 #ifdef __SHOUTCAST__
3792@@ -47,7 +49,7 @@
3793 #include <QEvent>
3794
3795 DlgPreferences::DlgPreferences(MixxxApp * mixxx, SkinLoader* pSkinLoader,
3796- SoundManager * soundman,
3797+ SoundManager * soundman, PlayerManager* pPlayerManager,
3798 MidiDeviceManager * midi, ConfigObject<ConfigValue> * _config)
3799 : QDialog(), Ui::DlgPreferencesDlg() {
3800 m_pMixxx = mixxx;
3801@@ -65,7 +67,7 @@
3802 //contentsTreeWidget->setCurrentRow(0);
3803
3804 // Construct widgets for use in tabs
3805- wsound = new DlgPrefSound(this, soundman, config);
3806+ wsound = new DlgPrefSound(this, soundman, pPlayerManager, config);
3807 wplaylist = new DlgPrefPlaylist(this, config);
3808 wcontrols = new DlgPrefControls(this, mixxx, pSkinLoader, config);
3809 weq = new DlgPrefEQ(this, config);
3810@@ -75,6 +77,8 @@
3811 wrecord = new DlgPrefRecord(this, config);
3812 #ifdef __VINYLCONTROL__
3813 wvinylcontrol = new DlgPrefVinyl(this, soundman, config);
3814+#else
3815+ wnovinylcontrol = new DlgPrefNoVinyl(this, soundman, config);
3816 #endif
3817 #ifdef __SHOUTCAST__
3818 wshoutcast = new DlgPrefShoutcast(this, config);
3819@@ -96,6 +100,8 @@
3820 pagesWidget->addWidget(wreplaygain);
3821 #ifdef __VINYLCONTROL__
3822 pagesWidget->addWidget(wvinylcontrol);
3823+#else
3824+ pagesWidget->addWidget(wnovinylcontrol);
3825 #endif
3826 #ifdef __SHOUTCAST__
3827 pagesWidget->addWidget(wshoutcast);
3828@@ -134,6 +140,7 @@
3829
3830 #ifdef __VINYLCONTROL__
3831 connect(wvinylcontrol, SIGNAL(refreshVCProxies()), wsound, SLOT(forceApply()));
3832+ connect(wvinylcontrol, SIGNAL(applySound()), wsound, SLOT(slotApply()));
3833 connect(buttonBox, SIGNAL(accepted()), wvinylcontrol, SLOT(slotApply())); //It's important for this to be before the
3834 //connect for wsound...
3835 #endif
3836@@ -170,7 +177,7 @@
3837 m_pSoundButton->setText(0, tr("Sound Hardware"));
3838 m_pSoundButton->setTextAlignment(0, Qt::AlignLeft | Qt::AlignVCenter);
3839 m_pSoundButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
3840-
3841+
3842 /*
3843 QTreeWidgetItem * midiButton = new QTreeWidgetItem(contentsTreeWidget);
3844 midiButton->setIcon(0, QIcon(":/images/preferences/controllers.png"));
3845@@ -242,6 +249,14 @@
3846 m_pVinylControlButton->setText(0, tr("Vinyl Control"));
3847 m_pVinylControlButton->setTextAlignment(0, Qt::AlignLeft | Qt::AlignVCenter);
3848 m_pVinylControlButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
3849+#else
3850+ m_pVinylControlButton = new QTreeWidgetItem(contentsTreeWidget, QTreeWidgetItem::Type);
3851+ //QT screws up my nice vinyl svg for some reason, so we'll use a PNG version
3852+ //instead...
3853+ m_pVinylControlButton->setIcon(0, QIcon(":/images/preferences/ic_preferences_vinyl.png"));
3854+ m_pVinylControlButton->setText(0, tr("Vinyl Control"));
3855+ m_pVinylControlButton->setTextAlignment(0, Qt::AlignLeft | Qt::AlignVCenter);
3856+ m_pVinylControlButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
3857 #endif
3858
3859 #ifdef __SHOUTCAST__
3860@@ -277,11 +292,14 @@
3861 else if (current == m_pBPMdetectButton)
3862 pagesWidget->setCurrentWidget(wbpm);
3863 else if (current == m_pReplayGainButton)
3864- pagesWidget->setCurrentWidget(wreplaygain);
3865+ pagesWidget->setCurrentWidget(wreplaygain);
3866
3867 #ifdef __VINYLCONTROL__
3868 else if (current == m_pVinylControlButton)
3869 pagesWidget->setCurrentWidget(wvinylcontrol);
3870+#else
3871+ else if (current == m_pVinylControlButton)
3872+ pagesWidget->setCurrentWidget(wnovinylcontrol);
3873 #endif
3874 #ifdef __SHOUTCAST__
3875 else if (current == m_pShoutcastButton)
3876
3877=== modified file 'mixxx/src/dlgpreferences.h'
3878--- mixxx/src/dlgpreferences.h 2010-10-29 13:22:37 +0000
3879+++ mixxx/src/dlgpreferences.h 2011-04-22 09:04:29 +0000
3880@@ -42,11 +42,13 @@
3881 class DlgPrefRecord;
3882 class DlgPrefBpm;
3883 class DlgPrefVinyl;
3884+class DlgPrefNoVinyl;
3885 class DlgPrefShoutcast;
3886 class DlgPrefReplayGain;
3887 class PowerMate;
3888 class MidiDeviceManager;
3889 class SkinLoader;
3890+class PlayerManager;
3891
3892 /**
3893 *@author Tue & Ken Haste Andersen
3894@@ -57,7 +59,9 @@
3895 Q_OBJECT
3896 public:
3897 DlgPreferences(MixxxApp *mixxx, SkinLoader* pSkinLoader, SoundManager *soundman,
3898- MidiDeviceManager* midi, ConfigObject<ConfigValue> *config);
3899+ PlayerManager* pPlayerManager, MidiDeviceManager* midi,
3900+ ConfigObject<ConfigValue> *config);
3901+
3902 ~DlgPreferences();
3903 void createIcons();
3904 public slots:
3905@@ -86,19 +90,20 @@
3906 DlgPrefRecord *wrecord;
3907 DlgPrefBpm *wbpm;
3908 DlgPrefVinyl *wvinylcontrol;
3909+ DlgPrefNoVinyl *wnovinylcontrol;
3910 DlgPrefShoutcast *wshoutcast;
3911 DlgPrefReplayGain *wreplaygain;
3912
3913- QTreeWidgetItem* m_pSoundButton;
3914- QTreeWidgetItem* m_pPlaylistButton;
3915- QTreeWidgetItem* m_pControlsButton;
3916- QTreeWidgetItem* m_pEqButton;
3917- QTreeWidgetItem* m_pCrossfaderButton;
3918- QTreeWidgetItem* m_pRecordingButton;
3919- QTreeWidgetItem* m_pBPMdetectButton;
3920- QTreeWidgetItem* m_pVinylControlButton;
3921- QTreeWidgetItem* m_pShoutcastButton;
3922- QTreeWidgetItem* m_pReplayGainButton;
3923+ QTreeWidgetItem* m_pSoundButton;
3924+ QTreeWidgetItem* m_pPlaylistButton;
3925+ QTreeWidgetItem* m_pControlsButton;
3926+ QTreeWidgetItem* m_pEqButton;
3927+ QTreeWidgetItem* m_pCrossfaderButton;
3928+ QTreeWidgetItem* m_pRecordingButton;
3929+ QTreeWidgetItem* m_pBPMdetectButton;
3930+ QTreeWidgetItem* m_pVinylControlButton;
3931+ QTreeWidgetItem* m_pShoutcastButton;
3932+ QTreeWidgetItem* m_pReplayGainButton;
3933 QTreeWidgetItem* m_pMIDITreeItem;
3934 QList<QTreeWidgetItem*> m_midiBindingsButtons;
3935
3936
3937=== added file 'mixxx/src/dlgprefnovinyl.cpp'
3938--- mixxx/src/dlgprefnovinyl.cpp 1970-01-01 00:00:00 +0000
3939+++ mixxx/src/dlgprefnovinyl.cpp 2011-04-22 09:04:29 +0000
3940@@ -0,0 +1,32 @@
3941+/***************************************************************************
3942+ DlgPrefNoVinyl.cpp - description
3943+ -------------------
3944+ begin : Thu Feb 24 2011
3945+ copyright : (C) 2011 by Owen Williams
3946+ email : owen-bugs@ywwg.com
3947+***************************************************************************/
3948+
3949+/***************************************************************************
3950+* *
3951+* This program is free software; you can redistribute it and/or modify *
3952+* it under the terms of the GNU General Public License as published by *
3953+* the Free Software Foundation; either version 2 of the License, or *
3954+* (at your option) any later version. *
3955+* *
3956+***************************************************************************/
3957+
3958+
3959+#include <QtCore>
3960+#include <QtDebug>
3961+#include <QtGui>
3962+#include "dlgprefnovinyl.h"
3963+
3964+DlgPrefNoVinyl::DlgPrefNoVinyl(QWidget * parent, SoundManager * soundman,
3965+ ConfigObject<ConfigValue> * _config) : QWidget(parent), Ui::DlgPrefNoVinylDlg()
3966+{
3967+ setupUi(this);
3968+}
3969+
3970+DlgPrefNoVinyl::~DlgPrefNoVinyl()
3971+{
3972+}
3973
3974=== added file 'mixxx/src/dlgprefnovinyl.h'
3975--- mixxx/src/dlgprefnovinyl.h 1970-01-01 00:00:00 +0000
3976+++ mixxx/src/dlgprefnovinyl.h 2011-04-22 09:04:29 +0000
3977@@ -0,0 +1,39 @@
3978+/***************************************************************************
3979+ dlgprefnovinyl.h - description
3980+ -------------------
3981+ begin : Thu Feb 24 2011
3982+ copyright : (C) 2011 by Owen Williams
3983+ email : owen-bugs@ywwg.com
3984+ ***************************************************************************/
3985+
3986+/***************************************************************************
3987+ * *
3988+ * This program is free software; you can redistribute it and/or modify *
3989+ * it under the terms of the GNU General Public License as published by *
3990+ * the Free Software Foundation; either version 2 of the License, or *
3991+ * (at your option) any later version. *
3992+ * *
3993+ ***************************************************************************/
3994+
3995+#ifndef DLGPREFNOVINYL_H
3996+#define DLGPREFNOVINYL_H
3997+
3998+#include "ui_dlgprefnovinyldlg.h"
3999+#include "configobject.h"
4000+
4001+class QWidget;
4002+class SoundManager;
4003+
4004+/**
4005+ *@author Stefan Langhammer
4006+ *@author Albert Santoni
4007+ */
4008+
4009+class DlgPrefNoVinyl : public QWidget, Ui::DlgPrefNoVinylDlg {
4010+ Q_OBJECT
4011+public:
4012+ DlgPrefNoVinyl(QWidget *parent, SoundManager* soundman, ConfigObject<ConfigValue> *_config);
4013+ ~DlgPrefNoVinyl();
4014+};
4015+
4016+#endif
4017
4018=== added file 'mixxx/src/dlgprefnovinyldlg.ui'
4019--- mixxx/src/dlgprefnovinyldlg.ui 1970-01-01 00:00:00 +0000
4020+++ mixxx/src/dlgprefnovinyldlg.ui 2011-04-22 09:04:29 +0000
4021@@ -0,0 +1,475 @@
4022+<?xml version="1.0" encoding="UTF-8"?>
4023+<ui version="4.0">
4024+ <class>DlgPrefNoVinylDlg</class>
4025+ <widget class="QWidget" name="DlgPrefNoVinylDlg">
4026+ <property name="enabled">
4027+ <bool>true</bool>
4028+ </property>
4029+ <property name="geometry">
4030+ <rect>
4031+ <x>0</x>
4032+ <y>0</y>
4033+ <width>514</width>
4034+ <height>547</height>
4035+ </rect>
4036+ </property>
4037+ <property name="windowTitle">
4038+ <string>Form1</string>
4039+ </property>
4040+ <layout class="QGridLayout" name="gridLayout_3">
4041+ <item row="0" column="0" colspan="3">
4042+ <widget class="QGroupBox" name="groupBox_2">
4043+ <property name="enabled">
4044+ <bool>false</bool>
4045+ </property>
4046+ <property name="title">
4047+ <string>Input</string>
4048+ </property>
4049+ <layout class="QVBoxLayout" name="verticalLayout">
4050+ <item>
4051+ <widget class="QLabel" name="devicesLabel">
4052+ <property name="text">
4053+ <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
4054+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
4055+p, li { white-space: pre-wrap; }
4056+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
4057+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Select sound devices for vinyl control in the Sound Hardware pane.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
4058+ </property>
4059+ </widget>
4060+ </item>
4061+ <item>
4062+ <widget class="QLabel" name="label_2">
4063+ <property name="text">
4064+ <string>&lt;a href=&quot;http://www.mixxx.org/wiki/doku.php/vinyl_control#troubleshooting&quot;&gt;Troubleshooting&lt;/a&gt;</string>
4065+ </property>
4066+ <property name="openExternalLinks">
4067+ <bool>true</bool>
4068+ </property>
4069+ </widget>
4070+ </item>
4071+ <item>
4072+ <layout class="QHBoxLayout" name="horizontalLayout_2">
4073+ <item>
4074+ <widget class="QLabel" name="textLabel1_3">
4075+ <property name="text">
4076+ <string>Turntable Preamp</string>
4077+ </property>
4078+ <property name="wordWrap">
4079+ <bool>false</bool>
4080+ </property>
4081+ </widget>
4082+ </item>
4083+ <item>
4084+ <widget class="QSlider" name="VinylGain">
4085+ <property name="minimum">
4086+ <number>1</number>
4087+ </property>
4088+ <property name="maximum">
4089+ <number>150</number>
4090+ </property>
4091+ <property name="orientation">
4092+ <enum>Qt::Horizontal</enum>
4093+ </property>
4094+ </widget>
4095+ </item>
4096+ </layout>
4097+ </item>
4098+ <item>
4099+ <layout class="QHBoxLayout" name="horizontalLayout">
4100+ <item>
4101+ <spacer name="horizontalSpacer_3">
4102+ <property name="orientation">
4103+ <enum>Qt::Horizontal</enum>
4104+ </property>
4105+ <property name="sizeType">
4106+ <enum>QSizePolicy::Fixed</enum>
4107+ </property>
4108+ <property name="sizeHint" stdset="0">
4109+ <size>
4110+ <width>100</width>
4111+ <height>20</height>
4112+ </size>
4113+ </property>
4114+ </spacer>
4115+ </item>
4116+ <item>
4117+ <widget class="QLabel" name="textLabel2">
4118+ <property name="text">
4119+ <string>1 (Off)</string>
4120+ </property>
4121+ <property name="wordWrap">
4122+ <bool>false</bool>
4123+ </property>
4124+ </widget>
4125+ </item>
4126+ <item>
4127+ <spacer name="horizontalSpacer">
4128+ <property name="orientation">
4129+ <enum>Qt::Horizontal</enum>
4130+ </property>
4131+ <property name="sizeHint" stdset="0">
4132+ <size>
4133+ <width>40</width>
4134+ <height>20</height>
4135+ </size>
4136+ </property>
4137+ </spacer>
4138+ </item>
4139+ <item>
4140+ <widget class="QLabel" name="textLabel3">
4141+ <property name="sizePolicy">
4142+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
4143+ <horstretch>0</horstretch>
4144+ <verstretch>0</verstretch>
4145+ </sizepolicy>
4146+ </property>
4147+ <property name="text">
4148+ <string>150</string>
4149+ </property>
4150+ <property name="wordWrap">
4151+ <bool>false</bool>
4152+ </property>
4153+ </widget>
4154+ </item>
4155+ </layout>
4156+ </item>
4157+ </layout>
4158+ </widget>
4159+ </item>
4160+ <item row="1" column="0" colspan="3">
4161+ <widget class="QGroupBox" name="groupBox_3">
4162+ <property name="enabled">
4163+ <bool>false</bool>
4164+ </property>
4165+ <property name="title">
4166+ <string>Vinyl Configuration</string>
4167+ </property>
4168+ <layout class="QGridLayout" name="gridLayout_2">
4169+ <item row="0" column="0">
4170+ <widget class="QLabel" name="TextLabel29">
4171+ <property name="enabled">
4172+ <bool>false</bool>
4173+ </property>
4174+ <property name="sizePolicy">
4175+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
4176+ <horstretch>0</horstretch>
4177+ <verstretch>0</verstretch>
4178+ </sizepolicy>
4179+ </property>
4180+ <property name="font">
4181+ <font/>
4182+ </property>
4183+ <property name="text">
4184+ <string>Deck 1 Vinyl Type</string>
4185+ </property>
4186+ <property name="wordWrap">
4187+ <bool>false</bool>
4188+ </property>
4189+ </widget>
4190+ </item>
4191+ <item row="0" column="2">
4192+ <widget class="QComboBox" name="ComboBoxVinylType1">
4193+ <property name="enabled">
4194+ <bool>false</bool>
4195+ </property>
4196+ <property name="sizePolicy">
4197+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
4198+ <horstretch>0</horstretch>
4199+ <verstretch>0</verstretch>
4200+ </sizepolicy>
4201+ </property>
4202+ <property name="font">
4203+ <font/>
4204+ </property>
4205+ </widget>
4206+ </item>
4207+ <item row="0" column="3">
4208+ <widget class="QComboBox" name="ComboBoxVinylSpeed1">
4209+ <property name="enabled">
4210+ <bool>false</bool>
4211+ </property>
4212+ <property name="sizePolicy">
4213+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
4214+ <horstretch>0</horstretch>
4215+ <verstretch>0</verstretch>
4216+ </sizepolicy>
4217+ </property>
4218+ <property name="font">
4219+ <font/>
4220+ </property>
4221+ </widget>
4222+ </item>
4223+ <item row="1" column="0">
4224+ <widget class="QLabel" name="TextLabel28">
4225+ <property name="enabled">
4226+ <bool>false</bool>
4227+ </property>
4228+ <property name="sizePolicy">
4229+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
4230+ <horstretch>0</horstretch>
4231+ <verstretch>0</verstretch>
4232+ </sizepolicy>
4233+ </property>
4234+ <property name="font">
4235+ <font/>
4236+ </property>
4237+ <property name="text">
4238+ <string>Deck 2 Vinyl Type</string>
4239+ </property>
4240+ <property name="wordWrap">
4241+ <bool>false</bool>
4242+ </property>
4243+ </widget>
4244+ </item>
4245+ <item row="1" column="2">
4246+ <widget class="QComboBox" name="ComboBoxVinylType2">
4247+ <property name="enabled">
4248+ <bool>false</bool>
4249+ </property>
4250+ <property name="sizePolicy">
4251+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
4252+ <horstretch>0</horstretch>
4253+ <verstretch>0</verstretch>
4254+ </sizepolicy>
4255+ </property>
4256+ <property name="font">
4257+ <font/>
4258+ </property>
4259+ </widget>
4260+ </item>
4261+ <item row="1" column="3">
4262+ <widget class="QComboBox" name="ComboBoxVinylSpeed2">
4263+ <property name="enabled">
4264+ <bool>false</bool>
4265+ </property>
4266+ <property name="sizePolicy">
4267+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
4268+ <horstretch>0</horstretch>
4269+ <verstretch>0</verstretch>
4270+ </sizepolicy>
4271+ </property>
4272+ <property name="font">
4273+ <font/>
4274+ </property>
4275+ </widget>
4276+ </item>
4277+ <item row="2" column="0">
4278+ <widget class="QLabel" name="TextLabel2_2">
4279+ <property name="enabled">
4280+ <bool>false</bool>
4281+ </property>
4282+ <property name="sizePolicy">
4283+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
4284+ <horstretch>0</horstretch>
4285+ <verstretch>0</verstretch>
4286+ </sizepolicy>
4287+ </property>
4288+ <property name="font">
4289+ <font/>
4290+ </property>
4291+ <property name="text">
4292+ <string>Lead-in time</string>
4293+ </property>
4294+ <property name="wordWrap">
4295+ <bool>false</bool>
4296+ </property>
4297+ </widget>
4298+ </item>
4299+ <item row="2" column="2">
4300+ <widget class="QLineEdit" name="LeadinTime">
4301+ <property name="sizePolicy">
4302+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
4303+ <horstretch>0</horstretch>
4304+ <verstretch>0</verstretch>
4305+ </sizepolicy>
4306+ </property>
4307+ </widget>
4308+ </item>
4309+ <item row="2" column="3">
4310+ <widget class="QLabel" name="TextLabel2_2_2">
4311+ <property name="enabled">
4312+ <bool>false</bool>
4313+ </property>
4314+ <property name="font">
4315+ <font/>
4316+ </property>
4317+ <property name="text">
4318+ <string>seconds</string>
4319+ </property>
4320+ <property name="wordWrap">
4321+ <bool>false</bool>
4322+ </property>
4323+ </widget>
4324+ </item>
4325+ <item row="3" column="1">
4326+ <spacer name="horizontalSpacer_2">
4327+ <property name="orientation">
4328+ <enum>Qt::Horizontal</enum>
4329+ </property>
4330+ <property name="sizeHint" stdset="0">
4331+ <size>
4332+ <width>40</width>
4333+ <height>20</height>
4334+ </size>
4335+ </property>
4336+ </spacer>
4337+ </item>
4338+ </layout>
4339+ </widget>
4340+ </item>
4341+ <item row="2" column="0" rowspan="3">
4342+ <widget class="QGroupBox" name="groupBox">
4343+ <property name="enabled">
4344+ <bool>false</bool>
4345+ </property>
4346+ <property name="sizePolicy">
4347+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
4348+ <horstretch>0</horstretch>
4349+ <verstretch>0</verstretch>
4350+ </sizepolicy>
4351+ </property>
4352+ <property name="maximumSize">
4353+ <size>
4354+ <width>16777215</width>
4355+ <height>16777215</height>
4356+ </size>
4357+ </property>
4358+ <property name="title">
4359+ <string>Control Mode</string>
4360+ </property>
4361+ <property name="alignment">
4362+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
4363+ </property>
4364+ <layout class="QVBoxLayout">
4365+ <item>
4366+ <widget class="QRadioButton" name="AbsoluteMode">
4367+ <property name="text">
4368+ <string>Absolute Mode</string>
4369+ </property>
4370+ </widget>
4371+ </item>
4372+ <item>
4373+ <widget class="QRadioButton" name="RelativeMode">
4374+ <property name="text">
4375+ <string>Relative Mode</string>
4376+ </property>
4377+ </widget>
4378+ </item>
4379+ <item>
4380+ <widget class="QCheckBox" name="NeedleSkipEnable">
4381+ <property name="text">
4382+ <string>Enable Needle Skip Prevention</string>
4383+ </property>
4384+ </widget>
4385+ </item>
4386+ <item>
4387+ <spacer name="verticalSpacer_3">
4388+ <property name="orientation">
4389+ <enum>Qt::Vertical</enum>
4390+ </property>
4391+ <property name="sizeHint" stdset="0">
4392+ <size>
4393+ <width>20</width>
4394+ <height>40</height>
4395+ </size>
4396+ </property>
4397+ </spacer>
4398+ </item>
4399+ </layout>
4400+ </widget>
4401+ </item>
4402+ <item row="2" column="1" colspan="2">
4403+ <widget class="QGroupBox" name="groupBoxSignalQuality">
4404+ <property name="enabled">
4405+ <bool>false</bool>
4406+ </property>
4407+ <property name="title">
4408+ <string>Signal Quality</string>
4409+ </property>
4410+ <property name="alignment">
4411+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
4412+ </property>
4413+ <layout class="QGridLayout">
4414+ <item row="0" column="0">
4415+ <spacer name="verticalSpacer_2">
4416+ <property name="orientation">
4417+ <enum>Qt::Vertical</enum>
4418+ </property>
4419+ <property name="sizeHint" stdset="0">
4420+ <size>
4421+ <width>20</width>
4422+ <height>40</height>
4423+ </size>
4424+ </property>
4425+ </spacer>
4426+ </item>
4427+ </layout>
4428+ </widget>
4429+ </item>
4430+ <item row="3" column="1" colspan="2">
4431+ <widget class="QLabel" name="label">
4432+ <property name="enabled">
4433+ <bool>false</bool>
4434+ </property>
4435+ <property name="toolTip">
4436+ <string>http://www.xwax.co.uk</string>
4437+ </property>
4438+ <property name="text">
4439+ <string>Powered by xwax</string>
4440+ </property>
4441+ <property name="alignment">
4442+ <set>Qt::AlignBottom|Qt::AlignRight|Qt::AlignTrailing</set>
4443+ </property>
4444+ </widget>
4445+ </item>
4446+ <item row="4" column="2">
4447+ <widget class="QPushButton" name="applyButton">
4448+ <property name="enabled">
4449+ <bool>false</bool>
4450+ </property>
4451+ <property name="sizePolicy">
4452+ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
4453+ <horstretch>0</horstretch>
4454+ <verstretch>0</verstretch>
4455+ </sizepolicy>
4456+ </property>
4457+ <property name="sizeHint" stdset="0">
4458+ <size>
4459+ <width>85</width>
4460+ <height>27</height>
4461+ </size>
4462+ </property>
4463+ <property name="text">
4464+ <string>Apply</string>
4465+ </property>
4466+ </widget>
4467+ </item>
4468+ <item row="5" column="2">
4469+ <spacer name="verticalSpacer">
4470+ <property name="orientation">
4471+ <enum>Qt::Vertical</enum>
4472+ </property>
4473+ <property name="sizeHint" stdset="0">
4474+ <size>
4475+ <width>0</width>
4476+ <height>0</height>
4477+ </size>
4478+ </property>
4479+ </spacer>
4480+ </item>
4481+ <item row="5" column="0" colspan="2">
4482+ <widget class="QLabel" name="label_3">
4483+ <property name="text">
4484+ <string>&lt;b&gt;This version of Mixxx does not support vinyl control.&lt;/b&gt; &lt;br&gt; Please visit &lt;a href=&quot;http://mixxx.org&quot;&gt;Mixxx.org&lt;/a&gt; for more information.</string>
4485+ </property>
4486+ <property name="wordWrap">
4487+ <bool>true</bool>
4488+ </property>
4489+ </widget>
4490+ </item>
4491+ </layout>
4492+ </widget>
4493+ <layoutdefault spacing="6" margin="11"/>
4494+ <resources/>
4495+ <connections/>
4496+</ui>
4497
4498=== modified file 'mixxx/src/dlgprefrecord.cpp'
4499--- mixxx/src/dlgprefrecord.cpp 2011-01-21 12:41:27 +0000
4500+++ mixxx/src/dlgprefrecord.cpp 2011-04-22 09:04:29 +0000
4501@@ -23,114 +23,114 @@
4502 #include "controlobjectthreadmain.h"
4503 #include "recording/encoder.h"
4504
4505+
4506 DlgPrefRecord::DlgPrefRecord(QWidget * parent, ConfigObject<ConfigValue> * _config) : QWidget(parent), Ui::DlgPrefRecordDlg()
4507 {
4508 config = _config;
4509 confirmOverwrite = false;
4510+ radioFlac = 0;
4511+ radioMp3 = 0;
4512+ radioOgg = 0;
4513+ radioAiff= 0;
4514+ radioWav = 0;
4515+
4516
4517 setupUi(this);
4518
4519 recordControl = new ControlObjectThreadMain(ControlObject::getControl(ConfigKey("[Master]", "Record"))); //See RECORD_* #defines in defs_recording.h
4520
4521-
4522- //Fill up encoding list
4523- comboBoxEncoding->addItem(ENCODING_WAVE);
4524-#ifdef SF_FORMAT_FLAC
4525- comboBoxEncoding->addItem(ENCODING_FLAC);
4526-#endif
4527- comboBoxEncoding->addItem(ENCODING_AIFF);
4528-#ifdef __SHOUTCAST__
4529- comboBoxEncoding->addItem(ENCODING_MP3);
4530- comboBoxEncoding->addItem(ENCODING_OGG);
4531-#endif
4532-
4533- int encodingIndex = comboBoxEncoding->findText(config->getValueString(ConfigKey("[Recording]","Encoding")));
4534- if (encodingIndex >= 0)
4535- comboBoxEncoding->setCurrentIndex(encodingIndex);
4536+
4537+
4538+#ifdef __SHOUTCAST__
4539+ radioOgg = new QRadioButton("Ogg Vorbis");
4540+ radioMp3 = new QRadioButton(ENCODING_MP3);
4541+ connect(radioOgg,SIGNAL(clicked()),
4542+ this, SLOT(slotApply()));
4543+ connect(radioMp3, SIGNAL(clicked()),
4544+ this, SLOT(slotApply()));
4545+ horizontalLayout->addWidget(radioOgg);
4546+ horizontalLayout->addWidget(radioMp3);
4547+
4548+#endif
4549+
4550+ //AIFF and WAVE are supported by default
4551+ radioWav = new QRadioButton(ENCODING_WAVE);
4552+ connect(radioWav, SIGNAL(clicked()),
4553+ this, SLOT(slotApply()));
4554+ horizontalLayout->addWidget(radioWav);
4555+
4556+ radioAiff = new QRadioButton(ENCODING_AIFF);
4557+ connect(radioAiff, SIGNAL(clicked()),
4558+ this, SLOT(slotApply()));
4559+ horizontalLayout->addWidget(radioAiff);
4560+
4561+
4562+#ifdef SF_FORMAT_FLAC
4563+ radioFlac = new QRadioButton(ENCODING_FLAC);
4564+ connect(radioFlac,SIGNAL(clicked()),
4565+ this, SLOT(slotApply()));
4566+ horizontalLayout->addWidget(radioFlac);
4567+#endif
4568+
4569+ //Read config and check radio button
4570+ QString format = config->getValueString(ConfigKey("[Recording]","Encoding"));
4571+ if(format == ENCODING_WAVE)
4572+ radioWav->setChecked(true);
4573+#ifdef __SHOUTCAST__
4574+ else if(format == ENCODING_OGG)
4575+ radioOgg->setChecked(true);
4576+ else if (format == ENCODING_MP3)
4577+ radioMp3->setChecked(true);
4578+#endif
4579+#ifdef SF_FORMAT_FLAC
4580+ else if (format == ENCODING_AIFF)
4581+ radioAiff->setChecked(true);
4582+#endif
4583 else //Invalid, so set default and save
4584 {
4585- comboBoxEncoding->setCurrentIndex(0);
4586- config->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(comboBoxEncoding->currentText()));
4587+ //If no config was available, set to WAVE as default
4588+ radioWav->setChecked(true);
4589+ config->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(ENCODING_WAVE));
4590 }
4591
4592 //Connections
4593- connect(PushButtonBrowse, SIGNAL(clicked()), this, SLOT(slotBrowseSave()));
4594- connect(PushButtonBrowseCue, SIGNAL(clicked()), this, SLOT(slotBrowseCueSave()));
4595- connect(LineEditRecPath, SIGNAL(returnPressed()), this, SLOT(slotApply()));
4596- connect(comboBoxEncoding, SIGNAL(activated(int)), this, SLOT(slotRecordPathChange()));
4597 connect(SliderQuality, SIGNAL(valueChanged(int)), this, SLOT(slotSliderQuality()));
4598 connect(SliderQuality, SIGNAL(sliderMoved(int)), this, SLOT(slotSliderQuality()));
4599 connect(SliderQuality, SIGNAL(sliderReleased()), this, SLOT(slotSliderQuality()));
4600 connect(CheckBoxRecordCueFile, SIGNAL(stateChanged(int)), this, SLOT(slotEnableCueFile(int)));
4601- connect(LineEditRecPath, SIGNAL(textChanged(QString)), this, SLOT(slotRecordPathChanged(QString)));
4602+ connect(comboBoxSplitting, SIGNAL(activated(int)), this, SLOT(slotChangeSplitSize()));
4603
4604 slotApply();
4605 recordControl->slotSet(RECORD_OFF); //make sure a corrupt config file won't cause us to record constantly
4606-}
4607-
4608-void DlgPrefRecord::slotBrowseSave()
4609-{
4610- QString encodingType = comboBoxEncoding->currentText();
4611- QString encodingFileFilter = QString("Audio (*.%1)").arg(encodingType);
4612- QString selectedFile = QFileDialog::getSaveFileName(NULL, tr("Save Recording As..."), config->getValueString(ConfigKey(RECORDING_PREF_KEY,"Path")), encodingFileFilter);
4613- if (selectedFile.toLower() != "")
4614- {
4615- if(!selectedFile.toLower().endsWith("." + encodingType.toLower()))
4616- {
4617- selectedFile.append("." + encodingType.toLower());
4618- }
4619- LineEditRecPath->setText( selectedFile );
4620- }
4621-}
4622-
4623-void DlgPrefRecord::slotBrowseCueSave()
4624-{
4625- QString encodingFileFilter = QString("CUE file (*.cue)");
4626- QString selectedFile = QFileDialog::getSaveFileName(NULL, tr("Save Cue File As..."), config->getValueString(ConfigKey(RECORDING_PREF_KEY,"CuePath")), encodingFileFilter);
4627- if (selectedFile.toLower() != "")
4628- {
4629- if(!selectedFile.toLower().endsWith(".cue"))
4630- {
4631- selectedFile.append(".cue");
4632- }
4633- LineEditCuePath->setText( selectedFile );
4634- }
4635-}
4636-
4637-void DlgPrefRecord::slotEnableCueFile(int enabled)
4638-{
4639- bool status = enabled ? true : false;
4640-
4641-
4642- config->set(ConfigKey(RECORDING_PREF_KEY, "CueEnabled"), ConfigValue(CheckBoxRecordCueFile->isChecked()));
4643-
4644- LabelCueFile->setEnabled(status);
4645- LineEditCuePath->setEnabled(status);
4646- PushButtonBrowseCue->setEnabled(status);
4647-}
4648-
4649-void DlgPrefRecord::slotRecordPathChanged(QString path)
4650-{
4651- QString cuePath = path;
4652- int pos;
4653-
4654-
4655- pos = path.lastIndexOf(".");
4656- cuePath.replace(pos, 4, ".cue");
4657- cuePath.truncate(pos + 4);
4658-
4659- LineEditCuePath->setText(cuePath);
4660+
4661+ comboBoxSplitting->addItem(SPLIT_650MB);
4662+ comboBoxSplitting->addItem(SPLIT_700MB);
4663+ comboBoxSplitting->addItem(SPLIT_1024MB);
4664+ comboBoxSplitting->addItem(SPLIT_2048MB);
4665+ comboBoxSplitting->addItem(SPLIT_4096MB);
4666+
4667+ QString fileSizeStr = config->getValueString(ConfigKey("[Recording]","FileSize"));
4668+ int index = comboBoxSplitting->findText(fileSizeStr);
4669+ if(index > 0){
4670+ //set file split size
4671+ comboBoxSplitting->setCurrentIndex(index);
4672+ }
4673+ //Otherwise 650 MB will be default file split size
4674+
4675+ //Read CUEfile info
4676+ CheckBoxRecordCueFile->setChecked((bool) config->getValueString(ConfigKey("[Recording]","CueEnabled")).toInt());
4677+
4678 }
4679
4680 void DlgPrefRecord::slotSliderQuality()
4681 {
4682 updateTextQuality();
4683- QString encodingType = comboBoxEncoding->currentText();
4684- if (encodingType == "OGG")
4685+
4686+ if (radioOgg && radioOgg->isChecked())
4687 {
4688 config->set(ConfigKey(RECORDING_PREF_KEY, "OGG_Quality"), ConfigValue(SliderQuality->value()));
4689 }
4690- else if (encodingType == "MP3")
4691+ else if (radioMp3 && radioMp3->isChecked())
4692 {
4693 config->set(ConfigKey(RECORDING_PREF_KEY, "MP3_Quality"), ConfigValue(SliderQuality->value()));
4694 }
4695@@ -138,52 +138,61 @@
4696
4697 int DlgPrefRecord::getSliderQualityVal()
4698 {
4699-
4700- /* Commented by Tobias Rafreider
4701- * We always use the bitrate to denote the quality since it is more common to the users
4702- */
4703- return Encoder::convertToBitrate(SliderQuality->value());
4704+
4705+ /* Commented by Tobias Rafreider
4706+ * We always use the bitrate to denote the quality since it is more common to the users
4707+ */
4708+ return Encoder::convertToBitrate(SliderQuality->value());
4709
4710 }
4711
4712 void DlgPrefRecord::updateTextQuality()
4713 {
4714 int quality = getSliderQualityVal();
4715- QString encodingType = comboBoxEncoding->currentText();
4716-
4717+ //QString encodingType = comboBoxEncoding->currentText();
4718+
4719 TextQuality->setText(QString( QString::number(quality) + tr("kbps")));
4720-
4721-
4722+
4723+
4724 }
4725
4726 void DlgPrefRecord::slotEncoding()
4727 {
4728 //set defaults
4729 groupBoxQuality->setEnabled(true);
4730- config->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(comboBoxEncoding->currentText()));
4731- if (comboBoxEncoding->currentText() == ENCODING_WAVE ||
4732- comboBoxEncoding->currentText() == ENCODING_FLAC ||
4733- comboBoxEncoding->currentText() == ENCODING_AIFF)
4734- {
4735- groupBoxQuality->setEnabled(false);
4736- }
4737- else if (comboBoxEncoding->currentText() == ENCODING_OGG)
4738+ //config->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(comboBoxEncoding->currentText()));
4739+
4740+ if (radioWav && radioWav->isChecked()) {
4741+ config->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(ENCODING_WAVE));
4742+ groupBoxQuality->setEnabled(false);
4743+ }
4744+ else if(radioFlac && radioFlac->isChecked()){
4745+ config->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(ENCODING_FLAC));
4746+ groupBoxQuality->setEnabled(false);
4747+ }
4748+ else if(radioAiff && radioAiff->isChecked()){
4749+ config->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(ENCODING_AIFF));
4750+ groupBoxQuality->setEnabled(false);
4751+ }
4752+ else if (radioOgg && radioOgg->isChecked())
4753 {
4754 int value = config->getValueString(ConfigKey(RECORDING_PREF_KEY, "OGG_Quality")).toInt();
4755 //if value == 0 then a default value of 128kbps is proposed.
4756 if(!value)
4757 value = 6; // 128kbps
4758-
4759+
4760 SliderQuality->setValue(value);
4761+ config->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(ENCODING_OGG));
4762 }
4763- else if (comboBoxEncoding->currentText() == ENCODING_MP3)
4764+ else if (radioMp3 && radioMp3->isChecked())
4765 {
4766 int value = config->getValueString(ConfigKey(RECORDING_PREF_KEY, "MP3_Quality")).toInt();
4767 //if value == 0 then a default value of 128kbps is proposed.
4768 if(!value)
4769 value = 6; // 128kbps
4770-
4771+
4772 SliderQuality->setValue(value);
4773+ config->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(ENCODING_MP3));
4774 }
4775 else
4776 qDebug() << "Invalid recording encoding type in" << __FILE__ << "on line:" << __LINE__;
4777@@ -216,26 +225,42 @@
4778 //This function updates/refreshes the contents of this dialog
4779 void DlgPrefRecord::slotUpdate()
4780 {
4781- int encodingIndex = comboBoxEncoding->findText(config->getValueString(ConfigKey("[Recording]","Encoding")));
4782- if (encodingIndex >= 0)
4783- comboBoxEncoding->setCurrentIndex(encodingIndex);
4784- else //Invalid, so set default and save
4785- {
4786- comboBoxEncoding->setCurrentIndex(0);
4787- config->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(comboBoxEncoding->currentText()));
4788- }
4789-
4790- //Set the path from the saved value.
4791- LineEditRecPath->setText(config->getValueString(ConfigKey(RECORDING_PREF_KEY,"Path")));
4792-
4793+ if (radioWav && radioWav->isChecked())
4794+ {
4795+ config->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(ENCODING_WAVE));
4796+ }
4797+ else if (radioAiff && radioAiff->isChecked())
4798+ {
4799+ config->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(ENCODING_AIFF));
4800+ }
4801+ else if (radioFlac && radioFlac->isChecked())
4802+ {
4803+ config->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(ENCODING_FLAC));
4804+ }
4805+ else if (radioOgg && radioOgg->isChecked())
4806+ {
4807+ config->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(ENCODING_OGG));
4808+ }
4809+ else if (radioMp3 && radioMp3->isChecked())
4810+ {
4811+ config->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(ENCODING_MP3));
4812+ }
4813 loadMetaData();
4814 }
4815
4816 void DlgPrefRecord::slotApply()
4817 {
4818- config->set(ConfigKey(RECORDING_PREF_KEY, "Path"), LineEditRecPath->text());
4819- config->set(ConfigKey(RECORDING_PREF_KEY, "CuePath"), LineEditCuePath->text());
4820 setMetaData();
4821
4822 slotEncoding();
4823 }
4824+void DlgPrefRecord::slotEnableCueFile(int enabled)
4825+{
4826+ config->set(ConfigKey(RECORDING_PREF_KEY, "CueEnabled"), ConfigValue(CheckBoxRecordCueFile->isChecked()));
4827+
4828+}
4829+void DlgPrefRecord::slotChangeSplitSize()
4830+{
4831+ config->set(ConfigKey(RECORDING_PREF_KEY, "FileSize"), ConfigValue(comboBoxSplitting->currentText()));
4832+
4833+}
4834
4835=== modified file 'mixxx/src/dlgprefrecord.h'
4836--- mixxx/src/dlgprefrecord.h 2011-01-21 12:41:27 +0000
4837+++ mixxx/src/dlgprefrecord.h 2011-04-22 09:04:29 +0000
4838@@ -20,6 +20,7 @@
4839
4840 #include "ui_dlgprefrecorddlg.h"
4841 #include "configobject.h"
4842+#include <QRadioButton>
4843
4844 class ControlObject;
4845 class ControlObjectThreadMain;
4846@@ -39,27 +40,30 @@
4847 public slots:
4848 /** Apply changes to widget */
4849 void slotApply();
4850- void slotUpdate();
4851- void slotBrowseSave();
4852- void slotBrowseCueSave();
4853- void slotEnableCueFile(int);
4854- void slotRecordPathChanged(QString);
4855+ void slotUpdate();
4856 void slotEncoding();
4857 void slotSliderQuality();
4858 void slotRecordPathChange();
4859- int getSliderQualityVal();
4860- void updateTextQuality();
4861+ void slotEnableCueFile(int);
4862+ void slotChangeSplitSize();
4863 signals:
4864 void apply(const QString &);
4865 private:
4866 void setMetaData();
4867 void loadMetaData();
4868+ int getSliderQualityVal();
4869+ void updateTextQuality();
4870
4871 /** Pointer to config object */
4872 ConfigObject<ConfigValue> *config;
4873 ControlObjectThreadMain* recordControl;
4874 bool confirmOverwrite;
4875 QString fileTypeExtension;
4876+ QRadioButton *radioOgg;
4877+ QRadioButton *radioMp3;
4878+ QRadioButton *radioAiff;
4879+ QRadioButton *radioFlac;
4880+ QRadioButton *radioWav;
4881 };
4882
4883 #endif
4884
4885=== modified file 'mixxx/src/dlgprefrecorddlg.ui'
4886--- mixxx/src/dlgprefrecorddlg.ui 2011-01-21 12:41:27 +0000
4887+++ mixxx/src/dlgprefrecorddlg.ui 2011-04-22 09:04:29 +0000
4888@@ -1,316 +1,229 @@
4889-<?xml version="1.0" encoding="UTF-8"?>
4890-<ui version="4.0">
4891- <class>DlgPrefRecordDlg</class>
4892- <widget class="QWidget" name="DlgPrefRecordDlg">
4893- <property name="geometry">
4894- <rect>
4895- <x>0</x>
4896- <y>0</y>
4897- <width>412</width>
4898- <height>411</height>
4899- </rect>
4900- </property>
4901- <property name="windowTitle">
4902- <string>Form3</string>
4903- </property>
4904- <layout class="QVBoxLayout" name="verticalLayout">
4905- <item>
4906- <layout class="QGridLayout">
4907- <item row="0" column="0">
4908- <widget class="QLabel" name="TextLabel3_2">
4909- <property name="enabled">
4910- <bool>true</bool>
4911- </property>
4912- <property name="font">
4913- <font/>
4914- </property>
4915- <property name="text">
4916- <string>File</string>
4917- </property>
4918- <property name="wordWrap">
4919- <bool>false</bool>
4920- </property>
4921- </widget>
4922- </item>
4923- <item row="0" column="2">
4924- <widget class="QLineEdit" name="LineEditRecPath">
4925- <property name="font">
4926- <font/>
4927- </property>
4928- </widget>
4929- </item>
4930- <item row="0" column="3">
4931- <widget class="QPushButton" name="PushButtonBrowse">
4932- <property name="font">
4933- <font/>
4934- </property>
4935- <property name="text">
4936- <string>Browse...</string>
4937- </property>
4938- </widget>
4939- </item>
4940- <item row="1" column="0">
4941- <widget class="QLabel" name="TextLabel3_2_2">
4942- <property name="enabled">
4943- <bool>true</bool>
4944- </property>
4945- <property name="font">
4946- <font/>
4947- </property>
4948- <property name="text">
4949- <string>Encoding</string>
4950- </property>
4951- <property name="wordWrap">
4952- <bool>false</bool>
4953- </property>
4954- </widget>
4955- </item>
4956- <item row="1" column="2" colspan="2">
4957- <widget class="QComboBox" name="comboBoxEncoding"/>
4958- </item>
4959- <item row="0" column="1">
4960- <spacer>
4961- <property name="orientation">
4962- <enum>Qt::Horizontal</enum>
4963- </property>
4964- <property name="sizeHint" stdset="0">
4965- <size>
4966- <width>40</width>
4967- <height>20</height>
4968- </size>
4969- </property>
4970- </spacer>
4971- </item>
4972- <item row="1" column="1">
4973- <spacer>
4974- <property name="orientation">
4975- <enum>Qt::Horizontal</enum>
4976- </property>
4977- <property name="sizeHint" stdset="0">
4978- <size>
4979- <width>40</width>
4980- <height>20</height>
4981- </size>
4982- </property>
4983- </spacer>
4984- </item>
4985- </layout>
4986- </item>
4987- <item>
4988- <widget class="QGroupBox" name="groupBoxQuality">
4989- <property name="title">
4990- <string>Quality</string>
4991- </property>
4992- <layout class="QGridLayout" name="gridLayout">
4993- <item row="0" column="2">
4994- <widget class="QLabel" name="TextQuality">
4995- <property name="text">
4996- <string>Quality</string>
4997- </property>
4998- <property name="alignment">
4999- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
5000- </property>
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches