Merge lp:~mixxxdevelopers/mixxx/multi-playlist-crates into lp:~mhaulo/mixxx/multilevel_crates_playlists
- multi-playlist-crates
- Merge into multilevel_crates_playlists
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mika Haulo | Pending | ||
Review via email: mp+58787@code.launchpad.net |
Commit message
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
RAFFI TEA (raffitea) wrote : | # |
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.
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
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' |
2553 | Binary 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' |
2669 | Binary 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' |
2671 | Binary 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' |
2673 | Binary 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' |
2675 | Binary 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' |
2677 | Binary 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' |
2679 | Binary 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' |
2681 | Binary 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><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> |
4054 | +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> |
4055 | +p, li { white-space: pre-wrap; } |
4056 | +</style></head><body style=" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;"> |
4057 | +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Select sound devices for vinyl control in the Sound Hardware pane.</span></p></body></html></string> |
4058 | + </property> |
4059 | + </widget> |
4060 | + </item> |
4061 | + <item> |
4062 | + <widget class="QLabel" name="label_2"> |
4063 | + <property name="text"> |
4064 | + <string><a href="http://www.mixxx.org/wiki/doku.php/vinyl_control#troubleshooting">Troubleshooting</a></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><b>This version of Mixxx does not support vinyl control.</b> <br> Please visit <a href="http://mixxx.org">Mixxx.org</a> 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> |
JFI: My branch has been merged with current trunk. This is why the diff is huge.