Merge lp:~rryan/mixxx/atomic-co into lp:~mixxxdevelopers/mixxx/atomic-co

Proposed by RJ Skerry-Ryan
Status: Merged
Merged at revision: 3363
Proposed branch: lp:~rryan/mixxx/atomic-co
Merge into: lp:~mixxxdevelopers/mixxx/atomic-co
Diff against target: 8460 lines (+1998/-3446)
107 files modified
mixxx/.cproject (+0/-110)
mixxx/.gdbinit (+0/-26)
mixxx/.project (+0/-79)
mixxx/build/debian/changelog (+6/-0)
mixxx/build/depends.py (+15/-10)
mixxx/build/features.py (+2/-13)
mixxx/build/qtcreator/mixxx.pro (+0/-10)
mixxx/plugins/soundsourcem4a/SConscript (+1/-2)
mixxx/res/skins/Shade1024x600-Netbook/skin.xml (+0/-16)
mixxx/src/analyserbpm.cpp (+0/-102)
mixxx/src/analyserbpm.h (+0/-27)
mixxx/src/analyserqueue.cpp (+0/-11)
mixxx/src/control/control.cpp (+132/-0)
mixxx/src/control/control.h (+95/-0)
mixxx/src/control/controlbehavior.cpp (+63/-0)
mixxx/src/control/controlbehavior.h (+186/-0)
mixxx/src/control/controlvalue.h (+44/-32)
mixxx/src/controlbeat.cpp (+0/-83)
mixxx/src/controlbeat.h (+0/-59)
mixxx/src/controllers/controllerengine.cpp (+6/-8)
mixxx/src/controllers/midi/midicontroller.cpp (+75/-70)
mixxx/src/controllers/midi/midioutputhandler.cpp (+11/-18)
mixxx/src/controllers/midi/midioutputhandler.h (+2/-2)
mixxx/src/controllers/softtakeover.cpp (+1/-1)
mixxx/src/controllinpotmeter.cpp (+5/-24)
mixxx/src/controllinpotmeter.h (+1/-10)
mixxx/src/controllogpotmeter.cpp (+8/-73)
mixxx/src/controllogpotmeter.h (+3/-21)
mixxx/src/controlnull.cpp (+0/-27)
mixxx/src/controlnull.h (+0/-34)
mixxx/src/controlobject.cpp (+49/-104)
mixxx/src/controlobject.h (+31/-48)
mixxx/src/controlobjectthread.cpp (+41/-42)
mixxx/src/controlobjectthread.h (+33/-29)
mixxx/src/controlobjectthreadmain.cpp (+34/-3)
mixxx/src/controlobjectthreadmain.h (+9/-1)
mixxx/src/controlobjectthreadwidget.cpp (+7/-38)
mixxx/src/controlobjectthreadwidget.h (+4/-12)
mixxx/src/controlpotmeter.cpp (+13/-43)
mixxx/src/controlpotmeter.h (+5/-10)
mixxx/src/controlpushbutton.cpp (+22/-55)
mixxx/src/controlpushbutton.h (+1/-7)
mixxx/src/controlttrotary.cpp (+9/-26)
mixxx/src/controlttrotary.h (+2/-12)
mixxx/src/dlgabout.cpp (+193/-6)
mixxx/src/dlgbpmscheme.cpp (+0/-58)
mixxx/src/dlgbpmscheme.h (+0/-38)
mixxx/src/dlgbpmschemedlg.ui (+0/-184)
mixxx/src/dlgprefbpm.cpp (+0/-455)
mixxx/src/dlgprefbpm.h (+0/-67)
mixxx/src/dlgprefbpmdlg.ui (+0/-141)
mixxx/src/dlgprefeq.cpp (+4/-2)
mixxx/src/dlgprefeq.h (+1/-1)
mixxx/src/dlgpreferences.cpp (+1/-33)
mixxx/src/dlgpreferences.h (+0/-2)
mixxx/src/dlgprefrecord.cpp (+15/-17)
mixxx/src/dlgprefshoutcast.h (+3/-5)
mixxx/src/dlgtrackinfo.h (+9/-1)
mixxx/src/encoder/encoder.cpp (+2/-15)
mixxx/src/encoder/encoder.h (+9/-19)
mixxx/src/encoder/encodercallback.h (+8/-25)
mixxx/src/encoder/encodermp3.cpp (+80/-90)
mixxx/src/encoder/encodermp3.h (+11/-25)
mixxx/src/encoder/encodervorbis.cpp (+27/-41)
mixxx/src/encoder/encodervorbis.h (+15/-20)
mixxx/src/engine/bpmcontrol.cpp (+10/-0)
mixxx/src/engine/enginebuffer.cpp (+3/-0)
mixxx/src/engine/enginemaster.cpp (+8/-15)
mixxx/src/engine/enginemaster.h (+4/-4)
mixxx/src/engine/loopingcontrol.cpp (+10/-8)
mixxx/src/engine/ratecontrol.cpp (+16/-5)
mixxx/src/engine/sidechain/enginerecord.cpp (+64/-77)
mixxx/src/engine/sidechain/enginerecord.h (+19/-20)
mixxx/src/engine/sidechain/engineshoutcast.cpp (+86/-88)
mixxx/src/engine/sidechain/engineshoutcast.h (+12/-13)
mixxx/src/engine/sidechain/enginesidechain.cpp (+75/-156)
mixxx/src/engine/sidechain/enginesidechain.h (+29/-39)
mixxx/src/engine/sidechain/sidechainworker.h (+14/-0)
mixxx/src/library/autodjfeature.cpp (+3/-2)
mixxx/src/library/baseexternallibraryfeature.cpp (+2/-0)
mixxx/src/library/baseplaylistfeature.cpp (+2/-2)
mixxx/src/library/basesqltablemodel.cpp (+1/-1)
mixxx/src/library/dao/playlistdao.cpp (+56/-17)
mixxx/src/library/dao/playlistdao.h (+3/-3)
mixxx/src/library/legacylibraryimporter.cpp (+2/-1)
mixxx/src/library/playlistfeature.cpp (+2/-4)
mixxx/src/library/playlisttablemodel.cpp (+2/-2)
mixxx/src/library/setlogfeature.cpp (+6/-4)
mixxx/src/main.cpp (+2/-0)
mixxx/src/mixxx.cpp (+80/-285)
mixxx/src/mixxx.h (+8/-4)
mixxx/src/playermanager.cpp (+39/-9)
mixxx/src/playermanager.h (+11/-0)
mixxx/src/recording/recordingmanager.cpp (+43/-21)
mixxx/src/recording/recordingmanager.h (+4/-2)
mixxx/src/shoutcast/defs_shoutcast.h (+3/-0)
mixxx/src/shoutcast/shoutcastmanager.cpp (+30/-0)
mixxx/src/shoutcast/shoutcastmanager.h (+32/-0)
mixxx/src/skin/propertybinder.cpp (+1/-2)
mixxx/src/sounddeviceportaudio.cpp (+3/-2)
mixxx/src/soundmanager.cpp (+2/-0)
mixxx/src/test/analyserbpmtest.cpp (+0/-103)
mixxx/src/vinylcontrol/vinylcontrolmanager.cpp (+10/-10)
mixxx/src/waveform/renderers/waveformmarkset.cpp (+2/-2)
mixxx/src/widget/wpushbutton.cpp (+2/-1)
mixxx/src/widget/wtracktableview.cpp (+2/-0)
mixxx/vamp-plugins/SConscript (+1/-1)
To merge this branch: bzr merge lp:~rryan/mixxx/atomic-co
Reviewer Review Type Date Requested Status
Daniel Schürmann Approve
Review via email: mp+163831@code.launchpad.net
To post a comment you must log in.
Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

I'm getting really excited about these control changes!

* Create a value wrapper around COBase values -- ControlNumericPrivate (CNP).
* Add a static creation method / hash index of existing CNPs similar to CO.
* Add a ControlBehavior class hierarchy that encodes all the behaviors that CO/COPushButton/COTTRotary/COPotmeter/COLogpotmere/COLinpotmeter/etc. all used to have built in.
* Remove all value-space to parameter-space conversion methods from CO hierarchy (e.g. valueToWidget/valueFromWidget).
* Get rid of CO / COT proxying. CO and COT both refer to CNP now and are equals in the sense that they both make requests to CNP. The only difference is that CO also creates a CNP when it is created for the first time and sets its behavior while a COT only binds to an existing CNP.

* Add valueChangedFromEngine and valueChangedByThis signals to CO and COT respectively. You'll see that CNP solves the issue that was previously solved by the sync thread -- all mutations (add/sub/set/reset) to the CNP include a pointer to the setter. This is re-broadcast by the CNP and so CO/COT can check the pointer and choose to emit either valueChanged() or valueChangedFromEngine/valueChangedByThis().

I'm only keeping the name valueChangedFromEngine name on the CO to keep backwards compatibility with other engine branches that are still unmerged (e.g. engine-control-refactor).

I'm really liking where this is going. There is really no difference between CO and COT except the creation of a CNP and setting of a Behavior in the CO. We could easily swap this out with a static factory method like Control::createPushButton(options...) that returned a COT-style object (that we could finally rename as Control* to keep things shorter). We could also flatten the CO hierarchy if the behavior-setting was done by a factory/static method. ControlPotmeter is the only standout there since other parts of Mixxx introspect on the control using dynamic_cast. Those hacks should be replaced with something more generic at the CNP layer that lets you ask things about the behavior.

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

Hi RJ,

Here only some edges in advanced, not a complete review.

* Since ControlObjectBase is not a base class any more, we should rename it to ControlObjectAtomic
* the name ControlNumericPrivate is fine for now, but if we want to finaly allow other numeric types, this should be more specific. What about ControlDoublePrivate?
http://mixxx.org/wiki/doku.php/revamped_control_system#control_object_types
* I am not sure if I like your m_pBehavior logic. It looks like you intended to make it also non blocking thread save
But I think it is not required, because only the CO owner should be allowed to set the behaviour of the CO.
It is required to change from elsewhere?
I think your solution might be not entirely save, because this check may fail:
return m_pBehavior ? m_pBehavior->defaultValue(default_value) : default_value;
m_pBehavior may change to NULL or from NULL between the check and the use.
ControlObjectBase<ControlNumericBehaviour> would be a solution but again I don't think it is required.
* We schould check the same for

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

.. m_defaultValue.
* I would like to get rid of sub and add. It may implies that it is an atomic operation.
* We may introduce a One reader version, instead where sub and add is save.
* The same issue may occur for all other read modify write actions inside the user code.
* We only have to decide if we verify the use by the CPU (overhead) or if we rely on the correctness of the user code?

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

I like the idea of having a COT, which controls the value change signal for the own changes.

I am not sure if I have fully understand the new behaviour bit here are my comments:

I do not like the idea that ControlObject receives signals. For me it is not clear in which thread it lives.
And I would like to allow two QObjects in the same thread communicate with signals.

What about this:
* An Object has a COT member with set(double value);
* The COT calls set(value, this) of the CO
* The CO emits valueChanged(double value, QObject* sender) in any case
* COT is connected to this signal and remits valueChanged(double value) in case this != sender

This allows that all other QObjects will receive the valueChange signals regardless in which thread it lives.
The resend of COT is "cheap" a direct connection in any case.

Code that is resend resistant, can work with CO without COT the wrapper.

COT should be renamed to something like ControlObjectValve

review: Needs Fixing
Revision history for this message
RJ Skerry-Ryan (rryan) wrote :
Download full text (3.2 KiB)

> * Since ControlObjectBase is not a base class any more, we should rename it to ControlObjectAtomic

Sounds good to me.

> * the name ControlNumericPrivate is fine for now, but if we want to finaly allow other numeric types, this should be more specific. What about ControlDoublePrivate?
http://mixxx.org/wiki/doku.php/revamped_control_system#control_object_types

Good point, I hadn't considered we would want uint types. ControlDoublePrivate seems good. Maybe behaviors should be templated to save common logic across the value types?

> * I am not sure if I like your m_pBehavior logic. It looks like you intended to make it also non blocking thread save But I think it is not required, because only the CO owner should be allowed to set the behaviour of the CO. It is required to change from elsewhere?

I didn't want to limit who could setBehavior(). We may want to do it from elsewhere in the future?

> I think your solution might be not entirely save, because this check may fail:
return m_pBehavior ? m_pBehavior->defaultValue(default_value) : default_value;
m_pBehavior may change to NULL or from NULL between the check and the use.
ControlObjectBase<ControlNumericBehaviour> would be a solution but again I don't think it is required.

Oops! Good point. I'll fix that. The only reason I used QAtomicPointer was to do a fetchAndSetRelaxed() to atomically swap the pointer for a new one. All other accesses should only need normal pointer access.

> * We schould check the same for m_defaultValue.

In this case I think we should keep COBase for defaultValue (And in the future other Control properties like a 'disabled'). In the future (e.g. in effects) the user may be able to tweak the default value of a control that represents an effect parameter so it's possible that it would change rapidly in response to user input and be accessed at the same time by another thread.

> * I would like to get rid of sub and add. It may implies that it is an atomic operation.

We could remove them. The only use of sub/add is in RateControl at the moment. I kind of like them as part of the API but I agree it gives the impression of atomicity.

> * We may introduce a One reader version, instead where sub and add is save.

Hm, given we only found one place to use sub/add I don't know if it's worth the effort.

> * The same issue may occur for all other read modify write actions inside the user code.

Yea, ControlPotmeter for example doesn't use add()/sub() for increment/decrement. It has the same issue where it isn't atomic. Could we extend the COBase API to include add/sub? That's a little odd because COBase isn't just for numeric types. It could allow you to implement operator+/operator- on a custom type if you want to atomically do something to it. Or in the future we could use c++11 lambdas and pass a lambda into COBase that is be used to mutate the value.

> * We only have to decide if we verify the use by the CPU (overhead) or if we rely on the correctness of the user code?

I think a balance is good. Relying on user code to be correct too much will get us into trouble since not everyone writing user code is fully aware of all the details of the control system (a good ex...

Read more...

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :
Download full text (3.5 KiB)

> I do not like the idea that ControlObject receives signals. For me it is not clear in which thread it lives.

The only signal it gets is a DirectConnection so the thread shouldn't matter.

> And I would like to allow two QObjects in the same thread communicate with signals.

Could you explain more? I don't think I get it.

> What about this:
> * An Object has a COT member with set(double value);
> * The COT calls set(value, this) of the CO
> * The CO emits valueChanged(double value, QObject* sender) in any case
> * COT is connected to this signal and remits valueChanged(double value) in case this != sender

> This allows that all other QObjects will receive the valueChange signals regardless in which thread it lives.
> The resend of COT is "cheap" a direct connection in any case.

Yea, I also consider DirectConnection to be cheap performance-wise.

Basically, what I've implemented is almost exactly what you're describing except it has some additional benefits. Think of it like this:

* I have renamed ControlObject to ControlNumericPrivate.
* I pulled out all the logic that was previously specialized by sub-classing ControlObject into ControlBehavior.
* All of the previous ControlObject classes (CO, ControlPotmeter, ControlPushButton, etc.) have now been converted into ControlObjectThreads except they also create a CNP and set its behavior if it does not exist.

> Code that is resend resistant, can work with CO without COT the wrapper.

No code in Mixxx has been consciously written to be resend resistant except the slots that intentionally listen to both valueChanged and valueChangedFromEngine. If any other code is resend resistant then that is purely an accident :). Making CO emit valueChanged() for every set() is super dangerous.

The benefits are:

* Separating the behavior of a control from its type. In the future when we have multiple control types that you can lookup it will be handy to be able to represent the behavior separately from the plumbing of the values. It could also allow injection of logic into a control from outside. For example, if you wanted to make a custom control that only allowed set() under a certain circumstance, you could sub-class a behavior to describe the logic you desire and then set your custom behavior on your control.

* No more master/slave relationship between CO and COT. The reason it was this way was because the CO system was designed to only be used in the engine. Today controls are defined and used everywhere in Mixxx and it's really more of a shared key-value store than it is a way to communicate with the engine. Plus, we have to deal with ugly things like NULL-ifying our pointer to the CO when it is deleted in the COT and every time you want to create a COT, you have to call ControlObject::getControl() first. The way I have it, there is still a master/slave but the master is not available to anyone for direct use. CNP is the master, both CO and COT are slaves.

* This will benefit the engine-control-refactor branch. In that branch, CO is not used to communicate with the engine anymore. There is a new type, a CallbackControl which is connected to the CO system via a FIFO of control changes. The...

Read more...

Revision history for this message
Owen Williams (ywwg) wrote :

How much rewriting is this going to require, such as for my master_sync branch which has a lot of controlobject fiddliness?

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

> How much rewriting is this going to require, such as for my master_sync branch
> which has a lot of controlobject fiddliness?

This will be definitely a problem if we go to much a head with this branch.
I think in the current state there is some assembly line work required but since a controlObject is still a control Object there should be no logic changes required.

So I think we should try to finish and merge a branch soon, which has proved that ControlObjectBase is working.

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

> How much rewriting is this going to require, such as for my master_sync branch which has a lot of controlobject fiddliness?

For this branch, if we keep the separation between valueChanged and valueChangedFromEngine then it shouldn't need many/any changes.

For engine-control-refactor, the changes will be significant (hopefully mostly cosmetic though, the logic will need a review). I suggest getting master_sync merged before engine-control-refactor :).

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

> Maybe behaviors should be templated to save common logic across
> the value types?

Yes, we have only to deal with the not temple-atable Qt signals

> > * I would like to get rid of sub and add. It may implies that it is an
> atomic operation.
>
> We could remove them. The only use of sub/add is in RateControl at the moment.
> I kind of like them as part of the API but I agree it gives the impression of
> atomicity.

OK then, lets remove them

> > * The same issue may occur for all other read modify write actions inside
> the user code.
>
> Yea, ControlPotmeter for example doesn't use add()/sub() for
> increment/decrement. It has the same issue where it isn't atomic. Could we
> extend the COBase API to include add/sub? That's a little odd because COBase
> isn't just for numeric types. It could allow you to implement
> operator+/operator- on a custom type if you want to atomically do something to
> it. Or in the future we could use c++11 lambdas and pass a lambda into COBase
> that is be used to mutate the value.

Yes, we can implement an lockfee "read modify write" in the way ARM did it:
* Watch the current value
* Add or Sub a value
* Check the if the current value was changed in the meanwhile
* If Yes, retry.
I will try it out.

lp:~rryan/mixxx/atomic-co updated
3360. By Daniel Schürmann

merged rollback -r 3360 lp:~rryan/mixxx/atomic-co

3361. By Daniel Schürmann

set cReaderSlotCnt = std::numeric_limits<int>::max()

3362. By Daniel Schürmann

added alignement keywords

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

Played around with add and sub and I finaly came to the conclusion to remove it, in vafour of clean code.
It is only used once and it is fully save, if there is only one writer.

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

> COT should be renamed to something like ControlObjectValve

I'm up for making broad changes like this in the future but to be kind to every currently open branch author we should not rename either CO/COT/COTM/COTW until there are fewer major open branches.

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

> Played around with add and sub and I finaly came to the conclusion to remove it, in vafour of clean code.
> It is only used once and it is fully save, if there is only one writer.

Ok -- I'll do that in this branch.

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

> * the name ControlNumericPrivate is fine for now, but if we want to finaly allow other numeric types, this should be more specific. What about ControlDoublePrivate?

Fixed

> I think your solution might be not entirely save, because this check may fail:
return m_pBehavior ? m_pBehavior->defaultValue(default_value) : default_value;

Fixed

> Played around with add and sub and I finaly came to the conclusion to remove it, in vafour of clean code.

Fixed

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

I've re-reviewed the whole branch and merged with lp:~mixxxdevelopers/mixxx/atomic-co and think it's ready to merge into lp:mixxx. I can't wait to get this tested by bleeding-edgers. :)

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

"the name ControlNumericPrivate is fine for now, but if we want to finaly allow other numeric types, this should be more specific. What about ControlDoublePrivate?"

What happened to using QVariant?

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

I think QVariant is not suitable for our approach. Because I don't want to deal with type conversion inside of Mixxx.

I have planed to introduce the following types:

    double (legacy) for higest accuracy
    uint32_t, for fast access, and bool values
    uint8_t[4], for routing Midi Messages
    QString

These types should be modifiable by a common Script API using QScriptValue.

So we have the benefit of the typeless java script code but without performance overhead of QVariant.

http://mixxx.org/wiki/doku.php/revamped_control_system#control_object_types

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

Thanks, Daniel. That makes sense and it doesn't look to be too hard to add more types in the future if we need them.

Other comments/questions I have as I read through the changes:

* Before you get too far along, shouldn't the "Control" class be called "MixxxControl" or "InternalControl" to differentiate it from other types of controls, like external hardware ones? This will be especially important to avoid confusion if we plan to directly expose these to controller scripts.
* controlbehavior.h: don't the definitions of many of the classes have a bit too much code to have it all in the .h file?
* controlbehavior.h: hard-coding max and minPosition will be problematic if in the future we want to support controllers with 14-bit controls (spread across two messages) without scripting.
* controlvalue.h: what exactly does "sacrifice perfect consistency" mean? That occasionally a read value may be out of date? How likely is that to happen and can we somehow keep track of when it does incase we start seeing strange problems elsewhere as a result?
* midicontroller.cpp, line 270 (QString message): Come on, now. You actually made it harder to read. :)
* various places: isn't "getMidiValue" clearer than "getValueToMidi" since the output is a MIDI-scaled (0..127) value?
* controllinpotmeter.cpp and other places: That creation/deletion stuff looks weird to me, but it makes sense given the comment in control.h. As long as code outside the [Mixxx]Control classes won't have to do that jockeying, I'm good with it.

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

Oh, isn't a straight 1-bit bool better than a uint32_t for boolean values?

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

> Oh, isn't a straight 1-bit bool better than a uint32_t for boolean values?

Just noticed: We should introduce an int32_t control Object, not unsigned.

I do not like to have bool ControlObjects, because they have no value for invalid.
There is no performance overhead to store boolean into an int32_t.
It is only a question of min and max value of an control o0bject.

From the script, using boolean is fine.

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :
Download full text (3.1 KiB)

Hey Sean,

> * Before you get too far along, shouldn't the "Control" class be called "MixxxControl" or "InternalControl" to differentiate it from other types of controls, like external hardware ones? This will be especially important to avoid confusion if we plan to directly expose these to controller scripts.

MixxxControl is just as redundant as ControlObject. Control is much shorter to type. Controller scripts already call these control (getControl/setControl).

> * controlbehavior.h: don't the definitions of many of the classes have a bit too much code to have it all in the .h file?

Probably a good point. I was hoping to promote inline-ability but since it's all virtual that's a lost cause anyway.

> * controlbehavior.h: hard-coding max and minPosition will be problematic if in the future we want to support controllers with 14-bit controls (spread across two messages) without scripting.

This is all copy-pasta from the various Control* implementations. The big bug with Mixxx's control system has always been hard-coding the limits of parameter space to be 0-127 to match with MIDI. I aim to change that in the future, not in this branch. Parameter space should be 0-1 always.

> * controlvalue.h: what exactly does "sacrifice perfect consistency" mean? That occasionally a read value may be out of date? How likely is that to happen and can we somehow keep track of when it does incase we start seeing strange problems elsewhere as a result?

Yep, that's right. See the discussion on the ~mixxxdevelopers/mixxx/atomic-co merge. The number of concurrent readers must exceed INT_MAX for inconsistent reads to occur.

> * midicontroller.cpp, line 270 (QString message): Come on, now. You actually made it harder to read. :)

*shrug* all of this MIDI message string formatting probably belongs in a utility library anyway like src/controllers/midi/util.h.

> * various places: isn't "getMidiValue" clearer than "getValueToMidi" since the output is a MIDI-scaled (0..127) value?

This full function name could be written as getValueToMidiParameterSpace so it's much clearer if you're thinking about it in terms of value space vs. parameter space (it's parallel with widget parameter space). This is another thing I want to totally get rid of from the control system anyway. There should just be one single parameter space for controls (instead of two parameter spaces, MIDI parameters and widget parameters) and the MIDI subsystem should do the translation to/from raw MIDI values within the controller MIDI subsystem.

> * controllinpotmeter.cpp and other places: That creation/deletion stuff looks weird to me, but it makes sense given the comment in control.h. As long as code outside the [Mixxx]Control classes won't have to do that jockeying, I'm good with it.

Yea, unless you want to write a custom behavior this is always going to be an implementation detail. The reason that exists is that the control itself might be located in a place where it is not ok to malloc/free (e.g. the engine callback) so it is the caller of setBehavior's job to manage the destruction of the behavior (e.g. by passing the pointer into a FIFO that is read from by a garbage cleanup thread)...

Read more...

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

"There should just be one single parameter space for controls (instead of two parameter spaces, MIDI parameters and widget parameters) and the MIDI subsystem should do the translation to/from raw MIDI values within the controller MIDI subsystem."

For the record, I completely agree. (This was one thing that annoyed me during the controller subsystem rewrite, and it remains responsible for inconsistencies between straight XML-mapped controls and those set from script as well as code duplication to minimize them.)

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

> "the name ControlNumericPrivate is fine for now, but if we want to finaly allow other numeric types, this should be more specific. What about ControlDoublePrivate?"

> What happened to using QVariant?

I think we should still make a QVariant control so that things like scripts can pass around custom values without recompiling the Mixxx binary to add a new control type. We can also make a QVariant-based wrapper around controls for insertion into the controller engine. I agree w/ Daniel that it doesn't make sense to sacrifice the performance in areas where we know the type we will always use for the control.

> > Oh, isn't a straight 1-bit bool better than a uint32_t for boolean values?

> Just noticed: We should introduce an int32_t control Object, not unsigned.

> I do not like to have bool ControlObjects, because they have no value for invalid.
> There is no performance overhead to store boolean into an int32_t.
> It is only a question of min and max value of an control o0bject.

> From the script, using boolean is fine.

Daniel -- this is part of why your ControlValueAtomic really excites me. One thing that has always been a huge hack in Mixxx is co-opting the value space of a control to represent a disabled state or invalid value. We can just add these as properties of the control outside of its value. This is Control 2.0 stuff we have been talking about for a long time -- finally being able to make the GUI respond to a control being disconnected/inactive by graying it out . This is possible if we represent invalid/disabled as a separate value from the Control value.

And if we did that I think it would be fine to make a boolean control -- the API would be much nicer than what we do today to encode a bool in a double by always checking for v != 0.

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

> For the record, I completely agree. (This was one thing that annoyed me during the controller subsystem rewrite, and it remains responsible for inconsistencies between straight XML-mapped controls and those set from script as well as code duplication to minimize them.)

Yea, it's been this way since Mixxx 1.0 and it's a huge hack.

If we converted everything to have one parameter space then I think every control should have a setParameter()/getParameter() method that allows you to set the value in parameter space. I don't want to work on this (killing MIDI/widget parameter space) until we've merged this though. This branch diff is already quite large.

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

I also fully agree on both points, RJ.

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

> co-opting the value space of a control to represent a disabled state or invalid value

See the "scratch" CO where 0=disabled, but 1=play normal speed. Ugh. That's why I had to make a "scratch2" with a separate "scratch2_enabled" CO.

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

Barring strenuous objection, I'll go ahead and merge this. Daniel, do you agree this in a merge-worthy state?

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

Hi RJ,

Yes, I will merge it into lp:~mixxxdevelopers/mixxx/atomic-co now.

But I have not entirely reviewed and test it for merge into trunk.

I think I have not fully understand your COT changes yet so I have some code read todo.

---

the "scratch2" and "scratch2_enabled" think is definitely a subject for change in near future.
But there might be race conditions if we handle the scratch2_enabled like a property. For me it is a part of the atomic info scratch2 itself. If we introduce a int type control object we can easily reserve on value for invalid
eg -100 .. 100 + 0x7fffffff = invalid. A bool becomes 0 .. 1 + 0x7fffffff = invalid;
Or we can introduce a bitfield struct like this
struct {
   int value : 31;
   int invalid : 1;
}
Or if we don't mind using the ring implementation of ControlValueAtomic:
struct {
   double value;
   bool invalid;
}

In this way we never have an invalid flag on a valid value or vice versa.

review: Approve
Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

In that case, let's merge to lp:mixxx. Owen is waiting on this to get
master-sync merged. There will be logic issues we run into where parts of
Mixxx have not expected the CO and COT value to be flattened but we will
have to fix those as we come to them. The sooner we can get trunk testers
trying it out the better.

On Thu, May 16, 2013 at 4:48 PM, Daniel Schürmann <email address hidden>wrote:

> Review: Approve
>
> Hi RJ,
>
> Yes, I will merge it into lp:~mixxxdevelopers/mixxx/atomic-co now.
>
> But I have not entirely reviewed and test it for merge into trunk.
>
> I think I have not fully understand your COT changes yet so I have some
> code read todo.
>
> ---
>
> the "scratch2" and "scratch2_enabled" think is definitely a subject for
> change in near future.
> But there might be race conditions if we handle the scratch2_enabled like
> a property. For me it is a part of the atomic info scratch2 itself. If we
> introduce a int type control object we can easily reserve on value for
> invalid
> eg -100 .. 100 + 0x7fffffff = invalid. A bool becomes 0 .. 1 + 0x7fffffff
> = invalid;
> Or we can introduce a bitfield struct like this
> struct {
> int value : 31;
> int invalid : 1;
> }
> Or if we don't mind using the ring implementation of ControlValueAtomic:
> struct {
> double value;
> bool invalid;
> }
>
> In this way we never have an invalid flag on a valid value or vice versa.
>
>
>
> --
> https://code.launchpad.net/~rryan/mixxx/atomic-co/+merge/163831
> You are the owner of lp:~rryan/mixxx/atomic-co.
>

lp:~rryan/mixxx/atomic-co updated
3363. By Daniel Schürmann

merged from lp:~rryan/mixxx/atomic-co

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

OK, I will be finished today :-)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== removed file 'mixxx/.cproject'
2--- mixxx/.cproject 2013-03-13 21:41:26 +0000
3+++ mixxx/.cproject 1970-01-01 00:00:00 +0000
4@@ -1,110 +0,0 @@
5-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
6-<?fileVersion 4.0.0?>
7-
8-<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
9- <storageModule moduleId="org.eclipse.cdt.core.settings">
10- <cconfiguration id="0.1101443865">
11- <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="0.1101443865" moduleId="org.eclipse.cdt.core.settings" name="Default">
12- <externalSettings/>
13- <extensions>
14- <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
15- <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
16- <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
17- <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
18- <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
19- <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
20- </extensions>
21- </storageModule>
22- <storageModule moduleId="cdtBuildSystem" version="4.0.0">
23- <configuration artifactName="mixxx" buildProperties="" description="" id="0.1101443865" name="Default" parent="org.eclipse.cdt.build.core.prefbase.cfg">
24- <folderInfo id="0.1101443865." name="/" resourcePath="">
25- <toolChain id="cdt.managedbuild.toolchain.gnu.base.584041307" name="Linux GCC" resourceTypeBasedDiscovery="false" superClass="cdt.managedbuild.toolchain.gnu.base">
26- <targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.target.gnu.platform.base.351911640" name="Debug Platform" osList="linux,hpux,aix,qnx" superClass="cdt.managedbuild.target.gnu.platform.base"/>
27- <builder arguments="-j2 clementine=0" cleanBuildTarget="-c" command="scons" id="cdt.managedbuild.target.gnu.builder.base.2000599252" incrementalBuildTarget="" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
28- <tool id="cdt.managedbuild.tool.gnu.archiver.base.1227507869" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
29- <tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.919897767" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base">
30- <option id="gnu.cpp.compiler.option.include.paths.2035064794" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
31- <listOptionValue builtIn="false" value="/usr/include/qt4"/>
32- <listOptionValue builtIn="false" value="/usr/include/qt4/Qt"/>
33- <listOptionValue builtIn="false" value="/usr/include/qt4/QtCore"/>
34- <listOptionValue builtIn="false" value="/usr/include/qt4/QtGui"/>
35- <listOptionValue builtIn="false" value="/usr/include/qt4/QtOpenGL"/>
36- <listOptionValue builtIn="false" value="/usr/include/qt4/QtXml"/>
37- <listOptionValue builtIn="false" value="/usr/include/qt4/QtSvg"/>
38- <listOptionValue builtIn="false" value="/usr/include/qt4/QtSql"/>
39- <listOptionValue builtIn="false" value="/usr/include/qt4/QtScript"/>
40- <listOptionValue builtIn="false" value="/usr/include/qt4/QtXmlPatterns"/>
41- <listOptionValue builtIn="false" value="/usr/include/qt4/QtNetwork"/>
42- <listOptionValue builtIn="false" value="/usr/include/qt4/QtWebKit"/>
43- <listOptionValue builtIn="false" value="/usr/include/"/>
44- <listOptionValue builtIn="false" value="/usr/include/c++/4.5"/>
45- </option>
46- <option id="gnu.cpp.compiler.option.preprocessor.def.2028780733" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols">
47- <listOptionValue builtIn="false" value="&quot;offsetof(Itdb_Track, artist)=1&quot;"/>
48- </option>
49- <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1034465664" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
50- </tool>
51- <tool id="cdt.managedbuild.tool.gnu.c.compiler.base.36640467" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.base">
52- <option id="gnu.c.compiler.option.preprocessor.def.symbols.293455491" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" valueType="definedSymbols">
53- <listOptionValue builtIn="false" value="&quot;offsetof(Itdb_Track, artist)=1&quot;"/>
54- </option>
55- <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1672612692" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
56- </tool>
57- <tool id="cdt.managedbuild.tool.gnu.c.linker.base.1647233207" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"/>
58- <tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.316845026" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base">
59- <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.654332197" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
60- <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
61- <additionalInput kind="additionalinput" paths="$(LIBS)"/>
62- </inputType>
63- </tool>
64- <tool id="cdt.managedbuild.tool.gnu.assembler.base.1421936031" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.base">
65- <inputType id="cdt.managedbuild.tool.gnu.assembler.input.1129083033" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
66- </tool>
67- </toolChain>
68- </folderInfo>
69- </configuration>
70- </storageModule>
71- <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
72- <storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
73- </cconfiguration>
74- </storageModule>
75- <storageModule moduleId="cdtBuildSystem" version="4.0.0">
76- <project id="mixxx.null.1175989019" name="mixxx"/>
77- </storageModule>
78- <storageModule moduleId="refreshScope" versionNumber="1">
79- <resource resourceType="PROJECT" workspacePath="/mixxx"/>
80- </storageModule>
81- <storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
82- <storageModule moduleId="scannerConfiguration">
83- <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
84- <scannerConfigBuildInfo instanceId="0.1101443865;0.1101443865.;cdt.managedbuild.tool.gnu.c.compiler.base.36640467;cdt.managedbuild.tool.gnu.c.compiler.input.1672612692">
85- <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"/>
86- </scannerConfigBuildInfo>
87- <scannerConfigBuildInfo instanceId="0.1101443865;0.1101443865.;cdt.managedbuild.tool.gnu.cpp.compiler.base.919897767;cdt.managedbuild.tool.gnu.cpp.compiler.input.1034465664">
88- <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"/>
89- </scannerConfigBuildInfo>
90- <scannerConfigBuildInfo instanceId="0.1101443865">
91- <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>
92- <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
93- <buildOutputProvider>
94- <openAction enabled="true" filePath="/home/daniel/workspace/.metadata/.plugins/org.eclipse.cdt.ui/mixxx.build.log"/>
95- <parser enabled="true"/>
96- </buildOutputProvider>
97- <scannerInfoProvider id="specsFile">
98- <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="g++" useDefault="true"/>
99- <parser enabled="true"/>
100- </scannerInfoProvider>
101- </profile>
102- <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
103- <buildOutputProvider>
104- <openAction enabled="true" filePath="/home/daniel/workspace/.metadata/.plugins/org.eclipse.cdt.ui/mixxx.build.log"/>
105- <parser enabled="true"/>
106- </buildOutputProvider>
107- <scannerInfoProvider id="makefileGenerator">
108- <runAction arguments="-E -P -v -dD" command="" useDefault="true"/>
109- <parser enabled="true"/>
110- </scannerInfoProvider>
111- </profile>
112- </scannerConfigBuildInfo>
113- </storageModule>
114-</cproject>
115
116=== removed file 'mixxx/.gdbinit'
117--- mixxx/.gdbinit 2013-03-13 21:41:26 +0000
118+++ mixxx/.gdbinit 1970-01-01 00:00:00 +0000
119@@ -1,26 +0,0 @@
120-dir ~/workspace/qt/src/corelib
121-dir ~/workspace/qt/src/corelib/io
122-dir ~/workspace/qt/src/gui
123-dir ~/workspace/qt/src/gui/image
124-dir ~/workspace/qt/src/gui/kernel
125-dir ~/workspace/qt/src/network
126-dir ~/workspace/qt/src/sql
127-dir ~/workspace/qt/src/sql/drivers/sqlit
128-dir ~/workspace/qt/src/opengl
129-dir ~/workspace/sqlite/sqlite3-3.7.4
130-dir ~/workspace/daschuer-mixxx-clementine/src
131-dir ~/workspace/daschuer-mixxx-clementine/src/core
132-dir ~/workspace/daschuer-mixxx-clementine/ext
133-dir ~/workspace/daschuer-mixxx-clementine/3rdparty
134-
135-
136-python
137-import sys
138-
139-sys.path.insert(0, '/home/daniel/workspace')
140-from qt4 import register_qt4_printers
141-register_qt4_printers (None)
142-end
143-set print pretty 1
144-set charset UTF-8
145-
146
147=== removed file 'mixxx/.project'
148--- mixxx/.project 2013-03-13 21:41:26 +0000
149+++ mixxx/.project 1970-01-01 00:00:00 +0000
150@@ -1,79 +0,0 @@
151-<?xml version="1.0" encoding="UTF-8"?>
152-<projectDescription>
153- <name>mixxxco</name>
154- <comment></comment>
155- <projects>
156- </projects>
157- <buildSpec>
158- <buildCommand>
159- <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
160- <triggers>clean,full,incremental,</triggers>
161- <arguments>
162- <dictionary>
163- <key>?name?</key>
164- <value></value>
165- </dictionary>
166- <dictionary>
167- <key>org.eclipse.cdt.make.core.append_environment</key>
168- <value>true</value>
169- </dictionary>
170- <dictionary>
171- <key>org.eclipse.cdt.make.core.autoBuildTarget</key>
172- <value>all</value>
173- </dictionary>
174- <dictionary>
175- <key>org.eclipse.cdt.make.core.buildArguments</key>
176- <value>-j2 clementine=0</value>
177- </dictionary>
178- <dictionary>
179- <key>org.eclipse.cdt.make.core.buildCommand</key>
180- <value>scons</value>
181- </dictionary>
182- <dictionary>
183- <key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
184- <value>-c</value>
185- </dictionary>
186- <dictionary>
187- <key>org.eclipse.cdt.make.core.contents</key>
188- <value>org.eclipse.cdt.make.core.activeConfigSettings</value>
189- </dictionary>
190- <dictionary>
191- <key>org.eclipse.cdt.make.core.enableAutoBuild</key>
192- <value>false</value>
193- </dictionary>
194- <dictionary>
195- <key>org.eclipse.cdt.make.core.enableCleanBuild</key>
196- <value>true</value>
197- </dictionary>
198- <dictionary>
199- <key>org.eclipse.cdt.make.core.enableFullBuild</key>
200- <value>true</value>
201- </dictionary>
202- <dictionary>
203- <key>org.eclipse.cdt.make.core.fullBuildTarget</key>
204- <value></value>
205- </dictionary>
206- <dictionary>
207- <key>org.eclipse.cdt.make.core.stopOnError</key>
208- <value>true</value>
209- </dictionary>
210- <dictionary>
211- <key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
212- <value>false</value>
213- </dictionary>
214- </arguments>
215- </buildCommand>
216- <buildCommand>
217- <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
218- <triggers>full,incremental,</triggers>
219- <arguments>
220- </arguments>
221- </buildCommand>
222- </buildSpec>
223- <natures>
224- <nature>org.eclipse.cdt.core.cnature</nature>
225- <nature>org.eclipse.cdt.core.ccnature</nature>
226- <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
227- <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
228- </natures>
229-</projectDescription>
230
231=== modified file 'mixxx/Mixxx-Manual.pdf'
232Binary files mixxx/Mixxx-Manual.pdf 2011-12-23 22:25:23 +0000 and mixxx/Mixxx-Manual.pdf 2013-05-16 01:44:29 +0000 differ
233=== modified file 'mixxx/build/debian/changelog'
234--- mixxx/build/debian/changelog 2012-06-21 19:43:01 +0000
235+++ mixxx/build/debian/changelog 2013-05-16 01:44:29 +0000
236@@ -1,3 +1,9 @@
237+mixxx (1.11.0-0ubuntu1) lucid; urgency=low
238+
239+ * New upstream release.
240+
241+ -- RJ Ryan <rryan@mixxx.org> Thu, 09 May 2013 01:19:27 -0400
242+
243 mixxx (1.11.0~beta1-0ubuntu1) lucid; urgency=low
244
245 * New upstream beta release
246
247=== modified file 'mixxx/build/depends.py'
248--- mixxx/build/depends.py 2013-05-11 22:59:25 +0000
249+++ mixxx/build/depends.py 2013-05-16 01:44:29 +0000
250@@ -113,6 +113,14 @@
251 if not conf.CheckLib(libs):
252 raise Exception('Did not find libogg.a, libogg.lib, or the libogg development headers')
253
254+ # libvorbisenc only exists on Linux, OSX and mingw32 on Windows. On
255+ # Windows with MSVS it is included in vorbisfile.dll. libvorbis and
256+ # libogg are included from build.py so don't add here.
257+ if not build.platform_is_windows or build.toolchain_is_gnu:
258+ vorbisenc_found = conf.CheckLib(['libvorbisenc', 'vorbisenc'])
259+ if not vorbisenc_found:
260+ raise Exception('Did not find libvorbisenc.a, libvorbisenc.lib, or the libvorbisenc development headers.')
261+
262 def sources(self, build):
263 return ['soundsourceoggvorbis.cpp']
264
265@@ -412,18 +420,18 @@
266 sources = ["mixxxkeyboard.cpp",
267
268 "configobject.cpp",
269+ "control/control.cpp",
270+ "control/controlbehavior.cpp",
271 "controlobjectthread.cpp",
272 "controlobjectthreadwidget.cpp",
273 "controlobjectthreadmain.cpp",
274 "controlevent.cpp",
275 "controllogpotmeter.cpp",
276 "controlobject.cpp",
277- "controlnull.cpp",
278 "controlpotmeter.cpp",
279 "controllinpotmeter.cpp",
280 "controlpushbutton.cpp",
281 "controlttrotary.cpp",
282- "controlbeat.cpp",
283
284 "dlgpreferences.cpp",
285 "dlgprefsound.cpp",
286@@ -434,10 +442,8 @@
287 "controllers/dlgprefnocontrollers.cpp",
288 "dlgprefplaylist.cpp",
289 "dlgprefcontrols.cpp",
290- "dlgprefbpm.cpp",
291 "dlgprefreplaygain.cpp",
292 "dlgprefnovinyl.cpp",
293- "dlgbpmscheme.cpp",
294 "dlgabout.cpp",
295 "dlgprefeq.cpp",
296 "dlgprefcrossfader.cpp",
297@@ -465,7 +471,7 @@
298 "engine/engineflanger.cpp",
299 "engine/enginevumeter.cpp",
300 "engine/enginevinylsoundemu.cpp",
301- "engine/enginesidechain.cpp",
302+ "engine/sidechain/enginesidechain.cpp",
303 "engine/enginefilterbutterworth8.cpp",
304 "engine/enginexfader.cpp",
305 "engine/enginemicrophone.cpp",
306@@ -485,7 +491,6 @@
307
308 "analyserrg.cpp",
309 "analyserqueue.cpp",
310- "analyserbpm.cpp",
311 "analyserwaveform.cpp",
312
313 "controllers/controller.cpp",
314@@ -577,6 +582,7 @@
315 "library/recording/recordingfeature.cpp",
316 "dlgrecording.cpp",
317 "recording/recordingmanager.cpp",
318+ "engine/sidechain/enginerecord.cpp",
319
320 # External Library Features
321 "library/baseexternallibraryfeature.cpp",
322@@ -698,8 +704,9 @@
323 "dlgprefrecord.cpp",
324 "playerinfo.cpp",
325
326- "recording/enginerecord.cpp",
327- "recording/encoder.cpp",
328+ "encoder/encoder.cpp",
329+ "encoder/encodermp3.cpp",
330+ "encoder/encodervorbis.cpp",
331
332 "segmentation.cpp",
333 "tapfilter.cpp",
334@@ -743,10 +750,8 @@
335 build.env.Uic4('dlgprefcontrolsdlg.ui')
336 build.env.Uic4('dlgprefeqdlg.ui')
337 build.env.Uic4('dlgprefcrossfaderdlg.ui')
338- build.env.Uic4('dlgprefbpmdlg.ui')
339 build.env.Uic4('dlgprefreplaygaindlg.ui')
340 build.env.Uic4('dlgprefbeatsdlg.ui')
341- build.env.Uic4('dlgbpmschemedlg.ui')
342 # build.env.Uic4('dlgbpmtapdlg.ui')
343 build.env.Uic4('dlgprefvinyldlg.ui')
344 build.env.Uic4('dlgprefnovinyldlg.ui')
345
346=== modified file 'mixxx/build/features.py'
347--- mixxx/build/features.py 2013-05-01 20:29:44 +0000
348+++ mixxx/build/features.py 2013-05-16 01:44:29 +0000
349@@ -453,8 +453,6 @@
350 build.env.Append(CPPPATH=[self.INTERNAL_VAMP_PATH])
351 self.INTERNAL_LINK = True
352
353- build.env.Append(CPPDEFINES = '__VAMP__')
354-
355 # Needed on Linux at least. Maybe needed elsewhere?
356 if build.platform_is_linux:
357 # Optionally link libdl and libX11. Required for some distros.
358@@ -802,14 +800,6 @@
359 if not libshout_found:
360 raise Exception('Could not find libshout or its development headers. Please install it or compile Mixxx without Shoutcast support using the shoutcast=0 flag.')
361
362- # libvorbisenc only exists on Linux, OSX and mingw32 on Windows. On
363- # Windows with MSVS it is included in vorbisfile.dll. libvorbis and
364- # libogg are included from build.py so don't add here.
365- if not build.platform_is_windows or build.toolchain_is_gnu:
366- vorbisenc_found = conf.CheckLib(['libvorbisenc', 'vorbisenc'])
367- if not vorbisenc_found:
368- raise Exception("libvorbisenc was not found! Please install it or compile Mixxx without Shoutcast support using the shoutcast=0 flag.")
369-
370 if build.platform_is_windows and build.static_dependencies:
371 conf.CheckLib('winmm')
372 conf.CheckLib('ws2_32')
373@@ -817,9 +807,8 @@
374 def sources(self, build):
375 build.env.Uic4('dlgprefshoutcastdlg.ui')
376 return ['dlgprefshoutcast.cpp',
377- 'engine/engineshoutcast.cpp',
378- 'recording/encodervorbis.cpp',
379- 'recording/encodermp3.cpp']
380+ 'shoutcast/shoutcastmanager.cpp',
381+ 'engine/sidechain/engineshoutcast.cpp']
382
383
384 class FFMPEG(Feature):
385
386=== modified file 'mixxx/build/qtcreator/mixxx.pro'
387--- mixxx/build/qtcreator/mixxx.pro 2011-11-11 22:18:56 +0000
388+++ mixxx/build/qtcreator/mixxx.pro 2013-05-16 01:44:29 +0000
389@@ -98,9 +98,7 @@
390 }
391
392 HEADERS += $$UI_DIR/ui_dlgaboutdlg.h \
393- $$UI_DIR/ui_dlgbpmschemedlg.h \
394 $$UI_DIR/ui_dlgmidilearning.h \
395- $$UI_DIR/ui_dlgprefbpmdlg.h \
396 $$UI_DIR/ui_dlgprefcontrolsdlg.h \
397 $$UI_DIR/ui_dlgprefcrossfaderdlg.h \
398 $$UI_DIR/ui_dlgprefeqdlg.h \
399@@ -131,7 +129,6 @@
400 # done
401
402 HEADERS += \
403-$$BASE_DIR/src/analyserbpm.h \
404 $$BASE_DIR/src/analyser.h \
405 $$BASE_DIR/src/analyserqueue.h \
406 $$BASE_DIR/src/analyserwaveform.h \
407@@ -162,10 +159,8 @@
408 $$BASE_DIR/src/defs_version.h \
409 $$BASE_DIR/src/dlgabout.h \
410 $$BASE_DIR/src/dlgautodj.h \
411-$$BASE_DIR/src/dlgbpmscheme.h \
412 $$BASE_DIR/src/dlgladspa.h \
413 $$BASE_DIR/src/dlgmidilearning.h \
414-$$BASE_DIR/src/dlgprefbpm.h \
415 $$BASE_DIR/src/dlgprefcontrols.h \
416 $$BASE_DIR/src/dlgprefcrossfader.h \
417 $$BASE_DIR/src/dlgprefeq.h \
418@@ -373,7 +368,6 @@
419
420
421 SOURCES += \
422-$$BASE_DIR/src/analyserbpm.cpp \
423 $$BASE_DIR/src/analyserqueue.cpp \
424 $$BASE_DIR/src/analyserwaveform.cpp \
425 $$BASE_DIR/src/analyserwavesummary.cpp \
426@@ -396,10 +390,8 @@
427 $$BASE_DIR/src/controlvaluedelegate.cpp \
428 $$BASE_DIR/src/dlgabout.cpp \
429 $$BASE_DIR/src/dlgautodj.cpp \
430-$$BASE_DIR/src/dlgbpmscheme.cpp \
431 $$BASE_DIR/src/dlgladspa.cpp \
432 $$BASE_DIR/src/dlgmidilearning.cpp \
433-$$BASE_DIR/src/dlgprefbpm.cpp \
434 $$BASE_DIR/src/dlgprefcontrols.cpp \
435 $$BASE_DIR/src/dlgprefcrossfader.cpp \
436 $$BASE_DIR/src/dlgprefeq.cpp \
437@@ -622,9 +614,7 @@
438 FORMS += \
439 $$BASE_DIR/src/dlgaboutdlg.ui \
440 $$BASE_DIR/src/dlgautodj.ui \
441-$$BASE_DIR/src/dlgbpmschemedlg.ui \
442 $$BASE_DIR/src/dlgmidilearning.ui \
443-$$BASE_DIR/src/dlgprefbpmdlg.ui \
444 $$BASE_DIR/src/dlgprefcontrolsdlg.ui \
445 $$BASE_DIR/src/dlgprefcrossfaderdlg.ui \
446 $$BASE_DIR/src/dlgprefeqdlg.ui \
447
448=== modified file 'mixxx/plugins/soundsourcem4a/SConscript'
449--- mixxx/plugins/soundsourcem4a/SConscript 2011-03-07 22:25:20 +0000
450+++ mixxx/plugins/soundsourcem4a/SConscript 2013-05-16 01:44:29 +0000
451@@ -15,7 +15,6 @@
452 "soundsourcem4a.cpp", # MP4/M4A Support through FAAD/libmp4v2
453 ]
454
455-
456 #Tell SCons to build the SoundSourceM4A plugin
457 #=========================
458 if int(build.flags['faad']):
459@@ -24,7 +23,7 @@
460 conf = Configure(env)
461
462 have_mp4v2_h = conf.CheckHeader('mp4v2/mp4v2.h')
463- have_mp4 = (have_mp4v2_h and conf.CheckLib(['mp4v2', 'libmp4v2'])) or \
464+ have_mp4 = conf.CheckLib(['mp4v2', 'libmp4v2']) or \
465 conf.CheckLib('mp4')
466
467 have_faad = conf.CheckLib(['faad', 'libfaad'])
468
469=== modified file 'mixxx/res/controllers/Vestax VCI-300.midi.xml' (properties changed: +x to -x)
470=== modified file 'mixxx/res/controllers/Vestax-VCI-300-scripts.js' (properties changed: +x to -x)
471=== modified file 'mixxx/res/skins/Outline1024x600-Netbook/CHANGELOG.txt' (properties changed: +x to -x)
472=== modified file 'mixxx/res/skins/Outline1024x600-Netbook/skin.xml' (properties changed: +x to -x)
473=== modified file 'mixxx/res/skins/Outline1024x768-XGA/CHANGELOG.txt' (properties changed: +x to -x)
474=== modified file 'mixxx/res/skins/Outline1024x768-XGA/skin.xml' (properties changed: +x to -x)
475=== modified file 'mixxx/res/skins/Outline800x480-WVGA/skin.xml' (properties changed: +x to -x)
476=== modified file 'mixxx/res/skins/Shade1024x600-Netbook/skin.xml'
477--- mixxx/res/skins/Shade1024x600-Netbook/skin.xml 2013-05-11 22:59:25 +0000
478+++ mixxx/res/skins/Shade1024x600-Netbook/skin.xml 2013-05-16 01:44:29 +0000
479@@ -4133,13 +4133,11 @@
480 <ConfigKey>[Channel1],beatloop_0.125_toggle</ConfigKey>
481 <EmitOnPressAndRelease>true</EmitOnPressAndRelease>
482 <ButtonState>LeftButton</ButtonState>
483- <ConnectValueToWidget>false</ConnectValueToWidget>
484 </Connection>
485 <Connection>
486 <ConfigKey>[Channel1],beatlooproll_0.125_activate</ConfigKey>
487 <EmitOnPressAndRelease>true</EmitOnPressAndRelease>
488 <ButtonState>RightButton</ButtonState>
489- <ConnectValueToWidget>false</ConnectValueToWidget>
490 </Connection>
491 <Connection>
492 <ConfigKey>[Channel1],beatloop_0.125_enabled</ConfigKey>
493@@ -4167,13 +4165,11 @@
494 <ConfigKey>[Channel1],beatloop_0.25_toggle</ConfigKey>
495 <EmitOnPressAndRelease>true</EmitOnPressAndRelease>
496 <ButtonState>LeftButton</ButtonState>
497- <ConnectValueToWidget>false</ConnectValueToWidget>
498 </Connection>
499 <Connection>
500 <ConfigKey>[Channel1],beatlooproll_0.25_activate</ConfigKey>
501 <EmitOnPressAndRelease>true</EmitOnPressAndRelease>
502 <ButtonState>RightButton</ButtonState>
503- <ConnectValueToWidget>false</ConnectValueToWidget>
504 </Connection>
505 <Connection>
506 <ConfigKey>[Channel1],beatloop_0.25_enabled</ConfigKey>
507@@ -4201,13 +4197,11 @@
508 <ConfigKey>[Channel1],beatloop_0.5_toggle</ConfigKey>
509 <EmitOnPressAndRelease>true</EmitOnPressAndRelease>
510 <ButtonState>LeftButton</ButtonState>
511- <ConnectValueToWidget>false</ConnectValueToWidget>
512 </Connection>
513 <Connection>
514 <ConfigKey>[Channel1],beatlooproll_0.5_activate</ConfigKey>
515 <EmitOnPressAndRelease>true</EmitOnPressAndRelease>
516 <ButtonState>RightButton</ButtonState>
517- <ConnectValueToWidget>false</ConnectValueToWidget>
518 </Connection>
519 <Connection>
520 <ConfigKey>[Channel1],beatloop_0.5_enabled</ConfigKey>
521@@ -4235,13 +4229,11 @@
522 <ConfigKey>[Channel1],beatloop_1_toggle</ConfigKey>
523 <EmitOnPressAndRelease>true</EmitOnPressAndRelease>
524 <ButtonState>LeftButton</ButtonState>
525- <ConnectValueToWidget>false</ConnectValueToWidget>
526 </Connection>
527 <Connection>
528 <ConfigKey>[Channel1],beatlooproll_1_activate</ConfigKey>
529 <EmitOnPressAndRelease>true</EmitOnPressAndRelease>
530 <ButtonState>RightButton</ButtonState>
531- <ConnectValueToWidget>false</ConnectValueToWidget>
532 </Connection>
533 <Connection>
534 <ConfigKey>[Channel1],beatloop_1_enabled</ConfigKey>
535@@ -4269,13 +4261,11 @@
536 <ConfigKey>[Channel1],beatloop_2_toggle</ConfigKey>
537 <EmitOnPressAndRelease>true</EmitOnPressAndRelease>
538 <ButtonState>LeftButton</ButtonState>
539- <ConnectValueToWidget>false</ConnectValueToWidget>
540 </Connection>
541 <Connection>
542 <ConfigKey>[Channel1],beatlooproll_2_activate</ConfigKey>
543 <EmitOnPressAndRelease>true</EmitOnPressAndRelease>
544 <ButtonState>RightButton</ButtonState>
545- <ConnectValueToWidget>false</ConnectValueToWidget>
546 </Connection>
547 <Connection>
548 <ConfigKey>[Channel1],beatloop_2_enabled</ConfigKey>
549@@ -4303,13 +4293,11 @@
550 <ConfigKey>[Channel1],beatloop_4_toggle</ConfigKey>
551 <EmitOnPressAndRelease>true</EmitOnPressAndRelease>
552 <ButtonState>LeftButton</ButtonState>
553- <ConnectValueToWidget>false</ConnectValueToWidget>
554 </Connection>
555 <Connection>
556 <ConfigKey>[Channel1],beatlooproll_4_activate</ConfigKey>
557 <EmitOnPressAndRelease>true</EmitOnPressAndRelease>
558 <ButtonState>RightButton</ButtonState>
559- <ConnectValueToWidget>false</ConnectValueToWidget>
560 </Connection>
561 <Connection>
562 <ConfigKey>[Channel1],beatloop_4_enabled</ConfigKey>
563@@ -4337,13 +4325,11 @@
564 <ConfigKey>[Channel1],beatloop_8_toggle</ConfigKey>
565 <EmitOnPressAndRelease>true</EmitOnPressAndRelease>
566 <ButtonState>LeftButton</ButtonState>
567- <ConnectValueToWidget>false</ConnectValueToWidget>
568 </Connection>
569 <Connection>
570 <ConfigKey>[Channel1],beatlooproll_8_activate</ConfigKey>
571 <EmitOnPressAndRelease>true</EmitOnPressAndRelease>
572 <ButtonState>RightButton</ButtonState>
573- <ConnectValueToWidget>false</ConnectValueToWidget>
574 </Connection>
575 <Connection>
576 <ConfigKey>[Channel1],beatloop_8_enabled</ConfigKey>
577@@ -4371,13 +4357,11 @@
578 <ConfigKey>[Channel1],beatloop_16_toggle</ConfigKey>
579 <EmitOnPressAndRelease>true</EmitOnPressAndRelease>
580 <ButtonState>LeftButton</ButtonState>
581- <ConnectValueToWidget>false</ConnectValueToWidget>
582 </Connection>
583 <Connection>
584 <ConfigKey>[Channel1],beatlooproll_16_activate</ConfigKey>
585 <EmitOnPressAndRelease>true</EmitOnPressAndRelease>
586 <ButtonState>RightButton</ButtonState>
587- <ConnectValueToWidget>false</ConnectValueToWidget>
588 </Connection>
589 <Connection>
590 <ConfigKey>[Channel1],beatloop_16_enabled</ConfigKey>
591
592=== removed file 'mixxx/src/analyserbpm.cpp'
593--- mixxx/src/analyserbpm.cpp 2013-01-30 05:31:23 +0000
594+++ mixxx/src/analyserbpm.cpp 1970-01-01 00:00:00 +0000
595@@ -1,102 +0,0 @@
596-#include <QtDebug>
597-
598-#undef TRUE
599-#undef FALSE
600-#include "BPMDetect.h"
601-
602-#include "trackinfoobject.h"
603-#include "track/beatgrid.h"
604-#include "track/beatfactory.h"
605-#include "track/beatutils.h"
606-#include "analyserbpm.h"
607-
608-AnalyserBPM::AnalyserBPM(ConfigObject<ConfigValue> *_config) :
609- m_pConfig(_config),
610- m_pDetector(NULL),
611- m_iMinBpm(0),
612- m_iMaxBpm(0),
613- m_bProcessEntireSong(true) {
614-}
615-
616-bool AnalyserBPM::initialise(TrackPointer tio, int sampleRate, int totalSamples) {
617- Q_UNUSED(totalSamples);
618- if (loadStored(tio)) {
619- return false;
620- }
621-
622- m_iMinBpm = m_pConfig->getValueString(ConfigKey("[BPM]","BPMRangeStart")).toInt();
623- m_iMaxBpm = m_pConfig->getValueString(ConfigKey("[BPM]","BPMRangeEnd")).toInt();
624- m_bProcessEntireSong = (bool)m_pConfig->getValueString(ConfigKey("[BPM]","AnalyzeEntireSong")).toInt();
625-
626- // All SoundSource's return stereo data, no matter the real file's type
627- m_pDetector = new soundtouch::BPMDetect(2, sampleRate);
628- //m_pDetector = new BPMDetect(tio->getChannels(), sampleRate);
629- // defaultrange ? MIN_BPM : m_iMinBpm,
630- // defaultrange ? MAX_BPM : m_iMaxBpm);
631- return true;
632-}
633-
634-bool AnalyserBPM::loadStored(TrackPointer tio) const {
635- bool bpmEnabled = (bool)m_pConfig->getValueString(ConfigKey("[BPM]","BPMDetectionEnabled")).toInt();
636- // If BPM detection is enabled and the track does not have a BPM already,
637- // create a detector.
638- if(bpmEnabled && tio->getBpm() <= 0.0) {
639- return false;
640- }
641- return true;
642-}
643-
644-void AnalyserBPM::process(const CSAMPLE *pIn, const int iLen) {
645- // Check if BPM detection is enabled
646- if(m_pDetector == NULL) {
647- return;
648- }
649- //qDebug() << "AnalyserBPM::process() processing " << iLen << " samples";
650-
651- m_pDetector->inputSamples(pIn, iLen/2);
652-}
653-
654-void AnalyserBPM::cleanup(TrackPointer tio)
655-{
656- Q_UNUSED(tio);
657- if(m_pDetector != NULL)
658- {
659- delete m_pDetector;
660- m_pDetector = NULL;
661- }
662-}
663-
664-void AnalyserBPM::finalise(TrackPointer tio) {
665- // Check if BPM detection is enabled
666- if(m_pDetector == NULL) {
667- return;
668- }
669-
670- double bpm = m_pDetector->getBpm();
671- if (bpm != 0) {
672- // Shift it by 2's until it is in the desired range
673- double newbpm = BeatUtils::constrainBpm(
674- bpm, m_iMinBpm, m_iMaxBpm,
675- static_cast<bool>(m_pConfig->getValueString(
676- ConfigKey("[BPM]", "BPMAboveRangeEnabled")).toInt()));
677-
678- // Currently, the BPM is only analyzed if the track has no BPM. This
679- // means we don't have to worry that the track already has an existing
680- // BeatGrid.
681- BeatsPointer pBeats = BeatFactory::makeBeatGrid(tio.data(), newbpm, 0.0f);
682- tio->setBeats(pBeats);
683-
684- //if(pBpmReceiver) {
685- //pBpmReceiver->setComplete(tio, false, bpm);
686- //}
687- //qDebug() << "AnalyserBPM BPM detection successful for" << tio->getFilename();
688- //qDebug() << "AnalyserBPM BPM is " << newbpm << " (raw: " << bpm << ")";
689- } else {
690- //qDebug() << "AnalyserBPM BPM detection failed, setting to 0.";
691- }
692-
693- // Cleanup the BPM detector
694- delete m_pDetector;
695- m_pDetector = NULL;
696-
697-}
698
699=== removed file 'mixxx/src/analyserbpm.h'
700--- mixxx/src/analyserbpm.h 2012-12-13 23:22:57 +0000
701+++ mixxx/src/analyserbpm.h 1970-01-01 00:00:00 +0000
702@@ -1,27 +0,0 @@
703-#ifndef ANALYSER_BPM_H
704-#define ANALYSER_BPM_H
705-
706-#include "analyser.h"
707-#include "configobject.h"
708-
709-namespace soundtouch {
710-class BPMDetect;
711-}
712-
713-class AnalyserBPM : public Analyser {
714- public:
715- AnalyserBPM(ConfigObject<ConfigValue> *_config);
716- bool initialise(TrackPointer tio, int sampleRate, int totalSamples);
717- bool loadStored(TrackPointer tio) const;
718- void process(const CSAMPLE *pIn, const int iLen);
719- void cleanup(TrackPointer tio);
720- void finalise(TrackPointer tio);
721-
722- private:
723- ConfigObject<ConfigValue> *m_pConfig;
724- soundtouch::BPMDetect *m_pDetector;
725- int m_iMinBpm, m_iMaxBpm;
726- bool m_bProcessEntireSong;
727-};
728-
729-#endif
730
731=== modified file 'mixxx/src/analyserqueue.cpp'
732--- mixxx/src/analyserqueue.cpp 2013-02-28 20:30:15 +0000
733+++ mixxx/src/analyserqueue.cpp 2013-05-16 01:44:29 +0000
734@@ -14,12 +14,9 @@
735 #endif
736
737 #include "analyserwaveform.h"
738-#include "analyserbpm.h"
739 #include "analyserrg.h"
740-#ifdef __VAMP__
741 #include "analyserbeats.h"
742 #include "vamp/vampanalyser.h"
743-#endif
744
745 #include <typeinfo>
746
747@@ -407,13 +404,9 @@
748
749 ret->addAnalyser(new AnalyserWaveform(_config));
750 ret->addAnalyser(new AnalyserGain(_config));
751-#ifdef __VAMP__
752 VampAnalyser::initializePluginPaths();
753 ret->addAnalyser(new AnalyserBeats(_config));
754 //ret->addAnalyser(new AnalyserVampKeyTest(_config));
755-#else
756- ret->addAnalyser(new AnalyserBPM(_config));
757-#endif
758
759 ret->start(QThread::IdlePriority);
760 return ret;
761@@ -426,13 +419,9 @@
762
763 ret->addAnalyser(new AnalyserWaveform(_config));
764 ret->addAnalyser(new AnalyserGain(_config));
765-#ifdef __VAMP__
766 VampAnalyser::initializePluginPaths();
767 ret->addAnalyser(new AnalyserBeats(_config));
768 //ret->addAnalyser(new AnalyserVampKeyTest(_config));
769-#else
770- ret->addAnalyser(new AnalyserBPM(_config));
771-#endif
772
773 ret->start(QThread::IdlePriority);
774 return ret;
775
776=== added directory 'mixxx/src/control'
777=== added file 'mixxx/src/control/control.cpp'
778--- mixxx/src/control/control.cpp 1970-01-01 00:00:00 +0000
779+++ mixxx/src/control/control.cpp 2013-05-16 01:44:29 +0000
780@@ -0,0 +1,132 @@
781+#include <QtDebug>
782+#include <QMutexLocker>
783+
784+#include "control/control.h"
785+
786+#include "util/stat.h"
787+#include "util/timer.h"
788+
789+// Static member variable definition
790+QHash<ConfigKey, ControlDoublePrivate*> ControlDoublePrivate::m_sqCOHash;
791+QMutex ControlDoublePrivate::m_sqCOHashMutex;
792+
793+ControlDoublePrivate::ControlDoublePrivate()
794+ : m_bIgnoreNops(true),
795+ m_bTrack(false) {
796+ m_defaultValue.setValue(0);
797+ m_value.setValue(0);
798+}
799+
800+ControlDoublePrivate::ControlDoublePrivate(ConfigKey key,
801+ bool bIgnoreNops, bool bTrack)
802+ : m_key(key),
803+ m_bIgnoreNops(bIgnoreNops),
804+ m_bTrack(bTrack),
805+ m_trackKey("control " + m_key.group + "," + m_key.item),
806+ m_trackType(Stat::UNSPECIFIED),
807+ m_trackFlags(Stat::COUNT | Stat::SUM | Stat::AVERAGE |
808+ Stat::SAMPLE_VARIANCE | Stat::MIN | Stat::MAX) {
809+ m_defaultValue.setValue(0);
810+ m_value.setValue(0);
811+
812+ m_sqCOHashMutex.lock();
813+ m_sqCOHash.insert(m_key, this);
814+ m_sqCOHashMutex.unlock();
815+
816+ if (m_bTrack) {
817+ // TODO(rryan): Make configurable.
818+ Stat::track(m_trackKey, static_cast<Stat::StatType>(m_trackType),
819+ static_cast<Stat::ComputeFlags>(m_trackFlags),
820+ m_value.getValue());
821+ }
822+}
823+
824+ControlDoublePrivate::~ControlDoublePrivate() {
825+ m_sqCOHashMutex.lock();
826+ m_sqCOHash.remove(m_key);
827+ m_sqCOHashMutex.unlock();
828+}
829+
830+// static
831+ControlDoublePrivate* ControlDoublePrivate::getControl(
832+ const ConfigKey& key, bool bCreate, bool bIgnoreNops, bool bTrack) {
833+ QMutexLocker locker(&m_sqCOHashMutex);
834+ QHash<ConfigKey, ControlDoublePrivate*>::const_iterator it = m_sqCOHash.find(key);
835+ if (it != m_sqCOHash.end()) {
836+ return it.value();
837+ }
838+ locker.unlock();
839+
840+ ControlDoublePrivate* pControl = NULL;
841+ if (bCreate) {
842+ pControl = new ControlDoublePrivate(key, bIgnoreNops, bTrack);
843+ locker.relock();
844+ m_sqCOHash.insert(key, pControl);
845+ locker.unlock();
846+ }
847+
848+ if (pControl == NULL) {
849+ qWarning() << "ControlDoublePrivate::getControl returning NULL for ("
850+ << key.group << "," << key.item << ")";
851+ }
852+
853+ return pControl;
854+}
855+
856+double ControlDoublePrivate::get() const {
857+ return m_value.getValue();
858+}
859+
860+void ControlDoublePrivate::reset(QObject* pSender) {
861+ double defaultValue = m_defaultValue.getValue();
862+ set(defaultValue, pSender);
863+}
864+
865+void ControlDoublePrivate::set(const double& value, QObject* pSender) {
866+ if (m_bIgnoreNops && get() == value) {
867+ return;
868+ }
869+
870+ double dValue = value;
871+ // The behavior says to ignore the set, ignore it.
872+ ControlNumericBehavior* pBehavior = m_pBehavior;
873+ if (pBehavior && !pBehavior->setFilter(&dValue)) {
874+ return;
875+ }
876+ m_value.setValue(dValue);
877+ emit(valueChanged(dValue, pSender));
878+
879+ if (m_bTrack) {
880+ Stat::track(m_trackKey, static_cast<Stat::StatType>(m_trackType),
881+ static_cast<Stat::ComputeFlags>(m_trackFlags), dValue);
882+ }
883+}
884+
885+ControlNumericBehavior* ControlDoublePrivate::setBehavior(ControlNumericBehavior* pBehavior) {
886+ return m_pBehavior.fetchAndStoreRelaxed(pBehavior);
887+}
888+
889+void ControlDoublePrivate::setWidgetParameter(double dParam, QObject* pSetter) {
890+ ControlNumericBehavior* pBehavior = m_pBehavior;
891+ set(pBehavior ? pBehavior->widgetParameterToValue(dParam) : dParam, pSetter);
892+}
893+
894+double ControlDoublePrivate::getWidgetParameter() const {
895+ ControlNumericBehavior* pBehavior = m_pBehavior;
896+ return pBehavior ? pBehavior->valueToWidgetParameter(get()) : get();
897+}
898+
899+void ControlDoublePrivate::setMidiParameter(MidiOpCode opcode, double dParam) {
900+ ControlNumericBehavior* pBehavior = m_pBehavior;
901+ if (pBehavior) {
902+ pBehavior->setValueFromMidiParameter(opcode, dParam, this);
903+ } else {
904+ set(dParam, NULL);
905+ }
906+}
907+
908+double ControlDoublePrivate::getMidiParameter() const {
909+ ControlNumericBehavior* pBehavior = m_pBehavior;
910+ return pBehavior ? pBehavior->valueToMidiParameter(get()) : get();
911+}
912+
913
914=== added file 'mixxx/src/control/control.h'
915--- mixxx/src/control/control.h 1970-01-01 00:00:00 +0000
916+++ mixxx/src/control/control.h 2013-05-16 01:44:29 +0000
917@@ -0,0 +1,95 @@
918+#ifndef CONTROL_H
919+#define CONTROL_H
920+
921+#include <QHash>
922+#include <QMutex>
923+#include <QString>
924+#include <QObject>
925+#include <QAtomicPointer>
926+
927+#include "control/controlbehavior.h"
928+#include "control/controlvalue.h"
929+#include "configobject.h"
930+
931+class ControlDoublePrivate : public QObject {
932+ Q_OBJECT
933+ public:
934+ ControlDoublePrivate();
935+ ControlDoublePrivate(ConfigKey key, bool bIgnoreNops, bool bTrack);
936+ virtual ~ControlDoublePrivate();
937+
938+ // Gets the ControlDoublePrivate matching the given ConfigKey. If bCreate
939+ // is true, allocates a new ControlDoublePrivate for the ConfigKey if one
940+ // does not exist.
941+ static ControlDoublePrivate* getControl(
942+ const ConfigKey& key,
943+ bool bCreate, bool bIgnoreNops=true, bool bTrack=false);
944+ static inline ControlDoublePrivate* getControl(
945+ const QString& group, const QString& item,
946+ bool bCreate, bool bIgnoreNops=true, bool bTrack=false) {
947+ ConfigKey key(group, item);
948+ return getControl(key, bCreate, bIgnoreNops, bTrack);
949+ }
950+
951+ // Sets the control value.
952+ void set(const double& value, QObject* pSetter);
953+ // Gets the control value.
954+ double get() const;
955+ // Resets the control value to its default.
956+ void reset(QObject* pSetter);
957+
958+ // Set the behavior to be used when setting values and translating between
959+ // parameter and value space. Returns the previously set behavior (if any).
960+ // Caller must handle appropriate destruction of the previous behavior or
961+ // memory will leak.
962+ ControlNumericBehavior* setBehavior(ControlNumericBehavior* pBehavior);
963+
964+ void setWidgetParameter(double dParam, QObject* pSetter);
965+ double getWidgetParameter() const;
966+
967+ void setMidiParameter(MidiOpCode opcode, double dParam);
968+ double getMidiParameter() const;
969+
970+ inline bool ignoreNops() const {
971+ return m_bIgnoreNops;
972+ }
973+
974+ inline void setDefaultValue(double dValue) {
975+ m_defaultValue.setValue(dValue);
976+ }
977+ inline double defaultValue() const {
978+ double default_value = m_defaultValue.getValue();
979+ return m_pBehavior ? m_pBehavior->defaultValue(default_value) : default_value;
980+ }
981+
982+ signals:
983+ // Emitted when the ControlDoublePrivate value changes. pSetter is a
984+ // pointer to the setter of the value (potentially NULL).
985+ void valueChanged(double value, QObject* pSetter);
986+
987+ private:
988+ ConfigKey m_key;
989+ // Whether to ignore sets which would have no effect.
990+ bool m_bIgnoreNops;
991+
992+ // Whether to track value changes with the stats framework.
993+ bool m_bTrack;
994+ QString m_trackKey;
995+ int m_trackType;
996+ int m_trackFlags;
997+
998+ // The control value.
999+ ControlValueAtomic<double> m_value;
1000+ // The default control value.
1001+ ControlValueAtomic<double> m_defaultValue;
1002+
1003+ QAtomicPointer<ControlNumericBehavior> m_pBehavior;
1004+
1005+ // Hash of ControlDoublePrivate instantiations.
1006+ static QHash<ConfigKey,ControlDoublePrivate*> m_sqCOHash;
1007+ // Mutex guarding access to the ControlDoublePrivate hash.
1008+ static QMutex m_sqCOHashMutex;
1009+};
1010+
1011+
1012+#endif /* CONTROL_H */
1013
1014=== added file 'mixxx/src/control/controlbehavior.cpp'
1015--- mixxx/src/control/controlbehavior.cpp 1970-01-01 00:00:00 +0000
1016+++ mixxx/src/control/controlbehavior.cpp 2013-05-16 01:44:29 +0000
1017@@ -0,0 +1,63 @@
1018+#include "control/controlbehavior.h"
1019+#include "control/control.h"
1020+
1021+// static
1022+const int ControlPushButtonBehavior::kPowerWindowTimeMillis = 300;
1023+
1024+void ControlNumericBehavior::setValueFromMidiParameter(MidiOpCode o, double dParam,
1025+ ControlDoublePrivate* pControl) {
1026+ Q_UNUSED(o);
1027+ pControl->set(dParam, NULL);
1028+}
1029+
1030+void ControlPotmeterBehavior::setValueFromMidiParameter(MidiOpCode o, double dParam,
1031+ ControlDoublePrivate* pControl) {
1032+ Q_UNUSED(o);
1033+ pControl->set(widgetParameterToValue(dParam), NULL);
1034+}
1035+
1036+void ControlPushButtonBehavior::setValueFromMidiParameter(
1037+ MidiOpCode o, double dParam, ControlDoublePrivate* pControl) {
1038+ // This block makes push-buttons act as power window buttons.
1039+ if (m_buttonMode == POWERWINDOW && m_iNumStates == 2) {
1040+ if (o == MIDI_NOTE_ON) {
1041+ if (dParam > 0.) {
1042+ double value = pControl->get();
1043+ pControl->set(!value, NULL);
1044+ m_pushTimer.setSingleShot(true);
1045+ m_pushTimer.start(kPowerWindowTimeMillis);
1046+ }
1047+ } else if (o == MIDI_NOTE_OFF) {
1048+ if (!m_pushTimer.isActive()) {
1049+ pControl->set(0.0, NULL);
1050+ }
1051+ }
1052+ } else if (m_buttonMode == TOGGLE) {
1053+ // This block makes push-buttons act as toggle buttons.
1054+ if (m_iNumStates > 2) { //multistate button
1055+ if (dParam > 0.) { //looking for NOTE_ON doesn't seem to work...
1056+ double value = pControl->get();
1057+ value++;
1058+ if (value >= m_iNumStates) {
1059+ pControl->set(0, NULL);
1060+ } else {
1061+ pControl->set(value, NULL);
1062+ }
1063+ }
1064+ } else {
1065+ if (o == MIDI_NOTE_ON) {
1066+ if (dParam > 0.) {
1067+ double value = pControl->get();
1068+ pControl->set(!value, NULL);
1069+ }
1070+ }
1071+ }
1072+ } else { //Not a toggle button (trigger only when button pushed)
1073+ if (o == MIDI_NOTE_ON) {
1074+ double value = pControl->get();
1075+ pControl->set(!value, NULL);
1076+ } else if (o == MIDI_NOTE_OFF) {
1077+ pControl->set(0.0, NULL);
1078+ }
1079+ }
1080+}
1081
1082=== added file 'mixxx/src/control/controlbehavior.h'
1083--- mixxx/src/control/controlbehavior.h 1970-01-01 00:00:00 +0000
1084+++ mixxx/src/control/controlbehavior.h 2013-05-16 01:44:29 +0000
1085@@ -0,0 +1,186 @@
1086+#ifndef CONTROLBEHAVIOR_H
1087+#define CONTROLBEHAVIOR_H
1088+
1089+#include <math.h>
1090+
1091+#include <QTimer>
1092+
1093+#include "controllers/midi/midimessage.h"
1094+#include "mathstuff.h"
1095+
1096+class ControlDoublePrivate;
1097+
1098+class ControlNumericBehavior {
1099+ public:
1100+ // Returns true if the set should occur. Mutates dValue if the value should
1101+ // be changed.
1102+ virtual bool setFilter(double* dValue) {
1103+ Q_UNUSED(dValue);
1104+ return true;
1105+ }
1106+
1107+ virtual double defaultValue(double dDefault) const {
1108+ return dDefault;
1109+ }
1110+
1111+ virtual double valueToWidgetParameter(double dValue) {
1112+ return dValue;
1113+ }
1114+
1115+ virtual double widgetParameterToValue(double dParam) {
1116+ return dParam;
1117+ }
1118+
1119+ virtual double valueToMidiParameter(double dValue) {
1120+ return dValue;
1121+ }
1122+
1123+ virtual void setValueFromMidiParameter(MidiOpCode o, double dParam,
1124+ ControlDoublePrivate* pControl);
1125+};
1126+
1127+class ControlPotmeterBehavior : public ControlNumericBehavior {
1128+ public:
1129+ ControlPotmeterBehavior(double dMinValue, double dMaxValue)
1130+ : m_dMinValue(dMinValue),
1131+ m_dMaxValue(dMaxValue),
1132+ m_dValueRange(m_dMaxValue - m_dMinValue),
1133+ m_dDefaultValue(m_dMinValue + 0.5 * m_dValueRange) {
1134+ }
1135+
1136+ virtual bool setFilter(double* dValue) {
1137+ if (*dValue > m_dMaxValue) {
1138+ *dValue = m_dMaxValue;
1139+ } else if (*dValue < m_dMinValue) {
1140+ *dValue = m_dMinValue;
1141+ }
1142+ return true;
1143+ }
1144+
1145+ virtual double defaultValue(double dDefault) const {
1146+ Q_UNUSED(dDefault);
1147+ return m_dDefaultValue;
1148+ }
1149+
1150+ virtual double valueToWidgetParameter(double dValue) {
1151+ double dNorm = (dValue - m_dMinValue) / m_dValueRange;
1152+ return dNorm < 0.5 ? dNorm * 128.0 : dNorm * 126.0 + 1.0;
1153+ }
1154+
1155+ virtual double widgetParameterToValue(double dParam) {
1156+ double dNorm = dParam < 64 ? dParam / 128.0 : (dParam - 1.0) / 126.0;
1157+ return m_dMinValue + dNorm * m_dValueRange;
1158+ }
1159+
1160+ virtual double valueToMidiParameter(double dValue) {
1161+ return valueToWidgetParameter(dValue);
1162+ }
1163+
1164+ virtual void setValueFromMidiParameter(MidiOpCode o, double dParam,
1165+ ControlDoublePrivate* pControl);
1166+
1167+ protected:
1168+ double m_dMinValue;
1169+ double m_dMaxValue;
1170+ double m_dValueRange;
1171+ double m_dDefaultValue;
1172+};
1173+
1174+#define maxPosition 127
1175+#define minPosition 0
1176+#define middlePosition ((maxPosition-minPosition)/2)
1177+#define positionrange (maxPosition-minPosition)
1178+
1179+class ControlLogpotmeterBehavior : public ControlPotmeterBehavior {
1180+ public:
1181+ ControlLogpotmeterBehavior(double dMaxValue) : ControlPotmeterBehavior(0, dMaxValue) {
1182+ m_dB1 = log10(2.0) / middlePosition;
1183+ m_dB2 = log10(dMaxValue) / (maxPosition - middlePosition);
1184+ }
1185+
1186+ virtual double defaultValue(double dDefault) {
1187+ Q_UNUSED(dDefault);
1188+ return 1.0;
1189+ }
1190+
1191+ virtual double valueToWidgetParameter(double dValue) {
1192+ if (dValue > 1.0) {
1193+ return log10(dValue) / m_dB2 + middlePosition;
1194+ } else {
1195+ return log10(dValue + 1.0) / m_dB1;
1196+ }
1197+ }
1198+
1199+ virtual double widgetParameterToValue(double dParam) {
1200+ if (dParam <= middlePosition) {
1201+ return pow(10.0, m_dB1 * dParam) - 1;
1202+ } else {
1203+ return pow(10.0, m_dB2 * (dParam - middlePosition));
1204+ }
1205+ }
1206+
1207+ protected:
1208+ double m_dB1, m_dB2;
1209+};
1210+
1211+class ControlLinPotmeterBehavior : public ControlPotmeterBehavior {
1212+ public:
1213+ ControlLinPotmeterBehavior(double dMinValue, double dMaxValue)
1214+ : ControlPotmeterBehavior(dMinValue, dMaxValue) {
1215+ }
1216+
1217+ virtual double valueToWidgetParameter(double dValue) {
1218+ double dNorm = (dValue - m_dMinValue) / m_dValueRange;
1219+ return math_min(dNorm * 128, 127);
1220+ }
1221+
1222+ virtual double widgetParameterToValue(double dParam) {
1223+ double dNorm = dParam / 128.0;
1224+ return m_dMinValue + dNorm * m_dValueRange;
1225+ }
1226+};
1227+
1228+class ControlTTRotaryBehavior : public ControlNumericBehavior {
1229+ public:
1230+ virtual double valueToWidgetParameter(double dValue) {
1231+ return dValue * 200.0 + 64;
1232+ }
1233+
1234+ virtual double widgetParameterToValue(double dParam) {
1235+ // Non-linear scaling
1236+ double temp = ((dParam - 64.0) * (dParam - 64.0)) / 64.0;
1237+ if (dParam - 64 < 0) {
1238+ temp = -temp;
1239+ }
1240+ return temp;
1241+ }
1242+};
1243+
1244+class ControlPushButtonBehavior : public ControlNumericBehavior {
1245+ public:
1246+ static const int kPowerWindowTimeMillis;
1247+
1248+ // TODO(XXX) Duplicated from ControlPushButton. It's complicated and
1249+ // annoying to share them so I just copied them.
1250+ enum ButtonMode {
1251+ PUSH = 0,
1252+ TOGGLE,
1253+ POWERWINDOW
1254+ };
1255+
1256+ ControlPushButtonBehavior(ButtonMode buttonMode,
1257+ int iNumStates)
1258+ : m_buttonMode(buttonMode),
1259+ m_iNumStates(iNumStates) {
1260+ }
1261+
1262+ virtual void setValueFromMidiParameter(MidiOpCode o, double dParam,
1263+ ControlDoublePrivate* pControl);
1264+
1265+ private:
1266+ ButtonMode m_buttonMode;
1267+ int m_iNumStates;
1268+ QTimer m_pushTimer;
1269+};
1270+
1271+#endif /* CONTROLBEHAVIOR_H */
1272
1273=== renamed file 'mixxx/src/controlobjectbase.h' => 'mixxx/src/control/controlvalue.h'
1274--- mixxx/src/controlobjectbase.h 2013-05-15 20:33:26 +0000
1275+++ mixxx/src/control/controlvalue.h 2013-05-16 01:44:29 +0000
1276@@ -1,28 +1,34 @@
1277+#ifndef CONTROLVALUE_H
1278+#define CONTROLVALUE_H
1279
1280-#ifndef CONTROLOBJECTBASE_H_
1281-#define CONTROLOBJECTBASE_H_
1282+#include <limits>
1283
1284 #include <QAtomicInt>
1285 #include <QObject>
1286-#include <limits>
1287
1288 // for look free access, this value has to be >= the number of value using threads
1289 // value must be a fraction of an integer
1290 const int cRingSize = 8;
1291-// there are basicly unlimited readers allowed at each ring element
1292+// there are basicly unlimited readers allowed at each ring element
1293 // but we have to count them so max() is just fine.
1294 const int cReaderSlotCnt = std::numeric_limits<int>::max();
1295
1296-
1297+// A single instance of a value of type T along with an atomic integer which
1298+// tracks the current number of readers or writers of the slot. The value
1299+// m_readerSlots starts at cReaderSlotCnt and counts down to 0. If the value is
1300+// 0 or less then reads to the value fail because there are either too many
1301+// readers or a write is occurring. A write to the value will fail if
1302+// m_readerSlots is not equal to cReaderSlotCnt (e.g. there is an active
1303+// reader).
1304 template<typename T>
1305-class ControlObjectRingValue {
1306+class ControlRingValue {
1307 public:
1308- ControlObjectRingValue()
1309+ ControlRingValue()
1310 : m_value(T()),
1311 m_readerSlots(cReaderSlotCnt) {
1312 }
1313
1314- bool tryGet(T* value) {
1315+ bool tryGet(T* value) const {
1316 // Read while consuming one readerSlot
1317 bool hasSlot = (m_readerSlots.fetchAndAddAcquire(-1) > 0);
1318 if (hasSlot) {
1319@@ -44,14 +50,19 @@
1320
1321 private:
1322 T m_value;
1323- QAtomicInt m_readerSlots;
1324+ mutable QAtomicInt m_readerSlots;
1325 };
1326
1327 // Ring buffer based implementation for all Types sizeof(T) > sizeof(void*)
1328+
1329+// An implementation of ControlValueAtomicBase for non-atomic types T. Uses a
1330+// ring-buffer of ControlRingValues and a read pointer and write pointer to
1331+// provide getValue()/setValue() methods which *sacrifice perfect consistency*
1332+// for the benefit of wait-free read/write access to a value.
1333 template<typename T, bool ATOMIC = false>
1334-class ControlObjectValue {
1335+class ControlValueAtomicBase {
1336 public:
1337- inline T getValue() {
1338+ inline T getValue() const {
1339 T value = T();
1340 unsigned int index = (unsigned int)m_readIndex
1341 % (cRingSize);
1342@@ -59,10 +70,10 @@
1343 // We are here if
1344 // 1) there are more then cReaderSlotCnt reader (get) reading the same value or
1345 // 2) the formerly current value is locked by a writer
1346- // Case 1 does not happen because we have enough (0x7fffffff) reader slots.
1347+ // Case 1 does not happen because we have enough (0x7fffffff) reader slots.
1348 // Case 2 happens when the a reader is delayed after reading the
1349- // m_currentIndex and in the mean while a reader locks the formaly current value
1350- // because it has written cRingSize times. Reading the less recent value will fix
1351+ // m_currentIndex and in the mean while a reader locks the formaly current value
1352+ // because it has written cRingSize times. Reading the less recent value will fix
1353 // it because it is now actualy the current value.
1354 index = (index - 1) % (cRingSize);
1355 }
1356@@ -85,7 +96,7 @@
1357 }
1358
1359 protected:
1360- ControlObjectValue()
1361+ ControlValueAtomicBase()
1362 : m_readIndex(0),
1363 m_writeIndex(1) {
1364 Q_ASSERT((std::numeric_limits<unsigned int>::max() % cRingSize) == (cRingSize - 1));
1365@@ -94,16 +105,18 @@
1366 private:
1367 // In worst case, each reader can consume a reader slot from a different ring element.
1368 // In this case there is still one ring element available for writing.
1369- ControlObjectRingValue<T> m_ring[cRingSize];
1370+ ControlRingValue<T> m_ring[cRingSize];
1371 QAtomicInt m_readIndex;
1372 QAtomicInt m_writeIndex;
1373 };
1374
1375-// Specialized Template for atomic types.
1376+// Specialized template for types that are deemed to be atomic on the target
1377+// architecture. Instead of using a read/write ring to guarantee atomicity,
1378+// direct assignment/read of an aligned member variable is used.
1379 template<typename T>
1380-class ControlObjectValue<T, true> {
1381+class ControlValueAtomicBase<T, true> {
1382 public:
1383- inline T getValue() {
1384+ inline T getValue() const {
1385 return m_value;
1386 }
1387
1388@@ -112,8 +125,8 @@
1389 }
1390
1391 protected:
1392- ControlObjectValue()
1393- : m_value(T()) {
1394+ ControlValueAtomicBase()
1395+ : m_value(T()) {
1396 }
1397
1398 private:
1399@@ -126,20 +139,19 @@
1400 #endif
1401 };
1402
1403-// This is a proxy Template to select the native atomic or the ring buffer
1404-// Implementation depending on the target architecture
1405-// Note: Qt does not support templates for signal and slots
1406-// So the typified ControlObject has to handle the Event Queue connections
1407+// ControlValueAtomic is a wrapper around ControlValueAtomicBase which uses the
1408+// sizeof(T) to determine which underlying implementation of
1409+// ControlValueAtomicBase to use. For types where sizeof(T) <= sizeof(void*),
1410+// the specialized implementation of ControlValueAtomicBase for types that are
1411+// atomic on the architecture is used.
1412 template<typename T>
1413-class ControlObjectBase
1414- : public ControlObjectValue<T, sizeof(T) <= sizeof(void*)> {
1415+class ControlValueAtomic
1416+ : public ControlValueAtomicBase<T, sizeof(T) <= sizeof(void*)> {
1417 public:
1418
1419- ControlObjectBase()
1420- : ControlObjectValue<T, sizeof(T) <= sizeof(void*)>() {
1421+ ControlValueAtomic()
1422+ : ControlValueAtomicBase<T, sizeof(T) <= sizeof(void*)>() {
1423 }
1424 };
1425
1426-
1427-#endif // CONTROLOBJECTBASE_H_
1428-
1429+#endif /* CONTROLVALUE_H */
1430
1431=== removed file 'mixxx/src/controlbeat.cpp'
1432--- mixxx/src/controlbeat.cpp 2013-03-13 16:31:06 +0000
1433+++ mixxx/src/controlbeat.cpp 1970-01-01 00:00:00 +0000
1434@@ -1,83 +0,0 @@
1435-/***************************************************************************
1436- controlbeat.cpp - description
1437- -------------------
1438- begin : Mon Apr 7 2003
1439- copyright : (C) 2003 by Tue & Ken Haste Andersen
1440- email : haste@diku.dk
1441-***************************************************************************/
1442-
1443-/***************************************************************************
1444-* *
1445-* This program is free software; you can redistribute it and/or modify *
1446-* it under the terms of the GNU General Public License as published by *
1447-* the Free Software Foundation; either version 2 of the License, or *
1448-* (at your option) any later version. *
1449-* *
1450-***************************************************************************/
1451-
1452-#include "controlbeat.h"
1453-
1454-ControlBeat::ControlBeat(ConfigKey key, bool bMidiSimulateLatching)
1455- : ControlObject(key),
1456- m_bMidiSimulateLatching(bMidiSimulateLatching),
1457- m_bPressed(false),
1458- m_iValidPresses(0) {
1459-
1460- time.start();
1461- // Filter buffer
1462- buffer = new CSAMPLE[filterLength];
1463- for (int i = 0; i < filterLength; i++) {
1464- buffer[i] = 0.;
1465- }
1466-}
1467-
1468-ControlBeat::~ControlBeat()
1469-{
1470- delete [] buffer;
1471-}
1472-
1473-void ControlBeat::setValueFromMidi(MidiOpCode o, double v)
1474-{
1475- Q_UNUSED(o);
1476- Q_UNUSED(v);
1477- if (!m_bPressed || !m_bMidiSimulateLatching)
1478- {
1479- beatTap();
1480- m_bPressed = true;
1481- }
1482- else
1483- m_bPressed = false;
1484-}
1485-
1486-void ControlBeat::setValueFromThread(double dValue) {
1487- if (dValue > 0) {
1488- beatTap();
1489- }
1490-}
1491-
1492-void ControlBeat::beatTap()
1493-{
1494- int elapsed = time.restart();
1495-
1496- if (elapsed <= maxInterval) {
1497- // Move back in filter one sample
1498- for (int i = filterLength-1; i > 0; i--)
1499- buffer[i] = buffer[i-1];
1500-
1501- buffer[0] = 1000.*(60./elapsed);
1502- if (buffer[0] > maxBPM)
1503- buffer[0] = maxBPM;
1504-
1505- m_iValidPresses++;
1506- if (m_iValidPresses > filterLength)
1507- m_iValidPresses = filterLength;
1508-
1509- double temp = 0.;
1510- for (int i = 0; i < m_iValidPresses; ++i)
1511- temp += buffer[i];
1512- temp /= m_iValidPresses;
1513- set(temp);
1514- } else {
1515- m_iValidPresses = 0;
1516- }
1517-}
1518
1519=== removed file 'mixxx/src/controlbeat.h'
1520--- mixxx/src/controlbeat.h 2012-03-17 17:42:44 +0000
1521+++ mixxx/src/controlbeat.h 1970-01-01 00:00:00 +0000
1522@@ -1,59 +0,0 @@
1523-/***************************************************************************
1524- controlbeat.h - description
1525- -------------------
1526- begin : Mon Apr 7 2003
1527- copyright : (C) 2003 by Tue & Ken Haste Andersen
1528- email : haste@diku.dk
1529- ***************************************************************************/
1530-
1531-/***************************************************************************
1532- * *
1533- * This program is free software; you can redistribute it and/or modify *
1534- * it under the terms of the GNU General Public License as published by *
1535- * the Free Software Foundation; either version 2 of the License, or *
1536- * (at your option) any later version. *
1537- * *
1538- ***************************************************************************/
1539-
1540-#ifndef CONTROLBEAT_H
1541-#define CONTROLBEAT_H
1542-
1543-#include "controlobject.h"
1544-#include "configobject.h"
1545-#include "defs.h"
1546-#include <qdatetime.h>
1547-
1548-/**
1549- * Takes impulses as input, and convert it to a BPM measure.
1550- *
1551- *@author Tue & Ken Haste Andersen
1552- */
1553-
1554-/** Minimum allowed Beat per minute (BPM) */
1555-const int minBPM = 30;
1556-/** Maximum allowed bpm */
1557-const int maxBPM = 240;
1558-/** Maximum allowed interval between beats in milli seconds (calculated from minBPM) */
1559-const int maxInterval = (int)(1000.*(60./(CSAMPLE)minBPM));
1560-/** Filter length */
1561-const int filterLength = 5;
1562-
1563-class ControlBeat : public ControlObject {
1564- public:
1565- ControlBeat(ConfigKey key, bool bMidiSimulateLatching=false);
1566- virtual ~ControlBeat();
1567-
1568- protected:
1569- void setValueFromMidi(MidiOpCode o, double v);
1570- void setValueFromThread(double dValue);
1571- private:
1572- void beatTap();
1573-
1574- QTime time;
1575- CSAMPLE *buffer;
1576- bool m_bMidiSimulateLatching;
1577- bool m_bPressed;
1578- int m_iValidPresses;
1579-};
1580-
1581-#endif
1582
1583=== modified file 'mixxx/src/controllers/controllerengine.cpp'
1584--- mixxx/src/controllers/controllerengine.cpp 2013-05-01 21:53:11 +0000
1585+++ mixxx/src/controllers/controllerengine.cpp 2013-05-16 01:44:29 +0000
1586@@ -640,8 +640,11 @@
1587
1588 ControlObjectThread *cot = getControlObjectThread(group, name);
1589
1590- if (cot != NULL && !m_st.ignore(cot->getControlObject(), newValue)) {
1591- cot->slotSet(newValue);
1592+ if (cot != NULL) {
1593+ ControlObject* pControl = ControlObject::getControl(cot->getKey());
1594+ if (pControl && !m_st.ignore(pControl, newValue)) {
1595+ cot->slotSet(newValue);
1596+ }
1597 }
1598 }
1599
1600@@ -812,12 +815,7 @@
1601 return;
1602 }
1603
1604- ControlObject* pSenderCO = senderCOT->getControlObject();
1605- if (pSenderCO == NULL) {
1606- qWarning() << "ControllerEngine::slotValueChanged() The sender's CO is NULL.";
1607- return;
1608- }
1609- ConfigKey key = pSenderCO->getKey();
1610+ ConfigKey key = senderCOT->getKey();
1611
1612 //qDebug() << "[Controller]: SlotValueChanged" << key.group << key.item;
1613
1614
1615=== modified file 'mixxx/src/controllers/midi/midicontroller.cpp'
1616--- mixxx/src/controllers/midi/midicontroller.cpp 2013-05-01 21:53:11 +0000
1617+++ mixxx/src/controllers/midi/midicontroller.cpp 2013-05-16 01:44:29 +0000
1618@@ -165,6 +165,58 @@
1619 }
1620 }
1621
1622+QString formatMidiMessage(unsigned char status, unsigned char control, unsigned char value,
1623+ unsigned char channel, unsigned char opCode) {
1624+ switch (opCode) {
1625+ case MIDI_PITCH_BEND:
1626+ return QString("MIDI status 0x%1: pitch bend ch %2, value 0x%3")
1627+ .arg(QString::number(status, 16).toUpper(),
1628+ QString::number(channel+1, 10),
1629+ QString::number((value << 7) | control, 16).toUpper().rightJustified(4,'0'));
1630+ case MIDI_SONG_POS:
1631+ return QString("MIDI status 0x%1: song position 0x%2")
1632+ .arg(QString::number(status, 16).toUpper(),
1633+ QString::number((value << 7) | control, 16).toUpper().rightJustified(4,'0'));
1634+ case MIDI_PROGRAM_CH:
1635+ case MIDI_CH_AFTERTOUCH:
1636+ return QString("MIDI status 0x%1 (ch %2, opcode 0x%3), value 0x%4")
1637+ .arg(QString::number(status, 16).toUpper(),
1638+ QString::number(channel+1, 10),
1639+ QString::number((status & 255)>>4, 16).toUpper(),
1640+ QString::number(control, 16).toUpper().rightJustified(2,'0'));
1641+ case MIDI_SONG:
1642+ return QString("MIDI status 0x%1: select song #%2")
1643+ .arg(QString::number(status, 16).toUpper(),
1644+ QString::number(control+1, 10));
1645+ case MIDI_NOTE_OFF:
1646+ case MIDI_NOTE_ON:
1647+ case MIDI_AFTERTOUCH:
1648+ case MIDI_CC:
1649+ return QString("MIDI status 0x%1 (ch %2, opcode 0x%3), ctrl 0x%4, val 0x%5")
1650+ .arg(QString::number(status, 16).toUpper(),
1651+ QString::number(channel+1, 10),
1652+ QString::number((status & 255)>>4, 16).toUpper(),
1653+ QString::number(control, 16).toUpper().rightJustified(2,'0'),
1654+ QString::number(value, 16).toUpper().rightJustified(2,'0'));
1655+ default:
1656+ return QString("MIDI status 0x%1")
1657+ .arg(QString::number(status, 16).toUpper());
1658+ }
1659+}
1660+
1661+bool isMessageTwoBytes(unsigned char opCode) {
1662+ switch (opCode) {
1663+ case MIDI_SONG:
1664+ case MIDI_NOTE_OFF:
1665+ case MIDI_NOTE_ON:
1666+ case MIDI_AFTERTOUCH:
1667+ case MIDI_CC:
1668+ return true;
1669+ default:
1670+ return false;
1671+ }
1672+}
1673+
1674 void MidiController::receive(unsigned char status, unsigned char control,
1675 unsigned char value) {
1676 unsigned char channel = status & 0x0F;
1677@@ -173,57 +225,10 @@
1678 opCode = status;
1679 }
1680
1681- QString message;
1682- bool twoBytes = true;
1683-
1684- switch (opCode) {
1685- case MIDI_PITCH_BEND:
1686- twoBytes = false;
1687- message = QString("MIDI status 0x%1: pitch bend ch %2, value 0x%3")
1688- .arg(QString::number(status, 16).toUpper(),
1689- QString::number(channel+1, 10),
1690- QString::number((value << 7) | control, 16).toUpper().rightJustified(4,'0'));
1691- break;
1692- case MIDI_SONG_POS:
1693- twoBytes = false;
1694- message = QString("MIDI status 0x%1: song position 0x%2")
1695- .arg(QString::number(status, 16).toUpper(),
1696- QString::number((value << 7) | control, 16).toUpper().rightJustified(4,'0'));
1697- break;
1698- case MIDI_PROGRAM_CH:
1699- case MIDI_CH_AFTERTOUCH:
1700- twoBytes = false;
1701- message = QString("MIDI status 0x%1 (ch %2, opcode 0x%3), value 0x%4")
1702- .arg(QString::number(status, 16).toUpper(),
1703- QString::number(channel+1, 10),
1704- QString::number((status & 255)>>4, 16).toUpper(),
1705- QString::number(control, 16).toUpper().rightJustified(2,'0'));
1706- break;
1707- case MIDI_SONG:
1708- message = QString("MIDI status 0x%1: select song #%2")
1709- .arg(QString::number(status, 16).toUpper(),
1710- QString::number(control+1, 10));
1711- break;
1712- case MIDI_NOTE_OFF:
1713- case MIDI_NOTE_ON:
1714- case MIDI_AFTERTOUCH:
1715- case MIDI_CC:
1716- message = QString("MIDI status 0x%1 (ch %2, opcode 0x%3), ctrl 0x%4, val 0x%5")
1717- .arg(QString::number(status, 16).toUpper(),
1718- QString::number(channel+1, 10),
1719- QString::number((status & 255)>>4, 16).toUpper(),
1720- QString::number(control, 16).toUpper().rightJustified(2,'0'),
1721- QString::number(value, 16).toUpper().rightJustified(2,'0'));
1722- break;
1723- default:
1724- twoBytes = false;
1725- message = QString("MIDI status 0x%1")
1726- .arg(QString::number(status, 16).toUpper());
1727- break;
1728- }
1729+ bool twoBytes = isMessageTwoBytes(opCode);
1730
1731 if (debugging()) {
1732- qDebug() << message;
1733+ qDebug() << formatMidiMessage(status, control, value, channel, opCode);
1734 }
1735
1736 //if (m_bReceiveInhibit) return;
1737@@ -265,16 +270,12 @@
1738 //Reset the saved control.
1739 setControlToLearn(MixxxControl());
1740
1741- QString message = "error";
1742- if (twoBytes) {
1743- message = QString("0x%1 0x%2")
1744- .arg(QString::number(mappingKey.status, 16).toUpper(),
1745- QString::number(mappingKey.control, 16).toUpper()
1746- .rightJustified(2,'0'));
1747- } else {
1748- message = QString("0x%1")
1749- .arg(QString::number(mappingKey.status, 16).toUpper());
1750- }
1751+ QString message = twoBytes ? QString("0x%1 0x%2")
1752+ .arg(QString::number(mappingKey.status, 16).toUpper(),
1753+ QString::number(mappingKey.control, 16).toUpper()
1754+ .rightJustified(2,'0')) :
1755+ QString("0x%1")
1756+ .arg(QString::number(mappingKey.status, 16).toUpper());
1757 emit(learnedMessage(message));
1758 }
1759 }
1760@@ -333,7 +334,7 @@
1761
1762 // computeValue not (yet) done on pitch messages because it all assumes 7-bit numbers
1763 } else {
1764- double currMixxxControlValue = p->GetMidiValue();
1765+ double currMixxxControlValue = p->getValueToMidi();
1766 newValue = computeValue(options, currMixxxControlValue, value);
1767 }
1768
1769@@ -355,7 +356,7 @@
1770 return;
1771 }
1772 }
1773- p->setValueFromThread(newValue);
1774+ p->setValueFromThread(newValue, NULL);
1775 } else {
1776 if (options.soft_takeover) {
1777 if (m_st.ignore(p, newValue, true)) {
1778@@ -456,17 +457,20 @@
1779 return _newmidivalue;
1780 }
1781
1782-void MidiController::receive(QByteArray data) {
1783- int length = data.size();
1784- QString message = QString("%1: %2 bytes: [").arg(getName()).arg(length);
1785- for (int i = 0; i < length; ++i) {
1786+QString formatSysexMessage(QString controllerName, const QByteArray& data) {
1787+ QString message = QString("%1: %2 bytes: [").arg(controllerName).arg(data.size());
1788+ for (int i = 0; i < data.size(); ++i) {
1789 message += QString("%1%2").arg(
1790 QString("%1").arg((unsigned char)(data.at(i)), 2, 16, QChar('0')).toUpper(),
1791- QString("%1").arg((i < (length-1)) ? ' ' : ']'));
1792+ QString("%1").arg((i < (data.size()-1)) ? ' ' : ']'));
1793 }
1794+ return message;
1795+}
1796
1797- if (debugging())
1798- qDebug() << message;
1799+void MidiController::receive(QByteArray data) {
1800+ if (debugging()) {
1801+ qDebug() << formatSysexMessage(getName(), data);
1802+ }
1803
1804 //if (m_bReceiveInhibit) return;
1805
1806@@ -494,7 +498,7 @@
1807 setControlToLearn(MixxxControl());
1808
1809 QString message = QString("0x%1")
1810- .arg(QString::number(mappingKey.status, 16).toUpper());
1811+ .arg(QString::number(mappingKey.status, 16).toUpper());
1812 emit(learnedMessage(message));
1813 }
1814 // Don't process MIDI messages when learning
1815@@ -523,7 +527,8 @@
1816 }
1817 return;
1818 }
1819- qWarning() << "MidiController: No script function specified for" << message;
1820+ qWarning() << "MidiController: No script function specified for"
1821+ << formatSysexMessage(getName(), data);
1822 }
1823
1824 void MidiController::sendShortMsg(unsigned char status, unsigned char byte1, unsigned char byte2) {
1825
1826=== modified file 'mixxx/src/controllers/midi/midioutputhandler.cpp'
1827--- mixxx/src/controllers/midi/midioutputhandler.cpp 2013-03-13 16:31:06 +0000
1828+++ mixxx/src/controllers/midi/midioutputhandler.cpp 2013-05-16 01:44:29 +0000
1829@@ -6,10 +6,11 @@
1830 *
1831 */
1832
1833+#include <QtDebug>
1834+
1835 #include "controllers/midi/midioutputhandler.h"
1836 #include "controllers/midi/midicontroller.h"
1837-
1838-#include <QDebug>
1839+#include "controlobject.h"
1840
1841 MidiOutputHandler::MidiOutputHandler(QString group, QString key,
1842 MidiController *controller,
1843@@ -25,32 +26,24 @@
1844 m_on(on),
1845 m_off(off),
1846 m_lastVal(0) {
1847+ connect(&m_cobj, SIGNAL(valueChanged(double)),
1848+ this, SLOT(controlChanged(double)));
1849 }
1850
1851 MidiOutputHandler::~MidiOutputHandler() {
1852- if (m_cobj != NULL) {
1853- ConfigKey cKey = m_cobj->getKey();
1854- if (m_pController->debugging()) {
1855- qDebug() << QString("Destroying static MIDI output handler on %1 for %2,%3")
1856- .arg(m_pController->getName(), cKey.group, cKey.item);
1857- }
1858+ ConfigKey cKey = m_cobj.getKey();
1859+ if (m_pController->debugging()) {
1860+ qDebug() << QString("Destroying static MIDI output handler on %1 for %2,%3")
1861+ .arg(m_pController->getName(), cKey.group, cKey.item);
1862 }
1863 }
1864
1865 bool MidiOutputHandler::validate() {
1866- if (m_cobj == NULL) {
1867- return false;
1868- }
1869- connect(m_cobj, SIGNAL(valueChanged(double)),
1870- this, SLOT(controlChanged(double)));
1871- return true;
1872+ return m_cobj.valid();
1873 }
1874
1875 void MidiOutputHandler::update() {
1876- if (m_cobj == NULL) {
1877- return;
1878- }
1879- controlChanged(m_cobj->get());
1880+ controlChanged(m_cobj.get());
1881 }
1882
1883 void MidiOutputHandler::controlChanged(double value) {
1884
1885=== modified file 'mixxx/src/controllers/midi/midioutputhandler.h'
1886--- mixxx/src/controllers/midi/midioutputhandler.h 2012-04-24 05:51:32 +0000
1887+++ mixxx/src/controllers/midi/midioutputhandler.h 2013-05-16 01:44:29 +0000
1888@@ -11,7 +11,7 @@
1889 #ifndef MIDIOUTPUTHANDLER_H
1890 #define MIDIOUTPUTHANDLER_H
1891
1892-#include "controlobject.h"
1893+#include "controlobjectthread.h"
1894
1895 class MidiController; // forward declaration
1896
1897@@ -32,7 +32,7 @@
1898
1899 private:
1900 MidiController* m_pController;
1901- ControlObject* m_cobj;
1902+ ControlObjectThread m_cobj;
1903 float m_min;
1904 float m_max;
1905 unsigned char m_status;
1906
1907=== modified file 'mixxx/src/controllers/softtakeover.cpp'
1908--- mixxx/src/controllers/softtakeover.cpp 2013-04-27 22:06:33 +0000
1909+++ mixxx/src/controllers/softtakeover.cpp 2013-05-16 01:44:29 +0000
1910@@ -79,7 +79,7 @@
1911 threshold = scaleFactor*(threshold/128.0f);
1912 }
1913
1914- double currentValue = midiVal ? control->GetMidiValue() : control->get();
1915+ double currentValue = midiVal ? control->getValueToMidi() : control->get();
1916 double difference = currentValue - newValue;
1917 double prevDiff = 0;
1918 bool sameSide = false;
1919
1920=== modified file 'mixxx/src/controllinpotmeter.cpp'
1921--- mixxx/src/controllinpotmeter.cpp 2013-03-13 16:31:06 +0000
1922+++ mixxx/src/controllinpotmeter.cpp 2013-05-16 01:44:29 +0000
1923@@ -1,34 +1,15 @@
1924 #include "controllinpotmeter.h"
1925 #include "defs.h"
1926
1927-
1928 // This control has a linear link between the m_dValue and the Midi Value
1929 // limitation: m_dMaxValue represents the midi value of 128 and is never reached
1930 ControlLinPotmeter::ControlLinPotmeter(ConfigKey key, double dMinValue, double dMaxValue) :
1931 ControlPotmeter(key, dMinValue, dMaxValue) {
1932-
1933-}
1934-
1935-double ControlLinPotmeter::getValueToWidget(double dValue) {
1936- double out = (dValue - m_dMinValue) / m_dValueRange;
1937- return math_min(out * 128, 127);
1938-}
1939-
1940-double ControlLinPotmeter::GetMidiValue() {
1941- double out = get();
1942- out = (out - m_dMinValue) / m_dValueRange;
1943- return math_min(out * 128, 127);
1944-}
1945-
1946-double ControlLinPotmeter::getValueFromWidget(double dValue) {
1947- double out = dValue / 128;
1948- return m_dMinValue + out * m_dValueRange;
1949-}
1950-
1951-void ControlLinPotmeter::setValueFromMidi(MidiOpCode o, double v) {
1952- Q_UNUSED(o);
1953- double out = v / 128;
1954- set(m_dMinValue + out * m_dValueRange);
1955+ if (m_pControl) {
1956+ ControlNumericBehavior* pOldBehavior = m_pControl->setBehavior(
1957+ new ControlLinPotmeterBehavior(dMinValue, dMaxValue));
1958+ delete pOldBehavior;
1959+ }
1960 }
1961
1962
1963
1964=== modified file 'mixxx/src/controllinpotmeter.h'
1965--- mixxx/src/controllinpotmeter.h 2012-12-22 14:07:45 +0000
1966+++ mixxx/src/controllinpotmeter.h 2013-05-16 01:44:29 +0000
1967@@ -3,19 +3,10 @@
1968
1969 #include "controlpotmeter.h"
1970
1971-class ControlLinPotmeter : public ControlPotmeter
1972-{
1973+class ControlLinPotmeter : public ControlPotmeter {
1974 Q_OBJECT
1975 public:
1976-
1977 ControlLinPotmeter(ConfigKey key, double dMinValue=0.0, double dMaxValue=1.0);
1978-
1979- double getValueToWidget(double dValue);
1980- double GetMidiValue();
1981- double getValueFromWidget(double dValue);
1982-
1983- protected:
1984- void setValueFromMidi(MidiOpCode o, double v);
1985 };
1986
1987 #endif // CONTROLLINPOTMETER_H
1988
1989=== modified file 'mixxx/src/controllogpotmeter.cpp'
1990--- mixxx/src/controllogpotmeter.cpp 2013-03-13 16:31:06 +0000
1991+++ mixxx/src/controllogpotmeter.cpp 2013-05-16 01:44:29 +0000
1992@@ -15,14 +15,8 @@
1993 * *
1994 ***************************************************************************/
1995
1996-#include <math.h>
1997 #include "controllogpotmeter.h"
1998
1999-#define maxPosition 127
2000-#define minPosition 0
2001-#define middlePosition ((maxPosition-minPosition)/2)
2002-#define positionrange (maxPosition-minPosition)
2003-
2004 /* -------- ------------------------------------------------------
2005 Purpose: Creates a new logarithmic potmeter, where the value is
2006 given by:
2007@@ -41,72 +35,13 @@
2008 ControlLogpotmeter::ControlLogpotmeter(ConfigKey key, double dMaxValue)
2009 : ControlPotmeter(key, 0, dMaxValue) {
2010 // Override ControlPotmeters default value of 0.5
2011- m_dDefaultValue = 1.0;
2012- set(m_dDefaultValue);
2013-
2014- if (m_dMaxValue == 1.) {
2015- m_bTwoState = false;
2016- m_fB1 = log10(2.)/maxPosition;
2017- } else {
2018- m_bTwoState = true;
2019- m_fB1 = log10(2.)/middlePosition;
2020- m_fB2 = log10(dMaxValue)/(maxPosition-middlePosition);
2021- }
2022-}
2023-
2024-double ControlLogpotmeter::getValueFromWidget(double dValue)
2025-{
2026- double dResult = 0;
2027-
2028- // Calculate the value linearly:
2029- if (!m_bTwoState)
2030- {
2031- dResult = pow(10., (double)(m_fB1*dValue)) - 1;
2032- }
2033- else
2034- {
2035- if (dValue <= middlePosition)
2036- dResult = pow(10., m_fB1*dValue) - 1;
2037- else
2038- dResult = pow(10., m_fB2*(dValue - middlePosition));
2039- }
2040-
2041- //qDebug() << "Midi: " << dValue << " ValueFromWidget : " << m_dValue;
2042- return dResult;
2043-}
2044-
2045-double ControlLogpotmeter::getValueToWidget(double dValue)
2046-{
2047- double pos;
2048-
2049- if (!m_bTwoState)
2050- {
2051- pos = log10(dValue+1)/m_fB1;
2052- }
2053- else
2054- {
2055- if (dValue > 1.) {
2056- pos = log10(dValue) / m_fB2 + middlePosition;
2057- } else {
2058- pos = log10(dValue+1) / m_fB1;
2059- }
2060- }
2061- //qDebug() << "GetValueToWidget : " << pos;
2062- return pos;
2063-}
2064-
2065-double ControlLogpotmeter::GetMidiValue()
2066-{
2067- double midival = 0.;
2068-
2069- midival = getValueToWidget(get());
2070- // midival = 127.*(midival-m_dMinValue)/m_dValueRange
2071- //qDebug() << "GetMidiValue : " << midival;
2072- return midival;
2073-}
2074-
2075-void ControlLogpotmeter::setValueFromMidi(MidiOpCode o, double v) {
2076- Q_UNUSED(o);
2077- set(getValueFromWidget(v));
2078+ setDefaultValue(1.0);
2079+ set(1.0);
2080+
2081+ if (m_pControl) {
2082+ ControlNumericBehavior* pOldBehavior = m_pControl->setBehavior(
2083+ new ControlLogpotmeterBehavior(dMaxValue));
2084+ delete pOldBehavior;
2085+ }
2086 }
2087
2088
2089=== modified file 'mixxx/src/controllogpotmeter.h'
2090--- mixxx/src/controllogpotmeter.h 2012-03-17 17:42:44 +0000
2091+++ mixxx/src/controllogpotmeter.h 2013-05-16 01:44:29 +0000
2092@@ -3,7 +3,7 @@
2093 -------------------
2094 begin : Wed Feb 20 2002
2095 copyright : (C) 2002 by Tue and Ken Haste Andersen
2096- email :
2097+ email :
2098 ***************************************************************************/
2099
2100 /***************************************************************************
2101@@ -26,28 +26,10 @@
2102 *@author Tue and Ken Haste Andersen
2103 */
2104
2105-class ControlLogpotmeter : public ControlPotmeter
2106-{
2107+class ControlLogpotmeter : public ControlPotmeter {
2108 Q_OBJECT
2109-public:
2110+ public:
2111 ControlLogpotmeter(ConfigKey key, double dMaxValue=5.);
2112-
2113- double getValueFromWidget(double dValue);
2114- double getValueToWidget(double dValue);
2115-
2116- double GetMidiValue();
2117-
2118- void setValueFromMidi(MidiOpCode o, double v);
2119-
2120-protected:
2121-
2122- // This is true, if the log potmeter is divided into two states, one from 0 to 1, and
2123- // the second from 1 to m_dMaxValue. Two states is often used with knobs where the first
2124- // half rotation is used to control a value between 0 and 1, and the second half between
2125- // 1 and some bigger value.
2126- bool m_bTwoState;
2127-
2128- double m_fB1, m_fB2;
2129 };
2130
2131 #endif
2132
2133=== removed file 'mixxx/src/controlnull.cpp'
2134--- mixxx/src/controlnull.cpp 2007-09-09 22:52:24 +0000
2135+++ mixxx/src/controlnull.cpp 1970-01-01 00:00:00 +0000
2136@@ -1,27 +0,0 @@
2137-/***************************************************************************
2138- controlnull.cpp - description
2139- -------------------
2140- begin : Sat Jun 15 2002
2141- copyright : (C) 2002 by Tue & Ken Haste Andersen
2142- email : haste@diku.dk
2143-***************************************************************************/
2144-
2145-/***************************************************************************
2146-* *
2147-* This program is free software; you can redistribute it and/or modify *
2148-* it under the terms of the GNU General Public License as published by *
2149-* the Free Software Foundation; either version 2 of the License, or *
2150-* (at your option) any later version. *
2151-* *
2152-***************************************************************************/
2153-
2154-#include "controlnull.h"
2155-
2156-ControlNull::ControlNull() : ControlObject()
2157-{
2158-}
2159-
2160-ControlNull::~ControlNull()
2161-{
2162-}
2163-
2164
2165=== removed file 'mixxx/src/controlnull.h'
2166--- mixxx/src/controlnull.h 2004-10-01 08:18:11 +0000
2167+++ mixxx/src/controlnull.h 1970-01-01 00:00:00 +0000
2168@@ -1,34 +0,0 @@
2169-/***************************************************************************
2170- controlnull.h - description
2171- -------------------
2172- begin : Sat Jun 15 2002
2173- copyright : (C) 2002 by Tue & Ken Haste Andersen
2174- email : haste@diku.dk
2175- ***************************************************************************/
2176-
2177-/***************************************************************************
2178- * *
2179- * This program is free software; you can redistribute it and/or modify *
2180- * it under the terms of the GNU General Public License as published by *
2181- * the Free Software Foundation; either version 2 of the License, or *
2182- * (at your option) any later version. *
2183- * *
2184- ***************************************************************************/
2185-
2186-#ifndef CONTROLNULL_H
2187-#define CONTROLNULL_H
2188-
2189-#include "controlobject.h"
2190-
2191-/**
2192- *@author Tue & Ken Haste Andersen
2193- */
2194-
2195-class ControlNull : public ControlObject {
2196- Q_OBJECT
2197-public:
2198- ControlNull();
2199- ~ControlNull();
2200-};
2201-
2202-#endif
2203
2204=== modified file 'mixxx/src/controlobject.cpp'
2205--- mixxx/src/controlobject.cpp 2013-03-17 16:08:55 +0000
2206+++ mixxx/src/controlobject.cpp 2013-05-16 01:44:29 +0000
2207@@ -22,6 +22,7 @@
2208
2209 #include "controlobject.h"
2210 #include "controlevent.h"
2211+#include "control/control.h"
2212 #include "util/stat.h"
2213 #include "util/timer.h"
2214
2215@@ -31,38 +32,30 @@
2216
2217
2218 ControlObject::ControlObject()
2219- : ControlObjectBase<double>(),
2220- m_dDefaultValue(0),
2221- m_bIgnoreNops(true) {
2222- set(m_dDefaultValue);
2223+ : m_pControl(NULL) {
2224 }
2225
2226-ControlObject::ControlObject(ConfigKey key, bool bIgnoreNops, bool track)
2227- : m_dDefaultValue(0),
2228- m_key(key),
2229- m_bIgnoreNops(bIgnoreNops),
2230- m_bTrack(track),
2231- m_trackKey("control " + m_key.group + "," + m_key.item),
2232- m_trackType(Stat::UNSPECIFIED),
2233- m_trackFlags(Stat::COUNT | Stat::SUM | Stat::AVERAGE |
2234- Stat::SAMPLE_VARIANCE | Stat::MIN | Stat::MAX) {
2235- set(m_dDefaultValue),
2236+ControlObject::ControlObject(ConfigKey key, bool bIgnoreNops, bool bTrack)
2237+ : m_key(key),
2238+ m_pControl(ControlDoublePrivate::getControl(m_key, true, bIgnoreNops, bTrack)) {
2239+ connect(m_pControl, SIGNAL(valueChanged(double, QObject*)),
2240+ this, SLOT(privateValueChanged(double, QObject*)),
2241+ Qt::DirectConnection);
2242+
2243 m_sqCOHashMutex.lock();
2244 m_sqCOHash.insert(m_key, this);
2245 m_sqCOHashMutex.unlock();
2246-
2247- if (m_bTrack) {
2248- // TODO(rryan): Make configurable.
2249- Stat::track(m_trackKey, static_cast<Stat::StatType>(m_trackType),
2250- static_cast<Stat::ComputeFlags>(m_trackFlags), m_dDefaultValue);
2251- }
2252 }
2253
2254-ControlObject::ControlObject(const QString& group, const QString& item, bool bIgnoreNops)
2255- : m_dDefaultValue(0),
2256- m_key(group, item),
2257- m_bIgnoreNops(bIgnoreNops) {
2258- set(m_dDefaultValue);
2259+ControlObject::ControlObject(const QString& group, const QString& item,
2260+ bool bIgnoreNops, bool bTrack)
2261+ : m_key(group, item),
2262+ m_pControl(ControlDoublePrivate::getControl(m_key, true, bIgnoreNops, bTrack)) {
2263+
2264+ connect(m_pControl, SIGNAL(valueChanged(double, QObject*)),
2265+ this, SLOT(privateValueChanged(double, QObject*)),
2266+ Qt::DirectConnection);
2267+
2268 m_sqCOHashMutex.lock();
2269 m_sqCOHash.insert(m_key, this);
2270 m_sqCOHashMutex.unlock();
2271@@ -72,16 +65,15 @@
2272 m_sqCOHashMutex.lock();
2273 m_sqCOHash.remove(m_key);
2274 m_sqCOHashMutex.unlock();
2275+}
2276
2277- ControlObjectThread * obj;
2278- m_qProxyListMutex.lock();
2279- QListIterator<ControlObjectThread*> it(m_qProxyList);
2280- while (it.hasNext())
2281- {
2282- obj = it.next();
2283- obj->slotParentDead();
2284+void ControlObject::privateValueChanged(double dValue, QObject* pSetter) {
2285+ // Only emit valueChanged() if we did not originate this change.
2286+ if (pSetter != this) {
2287+ emit(valueChanged(dValue));
2288+ } else {
2289+ emit(valueChangedFromEngine(dValue));
2290 }
2291- m_qProxyListMutex.unlock();
2292 }
2293
2294 /*
2295@@ -114,19 +106,6 @@
2296 }
2297 */
2298
2299-void ControlObject::addProxy(ControlObjectThread * pControlObjectThread)
2300-{
2301- m_qProxyListMutex.lock();
2302- m_qProxyList.append(pControlObjectThread);
2303- m_qProxyListMutex.unlock();
2304-}
2305-
2306-void ControlObject::removeProxy(ControlObjectThread * pControlObjectThread) {
2307- m_qProxyListMutex.lock();
2308- m_qProxyList.removeAll(pControlObjectThread);
2309- m_qProxyListMutex.unlock();
2310-}
2311-
2312 void ControlObject::getControls(QList<ControlObject*>* pControlList) {
2313 m_sqCOHashMutex.lock();
2314 for (QHash<ConfigKey, ControlObject*>::const_iterator it = m_sqCOHash.begin();
2315@@ -148,68 +127,34 @@
2316 return NULL;
2317 }
2318
2319-void ControlObject::setValueFromMidi(MidiOpCode o, double v)
2320-{
2321- Q_UNUSED(o);
2322- set(v);
2323-}
2324-
2325-double ControlObject::GetMidiValue()
2326-{
2327- return get();
2328-}
2329-
2330-void ControlObject::setValueFromThread(double dValue)
2331-{
2332- set(dValue);
2333-}
2334-
2335-void ControlObject::add(double dValue)
2336-{
2337- if (m_bIgnoreNops && !dValue) {
2338- return;
2339- }
2340- set(get() + dValue);
2341-}
2342-
2343-void ControlObject::sub(double dValue)
2344-{
2345- if (m_bIgnoreNops && !dValue) {
2346- return;
2347- }
2348- set(get() - dValue);
2349-}
2350-
2351-double ControlObject::getValueFromWidget(double v)
2352-{
2353- return v;
2354-}
2355-
2356-double ControlObject::getValueToWidget(double v)
2357-{
2358- return v;
2359-}
2360-
2361-double ControlObject::get() {
2362- return getValue();
2363+void ControlObject::setValueFromMidi(MidiOpCode o, double v) {
2364+ if (m_pControl) {
2365+ m_pControl->setMidiParameter(o, v);
2366+ }
2367+}
2368+
2369+double ControlObject::getValueToMidi() const {
2370+ return m_pControl ? m_pControl->getMidiParameter() : 0.0;
2371+}
2372+
2373+void ControlObject::setValueFromThread(double dValue, QObject* pSender) {
2374+ if (m_pControl) {
2375+ m_pControl->set(dValue, pSender);
2376+ }
2377+}
2378+
2379+double ControlObject::get() const {
2380+ return m_pControl ? m_pControl->get() : 0.0;
2381 }
2382
2383 void ControlObject::reset() {
2384- set(m_dDefaultValue);
2385+ if (m_pControl) {
2386+ m_pControl->reset(this);
2387+ }
2388 }
2389
2390-void ControlObject::set(const double& value, bool emitValueChanged) {
2391- if (m_bIgnoreNops) {
2392- if (get() == value) {
2393- return;
2394- }
2395- }
2396- setValue(value);
2397- if (emitValueChanged) {
2398- emit(valueChanged(value));
2399- if (m_bTrack) {
2400- Stat::track(m_trackKey, static_cast<Stat::StatType>(m_trackType),
2401- static_cast<Stat::ComputeFlags>(m_trackFlags), value);
2402- }
2403+void ControlObject::set(const double& value) {
2404+ if (m_pControl) {
2405+ m_pControl->set(value, this);
2406 }
2407 }
2408
2409=== modified file 'mixxx/src/controlobject.h'
2410--- mixxx/src/controlobject.h 2013-03-17 21:00:23 +0000
2411+++ mixxx/src/controlobject.h 2013-05-16 01:44:29 +0000
2412@@ -23,22 +23,19 @@
2413 #include <QMutex>
2414
2415 #include "configobject.h"
2416-#include "controlobjectthread.h"
2417 #include "controllers/midi/midimessage.h"
2418-#include "controlobjectbase.h"
2419-
2420-class QWidget;
2421-class ConfigKey;
2422-
2423-class ControlObject
2424- : public QObject,
2425- private ControlObjectBase<double> {
2426+#include "control/control.h"
2427+
2428+class ControlObject : public QObject {
2429 Q_OBJECT
2430 public:
2431 ControlObject();
2432- ControlObject(ConfigKey key, bool bIgnoreNops=true, bool track=false);
2433- ControlObject(const QString& group, const QString& item, bool bIgnoreNops=true);
2434+ ControlObject(ConfigKey key,
2435+ bool bIgnoreNops=true, bool bTrack=false);
2436+ ControlObject(const QString& group, const QString& item,
2437+ bool bIgnoreNops=true, bool bTrack=false);
2438 virtual ~ControlObject();
2439+
2440 /** Returns a pointer to the ControlObject matching the given ConfigKey */
2441 static ControlObject* getControl(const ConfigKey& key);
2442 static inline ControlObject* getControl(const QString& group, const QString& item) {
2443@@ -49,61 +46,48 @@
2444 // Adds all ControlObjects that currently exist to pControlList
2445 static void getControls(QList<ControlObject*>* pControlsList);
2446
2447- // Used to add a pointer to the corresponding ControlObjectThread of this ControlObject
2448- void addProxy(ControlObjectThread *pControlObjectThread);
2449- // To get rid of a proxy when the corresponding object is being deleted for example
2450- void removeProxy(ControlObjectThread *pControlObjectThread);
2451 // Return the key of the object
2452- inline ConfigKey getKey() { return m_key; }
2453+ inline ConfigKey getKey() const { return m_key; }
2454 // Returns the value of the ControlObject
2455- double get();
2456+ double get() const;
2457 // Sets the ControlObject value
2458- void set(const double& value, bool emmitValueChanged = true);
2459+ void set(const double& value);
2460 // Sets the default value
2461 void reset();
2462- // Add to value
2463- void add(double dValue);
2464- // Subtract from value
2465- void sub(double dValue);
2466- // Return a ControlObject value, corresponding to the widget input value.
2467- virtual double getValueFromWidget(double dValue);
2468- // Return a widget value corresponding to the ControlObject input value.
2469- virtual double getValueToWidget(double dValue);
2470- // get value (range 0..127)
2471- virtual double GetMidiValue();
2472- virtual void setDefaultValue(double dValue) {
2473- m_dDefaultValue = dValue;
2474+
2475+ inline void setDefaultValue(double dValue) {
2476+ if (m_pControl) {
2477+ m_pControl->setDefaultValue(dValue);
2478+ }
2479 }
2480- virtual double defaultValue() const {
2481- return m_dDefaultValue;
2482+ inline double defaultValue() const {
2483+ return m_pControl ? m_pControl->defaultValue() : 0.0;
2484 }
2485
2486 signals:
2487 void valueChanged(double);
2488+ void valueChangedFromEngine(double);
2489
2490 public:
2491- // Called when a widget has changed value.
2492+ // DEPRECATED: Called to set the control value from the controller
2493+ // subsystem.
2494 virtual void setValueFromMidi(MidiOpCode o, double v);
2495- // Called when another thread has changed value.
2496- virtual void setValueFromThread(double dValue);
2497+ virtual double getValueToMidi() const;
2498+ // DEPRECATED: Called to set the control value from another thread.
2499+ virtual void setValueFromThread(double dValue, QObject* pSetter);
2500
2501 protected:
2502- double m_dDefaultValue;
2503 // Key of the object
2504 ConfigKey m_key;
2505+ ControlDoublePrivate* m_pControl;
2506+
2507+ private slots:
2508+ void privateValueChanged(double value, QObject* pSetter);
2509
2510 private:
2511- // Whether to ignore set/add/sub()'s which would have no effect
2512- bool m_bIgnoreNops;
2513- // Whether to track value changes with the stats framework.
2514- bool m_bTrack;
2515- QString m_trackKey;
2516- int m_trackType;
2517- int m_trackFlags;
2518- // List of associated proxy objects
2519- QList<ControlObjectThread*> m_qProxyList;
2520- // Mutex for the proxy list
2521- QMutex m_qProxyListMutex;
2522+ inline bool ignoreNops() const {
2523+ return m_pControl ? m_pControl->ignoreNops() : true;
2524+ }
2525
2526 // Hash of ControlObject instantiations
2527 static QHash<ConfigKey,ControlObject*> m_sqCOHash;
2528@@ -111,5 +95,4 @@
2529 static QMutex m_sqCOHashMutex;
2530 };
2531
2532-
2533 #endif
2534
2535=== modified file 'mixxx/src/controlobjectthread.cpp'
2536--- mixxx/src/controlobjectthread.cpp 2013-03-14 14:57:52 +0000
2537+++ mixxx/src/controlobjectthread.cpp 2013-05-16 01:44:29 +0000
2538@@ -20,64 +20,63 @@
2539
2540 #include "controlobjectthread.h"
2541 #include "controlobject.h"
2542+#include "control/control.h"
2543
2544 ControlObjectThread::ControlObjectThread(ControlObject* pControlObject, QObject* pParent)
2545 : QObject(pParent),
2546- m_pControlObject(pControlObject) {
2547- // Register with the associated ControlObject
2548- if (m_pControlObject != NULL) {
2549- m_pControlObject->addProxy(this);
2550- connect(m_pControlObject, SIGNAL(destroyed()),
2551- this, SLOT(slotParentDead()));
2552- connect(m_pControlObject, SIGNAL(valueChanged(double)),
2553- this, SLOT(slotParentValueChanged(double)));
2554- }
2555- emitValueChanged();
2556+ m_key(pControlObject ? pControlObject->getKey() : ConfigKey()),
2557+ m_pControl(NULL) {
2558+ if (pControlObject) {
2559+ m_pControl = ControlDoublePrivate::getControl(pControlObject->getKey(), false);
2560+ }
2561+ if (m_pControl) {
2562+ connect(m_pControl, SIGNAL(valueChanged(double, QObject*)),
2563+ this, SLOT(slotValueChanged(double, QObject*)),
2564+ Qt::DirectConnection);
2565+ }
2566 }
2567
2568 ControlObjectThread::~ControlObjectThread() {
2569- if (m_pControlObject) {
2570- // Our parent is still around, make sure it doesn't send us any more events
2571- m_pControlObject->removeProxy(this);
2572- }
2573+}
2574+
2575+bool ControlObjectThread::valid() const {
2576+ return m_pControl != NULL;
2577 }
2578
2579 double ControlObjectThread::get() {
2580- if (m_pControlObject) {
2581- return m_pControlObject->get();
2582- } else {
2583- return 0.0;
2584- }
2585-
2586+ return m_pControl ? m_pControl->get() : 0.0;
2587 }
2588
2589 void ControlObjectThread::slotSet(double v) {
2590- m_pControlObject->set(v);
2591+ set(v);
2592+}
2593+
2594+void ControlObjectThread::set(double v) {
2595+ if (m_pControl) {
2596+ m_pControl->set(v, this);
2597+ }
2598+}
2599+
2600+void ControlObjectThread::reset() {
2601+ if (m_pControl) {
2602+ // NOTE(rryan): This is important. The originator of this action does
2603+ // not know the resulting value so it makes sense that we should emit a
2604+ // general valueChanged() signal even though the change originated from
2605+ // us. For this reason, we provide NULL here so that the change is
2606+ // broadcast as valueChanged() and not valueChangedByThis().
2607+ m_pControl->reset(NULL);
2608+ }
2609 }
2610
2611 void ControlObjectThread::emitValueChanged() {
2612 emit(valueChanged(get()));
2613 }
2614
2615-void ControlObjectThread::add(double v) {
2616- m_pControlObject->add(v);
2617-}
2618-
2619-void ControlObjectThread::sub(double v) {
2620- m_pControlObject->sub(v);
2621-}
2622-
2623-void ControlObjectThread::slotParentDead() {
2624- // Now we've got a chance of avoiding segfaults with judicious
2625- // use of if(m_pControlObject)
2626- m_pControlObject = NULL;
2627-}
2628-
2629-void ControlObjectThread::slotParentValueChanged(double v) {
2630- // This is base implementation of this function without scaling
2631- emit(valueChanged(v));
2632-}
2633-
2634-ControlObject* ControlObjectThread::getControlObject() {
2635- return m_pControlObject;
2636+void ControlObjectThread::slotValueChanged(double v, QObject* pSetter) {
2637+ if (pSetter != this) {
2638+ // This is base implementation of this function without scaling
2639+ emit(valueChanged(v));
2640+ } else {
2641+ emit(valueChangedByThis(v));
2642+ }
2643 }
2644
2645=== modified file 'mixxx/src/controlobjectthread.h'
2646--- mixxx/src/controlobjectthread.h 2013-03-14 14:57:52 +0000
2647+++ mixxx/src/controlobjectthread.h 2013-05-16 01:44:29 +0000
2648@@ -24,6 +24,9 @@
2649 #include <qwaitcondition.h>
2650 #include <QQueue>
2651
2652+#include "configobject.h"
2653+
2654+class ControlDoublePrivate;
2655 class ControlObject;
2656
2657 class ControlObjectThread : public QObject {
2658@@ -32,40 +35,41 @@
2659 ControlObjectThread(ControlObject *pControlObject, QObject* pParent=NULL);
2660 virtual ~ControlObjectThread();
2661
2662- /** Returns the value of the object. Thread safe, blocking */
2663- virtual double get();
2664- /** Setting the value from an external controller. This happen when a ControlObject has
2665- * changed and its value is syncronized with this object. Thread safe, non blocking. Returns
2666- * true if successful, otherwise false. Thread safe, non blocking. */
2667- virtual void add(double v);
2668- /** Subtracts a value to the value property. Notification in a similar way
2669- * to set. Thread safe, blocking. */
2670- virtual void sub(double v);
2671 /** Called from update(); */
2672 void emitValueChanged();
2673
2674-
2675- // FIXME: Dangerous GED hack
2676- ControlObject* getControlObject();
2677-
2678-public slots:
2679- /** The value is changed by the engine, and the corresponding ControlObject is updated.
2680- * Thread safe, blocking. */
2681+ inline ConfigKey getKey() const {
2682+ return m_key;
2683+ }
2684+
2685+ // Returns the value of the object. Thread safe, non-blocking.
2686+ virtual double get();
2687+
2688+ bool valid() const;
2689+
2690+ public slots:
2691+ // Set the control to a new value. Non-blocking.
2692 virtual void slotSet(double v);
2693-
2694- // The danger signal! This is for safety in wierd shutdown scenarios where the
2695- // ControlObject dies to avoid segfaults.
2696- void slotParentDead();
2697-
2698- // Receives the Value from the parent and may scales the vale and re-emit it again
2699- virtual void slotParentValueChanged(double v);
2700-
2701-signals:
2702+ // Sets the control value to v. Thread safe, non-blocking.
2703+ virtual void set(double v);
2704+ // Resets the control to its default value. Thread safe, non-blocking.
2705+ virtual void reset();
2706+
2707+ signals:
2708 void valueChanged(double);
2709-
2710-protected:
2711- /// Pointer to corresponding ControlObject
2712- ControlObject *m_pControlObject;
2713+ // This means that the control value has changed as a result of a mutation
2714+ // (set/add/sub/reset) originating from this object.
2715+ void valueChangedByThis(double);
2716+
2717+ protected slots:
2718+ // Receives the value from the master control and re-emits either
2719+ // valueChanged(double) or valueChangedByThis(double) based on pSetter.
2720+ virtual void slotValueChanged(double v, QObject* pSetter);
2721+
2722+ protected:
2723+ ConfigKey m_key;
2724+ // Pointer to connected control.
2725+ ControlDoublePrivate* m_pControl;
2726 };
2727
2728 #endif
2729
2730=== modified file 'mixxx/src/controlobjectthreadmain.cpp'
2731--- mixxx/src/controlobjectthreadmain.cpp 2013-03-14 00:13:02 +0000
2732+++ mixxx/src/controlobjectthreadmain.cpp 2013-05-16 01:44:29 +0000
2733@@ -13,6 +13,37 @@
2734 ControlObjectThreadMain::ControlObjectThreadMain(ControlObject * pControlObject, QObject* pParent)
2735 : ControlObjectThread(pControlObject, pParent) {
2736 setObjectName("ControlObjectThreadMain");
2737-}
2738-
2739-
2740+ installEventFilter(this);
2741+}
2742+
2743+bool ControlObjectThreadMain::eventFilter(QObject* o, QEvent* e) {
2744+ // Handle events
2745+ if (e && e->type() == MIXXXEVENT_CONTROL) {
2746+ ControlEvent * ce = (ControlEvent *)e;
2747+ emit(valueChanged(ce->value()));
2748+ } else {
2749+ return QObject::eventFilter(o,e);
2750+ }
2751+ return true;
2752+}
2753+
2754+void ControlObjectThreadMain::slotValueChanged(double, QObject* pSetter) {
2755+ // The value argument to this function is in value space, but for some of
2756+ // our subclasses (e.g. ControlObjectThreadWidget) emit valueChanged(double)
2757+ // should emit in parameter space. So we emit the value of get() instead
2758+ // which will get the correct value.
2759+
2760+ // If we are already running in the main thread, then go ahead and update.
2761+ if (QThread::currentThread() == QApplication::instance()->thread()) {
2762+ if (pSetter != this) {
2763+ emit(valueChanged(get()));
2764+ } else {
2765+ emit(valueChangedByThis(get()));
2766+ }
2767+ } else {
2768+ // Otherwise, we have to post the event to the main thread event queue
2769+ // and then catch the event via eventFilter.
2770+ QApplication::postEvent(this, new ControlEvent(get()));
2771+ }
2772+
2773+}
2774
2775=== modified file 'mixxx/src/controlobjectthreadmain.h'
2776--- mixxx/src/controlobjectthreadmain.h 2013-03-14 00:13:02 +0000
2777+++ mixxx/src/controlobjectthreadmain.h 2013-05-16 01:44:29 +0000
2778@@ -12,7 +12,7 @@
2779 // ControlObjectThreadMain is a variant of ControlObjectThread that should only
2780 // ever have its methods called by the main thread. The benefit is that the
2781 // valueChanged() signal is proxied to the main thread automatically and the
2782-// get()/set()/add()/sub() methods are lock-free and performant relative to
2783+// get()/set() methods are lock-free and performant relative to
2784 // ControlObjectThread since COT requires using a mutex to maintain the
2785 // integrity of the control value. If you create a COTM, you must make sure to
2786 // only call its methods from the main thread.
2787@@ -20,6 +20,14 @@
2788 Q_OBJECT
2789 public:
2790 ControlObjectThreadMain(ControlObject *pControlObject, QObject* pParent=NULL);
2791+
2792+ bool eventFilter(QObject* o, QEvent* e);
2793+
2794+ protected slots:
2795+ // Receives the value from the master control, proxies it to the main
2796+ // thread, and re-emits either valueChanged(double) or
2797+ // valueChangedByThis(double) based on pSetter.
2798+ virtual void slotValueChanged(double v, QObject* pSetter);
2799 };
2800
2801 #endif
2802
2803=== modified file 'mixxx/src/controlobjectthreadwidget.cpp'
2804--- mixxx/src/controlobjectthreadwidget.cpp 2013-03-14 18:33:05 +0000
2805+++ mixxx/src/controlobjectthreadwidget.cpp 2013-05-16 01:44:29 +0000
2806@@ -6,12 +6,6 @@
2807
2808 ControlObjectThreadWidget::ControlObjectThreadWidget(ControlObject * pControlObject, QObject* pParent)
2809 : ControlObjectThreadMain(pControlObject, pParent) {
2810- // ControlObjectThread's constructor sets m_dValue to
2811- // m_pControlObject->get(). Since we represent the widget's value, we need
2812- // to reset m_dValue to be the result of getValueToWidget.
2813- if (m_pControlObject != NULL) {
2814- slotParentValueChanged(get());
2815- }
2816 }
2817
2818 ControlObjectThreadWidget::~ControlObjectThreadWidget() {
2819@@ -22,7 +16,7 @@
2820 EmitOption emitOption, Qt::MouseButton state) {
2821 if (connectValueFromWidget) {
2822 connect(widget, SIGNAL(valueReset()),
2823- this, SLOT(slotReset()));
2824+ this, SLOT(reset()));
2825
2826 if (emitOption & EMIT_ON_PRESS) {
2827 switch (state) {
2828@@ -77,37 +71,12 @@
2829 emit(valueChanged(get()));
2830 }
2831
2832-void ControlObjectThreadWidget::slotReset() {
2833- if (m_pControlObject) {
2834- m_pControlObject->reset();
2835-
2836- }
2837-}
2838-
2839 double ControlObjectThreadWidget::get() {
2840- if (m_pControlObject) {
2841- return m_pControlObject->getValueToWidget(m_pControlObject->get());
2842- } else {
2843- return 0.0;
2844- }
2845-}
2846-
2847-void ControlObjectThreadWidget::slotSet(double v) {
2848- m_pControlObject->set(m_pControlObject->getValueFromWidget(v));
2849-}
2850-
2851-void ControlObjectThreadWidget::add(double v) {
2852- m_pControlObject->add(m_pControlObject->getValueFromWidget(v));
2853-}
2854-
2855-void ControlObjectThreadWidget::sub(double v) {
2856- m_pControlObject->sub(m_pControlObject->getValueFromWidget(v));
2857-}
2858-
2859-// Receives the Value from the parent and may scales the vale and re-emit it again
2860-void ControlObjectThreadWidget::slotParentValueChanged(double v) {
2861- if (m_pControlObject) {
2862- double widgetValue = m_pControlObject->getValueToWidget(v);
2863- emit(valueChanged(widgetValue));
2864+ return m_pControl ? m_pControl->getWidgetParameter() : 0.0;
2865+}
2866+
2867+void ControlObjectThreadWidget::set(double v) {
2868+ if (m_pControl) {
2869+ m_pControl->setWidgetParameter(v, this);
2870 }
2871 }
2872
2873=== modified file 'mixxx/src/controlobjectthreadwidget.h'
2874--- mixxx/src/controlobjectthreadwidget.h 2013-03-14 14:57:52 +0000
2875+++ mixxx/src/controlobjectthreadwidget.h 2013-05-16 01:44:29 +0000
2876@@ -22,10 +22,9 @@
2877 @author Tue Haste Andersen
2878 */
2879
2880-class ControlObjectThreadWidget : public ControlObjectThreadMain
2881-{
2882+class ControlObjectThreadWidget : public ControlObjectThreadMain {
2883 Q_OBJECT
2884-public:
2885+ public:
2886
2887 enum EmitOption {
2888 EMIT_NEVER = 0x00,
2889@@ -45,15 +44,8 @@
2890
2891 virtual double get();
2892
2893- virtual void add(double v);
2894-
2895- virtual void sub(double v);
2896-
2897- private slots:
2898- void slotReset();
2899- // Receives the Value from the parent and may scales the vale and re-emit it again
2900- virtual void slotSet(double v);
2901- virtual void slotParentValueChanged(double v);
2902+ public slots:
2903+ virtual void set(double v);
2904 };
2905
2906 #endif
2907
2908=== modified file 'mixxx/src/controlpotmeter.cpp'
2909--- mixxx/src/controlpotmeter.cpp 2013-03-17 16:08:55 +0000
2910+++ mixxx/src/controlpotmeter.cpp 2013-05-16 01:44:29 +0000
2911@@ -100,13 +100,11 @@
2912 {
2913 }
2914
2915-double ControlPotmeter::getMin()
2916-{
2917+double ControlPotmeter::getMin() const {
2918 return m_dMinValue;
2919 }
2920
2921-double ControlPotmeter::getMax()
2922-{
2923+double ControlPotmeter::getMax() const {
2924 return m_dMaxValue;
2925 }
2926
2927@@ -125,47 +123,19 @@
2928 m_dMinValue = dMinValue;
2929 m_dMaxValue = dMaxValue;
2930 m_dValueRange = m_dMaxValue - m_dMinValue;
2931- m_dDefaultValue = m_dMinValue + 0.5 * m_dValueRange;
2932- set(m_dDefaultValue);
2933+ double default_value = m_dMinValue + 0.5 * m_dValueRange;
2934+
2935+ if (m_pControl) {
2936+ ControlNumericBehavior* pOldBehavior = m_pControl->setBehavior(
2937+ new ControlPotmeterBehavior(dMinValue, dMaxValue));
2938+ delete pOldBehavior;
2939+ }
2940+
2941+ setDefaultValue(default_value);
2942+ set(default_value);
2943 //qDebug() << "" << this << ", min " << m_dMinValue << ", max " << m_dMaxValue << ", range " << m_dValueRange << ", val " << m_dValue;
2944 }
2945
2946-double ControlPotmeter::getValueToWidget(double dValue)
2947-{
2948- double out = (dValue-m_dMinValue)/m_dValueRange;
2949- return (out < 0.5) ? out*128. : out*126. + 1.;
2950-}
2951-
2952-double ControlPotmeter::GetMidiValue()
2953-{
2954- double out = (get()-m_dMinValue)/m_dValueRange;
2955- return (out < 0.5) ? out*128. : out*126. + 1.;
2956-}
2957-
2958-double ControlPotmeter::getValueFromWidget(double dValue)
2959-{
2960- double out = (dValue < 64) ? dValue / 128. : (dValue-1) / 126.;
2961- return m_dMinValue + out * m_dValueRange;
2962-}
2963-
2964-void ControlPotmeter::setValueFromThread(double dValue)
2965-{
2966- if (dValue > m_dMaxValue) {
2967- set(m_dMaxValue);
2968- } else if (dValue < m_dMinValue) {
2969- set(m_dMinValue);
2970- } else {
2971- set(dValue);
2972- }
2973-}
2974-
2975-void ControlPotmeter::setValueFromMidi(MidiOpCode o, double v)
2976-{
2977- Q_UNUSED(o);
2978- double out = (v < 64) ? v / 128. : (v-1) / 126.;
2979- set(m_dMinValue + out * m_dValueRange);
2980-}
2981-
2982 void ControlPotmeter::incValue(double keypos)
2983 {
2984 if (keypos>0)
2985@@ -245,7 +215,7 @@
2986
2987 void ControlPotmeter::setToDefault(double v) {
2988 if (v > 0) {
2989- set(m_dDefaultValue);
2990+ reset();
2991 }
2992 }
2993
2994
2995=== modified file 'mixxx/src/controlpotmeter.h'
2996--- mixxx/src/controlpotmeter.h 2013-03-17 16:08:55 +0000
2997+++ mixxx/src/controlpotmeter.h 2013-05-16 01:44:29 +0000
2998@@ -35,22 +35,15 @@
2999 ControlPotmeter(ConfigKey key, double dMinValue=0.0, double dMaxValue=1.0);
3000 ~ControlPotmeter();
3001 /** Returns the minimum allowed value */
3002- double getMin();
3003+ double getMin() const;
3004 /** Returns the maximum allowed value */
3005- double getMax();
3006+ double getMax() const;
3007 /** Sets the step size of the associated PushButtons */
3008 void setStep(double);
3009 /** Sets the small step size of the associated PushButtons */
3010 void setSmallStep(double);
3011- /** Sets the minimum and maximum allowed value. The control value is reset when calling
3012- * this method */
3013- void setRange(double dMinValue, double dMaxValue);
3014- double getValueFromWidget(double dValue);
3015- double getValueToWidget(double dValue);
3016- double GetMidiValue();
3017
3018 public slots:
3019- void setValueFromThread(double dValue);
3020 /** Increases the value. This method is called from an associated PushButton control */
3021 void incValue(double);
3022 /** Decreases the value. This method is called from an associated PushButton control */
3023@@ -73,7 +66,9 @@
3024 void toggleMinusValue(double);
3025
3026 protected:
3027- void setValueFromMidi(MidiOpCode o, double v);
3028+ /** Sets the minimum and maximum allowed value. The control value is reset when calling
3029+ * this method */
3030+ void setRange(double dMinValue, double dMaxValue);
3031
3032 double m_dMaxValue;
3033 double m_dMinValue;
3034
3035=== modified file 'mixxx/src/controlpushbutton.cpp'
3036--- mixxx/src/controlpushbutton.cpp 2013-03-13 16:31:06 +0000
3037+++ mixxx/src/controlpushbutton.cpp 2013-05-16 01:44:29 +0000
3038@@ -17,9 +17,6 @@
3039
3040 #include "controlpushbutton.h"
3041
3042-// static
3043-const int ControlPushButton::kPowerWindowTimeMillis = 300;
3044-
3045 /* -------- ------------------------------------------------------
3046 Purpose: Creates a new simulated latching push-button.
3047 Input: key - Key for the configuration file
3048@@ -28,6 +25,13 @@
3049 ControlObject(key, false),
3050 m_buttonMode(PUSH),
3051 m_iNoStates(2) {
3052+ if (m_pControl) {
3053+ ControlNumericBehavior* pOldBehavior = m_pControl->setBehavior(
3054+ new ControlPushButtonBehavior(
3055+ static_cast<ControlPushButtonBehavior::ButtonMode>(m_buttonMode),
3056+ m_iNoStates));
3057+ delete pOldBehavior;
3058+ }
3059 }
3060
3061 ControlPushButton::~ControlPushButton() {
3062@@ -37,62 +41,25 @@
3063 void ControlPushButton::setButtonMode(enum ButtonMode mode) {
3064 //qDebug() << "Setting " << m_Key.group << m_Key.item << "as toggle";
3065 m_buttonMode = mode;
3066+
3067+ if (m_pControl) {
3068+ ControlNumericBehavior* pOldBehavior = m_pControl->setBehavior(
3069+ new ControlPushButtonBehavior(
3070+ static_cast<ControlPushButtonBehavior::ButtonMode>(m_buttonMode),
3071+ m_iNoStates));
3072+ delete pOldBehavior;
3073+ }
3074 }
3075
3076 void ControlPushButton::setStates(int num_states) {
3077 m_iNoStates = num_states;
3078-}
3079-
3080-void ControlPushButton::setValueFromMidi(MidiOpCode o, double v) {
3081- // keyboard events are handled by this function as well
3082- //if (m_bMidiSimulateLatching)
3083-
3084- //qDebug() << "bMidiSimulateLatching is true!";
3085- // Only react on NOTE_ON midi events if simulating latching...
3086-
3087- //qDebug() << o << v;
3088-
3089- // This block makes push-buttons act as power window buttons.
3090- if (m_buttonMode == POWERWINDOW && m_iNoStates == 2) {
3091- if (o == MIDI_NOTE_ON) {
3092- if (v > 0.) {
3093- double value = get();
3094- set(!value);
3095- m_pushTimer.setSingleShot(true);
3096- m_pushTimer.start(kPowerWindowTimeMillis);
3097- }
3098- } else if (o == MIDI_NOTE_OFF) {
3099- if (!m_pushTimer.isActive()) {
3100- set(0.0);
3101- }
3102- }
3103- } else if (m_buttonMode == TOGGLE) {
3104- // This block makes push-buttons act as toggle buttons.
3105- if (m_iNoStates > 2) { //multistate button
3106- if (v > 0.) { //looking for NOTE_ON doesn't seem to work...
3107- double value = get();
3108- value++;
3109- if (value >= m_iNoStates) {
3110- set(0);
3111- } else {
3112- set(value);
3113- }
3114- }
3115- } else {
3116- if (o == MIDI_NOTE_ON) {
3117- if (v > 0.) {
3118- double value = get();
3119- set(!value);
3120- }
3121- }
3122- }
3123- } else { //Not a toggle button (trigger only when button pushed)
3124- if (o == MIDI_NOTE_ON) {
3125- double value = get();
3126- set(!value);
3127- } else if (o == MIDI_NOTE_OFF) {
3128- set(0.0);
3129- }
3130+
3131+ if (m_pControl) {
3132+ ControlNumericBehavior* pOldBehavior = m_pControl->setBehavior(
3133+ new ControlPushButtonBehavior(
3134+ static_cast<ControlPushButtonBehavior::ButtonMode>(m_buttonMode),
3135+ m_iNoStates));
3136+ delete pOldBehavior;
3137 }
3138 }
3139
3140
3141=== modified file 'mixxx/src/controlpushbutton.h'
3142--- mixxx/src/controlpushbutton.h 2012-05-01 05:59:37 +0000
3143+++ mixxx/src/controlpushbutton.h 2013-05-16 01:44:29 +0000
3144@@ -21,7 +21,6 @@
3145 #include "controlobject.h"
3146 #include "controllers/midi/midimessage.h"
3147 #include "defs.h"
3148-#include <QTimer>
3149
3150 /**
3151 *@author Tue and Ken Haste Andersen
3152@@ -31,11 +30,10 @@
3153 Q_OBJECT
3154 public:
3155 enum ButtonMode {
3156- PUSH,
3157+ PUSH = 0,
3158 TOGGLE,
3159 POWERWINDOW
3160 };
3161- static const int kPowerWindowTimeMillis;
3162
3163 ControlPushButton(ConfigKey key);
3164 virtual ~ControlPushButton();
3165@@ -46,13 +44,9 @@
3166 void setButtonMode(enum ButtonMode mode);
3167 void setStates(int num_states);
3168
3169- protected:
3170- void setValueFromMidi(MidiOpCode o, double v);
3171-
3172 private:
3173 enum ButtonMode m_buttonMode;
3174 int m_iNoStates;
3175- QTimer m_pushTimer;
3176 };
3177
3178 #endif
3179
3180=== modified file 'mixxx/src/controlttrotary.cpp'
3181--- mixxx/src/controlttrotary.cpp 2013-03-13 16:31:06 +0000
3182+++ mixxx/src/controlttrotary.cpp 2013-05-16 01:44:29 +0000
3183@@ -20,30 +20,13 @@
3184 Purpose: Creates a new rotary encoder
3185 Input: key
3186 -------- ------------------------------------------------------ */
3187-ControlTTRotary::ControlTTRotary(ConfigKey key) : ControlObject(key)
3188-{
3189-}
3190-
3191-double ControlTTRotary::getValueFromWidget(double dValue)
3192-{
3193- // Non-linear scaling
3194- double temp = (((dValue-64.)*(dValue-64.))/64.);
3195- if ((dValue-64.)<0)
3196- temp = -temp;
3197-
3198- //qDebug() << "tt rotary in " << dValue << ", out " << temp;
3199-
3200- return temp; //dValue-64.;
3201-}
3202-
3203-double ControlTTRotary::getValueToWidget(double dValue)
3204-{
3205- return dValue*200.+64.;
3206-}
3207-
3208-void ControlTTRotary::setValueFromMidi(MidiOpCode o, double v)
3209-{
3210- Q_UNUSED(o);
3211- set(v);
3212-}
3213+ControlTTRotary::ControlTTRotary(ConfigKey key) : ControlObject(key) {
3214+ if (m_pControl) {
3215+ ControlNumericBehavior* pOldBehavior = m_pControl->setBehavior(
3216+ new ControlTTRotaryBehavior());
3217+ delete pOldBehavior;
3218+ }
3219+}
3220+
3221+
3222
3223
3224=== modified file 'mixxx/src/controlttrotary.h'
3225--- mixxx/src/controlttrotary.h 2012-03-17 17:42:44 +0000
3226+++ mixxx/src/controlttrotary.h 2013-05-16 01:44:29 +0000
3227@@ -20,20 +20,10 @@
3228 #include "configobject.h"
3229 #include "controlobject.h"
3230
3231-/** Turn Table rotary controller class. The turntable rotary sends midi events: 0 when turning
3232- * backwards, and 1 when turning forward. This class keeps track of it's speed, using a timer
3233- * interrupt */
3234-class ControlTTRotary : public ControlObject
3235-{
3236+class ControlTTRotary : public ControlObject {
3237 Q_OBJECT
3238-public:
3239+ public:
3240 ControlTTRotary(ConfigKey key);
3241-
3242- double getValueFromWidget(double dValue);
3243- double getValueToWidget(double dValue);
3244-
3245-protected:
3246- void setValueFromMidi(MidiOpCode o, double v);
3247 };
3248
3249 #endif
3250
3251=== modified file 'mixxx/src/dlgabout.cpp'
3252--- mixxx/src/dlgabout.cpp 2011-12-22 18:55:10 +0000
3253+++ mixxx/src/dlgabout.cpp 2013-05-16 01:44:29 +0000
3254@@ -17,15 +17,202 @@
3255
3256 #include "dlgabout.h"
3257
3258-#include <qlineedit.h>
3259-#include <qwidget.h>
3260-#include <qslider.h>
3261-#include <qlabel.h>
3262-#include <qstring.h>
3263-#include <qpushbutton.h>
3264+#include "defs_version.h"
3265
3266 DlgAbout::DlgAbout(QWidget* parent) : QDialog(parent), Ui::DlgAboutDlg() {
3267 setupUi(this);
3268+
3269+ QString buildBranch, buildRevision;
3270+#ifdef BUILD_BRANCH
3271+ buildBranch = BUILD_BRANCH;
3272+#endif
3273+#ifdef BUILD_REV
3274+ buildRevision = BUILD_REV;
3275+#endif
3276+
3277+ QStringList version;
3278+ version.append(VERSION);
3279+ if (!buildBranch.isEmpty() || !buildRevision.isEmpty()) {
3280+ QStringList buildInfo;
3281+ buildInfo.append("build");
3282+ if (!buildBranch.isEmpty()) {
3283+ buildInfo.append(buildBranch);
3284+ }
3285+ if (!buildRevision.isEmpty()) {
3286+ buildInfo.append(QString("r%1").arg(buildRevision));
3287+ }
3288+ version.append(QString("(%1)").arg(buildInfo.join(" ")));
3289+ }
3290+ version_label->setText(version.join(" "));
3291+
3292+ QString s_devTeam = QString(tr("Mixxx %1 Development Team")).arg(VERSION);
3293+ QString s_contributions = tr("With contributions from:");
3294+ QString s_specialThanks = tr("And special thanks to:");
3295+ QString s_pastDevs = tr("Past Developers");
3296+ QString s_pastContribs = tr("Past Contributors");
3297+
3298+ QString credits = QString("<p align=\"center\"><b>%1</b></p>"
3299+"<p align=\"center\">"
3300+"Albert Santoni<br>"
3301+"RJ Ryan<br>"
3302+"Sean Pappalardo<br>"
3303+"Phillip Whelan<br>"
3304+"Tobias Rafreider<br>"
3305+"S. Brandt<br>"
3306+"Bill Good<br>"
3307+"Owen Williams<br>"
3308+"Vittorio Colao<br>"
3309+"Daniel Sch&uuml;rmann<br>"
3310+"Thomas Vincent<br>"
3311+"Ilkka Tuohela<br>"
3312+"Max Linke<br>"
3313+
3314+"</p>"
3315+"<p align=\"center\"><b>%2</b></p>"
3316+"<p align=\"center\">"
3317+"Mark Hills<br>"
3318+"Andre Roth<br>"
3319+"Robin Sheat<br>"
3320+"Mark Glines<br>"
3321+"Mathieu Rene<br>"
3322+"Miko Kiiski<br>"
3323+"Brian Jackson<br>"
3324+"Andreas Pflug<br>"
3325+"Bas van Schaik<br>"
3326+"J&aacute;n Jockusch<br>"
3327+"Oliver St&ouml;neberg<br>"
3328+"Jan Jockusch<br>"
3329+"C. Stewart<br>"
3330+"Bill Egert<br>"
3331+"Zach Shutters<br>"
3332+"Owen Bullock<br>"
3333+"Graeme Mathieson<br>"
3334+"Sebastian Actist<br>"
3335+"Jussi Sainio<br>"
3336+"David Gnedt<br>"
3337+"Antonio Passamani<br>"
3338+"Guy Martin<br>"
3339+"Anders Gunnarsson<br>"
3340+"Alex Barker<br>"
3341+"Mikko Jania<br>"
3342+"Juan Pedro Bol&iacute;var Puente<br>"
3343+"Linus Amvall<br>"
3344+"Irwin C&eacute;spedes B<br>"
3345+"Micz Flor<br>"
3346+"Daniel James<br>"
3347+"Mika Haulo<br>"
3348+"Matthew Mikolay<br>"
3349+"Tom Mast<br>"
3350+"Miko Kiiski<br>"
3351+"Vin&iacute;cius Dias dos Santos<br>"
3352+"Joe Colosimo<br>"
3353+"Shashank Kumar<br>"
3354+"Till Hofmann<br>"
3355+"Peter V&aacute;gner<br>"
3356+"Thanasis Liappis<br>"
3357+"Jens Nachtigall<br>"
3358+"Scott Ullrich<br>"
3359+"Jonas &Aring;dahl<br>"
3360+"Jonathan Costers<br>"
3361+"Daniel Lindenfelser<br>"
3362+"Maxime Bochon<br>"
3363+"Akash Shetye<br>"
3364+"Pascal Bleser<br>"
3365+"Florian Mahlknecht<br>"
3366+"Ben Clark<br>"
3367+"Tom Gascoigne<br>"
3368+"Neale Pickett<br>"
3369+"Aaron Mavrinac<br>"
3370+"Markus H&auml;rer<br>"
3371+"Andrey Smelov<br>"
3372+"Scott Stewart<br>"
3373+"Nimatek<br>"
3374+"Alban Bedel<br>"
3375+"Stefan N&uuml;rnberger<br>"
3376+"Steven Boswell<br>"
3377+"Jo&atilde;o Reys Santos<br>"
3378+"Carl Pillot<br>"
3379+"Vedant Agarwala<br>"
3380+
3381+"</p>"
3382+"<p align=\"center\"><b>%3</b></p>"
3383+"<p align=\"center\">"
3384+"Vestax<br>"
3385+"Stanton<br>"
3386+"Hercules<br>"
3387+"EKS<br>"
3388+"Echo Digital Audio<br>"
3389+"JP Disco<br>"
3390+"Google Summer of Code<br>"
3391+"Adam Bellinson<br>"
3392+"Alexandre Bancel<br>"
3393+"Melanie Thielker<br>"
3394+"Julien Rosener<br>"
3395+"Pau Arum&iacute;<br>"
3396+"David Garcia<br>"
3397+"Seb Ruiz<br>"
3398+"Joseph Mattiello<br>"
3399+"</p>"
3400+
3401+"<p align=\"center\"><b>%4</b></p>"
3402+"<p align=\"center\">"
3403+"Tue Haste Andersen<br>"
3404+"Ken Haste Andersen<br>"
3405+"Cedric Gestes<br>"
3406+"John Sully<br>"
3407+"Torben Hohn<br>"
3408+"Peter Chang<br>"
3409+"Micah Lee<br>"
3410+"Ben Wheeler<br>"
3411+"Wesley Stessens<br>"
3412+"Nathan Prado<br>"
3413+"Zach Elko<br>"
3414+"Tom Care<br>"
3415+"Pawel Bartkiewicz<br>"
3416+"Nick Guenther<br>"
3417+"Adam Davison<br>"
3418+"Garth Dahlstrom<br>"
3419+"</p>"
3420+
3421+"<p align=\"center\"><b>%5</b></p>"
3422+"<p align=\"center\">"
3423+"Ludek Hor&#225;cek<br>"
3424+"Svein Magne Bang<br>"
3425+"Kristoffer Jensen<br>"
3426+"Ingo Kossyk<br>"
3427+"Mads Holm<br>"
3428+"Lukas Zapletal<br>"
3429+"Jeremie Zimmermann<br>"
3430+"Gianluca Romanin<br>"
3431+"Tim Jackson<br>"
3432+"Stefan Langhammer<br>"
3433+"Frank Willascheck<br>"
3434+"Jeff Nelson<br>"
3435+"Kevin Schaper<br>"
3436+"Alex Markley<br>"
3437+"Oriol Puigb&oacute;<br>"
3438+"Ulrich Heske<br>"
3439+"James Hagerman<br>"
3440+"quil0m80<br>"
3441+"Martin Sakm&#225;r<br>"
3442+"Ilian Persson<br>"
3443+"Dave Jarvis<br>"
3444+"Thomas Baag<br>"
3445+"Karlis Kalnins<br>"
3446+"Amias Channer<br>"
3447+"Sacha Berger<br>"
3448+"James Evans<br>"
3449+"Martin Sakmar<br>"
3450+"Navaho Gunleg<br>"
3451+"Gavin Pryke<br>"
3452+"Michael Pujos<br>"
3453+"Claudio Bantaloukas<br>"
3454+"Pavol Rusnak<br>"
3455+"Bruno Buccolo<br>"
3456+"Ryan Baker<br>"
3457+ "</p>").arg(s_devTeam,s_contributions,s_specialThanks,s_pastDevs,s_pastContribs);
3458+
3459+ textBrowser->setHtml(credits);
3460 }
3461
3462 DlgAbout::~DlgAbout() {
3463
3464=== removed file 'mixxx/src/dlgbpmscheme.cpp'
3465--- mixxx/src/dlgbpmscheme.cpp 2010-01-14 23:32:38 +0000
3466+++ mixxx/src/dlgbpmscheme.cpp 1970-01-01 00:00:00 +0000
3467@@ -1,58 +0,0 @@
3468-/***************************************************************************
3469- dlgbpmscheme.cpp - description
3470- -------------------
3471- begin : Thu Jun 7 2007
3472- copyright : (C) 2007 by John Sully
3473- email : jsully@scs.ryerson.ca
3474-***************************************************************************/
3475-
3476-/***************************************************************************
3477-* *
3478-* This program is free software; you can redistribute it and/or modify *
3479-* it under the terms of the GNU General Public License as published by *
3480-* the Free Software Foundation; either version 2 of the License, or *
3481-* (at your option) any later version. *
3482-* *
3483-***************************************************************************/
3484-
3485-#include <QtCore>
3486-
3487-#include "dlgbpmscheme.h"
3488-#include "bpm/bpmscheme.h"
3489-
3490-DlgBpmScheme::DlgBpmScheme(BpmScheme *& bpmScheme) : QDialog(), Ui::DlgBpmSchemeDlg(), m_BpmScheme(bpmScheme)
3491-{
3492- setupUi(this);
3493-
3494- connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotApply()));
3495- //connect(chkAnalyzeEntireSong, SIGNAL(stateChanged(int)), this, SLOT(slotSetAnalyzeMode(int)));
3496-
3497- // Check to see if this is a new scheme. If so, create it with default values
3498- if(!bpmScheme)
3499- {
3500- bpmScheme = new BpmScheme("New Scheme Name", 50, 150, false);
3501- }
3502-
3503- // Populate the dialog values
3504- txtSchemeName->setText(bpmScheme->getName());
3505- spinBpmMin->setValue(bpmScheme->getMinBpm());
3506- spinBpmMax->setValue(bpmScheme->getMaxBpm());
3507- chkAnalyzeEntireSong->setChecked(bpmScheme->getAnalyzeEntireSong());
3508-}
3509-
3510-DlgBpmScheme::~DlgBpmScheme()
3511-{
3512-}
3513-
3514-void DlgBpmScheme::slotApply()
3515-{
3516- m_BpmScheme->setName(txtSchemeName->text());
3517- m_BpmScheme->setMinBpm(spinBpmMin->value());
3518- m_BpmScheme->setMaxBpm(spinBpmMax->value());
3519- m_BpmScheme->setAnalyzeEntireSong(chkAnalyzeEntireSong->isChecked());
3520-}
3521-
3522-void DlgBpmScheme::slotUpdate()
3523-{
3524-}
3525-
3526
3527=== removed file 'mixxx/src/dlgbpmscheme.h'
3528--- mixxx/src/dlgbpmscheme.h 2008-01-30 13:37:36 +0000
3529+++ mixxx/src/dlgbpmscheme.h 1970-01-01 00:00:00 +0000
3530@@ -1,38 +0,0 @@
3531-
3532-
3533-/***************************************************************************
3534- * *
3535- * This program is free software; you can redistribute it and/or modify *
3536- * it under the terms of the GNU General Public License as published by *
3537- * the Free Software Foundation; either version 2 of the License, or *
3538- * (at your option) any later version. *
3539- * *
3540- ***************************************************************************/
3541-
3542-#ifndef DLGBPMSCHEME_H
3543-#define DLGBPMSCHEME_H
3544-
3545-#include "ui_dlgbpmschemedlg.h"
3546-#include "configobject.h"
3547-#include <qstring.h>
3548-
3549-class BpmScheme;
3550-
3551-class QWidget;
3552-
3553-class DlgBpmScheme : public QDialog, Ui::DlgBpmSchemeDlg {
3554- Q_OBJECT
3555-public:
3556- DlgBpmScheme(BpmScheme *& bpmScheme);
3557- ~DlgBpmScheme();
3558-public slots:
3559- /** Apply changes to widget */
3560- void slotApply();
3561- void slotUpdate();
3562-signals:
3563- void apply(const QString &);
3564-private:
3565- BpmScheme *& m_BpmScheme;
3566-};
3567-
3568-#endif
3569
3570=== removed file 'mixxx/src/dlgbpmschemedlg.ui'
3571--- mixxx/src/dlgbpmschemedlg.ui 2012-04-30 18:38:29 +0000
3572+++ mixxx/src/dlgbpmschemedlg.ui 1970-01-01 00:00:00 +0000
3573@@ -1,184 +0,0 @@
3574-<?xml version="1.0" encoding="UTF-8"?>
3575-<ui version="4.0">
3576- <class>DlgBpmSchemeDlg</class>
3577- <widget class="QDialog" name="DlgBpmSchemeDlg">
3578- <property name="geometry">
3579- <rect>
3580- <x>0</x>
3581- <y>0</y>
3582- <width>352</width>
3583- <height>172</height>
3584- </rect>
3585- </property>
3586- <property name="windowTitle">
3587- <string>BPM Scheme</string>
3588- </property>
3589- <widget class="QDialogButtonBox" name="buttonBox">
3590- <property name="geometry">
3591- <rect>
3592- <x>0</x>
3593- <y>130</y>
3594- <width>341</width>
3595- <height>32</height>
3596- </rect>
3597- </property>
3598- <property name="orientation">
3599- <enum>Qt::Horizontal</enum>
3600- </property>
3601- <property name="standardButtons">
3602- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
3603- </property>
3604- </widget>
3605- <widget class="QLineEdit" name="txtSchemeName">
3606- <property name="geometry">
3607- <rect>
3608- <x>110</x>
3609- <y>10</y>
3610- <width>231</width>
3611- <height>23</height>
3612- </rect>
3613- </property>
3614- </widget>
3615- <widget class="QLabel" name="label">
3616- <property name="geometry">
3617- <rect>
3618- <x>10</x>
3619- <y>10</y>
3620- <width>111</width>
3621- <height>18</height>
3622- </rect>
3623- </property>
3624- <property name="text">
3625- <string>Scheme Name:</string>
3626- </property>
3627- <property name="buddy">
3628- <cstring>txtSchemeName</cstring>
3629- </property>
3630- </widget>
3631- <widget class="QGroupBox" name="groupBox">
3632- <property name="geometry">
3633- <rect>
3634- <x>10</x>
3635- <y>40</y>
3636- <width>331</width>
3637- <height>51</height>
3638- </rect>
3639- </property>
3640- <property name="title">
3641- <string>BPM Range</string>
3642- </property>
3643- <widget class="QSpinBox" name="spinBpmMin">
3644- <property name="geometry">
3645- <rect>
3646- <x>80</x>
3647- <y>20</y>
3648- <width>71</width>
3649- <height>23</height>
3650- </rect>
3651- </property>
3652- <property name="minimum">
3653- <number>1</number>
3654- </property>
3655- <property name="maximum">
3656- <number>220</number>
3657- </property>
3658- </widget>
3659- <widget class="QSpinBox" name="spinBpmMax">
3660- <property name="geometry">
3661- <rect>
3662- <x>210</x>
3663- <y>20</y>
3664- <width>71</width>
3665- <height>23</height>
3666- </rect>
3667- </property>
3668- <property name="minimum">
3669- <number>1</number>
3670- </property>
3671- <property name="maximum">
3672- <number>220</number>
3673- </property>
3674- </widget>
3675- <widget class="QLabel" name="label_2">
3676- <property name="geometry">
3677- <rect>
3678- <x>170</x>
3679- <y>20</y>
3680- <width>31</width>
3681- <height>18</height>
3682- </rect>
3683- </property>
3684- <property name="text">
3685- <string>Max</string>
3686- </property>
3687- <property name="buddy">
3688- <cstring>spinBpmMax</cstring>
3689- </property>
3690- </widget>
3691- <widget class="QLabel" name="label_3">
3692- <property name="geometry">
3693- <rect>
3694- <x>40</x>
3695- <y>20</y>
3696- <width>31</width>
3697- <height>18</height>
3698- </rect>
3699- </property>
3700- <property name="text">
3701- <string>Min</string>
3702- </property>
3703- <property name="buddy">
3704- <cstring>spinBpmMin</cstring>
3705- </property>
3706- </widget>
3707- </widget>
3708- <widget class="QCheckBox" name="chkAnalyzeEntireSong">
3709- <property name="geometry">
3710- <rect>
3711- <x>90</x>
3712- <y>100</y>
3713- <width>201</width>
3714- <height>22</height>
3715- </rect>
3716- </property>
3717- <property name="text">
3718- <string>Analyze Entire Track</string>
3719- </property>
3720- </widget>
3721- </widget>
3722- <resources/>
3723- <connections>
3724- <connection>
3725- <sender>buttonBox</sender>
3726- <signal>accepted()</signal>
3727- <receiver>DlgBpmSchemeDlg</receiver>
3728- <slot>accept()</slot>
3729- <hints>
3730- <hint type="sourcelabel">
3731- <x>248</x>
3732- <y>254</y>
3733- </hint>
3734- <hint type="destinationlabel">
3735- <x>157</x>
3736- <y>274</y>
3737- </hint>
3738- </hints>
3739- </connection>
3740- <connection>
3741- <sender>buttonBox</sender>
3742- <signal>rejected()</signal>
3743- <receiver>DlgBpmSchemeDlg</receiver>
3744- <slot>reject()</slot>
3745- <hints>
3746- <hint type="sourcelabel">
3747- <x>316</x>
3748- <y>260</y>
3749- </hint>
3750- <hint type="destinationlabel">
3751- <x>286</x>
3752- <y>274</y>
3753- </hint>
3754- </hints>
3755- </connection>
3756- </connections>
3757-</ui>
3758
3759=== removed file 'mixxx/src/dlgprefbpm.cpp'
3760--- mixxx/src/dlgprefbpm.cpp 2012-11-20 00:40:18 +0000
3761+++ mixxx/src/dlgprefbpm.cpp 1970-01-01 00:00:00 +0000
3762@@ -1,455 +0,0 @@
3763-/***************************************************************************
3764- dlgprefbpm.cpp - description
3765- -------------------
3766- begin : Thu Jun 7 2007
3767- copyright : (C) 2007 by John Sully
3768- email : jsully@scs.ryerson.ca
3769-***************************************************************************/
3770-
3771-/***************************************************************************
3772-* *
3773-* This program is free software; you can redistribute it and/or modify *
3774-* it under the terms of the GNU General Public License as published by *
3775-* the Free Software Foundation; either version 2 of the License, or *
3776-* (at your option) any later version. *
3777-* *
3778-***************************************************************************/
3779-
3780-#include <qlineedit.h>
3781-#include <qfiledialog.h>
3782-#include <qwidget.h>
3783-#include <qspinbox.h>
3784-#include <qcheckbox.h>
3785-#include <qlabel.h>
3786-#include <qstring.h>
3787-#include <qpushbutton.h>
3788-#include <QtCore>
3789-#include <QMessageBox>
3790-
3791-#include "dlgprefbpm.h"
3792-#include "dlgbpmscheme.h"
3793-#include "bpm/bpmscheme.h"
3794-#include "xmlparse.h"
3795-#include "mixxx.h"
3796-
3797-#define CONFIG_KEY "[BPM]"
3798-
3799-DlgPrefBpm::DlgPrefBpm(QWidget * parent, ConfigObject<ConfigValue> * _config)
3800- : QWidget(parent) {
3801- config = _config;
3802-
3803- setupUi(this);
3804-
3805- // Connection
3806- connect(chkDetectOnImport, SIGNAL(stateChanged(int)), this, SLOT(slotSetBpmDetectOnImport(int)));
3807- connect(chkWriteID3, SIGNAL(stateChanged(int)), this, SLOT(slotSetWriteID3Tag(int)));
3808- connect(chkEnableBpmDetection, SIGNAL(stateChanged(int)), this, SLOT(slotSetBpmEnabled(int)));
3809- connect(chkAboveRange, SIGNAL(stateChanged(int)), this, SLOT(slotSetAboveRange(int)));
3810-
3811- // TODO: Move this over the the scheme dialog
3812-
3813- connect(btnAdd, SIGNAL(pressed()), this, SLOT(slotAddBpmScheme()));
3814- connect(btnEdit, SIGNAL(pressed()), this, SLOT(slotEditBpmScheme()));
3815- connect(btnDelete, SIGNAL(pressed()), this, SLOT(slotDeleteBpmScheme()));
3816- connect(btnDefault, SIGNAL(pressed()), this, SLOT(slotDefaultBpmScheme()));
3817-
3818-
3819- // Determine if the config value has already been set. If not, default to enabled
3820- QString sBpmEnabled = config->getValueString(ConfigKey(CONFIG_KEY,"BPMDetectionEnabled"));
3821- if(sBpmEnabled.isNull() || sBpmEnabled.isEmpty())
3822- {
3823- config->set(ConfigKey(CONFIG_KEY,"BPMDetectionEnabled"), ConfigValue(1));
3824- }
3825-
3826- // Set default value for analyze mode check box
3827- int iBpmEnabled = config->getValueString(ConfigKey(CONFIG_KEY,"BPMDetectionEnabled")).toInt();
3828- if (iBpmEnabled)
3829- chkEnableBpmDetection->setChecked(true);
3830- else
3831- chkEnableBpmDetection->setChecked(false);
3832-
3833- int iBpmAboveRange = config->getValueString(ConfigKey(CONFIG_KEY,"BPMAboveRangeEnabled")).toInt();
3834- if (iBpmAboveRange)
3835- chkAboveRange->setChecked(true);
3836- else
3837- chkAboveRange->setChecked(false);
3838-
3839- // Set default value for detect BPM on import check box
3840- int iDetectBpmOnImport = config->getValueString(ConfigKey(CONFIG_KEY,"DetectBPMOnImport")).toInt();
3841- if (iDetectBpmOnImport)
3842- chkDetectOnImport->setChecked(true);
3843- else
3844- chkDetectOnImport->setChecked(false);
3845-
3846- // Set default value for write ID3 tag check box
3847- int iWriteID3Tag = config->getValueString(ConfigKey(CONFIG_KEY,"WriteID3Tag")).toInt();
3848- if (iWriteID3Tag)
3849- chkWriteID3->setChecked(true);
3850- else
3851- chkWriteID3->setChecked(false);
3852-
3853- chkWriteID3->setEnabled(false);
3854- chkDetectOnImport->setEnabled(false);
3855-
3856- // Load the BPM schemes
3857- loadBpmSchemes();
3858- populateBpmSchemeList();
3859-
3860- updateBpmEnabled();
3861-
3862-
3863- //Load BPM Range Values
3864- /*int iRangeStart = config->getValueString(ConfigKey("[BPM]","BPMRangeStart")).toInt();
3865- if(iRangeStart > 0 && iRangeStart <= 220)
3866- spinBoxBPMRangeStart->setValue(iRangeStart);
3867- else
3868- spinBoxBPMRangeStart->setValue(60);
3869-
3870- int iRangeEnd = config->getValueString(ConfigKey("[BPM]","BPMRangeEnd")).toInt();
3871- if(iRangeEnd > 0 && iRangeEnd <=220)
3872- spinBoxBPMRangeEnd->setValue(iRangeEnd);
3873- else
3874- spinBoxBPMRangeEnd->setValue(180);*/
3875-
3876-}
3877-
3878-DlgPrefBpm::~DlgPrefBpm()
3879-{
3880- saveBpmSchemes();
3881-
3882- while (!m_BpmSchemes.isEmpty())
3883- {
3884- delete m_BpmSchemes.takeFirst();
3885- }
3886-}
3887-
3888-void DlgPrefBpm::slotSetBpmDetectOnImport(int)
3889-{
3890- if (chkDetectOnImport->isChecked())
3891- config->set(ConfigKey(CONFIG_KEY,"DetectBPMOnImport"), ConfigValue(1));
3892- else
3893- config->set(ConfigKey(CONFIG_KEY,"DetectBPMOnImport"), ConfigValue(0));
3894-}
3895-
3896-void DlgPrefBpm::slotSetWriteID3Tag(int)
3897-{
3898- if (chkWriteID3->isChecked())
3899- config->set(ConfigKey(CONFIG_KEY,"WriteID3Tag"), ConfigValue(1));
3900- else
3901- config->set(ConfigKey(CONFIG_KEY,"WriteID3Tag"), ConfigValue(0));
3902-}
3903-
3904-void DlgPrefBpm::slotSetBpmEnabled(int)
3905-{
3906- if (chkEnableBpmDetection->isChecked())
3907- config->set(ConfigKey(CONFIG_KEY,"BPMDetectionEnabled"), ConfigValue(1));
3908- else
3909- config->set(ConfigKey(CONFIG_KEY,"BPMDetectionEnabled"), ConfigValue(0));
3910-
3911- updateBpmEnabled();
3912-
3913-}
3914-
3915-void DlgPrefBpm::slotSetAboveRange(int) {
3916- if (chkAboveRange->isChecked())
3917- config->set(ConfigKey(CONFIG_KEY,"BPMAboveRangeEnabled"), ConfigValue(1));
3918- else
3919- config->set(ConfigKey(CONFIG_KEY,"BPMAboveRangeEnabled"), ConfigValue(0));
3920-}
3921-
3922-void DlgPrefBpm::slotSetBpmRangeStart(int begin)
3923-{
3924- Q_UNUSED(begin);
3925- //config->set(ConfigKey("[BPM]","BPMRangeStart"),ConfigValue(begin));
3926-}
3927-
3928-void DlgPrefBpm::slotSetBpmRangeEnd(int end)
3929-{
3930- Q_UNUSED(end);
3931- //config->set(ConfigKey("[BPM]","BPMRangeEnd"),ConfigValue(end));
3932-}
3933-
3934-void DlgPrefBpm::slotEditBpmScheme()
3935-{
3936- int row = lstSchemes->currentRow();
3937-
3938- if(row > -1)
3939- {
3940- BpmScheme *schemeToEdit = m_BpmSchemes.at(row);
3941- QString oldname = schemeToEdit->getName();
3942-
3943- // Open the BPM scheme dialog to edit
3944- DlgBpmScheme* SchemeEdit = new DlgBpmScheme(schemeToEdit);
3945- SchemeEdit->setModal(true);
3946- SchemeEdit->exec();
3947-
3948- QListWidgetItem *item = lstSchemes->item(row);
3949- item->setText(schemeToEdit->getName());
3950-
3951- if(oldname == config->getValueString(ConfigKey("[BPM]","DefaultScheme")))
3952- {
3953- config->set(ConfigKey("[BPM]","DefaultScheme"), schemeToEdit->getName());
3954- }
3955- }
3956-}
3957-
3958-void DlgPrefBpm::slotAddBpmScheme()
3959-{
3960- BpmScheme *schemeToAdd = NULL;
3961-
3962- // Open the BPM scheme dialog to add
3963- DlgBpmScheme* SchemeEdit = new DlgBpmScheme(schemeToAdd);
3964- SchemeEdit->setModal(true);
3965-
3966- if(SchemeEdit->exec() == QDialog::Accepted)
3967- {
3968- if(schemeToAdd)
3969- {
3970- m_BpmSchemes.push_back(schemeToAdd);
3971- QListWidgetItem *addScheme = new QListWidgetItem(lstSchemes);
3972- addScheme->setText(schemeToAdd->getName());
3973- }
3974- }
3975- else
3976- {
3977- delete schemeToAdd;
3978- }
3979-
3980-
3981-}
3982-
3983-void DlgPrefBpm::slotDeleteBpmScheme()
3984-{
3985- int row = lstSchemes->currentRow();
3986-
3987- if(row > -1)
3988- {
3989- qDebug() << "Removing Bpm Scheme at position " << row;
3990- delete lstSchemes->takeItem(row);
3991- m_BpmSchemes.removeAt(row);
3992- }
3993-}
3994-
3995-void DlgPrefBpm::slotDefaultBpmScheme()
3996-{
3997- int row = lstSchemes->currentRow();
3998-
3999- if(row > -1)
4000- {
4001- BpmScheme* scheme = m_BpmSchemes.at(row);
4002-
4003- config->set(ConfigKey("[BPM]","BPMRangeEnd"),ConfigValue(scheme->getMaxBpm()));
4004- config->set(ConfigKey("[BPM]","BPMRangeStart"),ConfigValue(scheme->getMinBpm()));
4005- config->set(ConfigKey("[BPM]","AnalyzeEntireSong"),ConfigValue(scheme->getAnalyzeEntireSong()));
4006- config->set(ConfigKey("[BPM]","DefaultScheme"), scheme->getName());
4007-
4008- clearListIcons();
4009-
4010- QListWidgetItem *item = lstSchemes->item(row);
4011- item->setIcon(QIcon(":/images/preferences/ic_preferences_bpmdetect.png"));
4012- }
4013-}
4014-
4015-void DlgPrefBpm::clearListIcons()
4016-{
4017- for(int i=0; i < lstSchemes->count(); ++i)
4018- {
4019- lstSchemes->item(i)->setIcon(QIcon(""));
4020- }
4021-}
4022-
4023-void DlgPrefBpm::slotApply()
4024-{
4025- saveBpmSchemes();
4026-}
4027-
4028-void DlgPrefBpm::slotUpdate()
4029-{
4030-}
4031-
4032-void DlgPrefBpm::updateBpmEnabled()
4033-{
4034- int iBpmEnabled = config->getValueString(ConfigKey(CONFIG_KEY,"BPMDetectionEnabled")).toInt();
4035- if (iBpmEnabled)
4036- {
4037- chkDetectOnImport->setEnabled(true);
4038- chkWriteID3->setEnabled(true);
4039- chkAboveRange->setEnabled(true);
4040- grpBpmSchemes->setEnabled(true);
4041- }
4042- else
4043- {
4044- chkDetectOnImport->setEnabled(false);
4045- chkWriteID3->setEnabled(false);
4046- chkAboveRange->setEnabled(false);
4047- grpBpmSchemes->setEnabled(false);
4048- }
4049-
4050- // These are not implemented yet, so don't enable them
4051- chkDetectOnImport->setEnabled(false);
4052- chkWriteID3->setEnabled(false);
4053-
4054-}
4055-
4056-void DlgPrefBpm::loadBpmSchemes()
4057-{
4058- // Verify path for xml track file.
4059- QString schemeFileName = config->getValueString(ConfigKey("[BPM]","SchemeFile"));
4060- if (schemeFileName.trimmed().isEmpty() | !QFile(schemeFileName).exists() ) {
4061- schemeFileName = CmdlineArgs::Instance().getSettingsPath() + BPMSCHEME_FILE;
4062- qDebug() << "BPM Scheme File ConfigKey not set or file missing... setting to"<< schemeFileName;
4063- config->set(ConfigKey("[BPM]","SchemeFile"), schemeFileName);
4064- config->Save();
4065- }
4066-
4067- QString location(config->getValueString(ConfigKey("[BPM]","SchemeFile")));
4068- qDebug() << "BpmSchemes::readXML" << location;
4069-
4070- // Open XML file
4071- QFile file(location);
4072-
4073- // Check if we can open the file
4074- if (!file.exists())
4075- {
4076- qDebug() << "BPM Scheme:" << location << "does not exist.";
4077- file.close();
4078- return;
4079- }
4080-
4081- if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
4082- qDebug() << "BPM Scheme:" << location << "can't open file for reading.";
4083- return;
4084- }
4085-
4086- QByteArray fileData = file.readAll();
4087- QByteArray badHeader = QByteArray("<?xml version=\"1.0\" encoding=\"UTF-16\"?>");
4088- QByteArray goodHeader = QByteArray("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
4089-
4090- // We've been writing UTF-16 as the encoding forever but actually writing
4091- // the file in UTF-8 (well, latin1 actually). Qt seems to have started
4092- // caring recently. Manually fix the header if we are dealing with an old
4093- // file.
4094- fileData.replace(badHeader, goodHeader);
4095-
4096- QDomDocument domXML("Mixxx_BPM_Scheme_List");
4097-
4098-
4099-
4100- // Check if there is a parsing problem
4101- QString error_msg;
4102- int error_line;
4103- int error_column;
4104- if (!domXML.setContent(fileData, &error_msg, &error_line, &error_column))
4105- {
4106- qDebug() << "BPM Scheme Parse error in" << location;
4107- qDebug() << "Doctype:" << domXML.doctype().name();
4108- qDebug() << error_msg << "on line" << error_line << ", column" << error_column;
4109- file.close();
4110- return;
4111- }
4112-
4113- file.close();
4114-
4115- // Get the root element
4116- QDomElement elementRoot = domXML.documentElement();
4117-
4118- // Get version
4119- //int version = XmlParse::selectNodeInt(elementRoot, "Version");
4120-
4121- // Get all the BPM schemes written in the xml file:
4122- QDomNode node = XmlParse::selectNode(elementRoot, "Schemes").firstChild();
4123- BpmScheme* bpmScheme; //Current BPM Scheme
4124- while (!node.isNull())
4125- {
4126- if (node.isElement() && node.nodeName()=="Scheme")
4127- {
4128- bpmScheme = new BpmScheme();
4129- //Create the playlists internally.
4130- //If the playlist is "Library" or "Play Queue", insert it into
4131- //a special spot in the list of playlists.
4132- bpmScheme->setName(XmlParse::selectNodeQString(node, "Name"));
4133- bpmScheme->setMinBpm(XmlParse::selectNodeQString(node, "MinBpm").toInt());
4134- bpmScheme->setMaxBpm(XmlParse::selectNodeQString(node, "MaxBpm").toInt());
4135- bpmScheme->setAnalyzeEntireSong((bool)XmlParse::selectNodeQString(node,
4136- "AnalyzeEntireSong").toInt());
4137- bpmScheme->setComment(XmlParse::selectNodeQString(node, "Comment"));
4138-
4139- m_BpmSchemes.push_back(bpmScheme);
4140- }
4141-
4142- node = node.nextSibling();
4143- }
4144-
4145- if(m_BpmSchemes.size() == 0)
4146- {
4147- BpmScheme *scheme = new BpmScheme("Default", 70, 140, false);
4148- m_BpmSchemes.push_back(scheme);
4149- config->set(ConfigKey("[BPM]","DefaultScheme"), QString("Default"));
4150- config->set(ConfigKey("[BPM]","BPMRangeEnd"),ConfigValue(scheme->getMaxBpm()));
4151- config->set(ConfigKey("[BPM]","BPMRangeStart"),ConfigValue(scheme->getMinBpm()));
4152- config->set(ConfigKey("[BPM]","AnalyzeEntireSong"),ConfigValue(scheme->getAnalyzeEntireSong()));
4153- }
4154-}
4155-
4156-void DlgPrefBpm::saveBpmSchemes()
4157-{
4158- QString location(config->getValueString(ConfigKey("[BPM]","SchemeFile")));
4159-
4160- // Create the xml document:
4161- QDomDocument domXML( "Mixxx_BPM_Scheme_List" );
4162-
4163- // Ensure UTF16 encoding
4164- domXML.appendChild(domXML.createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\""));
4165-
4166- // Set the document type
4167- QDomElement elementRoot = domXML.createElement( "Mixxx_BPM_Scheme_List" );
4168- domXML.appendChild(elementRoot);
4169-
4170- // Add version information:
4171- //XmlParse::addElement(domXML, elementRoot, "Version", QString("%1").arg(TRACK_VERSION));
4172-
4173- // Write playlists
4174- QDomElement schemesroot = domXML.createElement("Schemes");
4175-
4176- QListIterator<BpmScheme*> it(m_BpmSchemes);
4177- BpmScheme* current;
4178- while (it.hasNext())
4179- {
4180- current = it.next();
4181-
4182- QDomElement elementNew = domXML.createElement("Scheme");
4183- current->writeXML(domXML, elementNew);
4184- schemesroot.appendChild(elementNew);
4185-
4186- }
4187- elementRoot.appendChild(schemesroot);
4188-
4189- // Open the file:
4190- QFile opmlFile(location);
4191- if (!opmlFile.open(QIODevice::WriteOnly))
4192- {
4193- QMessageBox::critical(0,
4194- tr("Error"),
4195- tr("Cannot open file %1").arg(location));
4196- return;
4197- }
4198- // QByteArray encoded in UTF-8
4199- QByteArray ba = domXML.toByteArray();
4200- opmlFile.write(ba.constData(), ba.size());
4201- opmlFile.close();
4202-}
4203-
4204-void DlgPrefBpm::populateBpmSchemeList()
4205-{
4206- QString defaultscheme = config->getValueString(ConfigKey("[BPM]","DefaultScheme"));
4207-
4208- for(int i=0; i < m_BpmSchemes.size(); ++i)
4209- {
4210- QListWidgetItem* scheme = new QListWidgetItem(lstSchemes);
4211- scheme->setText(m_BpmSchemes.at(i)->getName());
4212- if(m_BpmSchemes.at(i)->getName() == defaultscheme)
4213- {
4214- scheme->setIcon(QIcon(":/images/preferences/ic_preferences_bpmdetect.png"));
4215- }
4216- }
4217-}
4218
4219=== removed file 'mixxx/src/dlgprefbpm.h'
4220--- mixxx/src/dlgprefbpm.h 2008-05-11 15:27:38 +0000
4221+++ mixxx/src/dlgprefbpm.h 1970-01-01 00:00:00 +0000
4222@@ -1,67 +0,0 @@
4223-
4224-
4225-/***************************************************************************
4226- * *
4227- * This program is free software; you can redistribute it and/or modify *
4228- * it under the terms of the GNU General Public License as published by *
4229- * the Free Software Foundation; either version 2 of the License, or *
4230- * (at your option) any later version. *
4231- * *
4232- ***************************************************************************/
4233-
4234-#ifndef DLGPREFBPM_H
4235-#define DLGPREFBPM_H
4236-
4237-#include "ui_dlgprefbpmdlg.h"
4238-#include "configobject.h"
4239-
4240-#include <qlist.h>
4241-
4242-class QWidget;
4243-class BpmScheme;
4244-
4245-class DlgPrefBpm : public QWidget, Ui::DlgPrefBPMDlg {
4246- Q_OBJECT
4247-public:
4248- DlgPrefBpm(QWidget *parent, ConfigObject<ConfigValue> *_config);
4249- ~DlgPrefBpm();
4250-public slots:
4251-
4252- void slotSetBpmDetectOnImport(int);
4253- void slotSetWriteID3Tag(int);
4254- void slotSetBpmEnabled(int);
4255- void slotSetBpmRangeStart(int);
4256- void slotSetBpmRangeEnd(int);
4257- void slotSetAboveRange(int);
4258-
4259- void slotEditBpmScheme();
4260- void slotAddBpmScheme();
4261- void slotDeleteBpmScheme();
4262- void slotDefaultBpmScheme();
4263-
4264- /** Apply changes to widget */
4265- void slotApply();
4266- void slotUpdate();
4267-signals:
4268- void apply(const QString &);
4269-private:
4270-
4271- void clearListIcons();
4272-
4273- // Determines whether or not to gray out the preferences
4274- void updateBpmEnabled();
4275-
4276- // Private methods for loading and saving the BPM schemes
4277- // to and from the file system.
4278- void loadBpmSchemes();
4279- void saveBpmSchemes();
4280-
4281- // Method for filling in the list of BPM schemes on the dialog
4282- void populateBpmSchemeList();
4283-
4284- /** Pointer to config object */
4285- ConfigObject<ConfigValue> *config;
4286- QList<BpmScheme*> m_BpmSchemes;
4287-};
4288-
4289-#endif
4290
4291=== removed file 'mixxx/src/dlgprefbpmdlg.ui'
4292--- mixxx/src/dlgprefbpmdlg.ui 2012-04-30 18:38:29 +0000
4293+++ mixxx/src/dlgprefbpmdlg.ui 1970-01-01 00:00:00 +0000
4294@@ -1,141 +0,0 @@
4295-<?xml version="1.0" encoding="UTF-8"?>
4296-<ui version="4.0">
4297- <class>DlgPrefBPMDlg</class>
4298- <widget class="QWidget" name="DlgPrefBPMDlg">
4299- <property name="geometry">
4300- <rect>
4301- <x>0</x>
4302- <y>0</y>
4303- <width>433</width>
4304- <height>446</height>
4305- </rect>
4306- </property>
4307- <property name="windowTitle">
4308- <string>BPM Detection Settings</string>
4309- </property>
4310- <layout class="QVBoxLayout" name="verticalLayout">
4311- <item>
4312- <widget class="QGroupBox" name="groupBox">
4313- <property name="title">
4314- <string>BPM Detection</string>
4315- </property>
4316- <layout class="QVBoxLayout" name="verticalLayout_2">
4317- <item>
4318- <widget class="QCheckBox" name="chkEnableBpmDetection">
4319- <property name="text">
4320- <string>Enable BPM Detection</string>
4321- </property>
4322- </widget>
4323- </item>
4324- <item>
4325- <widget class="Line" name="line1">
4326- <property name="frameShape">
4327- <enum>QFrame::HLine</enum>
4328- </property>
4329- <property name="frameShadow">
4330- <enum>QFrame::Sunken</enum>
4331- </property>
4332- </widget>
4333- </item>
4334- <item>
4335- <widget class="QCheckBox" name="chkDetectOnImport">
4336- <property name="text">
4337- <string>Detect Tracks BPM on Import</string>
4338- </property>
4339- </widget>
4340- </item>
4341- <item>
4342- <widget class="QCheckBox" name="chkWriteID3">
4343- <property name="text">
4344- <string>Write BPM to ID3 Tag</string>
4345- </property>
4346- </widget>
4347- </item>
4348- <item>
4349- <widget class="QCheckBox" name="chkAboveRange">
4350- <property name="toolTip">
4351- <string>If BPM can be detected but not within specified range</string>
4352- </property>
4353- <property name="text">
4354- <string>Allow BPM above the range</string>
4355- </property>
4356- </widget>
4357- </item>
4358- </layout>
4359- </widget>
4360- </item>
4361- <item>
4362- <widget class="QGroupBox" name="grpBpmSchemes">
4363- <property name="minimumSize">
4364- <size>
4365- <width>409</width>
4366- <height>200</height>
4367- </size>
4368- </property>
4369- <property name="title">
4370- <string>BPM Schemes</string>
4371- </property>
4372- <layout class="QGridLayout">
4373- <item row="4" column="1">
4374- <spacer>
4375- <property name="orientation">
4376- <enum>Qt::Vertical</enum>
4377- </property>
4378- <property name="sizeHint" stdset="0">
4379- <size>
4380- <width>20</width>
4381- <height>40</height>
4382- </size>
4383- </property>
4384- </spacer>
4385- </item>
4386- <item row="0" column="0" rowspan="5">
4387- <widget class="QListWidget" name="lstSchemes">
4388- <property name="showDropIndicator" stdset="0">
4389- <bool>false</bool>
4390- </property>
4391- <property name="dragDropMode">
4392- <enum>QAbstractItemView::NoDragDrop</enum>
4393- </property>
4394- <property name="modelColumn">
4395- <number>0</number>
4396- </property>
4397- </widget>
4398- </item>
4399- <item row="0" column="1">
4400- <widget class="QPushButton" name="btnAdd">
4401- <property name="text">
4402- <string>Add</string>
4403- </property>
4404- </widget>
4405- </item>
4406- <item row="1" column="1">
4407- <widget class="QPushButton" name="btnEdit">
4408- <property name="text">
4409- <string>Edit</string>
4410- </property>
4411- </widget>
4412- </item>
4413- <item row="2" column="1">
4414- <widget class="QPushButton" name="btnDelete">
4415- <property name="text">
4416- <string>Delete</string>
4417- </property>
4418- </widget>
4419- </item>
4420- <item row="3" column="1">
4421- <widget class="QPushButton" name="btnDefault">
4422- <property name="text">
4423- <string>Default</string>
4424- </property>
4425- </widget>
4426- </item>
4427- </layout>
4428- </widget>
4429- </item>
4430- </layout>
4431- </widget>
4432- <layoutdefault spacing="6" margin="11"/>
4433- <resources/>
4434- <connections/>
4435-</ui>
4436
4437=== modified file 'mixxx/src/dlgprefeq.cpp'
4438--- mixxx/src/dlgprefeq.cpp 2012-04-29 15:54:21 +0000
4439+++ mixxx/src/dlgprefeq.cpp 2013-05-16 01:44:29 +0000
4440@@ -15,8 +15,6 @@
4441 * *
4442 ***************************************************************************/
4443
4444-#include "dlgprefeq.h"
4445-#include "engine/enginefilteriir.h"
4446 #include <qlineedit.h>
4447 #include <qwidget.h>
4448 #include <qslider.h>
4449@@ -28,6 +26,10 @@
4450
4451 #include <assert.h>
4452
4453+#include "dlgprefeq.h"
4454+#include "engine/enginefilteriir.h"
4455+#include "controlobject.h"
4456+
4457 #define CONFIG_KEY "[Mixer Profile]"
4458
4459 const int kFrequencyUpperLimit = 20050;
4460
4461=== modified file 'mixxx/src/dlgprefeq.h'
4462--- mixxx/src/dlgprefeq.h 2011-12-06 19:40:07 +0000
4463+++ mixxx/src/dlgprefeq.h 2013-05-16 01:44:29 +0000
4464@@ -21,7 +21,7 @@
4465 #include "ui_dlgprefeqdlg.h"
4466 #include "configobject.h"
4467 #include "engine/enginefilterblock.h"
4468-#include "controlobject.h"
4469+#include "controlobjectthread.h"
4470
4471 class QWidget;
4472 /**
4473
4474=== modified file 'mixxx/src/dlgpreferences.cpp'
4475--- mixxx/src/dlgpreferences.cpp 2013-03-14 18:29:16 +0000
4476+++ mixxx/src/dlgpreferences.cpp 2013-05-16 01:44:29 +0000
4477@@ -31,11 +31,7 @@
4478 #ifdef __SHOUTCAST__
4479 #include "dlgprefshoutcast.h"
4480 #endif
4481-#ifdef __VAMP__
4482- #include "dlgprefbeats.h"
4483-#else
4484- #include "dlgprefbpm.h"
4485-#endif
4486+#include "dlgprefbeats.h"
4487
4488 #ifdef __MODPLUG__
4489 #include "dlgprefmodplug.h"
4490@@ -91,13 +87,8 @@
4491 m_wcrossfader = new DlgPrefCrossfader(this, config);
4492 addPageWidget(m_wcrossfader);
4493
4494-#ifdef __VAMP__
4495 m_wbeats = new DlgPrefBeats(this, config);
4496 addPageWidget (m_wbeats);
4497-#else
4498- m_wbpm = new DlgPrefBpm(this, config);
4499- addPageWidget(m_wbpm);
4500-#endif
4501 m_wreplaygain = new DlgPrefReplayGain(this, config);
4502 addPageWidget(m_wreplaygain);
4503 m_wrecord = new DlgPrefRecord(this, config);
4504@@ -139,13 +130,8 @@
4505 connect(this, SIGNAL(showDlg()), m_weq, SLOT(slotUpdate()));
4506 connect(this, SIGNAL(showDlg()), m_wcrossfader, SLOT(slotUpdate()));
4507
4508-#ifdef __VAMP__
4509 connect(this, SIGNAL(showDlg()),
4510 m_wbeats, SLOT(slotUpdate()));
4511-#else
4512- connect(this, SIGNAL(showDlg()),
4513- m_wbpm, SLOT(slotUpdate()));
4514-#endif
4515
4516 connect(this, SIGNAL(showDlg()), m_wreplaygain,SLOT(slotUpdate()));
4517 connect(this, SIGNAL(showDlg()), m_wrecord, SLOT(slotUpdate()));
4518@@ -175,11 +161,7 @@
4519 connect(buttonBox, SIGNAL(accepted()), m_wcrossfader,SLOT(slotApply()));
4520 connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotApply()));
4521
4522-#ifdef __VAMP__
4523 connect(buttonBox, SIGNAL(accepted()), m_wbeats, SLOT(slotApply()));
4524-#else
4525- connect(buttonBox, SIGNAL(accepted()), m_wbpm, SLOT(slotApply()));
4526-#endif
4527 connect(buttonBox, SIGNAL(accepted()), m_wreplaygain,SLOT(slotApply()));
4528 connect(buttonBox, SIGNAL(accepted()), m_wrecord, SLOT(slotApply()));
4529 #ifdef __SHOUTCAST__
4530@@ -247,19 +229,11 @@
4531 m_pRecordingButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
4532
4533
4534-#ifdef __VAMP__
4535 m_pAnalysersButton = new QTreeWidgetItem(contentsTreeWidget, QTreeWidgetItem::Type);
4536 m_pAnalysersButton->setIcon(0, QIcon(":/images/preferences/ic_preferences_bpmdetect.png"));
4537 m_pAnalysersButton->setText(0, tr("Beat Detection"));
4538 m_pAnalysersButton->setTextAlignment(0, Qt::AlignLeft | Qt::AlignVCenter);
4539 m_pAnalysersButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
4540-#else
4541- m_pBPMdetectButton = new QTreeWidgetItem(contentsTreeWidget, QTreeWidgetItem::Type);
4542- m_pBPMdetectButton->setIcon(0, QIcon(":/images/preferences/ic_preferences_bpmdetect.png"));
4543- m_pBPMdetectButton->setText(0, tr("BPM Detection"));
4544- m_pBPMdetectButton->setTextAlignment(0, Qt::AlignLeft | Qt::AlignVCenter);
4545- m_pBPMdetectButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
4546-#endif
4547 m_pReplayGainButton = new QTreeWidgetItem(contentsTreeWidget, QTreeWidgetItem::Type);
4548 m_pReplayGainButton->setIcon(0, QIcon(":/images/preferences/ic_preferences_replaygain.png"));
4549 m_pReplayGainButton->setText(0, tr("Normalization"));
4550@@ -323,14 +297,8 @@
4551 pagesWidget->setCurrentWidget(m_wcrossfader->parentWidget()->parentWidget());
4552 } else if (current == m_pRecordingButton) {
4553 pagesWidget->setCurrentWidget(m_wrecord->parentWidget()->parentWidget());
4554-
4555-#ifdef __VAMP__
4556 } else if (current == m_pAnalysersButton ) {
4557 pagesWidget->setCurrentWidget(m_wbeats->parentWidget()->parentWidget());
4558-#else
4559- } else if (current == m_pBPMdetectButton) {
4560- pagesWidget->setCurrentWidget(m_wbpm->parentWidget()->parentWidget());
4561-#endif
4562 } else if (current == m_pReplayGainButton) {
4563 pagesWidget->setCurrentWidget(m_wreplaygain->parentWidget()->parentWidget());
4564
4565
4566=== modified file 'mixxx/src/dlgpreferences.h'
4567--- mixxx/src/dlgpreferences.h 2013-03-14 17:43:39 +0000
4568+++ mixxx/src/dlgpreferences.h 2013-05-16 01:44:29 +0000
4569@@ -35,7 +35,6 @@
4570 class DlgPrefEQ;
4571 class DlgPrefCrossfader;
4572 class DlgPrefRecord;
4573-class DlgPrefBpm;
4574 class DlgPrefBeats;
4575 class DlgPrefVinyl;
4576 class DlgPrefNoVinyl;
4577@@ -90,7 +89,6 @@
4578 DlgPrefEQ* m_weq;
4579 DlgPrefCrossfader* m_wcrossfader;
4580 DlgPrefRecord* m_wrecord;
4581- DlgPrefBpm* m_wbpm;
4582 DlgPrefBeats* m_wbeats;
4583 DlgPrefVinyl* m_wvinylcontrol;
4584 DlgPrefNoVinyl* m_wnovinylcontrol;
4585
4586=== modified file 'mixxx/src/dlgprefrecord.cpp'
4587--- mixxx/src/dlgprefrecord.cpp 2012-06-15 20:49:49 +0000
4588+++ mixxx/src/dlgprefrecord.cpp 2013-05-16 01:44:29 +0000
4589@@ -17,12 +17,12 @@
4590
4591 #include <QtCore>
4592 #include <QtGui>
4593+
4594 #include "dlgprefrecord.h"
4595 #include "recording/defs_recording.h"
4596 #include "controlobject.h"
4597 #include "controlobjectthreadmain.h"
4598-#include "recording/encoder.h"
4599-
4600+#include "encoder/encoder.h"
4601
4602 DlgPrefRecord::DlgPrefRecord(QWidget * parent, ConfigObject<ConfigValue> * _config)
4603 : QWidget(parent) {
4604@@ -39,12 +39,11 @@
4605 recordControl = new ControlObjectThreadMain(
4606 ControlObject::getControl(ConfigKey(RECORDING_PREF_KEY, "status")));
4607
4608-#ifdef __SHOUTCAST__
4609 radioOgg = new QRadioButton("Ogg Vorbis");
4610 radioMp3 = new QRadioButton(ENCODING_MP3);
4611
4612 // Setting recordings path
4613- QString recordingsPath = config->getValueString(ConfigKey("[Recording]","Directory"));
4614+ QString recordingsPath = config->getValueString(ConfigKey(RECORDING_PREF_KEY,"Directory"));
4615 if (recordingsPath == "") {
4616 // Initialize recordings path in config to old default path.
4617 // Do it here so we show current value in UI correctly.
4618@@ -67,8 +66,6 @@
4619 horizontalLayout->addWidget(radioOgg);
4620 horizontalLayout->addWidget(radioMp3);
4621
4622-#endif
4623-
4624 //AIFF and WAVE are supported by default
4625 radioWav = new QRadioButton(ENCODING_WAVE);
4626 connect(radioWav, SIGNAL(clicked()),
4627@@ -80,7 +77,6 @@
4628 this, SLOT(slotApply()));
4629 horizontalLayout->addWidget(radioAiff);
4630
4631-
4632 #ifdef SF_FORMAT_FLAC
4633 radioFlac = new QRadioButton(ENCODING_FLAC);
4634 connect(radioFlac,SIGNAL(clicked()),
4635@@ -89,18 +85,18 @@
4636 #endif
4637
4638 //Read config and check radio button
4639- QString format = config->getValueString(ConfigKey("[Recording]","Encoding"));
4640+ QString format = config->getValueString(ConfigKey(RECORDING_PREF_KEY,"Encoding"));
4641 if(format == ENCODING_WAVE)
4642 radioWav->setChecked(true);
4643-#ifdef __SHOUTCAST__
4644 else if(format == ENCODING_OGG)
4645 radioOgg->setChecked(true);
4646 else if (format == ENCODING_MP3)
4647 radioMp3->setChecked(true);
4648-#endif
4649-#ifdef SF_FORMAT_FLAC
4650 else if (format == ENCODING_AIFF)
4651 radioAiff->setChecked(true);
4652+#ifdef SF_FORMAT_FLAC
4653+ else if (format == ENCODING_FLAC)
4654+ radioFlac->setChecked(true);
4655 #endif
4656 else //Invalid, so set default and save
4657 {
4658@@ -109,6 +105,8 @@
4659 config->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(ENCODING_WAVE));
4660 }
4661
4662+ loadMetaData();
4663+
4664 //Connections
4665 connect(SliderQuality, SIGNAL(valueChanged(int)), this, SLOT(slotSliderQuality()));
4666 connect(SliderQuality, SIGNAL(sliderMoved(int)), this, SLOT(slotSliderQuality()));
4667@@ -125,7 +123,7 @@
4668 comboBoxSplitting->addItem(SPLIT_2048MB);
4669 comboBoxSplitting->addItem(SPLIT_4096MB);
4670
4671- QString fileSizeStr = config->getValueString(ConfigKey("[Recording]","FileSize"));
4672+ QString fileSizeStr = config->getValueString(ConfigKey(RECORDING_PREF_KEY,"FileSize"));
4673 int index = comboBoxSplitting->findText(fileSizeStr);
4674 if(index > 0){
4675 //set file split size
4676@@ -134,7 +132,7 @@
4677 //Otherwise 650 MB will be default file split size
4678
4679 //Read CUEfile info
4680- CheckBoxRecordCueFile->setChecked((bool) config->getValueString(ConfigKey("[Recording]","CueEnabled")).toInt());
4681+ CheckBoxRecordCueFile->setChecked((bool) config->getValueString(ConfigKey(RECORDING_PREF_KEY,"CueEnabled")).toInt());
4682
4683 }
4684
4685@@ -243,7 +241,7 @@
4686 void DlgPrefRecord::slotUpdate()
4687 {
4688 // Recordings path
4689- QString recordingsPath = config->getValueString(ConfigKey("[Recording]","Directory"));
4690+ QString recordingsPath = config->getValueString(ConfigKey(RECORDING_PREF_KEY,"Directory"));
4691 LineEditRecordings->setText(recordingsPath);
4692
4693 if (radioWav && radioWav->isChecked())
4694@@ -272,7 +270,7 @@
4695 void DlgPrefRecord::slotBrowseRecordingsDir()
4696 {
4697 QString fd = QFileDialog::getExistingDirectory(this, tr("Choose recordings directory"),
4698- config->getValueString(ConfigKey("[Recording]","Directory")));
4699+ config->getValueString(ConfigKey(RECORDING_PREF_KEY,"Directory")));
4700 if (fd != "")
4701 {
4702 LineEditRecordings->setText(fd);
4703@@ -293,10 +291,10 @@
4704 qDebug() << "Recordings path was empty in dialog";
4705 return;
4706 }
4707- if (LineEditRecordings->text() != config->getValueString(ConfigKey("[Recording]","Directory")))
4708+ if (LineEditRecordings->text() != config->getValueString(ConfigKey(RECORDING_PREF_KEY,"Directory")))
4709 {
4710 qDebug() << "Saved recordings path" << LineEditRecordings->text();
4711- config->set(ConfigKey("[Recording]","Directory"), LineEditRecordings->text());
4712+ config->set(ConfigKey(RECORDING_PREF_KEY,"Directory"), LineEditRecordings->text());
4713 }
4714 }
4715
4716
4717=== modified file 'mixxx/src/dlgprefshoutcast.h'
4718--- mixxx/src/dlgprefshoutcast.h 2008-01-26 19:29:41 +0000
4719+++ mixxx/src/dlgprefshoutcast.h 2013-05-16 01:44:29 +0000
4720@@ -5,7 +5,7 @@
4721 copyright : (C) 2008 by Wesley Stessens
4722 (C) 2007 by John Sully
4723 (C) 2008 by Albert Santoni
4724- email :
4725+ email :
4726 ***************************************************************************/
4727
4728 /***************************************************************************
4729@@ -24,9 +24,7 @@
4730 #include "controlobject.h"
4731 #include "configobject.h"
4732 #include "controlobjectthreadmain.h"
4733-
4734-#define SHOUTCAST_PREF_KEY "[Shoutcast]"
4735-#define SHOUTCAST_DEFAULT_PORT "8000"
4736+#include "shoutcast/defs_shoutcast.h"
4737
4738 class QWidget;
4739 /**
4740@@ -35,7 +33,7 @@
4741
4742 class DlgPrefShoutcast : public QWidget, public Ui::DlgPrefShoutcastDlg {
4743 Q_OBJECT
4744-public:
4745+public:
4746 DlgPrefShoutcast(QWidget *parent, ConfigObject<ConfigValue> *_config);
4747 ~DlgPrefShoutcast();
4748 public slots:
4749
4750=== modified file 'mixxx/src/dlgtrackinfo.h'
4751--- mixxx/src/dlgtrackinfo.h 2010-09-10 06:04:12 +0000
4752+++ mixxx/src/dlgtrackinfo.h 2013-05-16 01:44:29 +0000
4753@@ -10,7 +10,15 @@
4754 #include "ui_dlgtrackinfo.h"
4755
4756 #include "trackinfoobject.h"
4757-#include "controlbeat.h"
4758+
4759+/** Minimum allowed Beat per minute (BPM) */
4760+const int minBPM = 30;
4761+/** Maximum allowed bpm */
4762+const int maxBPM = 240;
4763+/** Maximum allowed interval between beats in milli seconds (calculated from minBPM) */
4764+const int maxInterval = (int)(1000.*(60./(CSAMPLE)minBPM));
4765+/** Filter length */
4766+const int filterLength = 5;
4767
4768 class Cue;
4769
4770
4771=== added directory 'mixxx/src/encoder'
4772=== renamed file 'mixxx/src/recording/encoder.cpp' => 'mixxx/src/encoder/encoder.cpp'
4773--- mixxx/src/recording/encoder.cpp 2010-11-01 17:24:48 +0000
4774+++ mixxx/src/encoder/encoder.cpp 2013-05-16 01:44:29 +0000
4775@@ -14,24 +14,11 @@
4776 * *
4777 ***************************************************************************/
4778
4779-#include <stdlib.h> // needed for random num gen
4780-#include <time.h> // needed for random num gen
4781-#include <string.h> // needed for memcpy
4782-#include <QDebug>
4783-
4784-#include "engine/engineabstractrecord.h"
4785-#include "controlobjectthreadmain.h"
4786-#include "controlobject.h"
4787-#include "playerinfo.h"
4788-#include "trackinfoobject.h"
4789-
4790-#include "encoder.h"
4791-
4792-// Constructor
4793+#include "encoder/encoder.h"
4794+
4795 Encoder::Encoder() {
4796 }
4797
4798-// Destructor
4799 Encoder::~Encoder() {
4800 }
4801
4802
4803=== renamed file 'mixxx/src/recording/encoder.h' => 'mixxx/src/encoder/encoder.h'
4804--- mixxx/src/recording/encoder.h 2010-09-07 07:50:15 +0000
4805+++ mixxx/src/encoder/encoder.h 2013-05-16 01:44:29 +0000
4806@@ -17,30 +17,20 @@
4807 #ifndef ENCODER_H
4808 #define ENCODER_H
4809
4810-#include <stdlib.h> // needed for random num gen
4811-#include <time.h> // needed for random num gen
4812-#include <string.h> // needed for memcpy
4813-#include <QDebug>
4814-
4815-#include "engine/engineabstractrecord.h"
4816-#include "controlobjectthreadmain.h"
4817-#include "controlobject.h"
4818-#include "playerinfo.h"
4819-#include "trackinfoobject.h"
4820-
4821-
4822-class Encoder : public QObject {
4823- Q_OBJECT
4824-
4825+#include "defs.h"
4826+
4827+class Encoder {
4828 public:
4829 Encoder();
4830 virtual ~Encoder();
4831- /*
4832- * General Encoder methods
4833- */
4834- virtual int initEncoder(int bitrate) = 0;
4835+
4836+ virtual int initEncoder(int bitrate, int samplerate) = 0;
4837+ // encodes the provided buffer of audio.
4838 virtual void encodeBuffer(const CSAMPLE *samples, const int size) = 0;
4839+ // Adds metadata to the encoded auio, i.e., the ID3 tag. Currently only used
4840+ // by EngineRecord, EngineShoutcast does something different.
4841 virtual void updateMetaData(char* artist, char* title, char* album) = 0;
4842+ // called at the end when encoding is finished
4843 virtual void flush() = 0;
4844 /**converts an OGG quality measure from 1..10 to a bitrate **/
4845 static int convertToBitrate(int quality);
4846
4847=== renamed file 'mixxx/src/engine/engineabstractrecord.h' => 'mixxx/src/encoder/encodercallback.h'
4848--- mixxx/src/engine/engineabstractrecord.h 2011-03-22 16:24:04 +0000
4849+++ mixxx/src/encoder/encodercallback.h 2013-05-16 01:44:29 +0000
4850@@ -1,29 +1,12 @@
4851-/***************************************************************************
4852- engineabstractrecord.h - Abstract Recording class
4853- -------------------
4854- copyright : (C) 2007 by Wesley Stessens
4855- ***************************************************************************/
4856-
4857-/***************************************************************************
4858- * *
4859- * This program is free software; you can redistribute it and/or modify *
4860- * it under the terms of the GNU General Public License as published by *
4861- * the Free Software Foundation; either version 2 of the License, or *
4862- * (at your option) any later version. *
4863- * *
4864- ***************************************************************************/
4865-
4866-#ifndef ENGINEABSTRACTRECORD_H
4867-#define ENGINEABSTRACTRECORD_H
4868-
4869-#include "defs.h"
4870-#include "engine/engineobject.h"
4871-
4872-class EngineAbstractRecord : public EngineObject {
4873+#ifndef ENCODERCALLBACK_H
4874+#define ENCODERCALLBACK_H
4875+
4876+class EncoderCallback {
4877 public:
4878- /** writes to encoded audio to a stream, e.g., a file stream or shoutcast stream **/
4879+ // writes to encoded audio to a stream, e.g., a file stream or shoutcast stream
4880 virtual void write(unsigned char *header, unsigned char *body,
4881- int headerLen, int bodyLen) = 0;
4882+ int headerLen, int bodyLen) = 0;
4883 };
4884
4885-#endif
4886+#endif /* ENCODERCALLBACK_H */
4887+
4888
4889=== renamed file 'mixxx/src/recording/encodermp3.cpp' => 'mixxx/src/encoder/encodermp3.cpp'
4890--- mixxx/src/recording/encodermp3.cpp 2012-05-14 20:47:43 +0000
4891+++ mixxx/src/encoder/encodermp3.cpp 2013-05-16 01:44:29 +0000
4892@@ -15,53 +15,20 @@
4893 * *
4894 ***************************************************************************/
4895
4896-#include <stdlib.h> // needed for random num
4897-#include <time.h> // needed for random num
4898-#include <string.h> // needed for memcpy
4899-#include <QDebug>
4900+#include <QtDebug>
4901+#include <QObject>
4902
4903-#include "recording/encodermp3.h"
4904-#include "engine/engineabstractrecord.h"
4905-#include "controlobjectthreadmain.h"
4906-#include "controlobject.h"
4907-#include "playerinfo.h"
4908-#include "trackinfoobject.h"
4909-#include "defs_recording.h"
4910+#include "encoder/encodermp3.h"
4911+#include "encoder/encodercallback.h"
4912 #include "errordialoghandler.h"
4913
4914-EncoderMp3::EncoderMp3(EngineAbstractRecord *engine) {
4915- m_pEngine = engine;
4916- m_metaDataTitle = NULL;
4917- m_metaDataArtist = NULL;
4918- m_metaDataAlbum = NULL;
4919- m_pMetaData = TrackPointer(NULL);
4920- m_bufferIn[0] = NULL;
4921- m_bufferIn[1] = NULL;
4922- m_bufferOut = NULL;
4923- m_bufferOutSize = 0;
4924- m_lameFlags = NULL;
4925- m_library = NULL;
4926- m_samplerate = NULL;
4927-
4928- //These are the function pointers for lame
4929- lame_init = 0;
4930- lame_set_num_channels = 0;
4931- lame_set_in_samplerate = 0;
4932- lame_set_out_samplerate = 0;
4933- lame_close = 0;
4934- lame_set_brate = 0;
4935- lame_set_mode = 0;
4936- lame_set_quality = 0;
4937- lame_set_bWriteVbrTag = 0;
4938- lame_encode_buffer_float = 0;
4939- lame_init_params = 0;
4940- lame_encode_flush = 0;
4941-
4942- id3tag_init= 0;
4943- id3tag_set_title = 0;
4944- id3tag_set_artist = 0;
4945- id3tag_set_album = 0;
4946-
4947+EncoderMp3::EncoderMp3(EncoderCallback* pCallback)
4948+ : m_lameFlags(NULL),
4949+ m_metaDataTitle(NULL),
4950+ m_metaDataArtist(NULL),
4951+ m_metaDataAlbum(NULL),
4952+ m_bufferOut(NULL),
4953+ m_bufferOutSize(0),
4954 /*
4955 * @ Author: Tobias Rafreider
4956 * Nobody has initialized the field before my code review. At runtime the
4957@@ -78,7 +45,30 @@
4958 * along with LAME. This bug was detected by using Valgrind memory analyser
4959 *
4960 */
4961- m_bufferInSize = 0;
4962+ m_bufferInSize(0),
4963+ m_pCallback(pCallback),
4964+ m_library(NULL) {
4965+ m_bufferIn[0] = NULL;
4966+ m_bufferIn[1] = NULL;
4967+
4968+ //These are the function pointers for lame
4969+ lame_init = 0;
4970+ lame_set_num_channels = 0;
4971+ lame_set_in_samplerate = 0;
4972+ lame_set_out_samplerate = 0;
4973+ lame_close = 0;
4974+ lame_set_brate = 0;
4975+ lame_set_mode = 0;
4976+ lame_set_quality = 0;
4977+ lame_set_bWriteVbrTag = 0;
4978+ lame_encode_buffer_float = 0;
4979+ lame_init_params = 0;
4980+ lame_encode_flush = 0;
4981+
4982+ id3tag_init= 0;
4983+ id3tag_set_title = 0;
4984+ id3tag_set_artist = 0;
4985+ id3tag_set_album = 0;
4986
4987 /*
4988 * Load shared library
4989@@ -86,7 +76,7 @@
4990 QStringList libnames;
4991 QString libname = "";
4992 #ifdef __LINUX__
4993- libnames << "mp3lame";
4994+ libnames << "mp3lame";
4995 #elif __WINDOWS__
4996 libnames << "lame_enc.dll";
4997 #elif __APPLE__
4998@@ -103,22 +93,21 @@
4999 m_library = NULL;
5000 }
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches