Merge lp:~daschuer/mixxx/autodj into lp:~mixxxdevelopers/mixxx/trunk

Proposed by Daniel Schürmann
Status: Merged
Merged at revision: 2989
Proposed branch: lp:~daschuer/mixxx/autodj
Merge into: lp:~mixxxdevelopers/mixxx/trunk
Diff against target: 1979 lines (+1168/-231)
22 files modified
mixxx/build/depends.py (+24/-4)
mixxx/lib/soundtouch-1.6.0/STTypes.h (+1/-1)
mixxx/res/images/autodj/bottom.svg (+137/-0)
mixxx/res/images/autodj/media-playlist-shuffle.svg (+214/-0)
mixxx/res/images/autodj/stock_mail-send-receive.svg (+87/-0)
mixxx/res/mixxx.qrc (+3/-0)
mixxx/src/dlgautodj.cpp (+433/-161)
mixxx/src/dlgautodj.h (+26/-2)
mixxx/src/dlgautodj.ui (+110/-18)
mixxx/src/library/autodjfeature.cpp (+30/-24)
mixxx/src/library/autodjfeature.h (+2/-0)
mixxx/src/library/browse/browsefeature.cpp (+14/-4)
mixxx/src/library/browse/browsetablemodel.cpp (+8/-8)
mixxx/src/library/dao/cratedao.h (+2/-0)
mixxx/src/library/dao/playlistdao.cpp (+11/-3)
mixxx/src/library/dao/playlistdao.h (+3/-1)
mixxx/src/library/playlistfeature.cpp (+23/-3)
mixxx/src/library/playlistfeature.h (+3/-0)
mixxx/src/library/playlisttablemodel.cpp (+11/-0)
mixxx/src/library/playlisttablemodel.h (+1/-0)
mixxx/src/widget/wtracktableview.cpp (+22/-2)
mixxx/src/widget/wtracktableview.h (+3/-0)
To merge this branch: bzr merge lp:~daschuer/mixxx/autodj
Reviewer Review Type Date Requested Status
Mixxx Development Team Pending
Review via email: mp+61320@code.launchpad.net

Description of the change

I have done some changes, which makes auto DJ useful for manual control.
* Manually to a deck loaded song is played by auto DJ
* Additional "Skip Next" Button
* Auto DJ did not change the "Repeat" Button any more
* "Repeat" works as desired (it temporary disables auto DJ)
* Lock fading of the two decks against each other, plus some other possible exceptions
* Enabling auto DJ always starts playback (we may discuss if it is desired)
* Next track is loaded immediately after fading (see bug 766817) also good to monitor what happens next in case browsing thou the library
* Additional "Fade Now" button (see bug 730577)
* "Fade Now" disables "Repeat"
* Track is deleted from the auto DJ list when it starts to play
* Image Buttons (fits to Outline-800x460-WVGA)
* "Add to Auto DJ Queue" from Rhythmbox and Browser
* "Add to Auto DJ Top 2" for playing a song after next
* Autoscroll Patch

To post a comment you must log in.
lp:~daschuer/mixxx/autodj updated
2800. By Daniel Schürmann

GUI cleanup

2801. By Daniel Schürmann

auto DJ with Transition time in sec configurable

Revision history for this message
jus (jus) wrote :

Tested r2801 of your autodj branch

* SKIP NEXT button
Does not work as expected. Play-count of the next track in queue is raised by one, but track is not skipped.
* CUSTOM TRANSITION TIME stepper
Changes to the transition time are not instantly effective for the transition from the currently playing track to the next queued track (same for the FADE NOW button). One would expect it works instantly when changed. Nonetheless it works for the next transition.
Furthermore i think the preference dialog is not an optimal place for the stepper. It should go from the preferences directly to the AutoDJ tab in the library widget. This would improve usability and allow easy in-session changes.

lp:~daschuer/mixxx/autodj updated
2802. By Daniel Schürmann

Transition settings from auto DJ toolbar.
Skip missing tracks. "Fade Now" works when both decks playing. Solved some issues with seek and jumps.

2803. By Daniel Schürmann

made skip next working

Revision history for this message
Daniel Schürmann (daschuer) wrote :

Hi jus, Thank you for testing.
At the beginning I had strange problems with the maximum size of the auto DJ tools.
The current solution consumes as much space as possible. What's the limit and where can I find it.
I think we will have a lot of problems with i18n. Maybe someone is able to define bitmap buttons or an auto DJ skin. A second toolbar is not nice, it would be look stupid on large screens and consumes to much space from tiny screens.

Do you think we should remove the transition from the preferences dialog?

Revision history for this message
jus (jus) wrote :

Thanks for fixing the bugs i mentioned in the first comment.

Can not tell if there is such limit hardcoded/where to find eventually. OTOH the AutoDJ pane looks fine in all other skins. The OUTLINE skin may have no future either, so the escaping library in OUTLINE is nothing to be really worried about for the moment.
> The current solution consumes as much space as possible. What's the limit and
> where can I find it.

Agree on the second toolbar, better have all buttons in one row.
Actually we can already style the buttons,spinbox etc. per skin using style-sheets. See the Spartan skin for example http://www.mixxx.org/forums/viewtopic.php?f=8&t=1812
A reason the buttons are currently not styled per default is that style-sheets break the color scheme support which the OUTLINE skins make exclusive use of http://mixxx.org/wiki/doku.php/skin_colour_scheme_architecture
> I think we will have a lot of problems with i18n. Maybe someone is able to
> define bitmap buttons or an auto DJ skin. A second toolbar is not nice, it
> would be look stupid on large screens and consumes to much space from tiny
> screens.
>

Yes, as it is now in the AutoDJ pane for direct access.
> Do you think we should remove the transition from the preferences dialog?

One last thing:
While "s" is the correct abbreviation for "seconds", do you think it is clear enough for translators? What do you think, maybe go with "sec" instead?

lp:~daschuer/mixxx/autodj updated
2804. By Daniel Schürmann

Transition removed from prefcrossfader.
Made the transition from auto DJ Toolbar persistent.
Fixed a bug: Where "loadTrack" was sometimes overtaking "stop"

2805. By Daniel Schürmann

Optimized Auto DJ start, merged with trunk

Revision history for this message
Daniel Schürmann (daschuer) wrote :

Hi jus,

I am surprised to hear that the OUTLINE skin may have no future, because It is my favourite on the netbook. It has clear buttons with a good size and waveforms on below the others. Only one thing: The position of the loaded track title should be below the waveforms.

I do not know if our American friends like "s" for second. My Problem is, that "sec" is simply to large for OUTLINE skin.

Revision history for this message
Sean M. Pappalardo (pegasus-renegadetech) wrote :

I'm American and I'll say that 's' for second is fine for us, so long as the context makes it obvious.

Jus is concerned with translations: on LP, it just displays the text to translate, so an 's' all by itself won't be obvious without a screen shot or something. LP does give the line number in the code, but then a translator would have to go look at the code to see exactly what that 's' means to know how (if) to translate it. If there's a detailed tool tip nearby then that might make it more obvious.

Revision history for this message
jus (jus) wrote :

Now it reads "Transition [QSpinBox] s" better would be "Transition (sec) [QSpinBox]" or "Fade (sec) [QSpinBox]". This would make the context pretty obvious for translators too.

If we`d just use "Transition (s)" it could be easily mistaken for being plural of "Transition".

Would love to see the additions to AutoDJ in trunk, using it extensively and it works (at least from a user perspective) without complains.

lp:~daschuer/mixxx/autodj updated
2806. By Daniel Schürmann

merged with trunk

2807. By Daniel Schürmann

auto DJ with pause (Transition negative)

2808. By Daniel Schürmann

auto DJ with pause works for second deck

2809. By Daniel Schürmann

fixed bug with double-entrys

2810. By Daniel Schürmann

Added image buttons for auto DJ panel, >Add to Auto DJ Queue< for Bowser and Rhythmbox

Revision history for this message
Daniel Schürmann (daschuer) wrote :

Now it has image buttons, Taken from "Multicolor-Gnome" Iconset.
I have changed the Text to "Transition [sec]" [SpinBox]

Revision history for this message
jus (jus) wrote :

> Now it has image buttons, Taken from "Multicolor-Gnome" Iconset.
Hi Daniel, would love to hear the idea behind this change.

I see the following drawbacks:
* Lack of consistency: Using a mix of labeled and styled un-labeled (styled) buttons for activating AutoDJ / Recordings / Analyze.
* Lack of unity of style within icons : Does not fit with our existing icons used in treeview & preferences.
* Duplicates functionality: Currently elements like buttons, spinboxes etc. can already be customized per skin using QT stylesheets in skin.xml

Revision history for this message
Daniel Schürmann (daschuer) wrote :

Hi jus,

styling is not the main part of this branch. I am not an expert in GUI or graphic design.
This is just a solution for our escaping and i18n problem.

Whats your main reason for the lack of unity?
Where are the existing icons from? Maybe there are similar icons in that icon set we can use.

Do you have an idea for styled buttons in Recordings and Analyse?

I have decided to use a static sylesheet within the dlgautodj because the library icons are also static. It should be no problem to move all library arts together it to the skin support later.
For now and in respect to the merging work-flow this should be best.

Revision history for this message
jus (jus) wrote :

I agree that we could use descriptive icons for some of the player-like elements in AutoDJ, namely "Shuffle Playlist","Skip Next Track" and "Fade Now" to save some horizontal space for smaller skins.

Suggestion:
* Remove the "Multicolor-Gnome" icons and references and replace it with an existing icon as dummy (e.g. ic_library_autodj.png). I`ll extend our existing custom iconset for the new icons needed as well as the per-skin styling of the transition spinbox later on.
* Restore the default "Enable Auto DJ" button, we follow the "Call to action button" paradigm for main buttons in AutoDJ/Analyze/Recordings.

lp:~daschuer/mixxx/autodj updated
2811. By Daniel Schürmann

fixed Library escaping bug; Restore old enable Auto DJ button

Revision history for this message
Daniel Schürmann (daschuer) wrote :

Hi jus,

it was a pain, restoring the "Enable Auto DJ" button forces me to solve the escaping library bug ..

Thank you for your offer to make buttons for auto DJ. I will leave the current svg buttons as dummys in the mean time.

lp:~daschuer/mixxx/autodj updated
2812. By Daniel Schürmann

fix Deere1280x800-EXPERIMENTAL side-effect of Bug #804529

Revision history for this message
jus (jus) wrote :

Currently there are more dummy buttons in your branch than buttons needed for AutoDJ. Do you plan to use the additional buttons in any way (e.g. for a feature to come?).

Revision history for this message
Daniel Schürmann (daschuer) wrote :

Hi jus,

I simply haven’t tidy up the resources.

By the way: I still have some ideas like "Auto trim" or "Auto End Looping" and changing the transition effects on the fly e.g. "Spin down (or up)" but those jobs are likely the job of Tom Mast.
He is currently working on a new base for autodj (lp:~thomasomast/mixxx/features_autodj). I'm looking forward to see what his code will offer.

Maybe he needs some artwork too.

lp:~daschuer/mixxx/autodj updated
2813. By Daniel Schürmann

* removed unused icons * added required delete statements

2814. By Daniel Schürmann

merged with lp:mixxx

2815. By Daniel Schürmann

merged with lp:mixxx

2816. By Daniel Schürmann

* change button text when enabling autodj
* calculate fade duration for the right track when enabling autodj
* made fade now less restictive

2817. By Daniel Schürmann

merged with lp:mixxx

2818. By Daniel Schürmann

clean up after merge

2819. By Daniel Schürmann

merged with lp:mixxx

2820. By Daniel Schürmann

merged with lp:mixxx

2821. By Daniel Schürmann

merged with trunk

2822. By Daniel Schürmann

merged with lp:mixxx

2823. By Daniel Schürmann

merged with lp:mixxx

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'mixxx/build/depends.py'
2--- mixxx/build/depends.py 2011-12-25 05:45:11 +0000
3+++ mixxx/build/depends.py 2012-03-01 22:38:18 +0000
4@@ -229,23 +229,43 @@
5 '#lib/%s/FIFOSampleBuffer.cpp' % self.SOUNDTOUCH_PATH,
6 '#lib/%s/FIRFilter.cpp' % self.SOUNDTOUCH_PATH,
7 '#lib/%s/PeakFinder.cpp' % self.SOUNDTOUCH_PATH,
8- '#lib/%s/BPMDetect.cpp' % self.SOUNDTOUCH_PATH,
9- '#lib/%s/mmx_optimized.cpp' % self.SOUNDTOUCH_PATH,
10- '#lib/%s/sse_optimized.cpp' % self.SOUNDTOUCH_PATH,]
11+ '#lib/%s/BPMDetect.cpp' % self.SOUNDTOUCH_PATH]
12
13 # SoundTouch CPU optimizations are only for x86
14 # architectures. SoundTouch automatically ignores these files when it is
15 # not being built for an architecture that supports them.
16- cpu_detection = '#lib/%s/cpu_detect_x86_win.cpp' if build.toolchain_is_msvs else '#lib/%s/cpu_detect_x86_gcc.cpp'
17+ cpu_detection = '#lib/%s/cpu_detect_x86_win.cpp' if build.toolchain_is_msvs else \
18+ '#lib/%s/cpu_detect_x86_gcc.cpp'
19 sources.append(cpu_detection % self.SOUNDTOUCH_PATH)
20+
21+ # Check if the compiler has SSE extention enabled
22+ # Allways the case on x64 (core instructions)
23+ optimize = int(util.get_flags(build.env, 'optimize', 1))
24+ if build.machine_is_64bit or \
25+ (build.toolchain_is_msvs and optimize > 2) or \
26+ (build.toolchain_is_gnu and optimize > 1):
27+ sources.extend(
28+ ['#lib/%s/mmx_optimized.cpp' % self.SOUNDTOUCH_PATH,
29+ '#lib/%s/sse_optimized.cpp' % self.SOUNDTOUCH_PATH,
30+ ])
31+
32 return sources
33
34+
35 def configure(self, build, conf):
36 if build.platform_is_windows:
37 # Regardless of the bitwidth, ST checks for WIN32
38 build.env.Append(CPPDEFINES = 'WIN32')
39 build.env.Append(CPPPATH=['#lib/%s' % self.SOUNDTOUCH_PATH])
40
41+ # Check if the compiler has SSE extention enabled
42+ # Allways the case on x64 (core instructions)
43+ optimize = int(util.get_flags(build.env, 'optimize', 1))
44+ if build.machine_is_64bit or \
45+ (build.toolchain_is_msvs and optimize > 2) or \
46+ (build.toolchain_is_gnu and optimize > 1):
47+ build.env.Append(CPPDEFINES='SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS')
48+
49 class TagLib(Dependence):
50 def configure(self, build, conf):
51 if not conf.CheckLib('tag'):
52
53=== modified file 'mixxx/lib/soundtouch-1.6.0/STTypes.h'
54--- mixxx/lib/soundtouch-1.6.0/STTypes.h 2011-07-24 21:30:08 +0000
55+++ mixxx/lib/soundtouch-1.6.0/STTypes.h 2012-03-01 22:38:18 +0000
56@@ -95,7 +95,7 @@
57 /// routines compiled for whatever reason, you may disable these optimizations
58 /// to make the library compile.
59
60- #define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1
61+ // #define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1
62
63 #endif
64
65
66=== added directory 'mixxx/res/images/autodj'
67=== added file 'mixxx/res/images/autodj/bottom.svg'
68--- mixxx/res/images/autodj/bottom.svg 1970-01-01 00:00:00 +0000
69+++ mixxx/res/images/autodj/bottom.svg 2012-03-01 22:38:18 +0000
70@@ -0,0 +1,137 @@
71+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
72+<!-- Created with Inkscape (http://www.inkscape.org/) -->
73+<svg
74+ xmlns:dc="http://purl.org/dc/elements/1.1/"
75+ xmlns:cc="http://creativecommons.org/ns#"
76+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
77+ xmlns:svg="http://www.w3.org/2000/svg"
78+ xmlns="http://www.w3.org/2000/svg"
79+ xmlns:xlink="http://www.w3.org/1999/xlink"
80+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
81+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
82+ width="48px"
83+ height="48px"
84+ id="svg4289"
85+ sodipodi:version="0.32"
86+ inkscape:version="0.46"
87+ sodipodi:docbase="/home/lapo/Icone/cvs/gnome-icon-theme/scalable/categories"
88+ sodipodi:docname="bottom.svg"
89+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
90+ <defs
91+ id="defs4291">
92+ <linearGradient
93+ id="linearGradient3155"
94+ inkscape:collect="always">
95+ <stop
96+ id="stop3157"
97+ offset="0"
98+ style="stop-color:#ffb584;stop-opacity:1;" />
99+ <stop
100+ id="stop3159"
101+ offset="1"
102+ style="stop-color:#ffb584;stop-opacity:0;" />
103+ </linearGradient>
104+ <linearGradient
105+ inkscape:collect="always"
106+ xlink:href="#linearGradient3155"
107+ id="linearGradient3273"
108+ gradientUnits="userSpaceOnUse"
109+ gradientTransform="matrix(0.1532521,0,0,0.1530054,-25.916429,-53.611392)"
110+ x1="325.71429"
111+ y1="369.50507"
112+ x2="325.71429"
113+ y2="546.64789" />
114+ </defs>
115+ <sodipodi:namedview
116+ id="base"
117+ pagecolor="#ffffff"
118+ bordercolor="#666"
119+ borderopacity="0.31372549"
120+ inkscape:pageopacity="0.0"
121+ inkscape:pageshadow="2"
122+ inkscape:zoom="5.656854"
123+ inkscape:cx="25.963489"
124+ inkscape:cy="20.551712"
125+ inkscape:current-layer="layer1"
126+ showgrid="true"
127+ inkscape:grid-bbox="true"
128+ inkscape:document-units="px"
129+ inkscape:window-width="1019"
130+ inkscape:window-height="732"
131+ inkscape:window-x="259"
132+ inkscape:window-y="19"
133+ inkscape:showpageshadow="false" />
134+ <metadata
135+ id="metadata4294">
136+ <rdf:RDF>
137+ <cc:Work
138+ rdf:about="">
139+ <dc:format>image/svg+xml</dc:format>
140+ <dc:type
141+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
142+ <dc:title>System Preferences</dc:title>
143+ <dc:creator>
144+ <cc:Agent>
145+ <dc:title>Andreas Nilsson</dc:title>
146+ </cc:Agent>
147+ </dc:creator>
148+ <dc:subject>
149+ <rdf:Bag>
150+ <rdf:li>category</rdf:li>
151+ <rdf:li>system</rdf:li>
152+ <rdf:li>preferences</rdf:li>
153+ <rdf:li>settings</rdf:li>
154+ <rdf:li>control center</rdf:li>
155+ </rdf:Bag>
156+ </dc:subject>
157+ <dc:contributor>
158+ <cc:Agent>
159+ <dc:title>Jakub Steiner</dc:title>
160+ </cc:Agent>
161+ </dc:contributor>
162+ <cc:license
163+ rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
164+ </cc:Work>
165+ <cc:License
166+ rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
167+ <cc:permits
168+ rdf:resource="http://web.resource.org/cc/Reproduction" />
169+ <cc:permits
170+ rdf:resource="http://web.resource.org/cc/Distribution" />
171+ <cc:requires
172+ rdf:resource="http://web.resource.org/cc/Notice" />
173+ <cc:permits
174+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
175+ <cc:requires
176+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
177+ <cc:requires
178+ rdf:resource="http://web.resource.org/cc/SourceCode" />
179+ </cc:License>
180+ </rdf:RDF>
181+ </metadata>
182+ <g
183+ id="layer1"
184+ inkscape:label="Layer 1"
185+ inkscape:groupmode="layer">
186+ <g
187+ id="g2453"
188+ inkscape:label="Calque 1"
189+ transform="matrix(0.1337942,0,0,0.1337942,-18.472238,-41.04701)" />
190+ <path
191+ style="fill:#ea5d00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9139747;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
192+ d="M 6.7500156,19.774362 L 24.043348,39.555555 L 41.25,19.774362 L 33.004787,19.774362 L 33.004787,4.0000015 L 15.136157,4.0000015 L 15.136157,19.774362 L 6.7500156,19.774362 z"
193+ id="path4348"
194+ sodipodi:nodetypes="cccccccc" />
195+ <rect
196+ y="39.555557"
197+ x="6.75"
198+ height="4.4444442"
199+ width="34.499985"
200+ id="rect4242"
201+ style="fill:#ea5d00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.84845495;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
202+ <path
203+ style="fill:url(#linearGradient3273);fill-opacity:1"
204+ d="M 15.131549,4.0000015 L 15.131549,19.76389 L 6.75,19.76389 L 15.027214,29.208333 C 17.837762,29.718667 20.845017,30.041667 23.999992,30.041667 C 27.180083,30.041667 30.212896,29.726456 33.042326,29.208333 L 41.249983,19.76389 L 33.007548,19.76389 L 33.007548,4.0000015 L 15.131549,4.0000015 z"
205+ id="path3261" />
206+ </g>
207+</svg>
208
209=== added file 'mixxx/res/images/autodj/media-playlist-shuffle.svg'
210--- mixxx/res/images/autodj/media-playlist-shuffle.svg 1970-01-01 00:00:00 +0000
211+++ mixxx/res/images/autodj/media-playlist-shuffle.svg 2012-03-01 22:38:18 +0000
212@@ -0,0 +1,214 @@
213+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
214+<!-- Created with Inkscape (http://www.inkscape.org/) -->
215+
216+<svg
217+ xmlns:dc="http://purl.org/dc/elements/1.1/"
218+ xmlns:cc="http://creativecommons.org/ns#"
219+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
220+ xmlns:svg="http://www.w3.org/2000/svg"
221+ xmlns="http://www.w3.org/2000/svg"
222+ xmlns:xlink="http://www.w3.org/1999/xlink"
223+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
224+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
225+ width="48"
226+ height="48"
227+ id="svg7854"
228+ sodipodi:version="0.32"
229+ inkscape:version="0.47 r22583"
230+ version="1.0"
231+ sodipodi:docname="media-playlist-shuffle.svg"
232+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
233+ inkscape:export-filename="/home/lapo/Icone/gnome-icon-theme/32x32/status/media-playlist-repeat.png"
234+ inkscape:export-xdpi="90"
235+ inkscape:export-ydpi="90">
236+ <defs
237+ id="defs7856">
238+ <linearGradient
239+ gradientUnits="userSpaceOnUse"
240+ y2="21.132059"
241+ x2="22.892584"
242+ y1="0.90414524"
243+ x1="22.892584"
244+ id="linearGradient3178"
245+ xlink:href="#linearGradient3172"
246+ inkscape:collect="always" />
247+ <linearGradient
248+ id="linearGradient3172">
249+ <stop
250+ id="stop3174"
251+ offset="0"
252+ style="stop-color:#ffb584;stop-opacity:1;" />
253+ <stop
254+ id="stop3176"
255+ offset="1"
256+ style="stop-color:#ffb584;stop-opacity:0;" />
257+ </linearGradient>
258+ <linearGradient
259+ inkscape:collect="always"
260+ xlink:href="#linearGradient3172"
261+ id="linearGradient3747"
262+ gradientUnits="userSpaceOnUse"
263+ x1="22.892584"
264+ y1="0.90414524"
265+ x2="22.892584"
266+ y2="21.132059" />
267+ <linearGradient
268+ inkscape:collect="always"
269+ xlink:href="#linearGradient3172"
270+ id="linearGradient3752"
271+ gradientUnits="userSpaceOnUse"
272+ x1="22.892584"
273+ y1="0.90414524"
274+ x2="22.892584"
275+ y2="21.132059"
276+ gradientTransform="matrix(0.644962,0,0,-1.1832362,59.235153,43.983663)" />
277+ <linearGradient
278+ inkscape:collect="always"
279+ xlink:href="#linearGradient3172"
280+ id="linearGradient3755"
281+ gradientUnits="userSpaceOnUse"
282+ gradientTransform="matrix(0.644962,0,0,1.1832362,9.235153,4.016337)"
283+ x1="22.892584"
284+ y1="0.90414524"
285+ x2="22.892584"
286+ y2="21.132059" />
287+ </defs>
288+ <sodipodi:namedview
289+ id="base"
290+ pagecolor="#ffffff"
291+ bordercolor="#afafaf"
292+ borderopacity="1"
293+ gridtolerance="15.1"
294+ guidetolerance="10"
295+ objecttolerance="10"
296+ inkscape:pageopacity="0"
297+ inkscape:pageshadow="2"
298+ inkscape:zoom="8"
299+ inkscape:cx="20.022534"
300+ inkscape:cy="20.71947"
301+ inkscape:document-units="px"
302+ inkscape:current-layer="layer1"
303+ width="48px"
304+ height="48px"
305+ inkscape:showpageshadow="false"
306+ inkscape:window-width="872"
307+ inkscape:window-height="723"
308+ inkscape:window-x="406"
309+ inkscape:window-y="21"
310+ showgrid="false"
311+ inkscape:grid-points="false"
312+ showborder="true"
313+ showguides="false"
314+ inkscape:guide-bbox="false"
315+ inkscape:grid-bbox="true"
316+ inkscape:object-paths="false"
317+ inkscape:window-maximized="0">
318+ <sodipodi:guide
319+ orientation="horizontal"
320+ position="8.6620581"
321+ id="guide7377" />
322+ <sodipodi:guide
323+ orientation="horizontal"
324+ position="6"
325+ id="guide7379" />
326+ <sodipodi:guide
327+ orientation="horizontal"
328+ position="36.062446"
329+ id="guide7492" />
330+ <sodipodi:guide
331+ orientation="horizontal"
332+ position="51"
333+ id="guide7046" />
334+ <sodipodi:guide
335+ orientation="horizontal"
336+ position="-17.5"
337+ id="guide7233" />
338+ <sodipodi:guide
339+ orientation="horizontal"
340+ position="-29"
341+ id="guide7235" />
342+ <sodipodi:guide
343+ orientation="horizontal"
344+ position="44.547727"
345+ id="guide6795" />
346+ <sodipodi:guide
347+ orientation="horizontal"
348+ position="16.970563"
349+ id="guide6797" />
350+ <sodipodi:guide
351+ orientation="horizontal"
352+ position="23.511301"
353+ id="guide6914" />
354+ <inkscape:grid
355+ id="GridFromPre046Settings"
356+ type="xygrid"
357+ originx="0px"
358+ originy="0px"
359+ spacingx="0.5px"
360+ spacingy="0.5px"
361+ color="#0000ff"
362+ empcolor="#0000ff"
363+ opacity="0.2"
364+ empopacity="0.4"
365+ empspacing="2" />
366+ </sodipodi:namedview>
367+ <metadata
368+ id="metadata7859">
369+ <rdf:RDF>
370+ <cc:Work
371+ rdf:about="">
372+ <dc:format>image/svg+xml</dc:format>
373+ <dc:type
374+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
375+ <dc:creator>
376+ <cc:Agent>
377+ <dc:title>Lapo Calamandrei</dc:title>
378+ </cc:Agent>
379+ </dc:creator>
380+ <dc:source />
381+ <cc:license
382+ rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
383+ <dc:title></dc:title>
384+ <dc:subject>
385+ <rdf:Bag />
386+ </dc:subject>
387+ </cc:Work>
388+ <cc:License
389+ rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
390+ <cc:permits
391+ rdf:resource="http://web.resource.org/cc/Reproduction" />
392+ <cc:permits
393+ rdf:resource="http://web.resource.org/cc/Distribution" />
394+ <cc:requires
395+ rdf:resource="http://web.resource.org/cc/Notice" />
396+ <cc:permits
397+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
398+ <cc:requires
399+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
400+ <cc:requires
401+ rdf:resource="http://web.resource.org/cc/SourceCode" />
402+ </cc:License>
403+ </rdf:RDF>
404+ </metadata>
405+ <g
406+ inkscape:label="Layer 1"
407+ inkscape:groupmode="layer"
408+ id="layer1">
409+ <path
410+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#ea5d00;fill:#ea5d00;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter"
411+ d="m 31.458167,11 0,0.971084 0,2.506024 -2.5498,0 c -2.309243,1e-6 -4.600856,0.959829 -6.438247,2.568675 -1.848702,1.618749 -3.250996,4.052721 -3.250996,6.954217 0,1.569915 -0.481869,2.684008 -1.211156,3.414458 -0.729287,0.73045 -1.72852,1.096385 -2.868526,1.096385 l -4.589641,0 -2.0398408,0 -0.5099602,0 0,0.501205 0,4.009639 0,0.501205 0.5099602,0 2.0398408,0 4.589641,0 c 4.913523,0 9.179283,-4.047685 9.179283,-9.522892 0,-1.311125 0.627138,-2.380239 1.593626,-3.226506 0.947549,-0.829685 2.290606,-1.284337 2.996016,-1.284337 l 2.5498,0 0,2.506024 0,0.971084 L 32.25498,22.40241 39.394422,17.390361 40,16.983133 39.394422,16.575904 32.25498,11.563855 31.458167,11 z M 8,14.477108 l 0,0.501205 0,4.009639 0,0.501205 0.5099602,0 2.0398408,0 4.589641,0 c 1.140006,0 2.139239,0.365935 2.868526,1.096385 0.383279,0.38389 0.711734,0.865992 0.924303,1.472289 0.409442,-1.928125 1.388391,-3.582339 2.645418,-4.855421 -0.0054,-0.0055 0.0055,-0.0258 0,-0.03133 -1.680631,-1.696317 -3.981485,-2.693972 -6.438247,-2.693972 l -4.589641,0 -2.0398408,0 -0.5099602,0 z m 23.458167,10.556627 0,0.971084 0,2.506024 -2.5498,0 c -0.70541,0 -2.048467,-0.454652 -2.996016,-1.284337 -0.528622,-0.462867 -0.932659,-0.998256 -1.211156,-1.59759 -0.308884,1.992948 -1.187966,3.74975 -2.422311,5.137349 0.06485,0.05987 0.125211,0.13014 0.191236,0.187952 1.837391,1.608846 4.129004,2.568674 6.438247,2.568675 l 2.5498,0 0,2.506024 0,0.971084 0.796813,-0.563855 7.139442,-5.012049 L 40,31.016867 39.394422,30.609639 32.25498,25.59759 31.458167,25.033735 z"
412+ id="path6784" />
413+ <path
414+ style="fill:url(#linearGradient3755);fill-opacity:1;stroke:none"
415+ d="m 24,29.65625 c -0.297307,0 -0.5803,-0.02559 -0.875,-0.03125 0.774683,-1.167911 1.33229,-2.514662 1.5625,-4 0.278497,0.599334 0.690128,1.130883 1.21875,1.59375 0.947549,0.829685 2.29459,1.28125 3,1.28125 l 2.5625,0 0,-2.5 0,-0.96875 0.78125,0.5625 3.46875,2.4375 C 32.250392,29.058149 28.258286,29.65625 24,29.65625 z M 22.5625,29.625 C 19.537058,29.52951 16.652999,29.1332 14.03125,28.5 l 1.09375,0 c 1.140006,0 2.145713,-0.3633 2.875,-1.09375 0.729287,-0.73045 1.21875,-1.836335 1.21875,-3.40625 0,-2.901496 1.401298,-5.350001 3.25,-6.96875 1.837391,-1.608846 4.128257,-2.562499 6.4375,-2.5625 l 2.5625,0 0,-2.5 0,-0.96875 0.78125,0.5625 7.15625,5 L 40,16.96875 39.40625,17.375 32.25,22.40625 l -0.78125,0.5625 0,-0.96875 0,-2.5 -2.5625,0 c -0.70541,0 -2.052451,0.451565 -3,1.28125 C 24.939762,21.627517 24.3125,22.688875 24.3125,24 c 0,2.153291 -0.650512,4.072677 -1.75,5.625 z m -3.625,-7.5625 C 18.724931,21.456203 18.383279,20.97764 18,20.59375 17.270713,19.8633 16.265006,19.5 15.125,19.5 l -4.5625,0 -2.0625,0 -0.5,0 0,-0.5 0,-4.03125 0,-0.5 0.5,0 2.0625,0 4.5625,0 c 2.456762,0 4.756869,0.991183 6.4375,2.6875 0.0055,0.0055 -0.0054,0.02575 0,0.03125 -1.257027,1.273082 -2.215558,2.946875 -2.625,4.875 z"
416+ id="path3741" />
417+ <g
418+ transform="matrix(0.1337942,0,0,-0.1337942,31.527762,89.04701)"
419+ inkscape:label="Calque 1"
420+ id="g3743" />
421+ <g
422+ transform="matrix(0.1672428,0,0,-0.1672428,38.442916,104.62323)"
423+ inkscape:label="Calque 1"
424+ id="g3745" />
425+ </g>
426+</svg>
427
428=== added file 'mixxx/res/images/autodj/stock_mail-send-receive.svg'
429--- mixxx/res/images/autodj/stock_mail-send-receive.svg 1970-01-01 00:00:00 +0000
430+++ mixxx/res/images/autodj/stock_mail-send-receive.svg 2012-03-01 22:38:18 +0000
431@@ -0,0 +1,87 @@
432+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
433+<!-- Created with Inkscape (http://www.inkscape.org/) -->
434+
435+<svg
436+ xmlns:dc="http://purl.org/dc/elements/1.1/"
437+ xmlns:cc="http://creativecommons.org/ns#"
438+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
439+ xmlns:svg="http://www.w3.org/2000/svg"
440+ xmlns="http://www.w3.org/2000/svg"
441+ xmlns:xlink="http://www.w3.org/1999/xlink"
442+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
443+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
444+ width="48px"
445+ height="48px"
446+ id="svg3787"
447+ version="1.1"
448+ inkscape:version="0.47 r22583"
449+ sodipodi:docname="Nouveau document 4">
450+ <defs
451+ id="defs3789">
452+ <linearGradient
453+ inkscape:collect="always"
454+ xlink:href="#linearGradient3172"
455+ id="linearGradient3767"
456+ gradientUnits="userSpaceOnUse"
457+ gradientTransform="matrix(0.644962,0,0,1.1832362,9.235153,4.016337)"
458+ x1="22.892584"
459+ y1="0.90414524"
460+ x2="22.892584"
461+ y2="21.132059" />
462+ <linearGradient
463+ id="linearGradient3172">
464+ <stop
465+ id="stop3174"
466+ offset="0"
467+ style="stop-color:#ffb584;stop-opacity:1;" />
468+ <stop
469+ id="stop3176"
470+ offset="1"
471+ style="stop-color:#ffb584;stop-opacity:0;" />
472+ </linearGradient>
473+ </defs>
474+ <sodipodi:namedview
475+ id="base"
476+ pagecolor="#ffffff"
477+ bordercolor="#666666"
478+ borderopacity="1.0"
479+ inkscape:pageopacity="0.0"
480+ inkscape:pageshadow="2"
481+ inkscape:zoom="7"
482+ inkscape:cx="24"
483+ inkscape:cy="24"
484+ inkscape:current-layer="layer1"
485+ showgrid="true"
486+ inkscape:grid-bbox="true"
487+ inkscape:document-units="px"
488+ inkscape:window-width="596"
489+ inkscape:window-height="502"
490+ inkscape:window-x="768"
491+ inkscape:window-y="24"
492+ inkscape:window-maximized="0" />
493+ <metadata
494+ id="metadata3792">
495+ <rdf:RDF>
496+ <cc:Work
497+ rdf:about="">
498+ <dc:format>image/svg+xml</dc:format>
499+ <dc:type
500+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
501+ <dc:title></dc:title>
502+ </cc:Work>
503+ </rdf:RDF>
504+ </metadata>
505+ <g
506+ id="layer1"
507+ inkscape:label="Layer 1"
508+ inkscape:groupmode="layer">
509+ <path
510+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#ea5d00;fill:#ea5d00;fill-opacity:1;stroke:none;stroke-width:0.99999988;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Charter;-inkscape-font-specification:Bitstream Charter"
511+ d="m 14.59375,4 -0.375,0.375 -9.46875,9.15625 -0.75,0.75 1.125,0 4.3125,0 0,18.03125 0,0.46875 0.53125,-0.03125 9.3125,-0.03125 0.5,0 0,-0.4375 0,-18 4.375,0 1.15625,0 -0.75,-0.75 L 14.96875,4.375 14.59375,4 z m 13.46875,11.21875 0,0.4375 0,18.0625 -4.25,0 -1.15625,0 0.75,0.75 L 32.875,43.625 33.25,44 l 0.40625,-0.375 9.5625,-9.15625 0.78125,-0.75 -1.15625,0 -4.40625,0 0,-18 0,-0.4375 -0.53125,0 -9.3125,-0.0625 -0.53125,0 z"
512+ id="path4360" />
513+ <path
514+ style="fill:url(#linearGradient3767);fill-opacity:1;stroke:none"
515+ d="M 19.78125,29.4375 C 15.932317,29.076763 12.418889,28.236656 9.4375,27.03125 l 0,-12.75 -4.3125,0 -1.125,0 0.75,-0.75 9.46875,-9.15625 0.375,-0.375 0.375,0.375 9.59375,9.15625 0.75,0.75 -1.15625,0 -4.375,0 0,15.15625 z m 8.28125,0 0,-13.78125 0,-0.4375 0.53125,0 9.3125,0.0625 0.53125,0 0,0.4375 0,11.34375 c -2.995811,1.195807 -6.517914,2.027067 -10.375,2.375 z"
516+ id="path3753" />
517+ </g>
518+</svg>
519
520=== modified file 'mixxx/res/mixxx.qrc'
521--- mixxx/res/mixxx.qrc 2011-12-22 18:43:09 +0000
522+++ mixxx/res/mixxx.qrc 2012-03-01 22:38:18 +0000
523@@ -1,5 +1,8 @@
524 <RCC>
525 <qresource prefix="/">
526+ <file>images/autodj/media-playlist-shuffle.svg</file>
527+ <file>images/autodj/stock_mail-send-receive.svg</file>
528+ <file>images/autodj/bottom.svg</file>
529 <file>html/crates.html</file>
530 <file>html/playlists.html</file>
531 <file>images/mixxx-icon.png</file>
532
533=== modified file 'mixxx/src/dlgautodj.cpp'
534--- mixxx/src/dlgautodj.cpp 2011-11-30 06:19:47 +0000
535+++ mixxx/src/dlgautodj.cpp 2012-03-01 22:38:18 +0000
536@@ -6,8 +6,10 @@
537 #include "controlobjectthreadmain.h"
538 #include "library/trackcollection.h"
539 #include "library/playlisttablemodel.h"
540+#include "playerinfo.h"
541 #include "dlgautodj.h"
542
543+#define CONFIG_KEY "[Auto DJ]"
544
545 DlgAutoDJ::DlgAutoDJ(QWidget* parent, ConfigObject<ConfigValue>* pConfig,
546 TrackCollection* pTrackCollection, MixxxKeyboard* pKeyboard)
547@@ -18,8 +20,12 @@
548 m_pConfig = pConfig;
549 m_pTrackCollection = pTrackCollection;
550 m_bAutoDJEnabled = false;
551- m_bPlayer1Primed = false;
552- m_bPlayer2Primed = false;
553+ m_bFadeNow = false;
554+ m_eState = ADJ_IDLE;
555+
556+ m_posThreshold1 = 1.0f;
557+ m_posThreshold2 = 1.0f;
558+
559 m_pTrackTableView = new WTrackTableView(this, pConfig, m_pTrackCollection);
560 m_pTrackTableView->installEventFilter(pKeyboard);
561
562@@ -55,9 +61,19 @@
563 connect(pushButtonShuffle, SIGNAL(clicked(bool)),
564 this, SLOT(shufflePlaylist(bool)));
565
566+ connect(pushButtonSkipNext, SIGNAL(clicked(bool)),
567+ this, SLOT(skipNext(bool)));
568+
569+ connect(pushButtonFadeNow, SIGNAL(clicked(bool)),
570+ this, SLOT(fadeNow(bool)));
571+
572+ connect(spinBoxTransition, SIGNAL(valueChanged(int)),
573+ this, SLOT(transitionValueChanged(int)));
574+
575 connect(pushButtonAutoDJ, SIGNAL(toggled(bool)),
576 this, SLOT(toggleAutoDJ(bool))); _blah;
577
578+ // playposition is from -0.14 to + 1.14
579 m_pCOPlayPos1 = new ControlObjectThreadMain(
580 ControlObject::getControl(ConfigKey("[Channel1]", "playposition")));
581 m_pCOPlayPos2 = new ControlObjectThreadMain(
582@@ -66,12 +82,24 @@
583 ControlObject::getControl(ConfigKey("[Channel1]", "play")));
584 m_pCOPlay2 = new ControlObjectThreadMain(
585 ControlObject::getControl(ConfigKey("[Channel2]", "play")));
586+ m_pCOPlay1Fb = new ControlObjectThreadMain(
587+ ControlObject::getControl(ConfigKey("[Channel1]", "play")));
588+ m_pCOPlay2Fb = new ControlObjectThreadMain(
589+ ControlObject::getControl(ConfigKey("[Channel2]", "play")));
590 m_pCORepeat1 = new ControlObjectThreadMain(
591 ControlObject::getControl(ConfigKey("[Channel1]", "repeat")));
592 m_pCORepeat2 = new ControlObjectThreadMain(
593 ControlObject::getControl(ConfigKey("[Channel2]", "repeat")));
594 m_pCOCrossfader = new ControlObjectThreadMain(
595 ControlObject::getControl(ConfigKey("[Master]", "crossfader")));
596+
597+ QString str_autoDjTransition = m_pConfig->getValueString(ConfigKey(CONFIG_KEY, "Transition"));
598+ if (str_autoDjTransition.isEmpty()) {
599+ spinBoxTransition->setValue(10); // default 10 sec
600+ }
601+ else {
602+ spinBoxTransition->setValue(str_autoDjTransition.toInt());
603+ }
604 }
605
606 DlgAutoDJ::~DlgAutoDJ()
607@@ -80,8 +108,12 @@
608 delete m_pCOPlayPos2;
609 delete m_pCOPlay1;
610 delete m_pCOPlay2;
611+ delete m_pCOPlay1Fb;
612+ delete m_pCOPlay2Fb;
613+ delete m_pCORepeat1;
614 delete m_pCORepeat2;
615 delete m_pCOCrossfader;
616+ delete m_pAutoDJTableModel;
617 }
618
619 void DlgAutoDJ::onShow()
620@@ -162,196 +194,436 @@
621 qDebug() << "Shuffling done";
622 }
623
624+void DlgAutoDJ::skipNext(bool buttonChecked)
625+{
626+ Q_UNUSED(buttonChecked);
627+ //m_pTrackTableView->sortByColumn(0, Qt::AscendingOrder);
628+ qDebug() << "Skip Next";
629+ //Load the next song from the queue.
630+
631+ if (m_pCOPlay1Fb->get() == 0.0f) {
632+ removePlayingTrackFromQueue("[Channel1]");
633+ loadNextTrackFromQueue();
634+ }
635+ else if (m_pCOPlay2Fb->get() == 0.0f) {
636+ removePlayingTrackFromQueue("[Channel2]");
637+ loadNextTrackFromQueue();
638+ }
639+
640+}
641+
642+void DlgAutoDJ::fadeNow(bool buttonChecked)
643+{
644+ Q_UNUSED(buttonChecked);
645+ qDebug() << "Fade Now";
646+ if (m_eState == ADJ_IDLE && m_bAutoDJEnabled) {
647+ m_bFadeNow = true;
648+ double crossfader = m_pCOCrossfader->get();
649+ if (crossfader <= 0.3f && m_pCOPlay1Fb->get() == 1.0f) {
650+ m_posThreshold1 = m_pCOPlayPos1->get() - ((crossfader + 1.0f) / 2 * (m_fadeDuration1));
651+ m_pCORepeat1->slotSet(0.0f); // Repeat is disabled by FadeNow but disables auto Fade
652+ }
653+ else if (crossfader >= -0.3f && m_pCOPlay2Fb->get() == 1.0f) {
654+ m_posThreshold2 = m_pCOPlayPos2->get() - ((1.0f - crossfader) / 2 * (m_fadeDuration2));
655+ m_pCORepeat2->slotSet(0.0f); // Repeat is disabled by FadeNow but disables auto Fade
656+ }
657+ }
658+}
659+
660 void DlgAutoDJ::toggleAutoDJ(bool toggle)
661 {
662- if (toggle) //Enable Auto DJ
663+ if (toggle) //Enable Auto DJ
664 {
665- if (m_pCOPlay1->get() == 1.0f && m_pCOPlay2->get() == 1.0f) {
666+ if ( m_pCOPlay1Fb->get() == 1.0f
667+ && m_pCOPlay2Fb->get() == 1.0f
668+ ){
669 qDebug() << "One player must be stopped before enabling Auto DJ mode";
670 pushButtonAutoDJ->setChecked(false);
671 return;
672 }
673
674- pushButtonAutoDJ->setText(tr("Disable Auto DJ"));
675+ // Never load the same track if it is already playing
676+ if (m_pCOPlay1Fb->get() == 1.0f) {
677+ removePlayingTrackFromQueue("[Channel1]");
678+ }
679+ if ( m_pCOPlay2Fb->get() == 1.0f) {
680+ removePlayingTrackFromQueue("[Channel2]");
681+ }
682+
683+ TrackPointer nextTrack = getNextTrackFromQueue();
684+ if (!nextTrack) {
685+ qDebug() << "Queue is empty now";
686+ pushButtonAutoDJ->setChecked(false);
687+ return;
688+ }
689+
690+ // Track is available so GO
691+ pushButtonAutoDJ->setToolTip(tr("Disable Auto DJ"));
692+ pushButtonAutoDJ->setText(tr("Disable Auto DJ"));
693+ qDebug() << "Auto DJ enabled";
694 m_bAutoDJEnabled = true;
695+
696 connect(m_pCOPlayPos1, SIGNAL(valueChanged(double)),
697 this, SLOT(player1PositionChanged(double)));
698 connect(m_pCOPlayPos2, SIGNAL(valueChanged(double)),
699 this, SLOT(player2PositionChanged(double)));
700
701-
702- //Manually override the "next track is already loaded" flag
703- //because we've already primed a player with the first track.
704- //We do this so that you don't lose the first song in your
705- //Auto DJ queue if you enable Auto DJ then change your mind
706- //and disable it right away. This just makes it a little bit
707- //more user friendly. :)
708- //m_bNextTrackAlreadyLoaded = true;
709- m_bPlayer1Primed = false;
710- m_bPlayer2Primed = false;
711-
712- //If there are no tracks in the Auto DJ queue, disable Auto DJ mode.
713- /* if (m_pAutoDJTableModel->rowCount() == 0)
714- {
715- //Queue was empty. Disable and return.
716- pushButtonAutoDJ->setChecked(false);
717- return;
718- }*/ //don't need this code, above block takes care of this case.
719-
720- //If only one of the players is playing...
721- if ((m_pCOPlay1->get() == 1.0f && m_pCOPlay2->get() == 0.0f) ||
722- (m_pCOPlay1->get() == 0.0f && m_pCOPlay2->get() == 1.0f))
723- {
724- //Load the first song from the queue.
725- if (!loadNextTrackFromQueue(false)) {
726- //Queue was empty. Disable and return.
727- pushButtonAutoDJ->setChecked(false);
728- return;
729- }
730- //Set the primed flags so the crossfading algorithm knows
731- //that it doesn't need to load a track into whatever player.
732- if (m_pCOPlay1->get() == 1.0f)
733- {
734- m_bPlayer1Primed = true;
735- }
736- if (m_pCOPlay2->get() == 1.0f)
737- {
738- m_bPlayer2Primed = true;
739- }
740- }
741- //If both players are stopped, start the first one (which should have just had a track loaded into it)
742- else if (m_pCOPlay1->get() == 0.0f && m_pCOPlay2->get() == 0.0f) {
743- //Load the first song from the queue.
744- if (!loadNextTrackFromQueue(false)) {
745- //Queue was empty. Disable and return.
746- pushButtonAutoDJ->setChecked(false);
747- return;
748- }
749- m_pCOCrossfader->slotSet(-1.0f); //Move crossfader to the left!
750- m_pCORepeat1->slotSet(1.0f); //Turn on repeat mode to avoid race condition between async load
751- //and "play" command.
752- m_pCOPlay1->slotSet(1.0f); //Play the track in player 1
753- }
754+ connect(m_pCOPlay1Fb, SIGNAL(valueChanged(double)),
755+ this, SLOT(player1PlayChanged(double)));
756+ connect(m_pCOPlay2Fb, SIGNAL(valueChanged(double)),
757+ this, SLOT(player2PlayChanged(double)));
758+
759+ if (m_pCOPlay1Fb->get() == 0.0f && m_pCOPlay2Fb->get() == 0.0f) {
760+ // both decks are stopped
761+ m_eState = ADJ_ENABLE_P1LOADED;
762+ m_pCOPlayPos1->slotSet(-0.001f); // Force Update on load Track
763+ }
764+ else if (m_pCOPlay1Fb->get() == 1.0f)
765+ {
766+ // deck 1 is already playing
767+ m_eState = ADJ_IDLE;
768+ player1PlayChanged(1.0f);
769+ }
770+ else {
771+ // deck 2 is already playing
772+ m_eState = ADJ_IDLE;
773+ player2PlayChanged(1.0f);
774+ }
775+ emit(loadTrack(nextTrack)); // Loads into first deck If stopped else into second else not
776 }
777- else //Disable Auto DJ
778- {
779+ else { //Disable Auto DJ
780+ pushButtonAutoDJ->setToolTip(tr("Enable Auto DJ"));
781 pushButtonAutoDJ->setText(tr("Enable Auto DJ"));
782 qDebug() << "Auto DJ disabled";
783 m_bAutoDJEnabled = false;
784+ m_bFadeNow = false;
785 m_pCOPlayPos1->disconnect(this);
786 m_pCOPlayPos2->disconnect(this);
787- m_pCORepeat1->slotSet(0.0f); //Turn off repeat mode
788- m_pCORepeat2->slotSet(0.0f); //Turn off repeat mode
789+ m_pCOPlay1->disconnect(this);
790+ m_pCOPlay2->disconnect(this);
791 }
792 }
793
794 void DlgAutoDJ::player1PositionChanged(double value)
795 {
796- const float posThreshold = 0.95; //95% playback is when we crossfade and do stuff
797- if (value > posThreshold)
798- {
799- //Crossfade!
800- float crossfadeValue = -1.0f + 2*(value-posThreshold)/(1.0f-posThreshold);
801- m_pCOCrossfader->slotSet(crossfadeValue); //Move crossfader to the right!
802- //If the second player doesn't have a new track loaded in it...
803- if (!m_bPlayer2Primed)
804- {
805- qDebug() << "pp1c loading";
806-
807- //Load the next track into Player 2
808- //if (!m_bNextTrackAlreadyLoaded) //Fudge to make us not skip the first track
809- {
810- if (!loadNextTrackFromQueue(true))
811- return;
812- }
813- //m_bNextTrackAlreadyLoaded = false; //Reset fudge
814- m_bPlayer2Primed = true;
815- }
816- //If the second player is stopped...
817- if (m_pCOPlay2->get() == 0.0f)
818- {
819- //Turn off repeat mode to tell Player 1 to stop at the end
820- m_pCORepeat1->slotSet(0.0f);
821-
822- //Turn on repeat mode to tell Player 2 to start playing when the new track is loaded.
823- //This helps us get around the fact that it takes time for the track to be loaded
824- //and that is executed asynchronously (so we get around the race condition).
825- m_pCORepeat2->slotSet(1.0f);
826- //Play!
827- m_pCOPlay2->slotSet(1.0f);
828- }
829-
830- if (value == 1.0f)
831- {
832- m_pCOPlay1->slotSet(0.0f); //Stop the player
833- m_bPlayer1Primed = false;
834+ // const float posThreshold = 0.95; //95% playback is when we crossfade and do stuff
835+ const float fadeDuration = m_fadeDuration1; // 0.05; // 5% playback is crossfade duration
836+
837+ // qDebug() << "player1PositionChanged(" << value << ")";
838+
839+ if (!m_bAutoDJEnabled) {
840+ //nothing to do
841+ return;
842+ }
843+
844+
845+ if (m_eState == ADJ_ENABLE_P1LOADED) {
846+ // Auto DJ Start
847+ if (m_pCOPlay1Fb->get() == 0.0f && m_pCOPlay2Fb->get() == 0.0f) {
848+ m_pCOCrossfader->slotSet(-1.0f); //Move crossfader to the left!
849+ m_pCOPlay1->slotSet(1.0f); //Play the track in player 1
850+ removePlayingTrackFromQueue("[Channel1]");
851+ }
852+ else if (m_pCOPlay1Fb->get() == 1.0f && m_pCOPlay2Fb->get() == 0.0f) {
853+ // Here we are, if first deck was playing before starting Auto DJ
854+ // or if it was started just before
855+ loadNextTrackFromQueue();
856+ m_eState = ADJ_IDLE;
857+ player1PlayChanged(1.0f); // if we start the deck from code we don`t get a signal
858+ // call function manually
859+ }
860+ else {
861+ m_eState = ADJ_IDLE;
862+ player2PlayChanged(1.0f);
863+ }
864+ return;
865+ }
866+
867+ if (m_eState == ADJ_P2FADING) {
868+ if (m_pCOPlay2Fb->get() == 0.0f && m_pCOPlay1Fb->get() == 1.0f) {
869+ loadNextTrackFromQueue();
870+ // End State
871+ m_pCOCrossfader->slotSet(-1.0f); //Move crossfader to the left!
872+ // qDebug() << "1: m_pCOCrossfader->slotSet(_-1.0f_);";
873+ m_eState = ADJ_IDLE;
874+ }
875+ return;
876+ }
877+
878+ if (m_eState == ADJ_IDLE) {
879+ if (m_pCORepeat1->get() == 1.0f) {
880+ //repeat disables auto DJ
881+ return;
882+ }
883+ }
884+
885+ if (value >= m_posThreshold1) {
886+ if ( m_eState == ADJ_IDLE
887+ && (m_pCOPlay1Fb->get() == 1.0f|| m_posThreshold1 >= 1.0f)
888+ ) {
889+ if (m_pCOPlay2Fb->get() == 0.0f) {
890+ // Start Deck 2
891+ player2PlayChanged(1.0f);
892+ m_pCOPlay2->slotSet(1.0f);
893+ if (fadeDuration < 0.0f) {
894+ // Scroll back for pause between tracks
895+ m_pCOPlayPos2->slotSet(m_fadeDuration2);
896+ }
897+ }
898+ removePlayingTrackFromQueue("[Channel2]");
899+
900+ m_eState = ADJ_P1FADING;
901+ }
902+
903+ float posFadeEnd = m_posThreshold1 + fadeDuration;
904+ if( posFadeEnd > 1.0f ) posFadeEnd = 1.0f;
905+
906+ if (value >= posFadeEnd) {
907+ // Pre-EndState
908+ // m_pCOCrossfader->slotSet(1.0f); //Move crossfader to the right!
909+
910+ m_pCOPlay1->slotSet(0.0f); //Stop the player
911+
912+ //m_posThreshold = 1.0f - fadeDuration; // back to default
913+
914+ // does not work always emediatly after stop
915+ // loadNextTrackFromQueue();
916+ // m_eState = ADJ_IDLE; // Fading ready
917+ }
918+ else {
919+ //Crossfade!
920+ float crossfadeValue = -1.0f + 2*(value-m_posThreshold1)/(posFadeEnd-m_posThreshold1);
921+ // crossfadeValue = -1.0f -> + 1.0f
922+ m_pCOCrossfader->slotSet(crossfadeValue); //Move crossfader to the right!
923+ // qDebug() << "1: m_pCOCrossfader->slotSet " << crossfadeValue;
924 }
925 }
926 }
927
928 void DlgAutoDJ::player2PositionChanged(double value)
929 {
930- const float posThreshold = 0.95; //95% playback is when we crossfade and do stuff
931- if (value > posThreshold)
932- {
933- //Crossfade!
934- float crossfadeValue = 1.0f - 2*(value-posThreshold)/(1.0f-posThreshold);
935- m_pCOCrossfader->slotSet(crossfadeValue); //Move crossfader to the right!
936-
937- //If the first player doesn't have the next track loaded, load a track into
938- //it and start playing it!
939- if (!m_bPlayer1Primed)
940- {
941- //Load the next track into player 1
942- //if (!m_bNextTrackAlreadyLoaded) //Fudge to make us not skip the first track
943- {
944- if (!loadNextTrackFromQueue(true))
945- return;
946- }
947- //m_bNextTrackAlreadyLoaded = false; //Reset fudge
948- m_bPlayer1Primed = true;
949- }
950- if (m_pCOPlay1->get() == 0.0f)
951- {
952- //Turn off repeat mode to tell Player 2 to stop at the end
953- m_pCORepeat2->slotSet(0.0f);
954-
955- //Turn on repeat mode to tell Player 1 to start playing when the new track is loaded.
956- //This helps us get around the fact that it takes time for the track to be loaded
957- //and that is executed asynchronously (so we get around the race condition).
958- m_pCORepeat1->slotSet(1.0f);
959- m_pCOPlay1->slotSet(1.0f);
960- }
961-
962- if (value == 1.0f)
963- {
964- m_pCOPlay2->slotSet(0.0f); //Stop the player
965- m_bPlayer2Primed = false;
966- }
967- }
968-}
969-
970-
971-bool DlgAutoDJ::loadNextTrackFromQueue(bool removeTopMostBeforeLoading)
972-{
973- if (removeTopMostBeforeLoading) {
974- //Only remove the top track if this isn't the start of Auto DJ mode.
975- m_pAutoDJTableModel->removeTrack(m_pAutoDJTableModel->index(0, 0));
976- }
977-
978- //Get the track at the top of the playlist...
979- TrackPointer nextTrack = m_pAutoDJTableModel->getTrack(m_pAutoDJTableModel->index(0, 0));
980-
981- if (!nextTrack) //We ran out of tracks in the queue...
982- {
983- //Disable auto DJ and return...
984- pushButtonAutoDJ->setChecked(false);
985- return false;
986- }
987-
988- //m_bNextTrackAlreadyLoaded = false;
989-
990- emit(loadTrack(nextTrack));
991+ // const float posThreshold = 0.95; //95% playback is when we crossfade and do stuff
992+ float fadeDuration = m_fadeDuration2; // 0.05; // 5% playback is crossfade duration
993+
994+ //qDebug() << "player2PositionChanged(" << value << ")";
995+
996+
997+ if (!m_bAutoDJEnabled) {
998+ //nothing to do
999+ return;
1000+ }
1001+
1002+ if (m_eState == ADJ_P1FADING) {
1003+ if (m_pCOPlay1Fb->get() == 0.0f && m_pCOPlay2Fb->get() == 1.0f) {
1004+ // End State
1005+ m_pCOCrossfader->slotSet(1.0f); //Move crossfader to the right!
1006+ // qDebug() << "1: m_pCOCrossfader->slotSet(_1.0f_);";
1007+ m_eState = ADJ_IDLE;
1008+ loadNextTrackFromQueue();
1009+ }
1010+ return;
1011+ }
1012+
1013+ if (m_eState == ADJ_IDLE) {
1014+ if (m_pCORepeat2->get() == 1.0f) {
1015+ //repeat disables auto DJ
1016+ return;
1017+ }
1018+ }
1019+
1020+ if (value >= m_posThreshold2) {
1021+ if( m_eState == ADJ_IDLE
1022+ && (m_pCOPlay2Fb->get() == 1.0f|| m_posThreshold2 >= 1.0f)
1023+ ) {
1024+ if (m_pCOPlay1Fb->get() == 0.0f) {
1025+ player1PlayChanged(1.0f);
1026+ m_pCOPlay1->slotSet(1.0f);
1027+ if(fadeDuration < 0 ){
1028+ // Scroll back for pause between tracks
1029+ m_pCOPlayPos1->slotSet(m_fadeDuration1);
1030+ }
1031+ }
1032+ removePlayingTrackFromQueue("[Channel1]");
1033+ m_eState = ADJ_P2FADING;
1034+ }
1035+
1036+ float posFadeEnd = m_posThreshold2 + fadeDuration;
1037+ if( posFadeEnd > 1.0f ) posFadeEnd = 1.0f;
1038+
1039+ if (value >= posFadeEnd) {
1040+ //Pre-End State
1041+ //m_pCOCrossfader->slotSet(-1.0f); //Move crossfader to the left!
1042+
1043+ m_pCOPlay2->slotSet(0.0f); //Stop the player
1044+
1045+ //m_posThreshold = 1.0f - fadeDuration; // back to default
1046+
1047+ // does not work always immediately after stop
1048+ // loadNextTrackFromQueue();
1049+ // m_eState = ADJ_IDLE; // Fading ready
1050+ }
1051+ else {
1052+ //Crossfade!
1053+ float crossfadeValue = 1.0f - 2*(value-m_posThreshold2)/(posFadeEnd-m_posThreshold2);
1054+ // crossfadeValue = 1.0f -> + -1.0f
1055+ m_pCOCrossfader->slotSet(crossfadeValue); //Move crossfader to the right!
1056+ // qDebug() << "2: m_pCOCrossfader->slotSet " << crossfadeValue;
1057+ }
1058+ }
1059+}
1060+
1061+
1062+TrackPointer DlgAutoDJ::getNextTrackFromQueue()
1063+{
1064+ //Get the track at the top of the playlist...
1065+
1066+ TrackPointer nextTrack;
1067+
1068+ for (;;) {
1069+ nextTrack = m_pAutoDJTableModel->getTrack(m_pAutoDJTableModel->index(0, 0));
1070+
1071+ if (nextTrack) {
1072+ if (nextTrack->exists()) {
1073+ // found a valid Track
1074+ return nextTrack;
1075+ }
1076+ else {
1077+ // Remove missing song from auto DJ playlist
1078+ m_pAutoDJTableModel->removeTrack(m_pAutoDJTableModel->index(0, 0));
1079+ }
1080+ }
1081+ else {
1082+ // we are running out of tracks
1083+ break;
1084+ }
1085+ }
1086+ return nextTrack;
1087+}
1088+
1089+
1090+bool DlgAutoDJ::loadNextTrackFromQueue()
1091+{
1092+ //Get the track at the top of the playlist...
1093+
1094+ TrackPointer nextTrack = getNextTrackFromQueue();
1095+
1096+ if (!nextTrack) { //We ran out of tracks in the queue...
1097+ //Disable auto DJ and return...
1098+ pushButtonAutoDJ->setChecked(false);
1099+ return false;
1100+ }
1101+
1102+ emit(loadTrack(nextTrack));
1103+ return true;
1104+}
1105+
1106+bool DlgAutoDJ::removePlayingTrackFromQueue(QString group)
1107+{
1108+ TrackPointer nextTrack, loadedTrack;
1109+ int nextId = 0, loadedId = 0;
1110+
1111+
1112+ //Get the track at the top of the playlist...
1113+ nextTrack = m_pAutoDJTableModel->getTrack(m_pAutoDJTableModel->index(0, 0));
1114+ if (nextTrack) {
1115+ nextId = nextTrack->getId();
1116+ }
1117+
1118+ //Get loaded track
1119+ loadedTrack = PlayerInfo::Instance().getTrackInfo(group);
1120+ if (loadedTrack) {
1121+ loadedId = loadedTrack->getId();
1122+ }
1123+
1124+ //When enable auto DJ and Topmost Song is already on second deck, nothing to do
1125+ // BaseTrackPlayer::getLoadedTrack()
1126+ // pTrack = PlayerInfo::Instance().getCurrentPlayingTrack();
1127+
1128+
1129+ if (loadedId != nextId) {
1130+ // Do not remove when the user has loaded a track manualy
1131+ return false;
1132+ }
1133+
1134+ // remove the top track
1135+ m_pAutoDJTableModel->removeTrack(m_pAutoDJTableModel->index(0, 0));
1136
1137 return true;
1138 }
1139+
1140+void DlgAutoDJ::player1PlayChanged(double value){
1141+ qDebug() << "player1PlayChanged(" << value << ")";
1142+
1143+ if (value == 1.0f && m_eState == ADJ_IDLE) {
1144+ TrackPointer loadedTrack = PlayerInfo::Instance().getTrackInfo("[Channel1]");
1145+ if (loadedTrack) {
1146+ int TrackDuration = loadedTrack->getDuration();
1147+ qDebug() << "TrackDuration = " << TrackDuration;
1148+
1149+ int autoDjTransition = spinBoxTransition->value();
1150+
1151+ if (TrackDuration > autoDjTransition) {
1152+ m_fadeDuration1 = (float)autoDjTransition / (float)TrackDuration;
1153+ }
1154+ else {
1155+ m_fadeDuration1 = 0;
1156+ }
1157+ if (autoDjTransition > 0) {
1158+ m_posThreshold1 = 1.0f - m_fadeDuration1;
1159+ }
1160+ else {
1161+ // in case of pause
1162+ m_posThreshold1 = 1.0f;
1163+ }
1164+ qDebug() << "m_fadeDuration1 = " << m_fadeDuration1;
1165+ }
1166+ }
1167+}
1168+
1169+void DlgAutoDJ::player2PlayChanged(double value){
1170+ qDebug() << "player2PlayChanged(" << value << ")";
1171+
1172+ if (value == 1.0f && m_eState == ADJ_IDLE) {
1173+ TrackPointer loadedTrack = PlayerInfo::Instance().getTrackInfo("[Channel2]");
1174+ if (loadedTrack) {
1175+ int TrackDuration = loadedTrack->getDuration();
1176+ qDebug() << "TrackDuration = " << TrackDuration;
1177+
1178+ int autoDjTransition = spinBoxTransition->value();
1179+
1180+ if (TrackDuration > autoDjTransition) {
1181+ m_fadeDuration2 = (float)autoDjTransition / (float)TrackDuration;
1182+ }
1183+ else {
1184+ m_fadeDuration2 = 0;
1185+ }
1186+ if (autoDjTransition > 0) {
1187+ m_posThreshold2 = 1.0f - m_fadeDuration2;
1188+ }
1189+ else {
1190+ // in case of pause
1191+ m_posThreshold2 = 1.0f;
1192+ }
1193+ qDebug() << "m_fadeDuration2 = " << m_fadeDuration2;
1194+ }
1195+ }
1196+}
1197+
1198+void DlgAutoDJ::transitionValueChanged(int value){
1199+
1200+ if (m_bAutoDJEnabled) {
1201+ if (m_bAutoDJEnabled && m_eState == ADJ_IDLE){
1202+ if (m_pCOPlay1Fb->get() == 1.0f) {
1203+ player1PlayChanged(1.0f);
1204+ }
1205+ if (m_pCOPlay2Fb->get() == 1.0f) {
1206+ player2PlayChanged(1.0f);
1207+ }
1208+ }
1209+ }
1210+ m_pConfig->set(ConfigKey(CONFIG_KEY, "Transition"), ConfigValue(value));
1211+}
1212+
1213+bool DlgAutoDJ::appendTrack(int trackId){
1214+ return m_pAutoDJTableModel->appendTrack(trackId);
1215+}
1216
1217=== modified file 'mixxx/src/dlgautodj.h'
1218--- mixxx/src/dlgautodj.h 2011-04-24 06:00:11 +0000
1219+++ mixxx/src/dlgautodj.h 2012-03-01 22:38:18 +0000
1220@@ -31,19 +31,36 @@
1221 virtual void loadSelectedTrack();
1222 virtual void loadSelectedTrackToGroup(QString group);
1223 virtual void moveSelection(int delta);
1224+ virtual bool appendTrack(int trackId);
1225
1226 public slots:
1227 void shufflePlaylist(bool buttonChecked);
1228+ void skipNext(bool buttonChecked);
1229+ void fadeNow(bool buttonChecked);
1230 void toggleAutoDJ(bool toggle);
1231 void player1PositionChanged(double value);
1232 void player2PositionChanged(double value);
1233+ void player1PlayChanged(double value);
1234+ void player2PlayChanged(double value);
1235+ void transitionValueChanged(int value);
1236
1237 signals:
1238 void loadTrack(TrackPointer tio);
1239 void loadTrackToPlayer(TrackPointer tio, QString group);
1240
1241 private:
1242- bool loadNextTrackFromQueue(bool removeTopMostBeforeLoading);
1243+ enum ADJstates
1244+ {
1245+ ADJ_IDLE = 0,
1246+ ADJ_P1FADING,
1247+ ADJ_P2FADING,
1248+ ADJ_ENABLE_P1LOADED,
1249+ ADJ_ENABLE_P1PLAYING
1250+ };
1251+
1252+ TrackPointer getNextTrackFromQueue();
1253+ bool loadNextTrackFromQueue();
1254+ bool removePlayingTrackFromQueue(QString group);
1255
1256 ConfigObject<ConfigValue>* m_pConfig;
1257 TrackCollection* m_pTrackCollection;
1258@@ -57,11 +74,18 @@
1259 make our first-track-gets-loaded-but-
1260 not-removed-from-the-queue behaviour
1261 work. */
1262- bool m_bPlayer1Primed, m_bPlayer2Primed;
1263+ bool m_bFadeNow;
1264+ enum ADJstates m_eState;
1265+ float m_posThreshold1;
1266+ float m_posThreshold2;
1267+ float m_fadeDuration1;
1268+ float m_fadeDuration2;
1269 ControlObjectThreadMain* m_pCOPlayPos1;
1270 ControlObjectThreadMain* m_pCOPlayPos2;
1271 ControlObjectThreadMain* m_pCOPlay1;
1272 ControlObjectThreadMain* m_pCOPlay2;
1273+ ControlObjectThreadMain* m_pCOPlay1Fb;
1274+ ControlObjectThreadMain* m_pCOPlay2Fb;
1275 ControlObjectThreadMain* m_pCORepeat1;
1276 ControlObjectThreadMain* m_pCORepeat2;
1277 ControlObjectThreadMain* m_pCOCrossfader;
1278
1279=== modified file 'mixxx/src/dlgautodj.ui'
1280--- mixxx/src/dlgautodj.ui 2011-10-05 03:30:02 +0000
1281+++ mixxx/src/dlgautodj.ui 2012-03-01 22:38:18 +0000
1282@@ -6,13 +6,28 @@
1283 <rect>
1284 <x>0</x>
1285 <y>0</y>
1286- <width>582</width>
1287+ <width>500</width>
1288 <height>399</height>
1289 </rect>
1290 </property>
1291 <property name="windowTitle">
1292 <string>Manage</string>
1293 </property>
1294+ <property name="styleSheet">
1295+ <string notr="true">#pushButtonShuffle{
1296+ border-image: url(:/images/autodj/media-playlist-shuffle.svg);
1297+}
1298+
1299+#pushButtonSkipNext{
1300+ border-image: url(:/images/autodj/bottom.svg);
1301+}
1302+
1303+#pushButtonFadeNow{
1304+ border-image: url(:/images/autodj/stock_mail-send-receive.svg);
1305+}
1306+
1307+</string>
1308+ </property>
1309 <layout class="QVBoxLayout" name="verticalLayout">
1310 <property name="leftMargin">
1311 <number>0</number>
1312@@ -25,13 +40,89 @@
1313 </property>
1314 <item>
1315 <layout class="QHBoxLayout" name="horizontalLayout">
1316+ <property name="sizeConstraint">
1317+ <enum>QLayout::SetMinimumSize</enum>
1318+ </property>
1319 <item>
1320 <widget class="QPushButton" name="pushButtonShuffle">
1321- <property name="text">
1322- <string>Shuffle playlist</string>
1323- </property>
1324- <property name="checkable">
1325- <bool>false</bool>
1326+ <property name="maximumSize">
1327+ <size>
1328+ <width>24</width>
1329+ <height>24</height>
1330+ </size>
1331+ </property>
1332+ <property name="toolTip">
1333+ <string>Shuffle Playlist</string>
1334+ </property>
1335+ <property name="text">
1336+ <string/>
1337+ </property>
1338+ <property name="checkable">
1339+ <bool>false</bool>
1340+ </property>
1341+ </widget>
1342+ </item>
1343+ <item>
1344+ <widget class="QPushButton" name="pushButtonSkipNext">
1345+ <property name="maximumSize">
1346+ <size>
1347+ <width>24</width>
1348+ <height>24</height>
1349+ </size>
1350+ </property>
1351+ <property name="toolTip">
1352+ <string>Skip Next Track</string>
1353+ </property>
1354+ <property name="text">
1355+ <string/>
1356+ </property>
1357+ <property name="checkable">
1358+ <bool>false</bool>
1359+ </property>
1360+ </widget>
1361+ </item>
1362+ <item>
1363+ <widget class="QLabel" name="label_2">
1364+ <property name="text">
1365+ <string>Transition [sec]</string>
1366+ </property>
1367+ </widget>
1368+ </item>
1369+ <item>
1370+ <widget class="QSpinBox" name="spinBoxTransition">
1371+ <property name="sizePolicy">
1372+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1373+ <horstretch>0</horstretch>
1374+ <verstretch>0</verstretch>
1375+ </sizepolicy>
1376+ </property>
1377+ <property name="maximumSize">
1378+ <size>
1379+ <width>45</width>
1380+ <height>16777215</height>
1381+ </size>
1382+ </property>
1383+ <property name="alignment">
1384+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
1385+ </property>
1386+ <property name="minimum">
1387+ <number>-9</number>
1388+ </property>
1389+ </widget>
1390+ </item>
1391+ <item>
1392+ <widget class="QPushButton" name="pushButtonFadeNow">
1393+ <property name="maximumSize">
1394+ <size>
1395+ <width>24</width>
1396+ <height>24</height>
1397+ </size>
1398+ </property>
1399+ <property name="toolTip">
1400+ <string>Fade Now</string>
1401+ </property>
1402+ <property name="text">
1403+ <string/>
1404 </property>
1405 </widget>
1406 </item>
1407@@ -42,24 +133,17 @@
1408 </property>
1409 <property name="sizeHint" stdset="0">
1410 <size>
1411- <width>40</width>
1412+ <width>1</width>
1413 <height>20</height>
1414 </size>
1415 </property>
1416 </spacer>
1417 </item>
1418 <item>
1419- <widget class="QLabel" name="label">
1420- <property name="text">
1421- <string>Add tracks to the queue below...</string>
1422- </property>
1423- <property name="buddy" >
1424- <cstring>m_pTrackTablePlaceholder</cstring>
1425- </property>
1426- </widget>
1427- </item>
1428- <item>
1429 <widget class="QPushButton" name="pushButtonAutoDJ">
1430+ <property name="toolTip">
1431+ <string>Enable Auto DJ</string>
1432+ </property>
1433 <property name="text">
1434 <string>Enable Auto DJ</string>
1435 </property>
1436@@ -88,6 +172,12 @@
1437 </item>
1438 <item>
1439 <widget class="QTableView" name="m_pTrackTablePlaceholder">
1440+ <property name="sizePolicy">
1441+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1442+ <horstretch>0</horstretch>
1443+ <verstretch>0</verstretch>
1444+ </sizepolicy>
1445+ </property>
1446 <property name="showGrid">
1447 <bool>true</bool>
1448 </property>
1449@@ -95,6 +185,8 @@
1450 </item>
1451 </layout>
1452 </widget>
1453- <resources/>
1454+ <resources>
1455+ <include location="../res/mixxx.qrc"/>
1456+ </resources>
1457 <connections/>
1458 </ui>
1459
1460=== modified file 'mixxx/src/library/autodjfeature.cpp'
1461--- mixxx/src/library/autodjfeature.cpp 2011-10-12 17:29:43 +0000
1462+++ mixxx/src/library/autodjfeature.cpp 2012-03-01 22:38:18 +0000
1463@@ -23,6 +23,7 @@
1464 m_pConfig(pConfig),
1465 m_pTrackCollection(pTrackCollection),
1466 m_playlistDao(pTrackCollection->getPlaylistDAO()) {
1467+ m_pAutoDJView = NULL;
1468 }
1469
1470 AutoDJFeature::~AutoDJFeature() {
1471@@ -36,19 +37,19 @@
1472 return QIcon(":/images/library/ic_library_autodj.png");
1473 }
1474
1475-void AutoDJFeature::bindWidget(WLibrarySidebar* sidebarWidget,
1476+void AutoDJFeature::bindWidget(WLibrarySidebar* /*sidebarWidget*/,
1477 WLibrary* libraryWidget,
1478 MixxxKeyboard* keyboard) {
1479
1480- DlgAutoDJ* pAutoDJView = new DlgAutoDJ(libraryWidget,
1481+ m_pAutoDJView = new DlgAutoDJ(libraryWidget,
1482 m_pConfig,
1483 m_pTrackCollection,
1484 keyboard);
1485- pAutoDJView->installEventFilter(keyboard);
1486- libraryWidget->registerView(m_sAutoDJViewName, pAutoDJView);
1487- connect(pAutoDJView, SIGNAL(loadTrack(TrackPointer)),
1488+ m_pAutoDJView->installEventFilter(keyboard);
1489+ libraryWidget->registerView(m_sAutoDJViewName, m_pAutoDJView);
1490+ connect(m_pAutoDJView, SIGNAL(loadTrack(TrackPointer)),
1491 this, SIGNAL(loadTrack(TrackPointer)));
1492- connect(pAutoDJView, SIGNAL(loadTrackToPlayer(TrackPointer, QString)),
1493+ connect(m_pAutoDJView, SIGNAL(loadTrackToPlayer(TrackPointer, QString)),
1494 this, SIGNAL(loadTrackToPlayer(TrackPointer, QString)));
1495 }
1496
1497@@ -59,18 +60,17 @@
1498 void AutoDJFeature::activate() {
1499 //qDebug() << "AutoDJFeature::activate()";
1500 //emit(showTrackModel(m_pAutoDJTableModelProxy));
1501- emit(switchToView("Auto DJ"));
1502-}
1503-
1504-void AutoDJFeature::activateChild(const QModelIndex& index) {
1505-
1506-}
1507-
1508-void AutoDJFeature::onRightClick(const QPoint& globalPos) {
1509-}
1510-
1511-void AutoDJFeature::onRightClickChild(const QPoint& globalPos,
1512- QModelIndex index) {
1513+ emit(switchToView(m_sAutoDJViewName));
1514+}
1515+
1516+void AutoDJFeature::activateChild(const QModelIndex& /*index*/) {
1517+}
1518+
1519+void AutoDJFeature::onRightClick(const QPoint& /*globalPos*/) {
1520+}
1521+
1522+void AutoDJFeature::onRightClickChild(const QPoint& /*globalPos*/,
1523+ QModelIndex /*index*/) {
1524 }
1525
1526 bool AutoDJFeature::dropAccept(QUrl url) {
1527@@ -98,12 +98,18 @@
1528 }
1529
1530 // TODO(XXX) No feedback on whether this worked.
1531- int playlistId = m_playlistDao.getPlaylistIdFromName(AUTODJ_TABLE);
1532- m_playlistDao.appendTrackToPlaylist(trackId, playlistId);
1533+ if( m_pAutoDJView ){
1534+ m_pAutoDJView->appendTrack(trackId);
1535+ }
1536+ else{
1537+ int playlistId = m_playlistDao.getPlaylistIdFromName(AUTODJ_TABLE);
1538+ m_playlistDao.appendTrackToPlaylist(trackId, playlistId);
1539+ }
1540+
1541 return true;
1542 }
1543
1544-bool AutoDJFeature::dropAcceptChild(const QModelIndex& index, QUrl url) {
1545+bool AutoDJFeature::dropAcceptChild(const QModelIndex& /*index*/, QUrl /*url*/) {
1546 return false;
1547 }
1548
1549@@ -112,10 +118,10 @@
1550 return SoundSourceProxy::isFilenameSupported(file.fileName());
1551 }
1552
1553-bool AutoDJFeature::dragMoveAcceptChild(const QModelIndex& index,
1554- QUrl url) {
1555+bool AutoDJFeature::dragMoveAcceptChild(const QModelIndex& /*index*/,
1556+ QUrl /*url*/) {
1557 return false;
1558 }
1559-void AutoDJFeature::onLazyChildExpandation(const QModelIndex &index){
1560+void AutoDJFeature::onLazyChildExpandation(const QModelIndex& /*index*/){
1561 //Nothing to do because the childmodel is not of lazy nature.
1562 }
1563
1564=== modified file 'mixxx/src/library/autodjfeature.h'
1565--- mixxx/src/library/autodjfeature.h 2011-03-10 13:37:21 +0000
1566+++ mixxx/src/library/autodjfeature.h 2012-03-01 22:38:18 +0000
1567@@ -11,6 +11,7 @@
1568 #include "library/dao/playlistdao.h"
1569 #include "configobject.h"
1570 #include "treeitemmodel.h"
1571+#include "dlgautodj.h"
1572
1573 class PlaylistTableModel;
1574 class TrackCollection;
1575@@ -50,6 +51,7 @@
1576 PlaylistDAO& m_playlistDao;
1577 const static QString m_sAutoDJViewName;
1578 TreeItemModel m_childModel;
1579+ DlgAutoDJ* m_pAutoDJView;
1580 };
1581
1582
1583
1584=== modified file 'mixxx/src/library/browse/browsefeature.cpp'
1585--- mixxx/src/library/browse/browsefeature.cpp 2012-01-07 08:36:51 +0000
1586+++ mixxx/src/library/browse/browsefeature.cpp 2012-03-01 22:38:18 +0000
1587@@ -119,19 +119,25 @@
1588 }
1589
1590 bool BrowseFeature::dropAccept(QUrl url) {
1591- return false;
1592+ Q_UNUSED(url);
1593+ return false;
1594 }
1595
1596 bool BrowseFeature::dropAcceptChild(const QModelIndex& index, QUrl url) {
1597- return false;
1598+ Q_UNUSED(index);
1599+ Q_UNUSED(url);
1600+ return false;
1601 }
1602
1603 bool BrowseFeature::dragMoveAccept(QUrl url) {
1604- return false;
1605+ Q_UNUSED(url);
1606+ return false;
1607 }
1608
1609 bool BrowseFeature::dragMoveAcceptChild(const QModelIndex& index, QUrl url) {
1610- return false;
1611+ Q_UNUSED(index);
1612+ Q_UNUSED(url);
1613+ return false;
1614 }
1615
1616 void BrowseFeature::activate() {
1617@@ -150,10 +156,14 @@
1618 }
1619
1620 void BrowseFeature::onRightClick(const QPoint& globalPos) {
1621+ Q_UNUSED(globalPos);
1622 }
1623
1624 void BrowseFeature::onRightClickChild(const QPoint& globalPos, QModelIndex index) {
1625+ Q_UNUSED(globalPos);
1626+ Q_UNUSED(index);
1627 }
1628+
1629 /*
1630 * This is called whenever you double click or use the triangle symbol to expand
1631 * the subtree. The method will read the subfolders.
1632
1633=== modified file 'mixxx/src/library/browse/browsetablemodel.cpp'
1634--- mixxx/src/library/browse/browsetablemodel.cpp 2011-12-28 20:30:15 +0000
1635+++ mixxx/src/library/browse/browsetablemodel.cpp 2012-03-01 22:38:18 +0000
1636@@ -114,19 +114,19 @@
1637 }
1638
1639 int BrowseTableModel::getTrackId(const QModelIndex& index) const {
1640- Q_UNUSED(index);
1641- // We can't implement this as it stands.
1642+ Q_UNUSED(index);
1643+ // We can't implement this as it stands.
1644 return -1;
1645 }
1646
1647 const QLinkedList<int> BrowseTableModel::getTrackRows(int trackId) const {
1648- Q_UNUSED(trackId);
1649- // We can't implement this as it stands.
1650- return QLinkedList<int>();
1651+ Q_UNUSED(trackId);
1652+ // We can't implement this as it stands.
1653+ return QLinkedList<int>();
1654 }
1655
1656 void BrowseTableModel::search(const QString& searchText) {
1657- Q_UNUSED(searchText);
1658+ Q_UNUSED(searchText);
1659 }
1660
1661 const QString BrowseTableModel::currentSearch() const {
1662@@ -217,7 +217,7 @@
1663 {
1664 Q_UNUSED(index);
1665 Q_UNUSED(location);
1666- return false;
1667+ return false;
1668 }
1669
1670 QMimeData* BrowseTableModel::mimeData(const QModelIndexList &indexes) const {
1671@@ -320,7 +320,7 @@
1672 {
1673 Q_UNUSED(role);
1674
1675- if(!index.isValid())
1676+ if(!index.isValid())
1677 return false;
1678 qDebug() << "BrowseTableModel::setData(" << index.data() << ")";
1679 int row = index.row();
1680
1681=== modified file 'mixxx/src/library/dao/cratedao.h'
1682--- mixxx/src/library/dao/cratedao.h 2011-10-21 00:42:23 +0000
1683+++ mixxx/src/library/dao/cratedao.h 2012-03-01 22:38:18 +0000
1684@@ -47,6 +47,8 @@
1685 void changed(int crateId);
1686 void trackAdded(int crateId, int trackId);
1687 void trackRemoved(int crateId, int trackId);
1688+ void renamed(int crateId);
1689+ void lockChanged(int crateId);
1690
1691 private:
1692 QSqlDatabase& m_database;
1693
1694=== modified file 'mixxx/src/library/dao/playlistdao.cpp'
1695--- mixxx/src/library/dao/playlistdao.cpp 2011-12-18 20:23:14 +0000
1696+++ mixxx/src/library/dao/playlistdao.cpp 2012-03-01 22:38:18 +0000
1697@@ -398,7 +398,7 @@
1698 emit(changed(playlistId));
1699 }
1700
1701-void PlaylistDAO::addToAutoDJQueue(int playlistId) {
1702+void PlaylistDAO::addToAutoDJQueue(int playlistId, bool bTop) {
1703 //qDebug() << "Adding tracks from playlist " << playlistId << " to the Auto-DJ Queue";
1704
1705 // Query the PlaylistTracks database to locate tracks in the selected playlist
1706@@ -413,7 +413,15 @@
1707 // Get the ID of the Auto-DJ playlist
1708 int autoDJId = getPlaylistIdFromName(AUTODJ_TABLE);
1709 // Loop through the tracks, adding them to the Auto-DJ Queue
1710- while(query.next()) {
1711- appendTrackToPlaylist(query.value(0).toInt(), autoDJId);
1712+
1713+ int i = 2; // Start at position 2 because position 1 was already loaded to the deck
1714+
1715+ while (query.next()) {
1716+ if (bTop) {
1717+ insertTrackIntoPlaylist(query.value(0).toInt(), autoDJId, i++);
1718+ }
1719+ else {
1720+ appendTrackToPlaylist(query.value(0).toInt(), autoDJId);
1721+ }
1722 }
1723 }
1724
1725=== modified file 'mixxx/src/library/dao/playlistdao.h'
1726--- mixxx/src/library/dao/playlistdao.h 2011-10-21 00:42:23 +0000
1727+++ mixxx/src/library/dao/playlistdao.h 2012-03-01 22:38:18 +0000
1728@@ -53,13 +53,15 @@
1729 /** Insert a track into a specific position in a playlist */
1730 void insertTrackIntoPlaylist(int trackId, int playlistId, int position);
1731 /** Add a playlist to the Auto-DJ Queue */
1732- void addToAutoDJQueue(int playlistId);
1733+ void addToAutoDJQueue(int playlistId, bool bTop);
1734 signals:
1735 void added(int playlistId);
1736 void deleted(int playlistId);
1737 void changed(int playlistId);
1738 void trackAdded(int playlistId, int trackId, int position);
1739 void trackRemoved(int playlistId, int trackId, int position);
1740+ void renamed(int playlistId);
1741+ void lockChanged(int playlistId);
1742 private:
1743 QSqlDatabase& m_database;
1744 DISALLOW_COPY_AND_ASSIGN(PlaylistDAO);
1745
1746=== modified file 'mixxx/src/library/playlistfeature.cpp'
1747--- mixxx/src/library/playlistfeature.cpp 2011-11-30 05:27:44 +0000
1748+++ mixxx/src/library/playlistfeature.cpp 2012-03-01 22:38:18 +0000
1749@@ -35,10 +35,14 @@
1750 connect(m_pCreatePlaylistAction, SIGNAL(triggered()),
1751 this, SLOT(slotCreatePlaylist()));
1752
1753- m_pAddToAutoDJAction = new QAction(tr("Add to Auto-DJ Queue"),this);
1754+ m_pAddToAutoDJAction = new QAction(tr("Add to Auto-DJ bottom"),this);
1755 connect(m_pAddToAutoDJAction, SIGNAL(triggered()),
1756 this, SLOT(slotAddToAutoDJ()));
1757
1758+ m_pAddToAutoDJTopAction = new QAction(tr("Add to Auto-DJ top 2"),this);
1759+ connect(m_pAddToAutoDJTopAction, SIGNAL(triggered()),
1760+ this, SLOT(slotAddToAutoDJTop()));
1761+
1762 m_pDeletePlaylistAction = new QAction(tr("Remove"),this);
1763 connect(m_pDeletePlaylistAction, SIGNAL(triggered()),
1764 this, SLOT(slotDeletePlaylist()));
1765@@ -77,6 +81,7 @@
1766 delete m_pDeletePlaylistAction;
1767 delete m_pImportPlaylistAction;
1768 delete m_pAddToAutoDJAction;
1769+ delete m_pAddToAutoDJTopAction;
1770 delete m_pRenamePlaylistAction;
1771 delete m_pLockPlaylistAction;
1772 }
1773@@ -142,6 +147,7 @@
1774 menu.addAction(m_pCreatePlaylistAction);
1775 menu.addSeparator();
1776 menu.addAction(m_pAddToAutoDJAction);
1777+ menu.addAction(m_pAddToAutoDJTopAction);
1778 menu.addAction(m_pRenamePlaylistAction);
1779 menu.addAction(m_pDeletePlaylistAction);
1780 menu.addAction(m_pLockPlaylistAction);
1781@@ -430,7 +436,7 @@
1782 //Nothing to do because the childmodel is not of lazy nature.
1783 }
1784
1785-void PlaylistFeature::slotExportPlaylist(){
1786+void PlaylistFeature::slotExportPlaylist() {
1787 qDebug() << "Export playlist" << m_lastRightClickedIndex.data();
1788 QString file_location = QFileDialog::getSaveFileName(
1789 NULL,
1790@@ -481,12 +487,26 @@
1791
1792 void PlaylistFeature::slotAddToAutoDJ() {
1793 //qDebug() << "slotAddToAutoDJ() row:" << m_lastRightClickedIndex.data();
1794+ addToAutoDJ(false); // Top = True
1795+}
1796+
1797+
1798+void PlaylistFeature::slotAddToAutoDJTop() {
1799+ //qDebug() << "slotAddToAutoDJTop() row:" << m_lastRightClickedIndex.data();
1800+ addToAutoDJ(true); // bTop = True
1801+}
1802+
1803+
1804+
1805+void PlaylistFeature::addToAutoDJ(bool bTop) {
1806+ //qDebug() << "slotAddToAutoDJ() row:" << m_lastRightClickedIndex.data();
1807
1808 if (m_lastRightClickedIndex.isValid()) {
1809 int playlistId = m_playlistDao.getPlaylistIdFromName(
1810 m_lastRightClickedIndex.data().toString());
1811 if (playlistId >= 0) {
1812- m_playlistDao.addToAutoDJQueue(playlistId);
1813+ // Insert this playlist
1814+ m_playlistDao.addToAutoDJQueue(playlistId, bTop);
1815 }
1816 }
1817 emit(featureUpdated());
1818
1819=== modified file 'mixxx/src/library/playlistfeature.h'
1820--- mixxx/src/library/playlistfeature.h 2011-11-27 06:59:02 +0000
1821+++ mixxx/src/library/playlistfeature.h 2012-03-01 22:38:18 +0000
1822@@ -50,6 +50,7 @@
1823 void slotCreatePlaylist();
1824 void slotDeletePlaylist();
1825 void slotAddToAutoDJ();
1826+ void slotAddToAutoDJTop();
1827 void slotRenamePlaylist();
1828 void slotTogglePlaylistLock();
1829 void slotImportPlaylist();
1830@@ -59,6 +60,7 @@
1831 private:
1832 void constructChildModel();
1833 void clearChildModel();
1834+ void addToAutoDJ(bool bTop);
1835
1836 TrackCollection* m_pTrackCollection;
1837 PlaylistTableModel* m_pPlaylistTableModel;
1838@@ -67,6 +69,7 @@
1839 QAction *m_pCreatePlaylistAction;
1840 QAction *m_pDeletePlaylistAction;
1841 QAction *m_pAddToAutoDJAction;
1842+ QAction *m_pAddToAutoDJTopAction;
1843 QAction *m_pRenamePlaylistAction;
1844 QAction *m_pLockPlaylistAction;
1845 QAction *m_pImportPlaylistAction;
1846
1847=== modified file 'mixxx/src/library/playlisttablemodel.cpp'
1848--- mixxx/src/library/playlisttablemodel.cpp 2011-12-18 20:23:14 +0000
1849+++ mixxx/src/library/playlisttablemodel.cpp 2012-03-01 22:38:18 +0000
1850@@ -94,6 +94,16 @@
1851 return true;
1852 }
1853
1854+bool PlaylistTableModel::appendTrack(int trackId) {
1855+ if (trackId < 0)
1856+ return false;
1857+
1858+ m_playlistDao.appendTrackToPlaylist(trackId, m_iPlaylistId);
1859+
1860+ select(); //Repopulate the data model.
1861+ return true;
1862+}
1863+
1864 TrackPointer PlaylistTableModel::getTrack(const QModelIndex& index) const {
1865 //FIXME: use position instead of location for playlist tracks?
1866
1867@@ -326,6 +336,7 @@
1868 }
1869
1870 QItemDelegate* PlaylistTableModel::delegateForColumn(const int i) {
1871+ Q_UNUSED(i);
1872 return NULL;
1873 }
1874
1875
1876=== modified file 'mixxx/src/library/playlisttablemodel.h'
1877--- mixxx/src/library/playlisttablemodel.h 2011-11-30 05:27:44 +0000
1878+++ mixxx/src/library/playlisttablemodel.h 2012-03-01 22:38:18 +0000
1879@@ -30,6 +30,7 @@
1880 virtual void removeTrack(const QModelIndex& index);
1881 virtual void removeTracks(const QModelIndexList& indices);
1882 virtual bool addTrack(const QModelIndex& index, QString location);
1883+ virtual bool appendTrack(int trackId);
1884 virtual void moveTrack(const QModelIndex& sourceIndex, const QModelIndex& destIndex);
1885 virtual void shuffleTracks(const QModelIndex& currentIndex);
1886
1887
1888=== modified file 'mixxx/src/widget/wtracktableview.cpp'
1889--- mixxx/src/widget/wtracktableview.cpp 2011-12-14 17:22:49 +0000
1890+++ mixxx/src/widget/wtracktableview.cpp 2012-03-01 22:38:18 +0000
1891@@ -82,6 +82,7 @@
1892
1893 delete m_pReloadMetadataAct;
1894 delete m_pAutoDJAct;
1895+ delete m_pAutoDJTopAct;
1896 delete m_pRemoveAct;
1897 delete m_pPropertiesAct;
1898 delete m_pMenu;
1899@@ -256,9 +257,12 @@
1900 m_pPropertiesAct = new QAction(tr("Properties..."), this);
1901 connect(m_pPropertiesAct, SIGNAL(triggered()), this, SLOT(slotShowTrackInfo()));
1902
1903- m_pAutoDJAct = new QAction(tr("Add to Auto DJ Queue"),this);
1904+ m_pAutoDJAct = new QAction(tr("Add to Auto-DJ bottom"),this);
1905 connect(m_pAutoDJAct, SIGNAL(triggered()), this, SLOT(slotSendToAutoDJ()));
1906
1907+ m_pAutoDJTopAct = new QAction(tr("Add to Auto-DJ top 2"),this);
1908+ connect(m_pAutoDJTopAct, SIGNAL(triggered()), this, SLOT(slotSendToAutoDJTop()));
1909+
1910 m_pReloadMetadataAct = new QAction(tr("Reload Track Metadata"), this);
1911 connect(m_pReloadMetadataAct, SIGNAL(triggered()), this, SLOT(slotReloadTrackMetadata()));
1912 }
1913@@ -356,6 +360,7 @@
1914
1915 if (modelHasCapabilities(TrackModel::TRACKMODELCAPS_ADDTOAUTODJ)) {
1916 m_pMenu->addAction(m_pAutoDJAct);
1917+ m_pMenu->addAction(m_pAutoDJTopAct);
1918 m_pMenu->addSeparator();
1919 }
1920
1921@@ -800,6 +805,15 @@
1922 }
1923
1924 void WTrackTableView::slotSendToAutoDJ() {
1925+ // append to auto DJ
1926+ sendToAutoDJ(false); // bTop = false
1927+}
1928+
1929+void WTrackTableView::slotSendToAutoDJTop() {
1930+ sendToAutoDJ(true); // bTop = true
1931+}
1932+
1933+void WTrackTableView::sendToAutoDJ(bool bTop) {
1934 if (!modelHasCapabilities(TrackModel::TRACKMODELCAPS_ADDTOAUTODJ)) {
1935 return;
1936 }
1937@@ -819,7 +833,13 @@
1938 (pTrack = trackModel->getTrack(index))) {
1939 int iTrackId = pTrack->getId();
1940 if (iTrackId != -1) {
1941- playlistDao.appendTrackToPlaylist(iTrackId, iAutoDJPlaylistId);
1942+ if (bTop) {
1943+ // Load track to position two because position one is already loaded to the player
1944+ playlistDao.insertTrackIntoPlaylist(iTrackId, iAutoDJPlaylistId, 2);
1945+ }
1946+ else {
1947+ playlistDao.appendTrackToPlaylist(iTrackId, iAutoDJPlaylistId);
1948+ }
1949 }
1950 }
1951 }
1952
1953=== modified file 'mixxx/src/widget/wtracktableview.h'
1954--- mixxx/src/widget/wtracktableview.h 2011-10-14 03:58:14 +0000
1955+++ mixxx/src/widget/wtracktableview.h 2012-03-01 22:38:18 +0000
1956@@ -46,6 +46,7 @@
1957 void slotNextTrackInfo();
1958 void slotPrevTrackInfo();
1959 void slotSendToAutoDJ();
1960+ void slotSendToAutoDJTop();
1961 void slotReloadTrackMetadata();
1962 void addSelectionToPlaylist(int iPlaylistId);
1963 void addSelectionToCrate(int iCrateId);
1964@@ -53,6 +54,7 @@
1965 void doSortByColumn(int headerSection);
1966
1967 private:
1968+ void sendToAutoDJ(bool bTop);
1969 void showTrackInfo(QModelIndex index);
1970 void createActions();
1971 void dragMoveEvent(QDragMoveEvent * event);
1972@@ -89,6 +91,7 @@
1973
1974 // Send to Auto-DJ Action
1975 QAction *m_pAutoDJAct;
1976+ QAction *m_pAutoDJTopAct;
1977
1978 // Remove from table
1979 QAction *m_pRemoveAct;