-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a preference option for the order that tracks will be loaded in 4-deck skins #6
Conversation
Gihub complains: Any idea to solve it? |
I'll remove my new skins, that should help |
OK This should be readable now. |
@@ -123,6 +147,8 @@ class PlayerManager : public QObject { | |||
// Used to protect access to PlayerManager state across threads. | |||
mutable QMutex m_mutex; | |||
|
|||
QList<QList<int> > ms_deck_orderings; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you name this with camelCase
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, what's ms_?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh it was originally a static member, so I was like, ms_!
I added some particular comments on the implementation, but in general I think we should do something more general than make a hard-coded fix for 4-decks. |
@@ -34,17 +34,24 @@ | |||
m_pAnalyserQueue(NULL), | |||
m_pCONumDecks(new ControlObject(ConfigKey("[Master]", "num_decks"), true, true)), | |||
m_pCONumSamplers(new ControlObject(ConfigKey("[Master]", "num_samplers"), true, true)), | |||
m_pCONumPreviewDecks(new ControlObject(ConfigKey("[Master]", "num_preview_decks"), true, true)) { | |||
m_pCONumPreviewDecks(new ControlObject(ConfigKey("[Master]", "num_preview_decks"), true, true)), | |||
m_pCOSkinNumDecks(new ControlObject(ConfigKey("[Skin]", "num_decks"), true, true)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to create [Skin],num_samplers and [Skin],num_preview_decks as well.
The [Skin],num_decks thing is kind of unsettling the more I think about it. If you can't load a track into a deck the skin didn't declare (e.g. decks the MIDI controller declares) then what's the point of letting a MIDI controller declare decks? This change means that in order to use N-decks your skin must support the N. What issues are solved by the [Skin],num_decks change? I wonder if there's a better fix. |
I strongly disagree with allowing decks to exist that aren't visible in the skin. It's a recipe for user confusion -- it's even confused me when I have a third track that I can't see loaded in a 2-deck skin. The problem skin-decks solves is when I switch between 2-deck skins and 4-deck skins. I want to be able to load as many tracks as the skin has, period. Is there an example of a midi controller we support that has 4 decks that would be usable without a 4 deck skin? It would have to have waveform overview displays, text displays, something like a CDJ. This change reveals the need for more 4-deck skins, but that's the point. We don't support 4 decks if you can't see them in the interface. As for hard-coding 4-deck solutions, I think 4-decks is a special case. With more decks, like 8 or 16, the user is doing loop-based work and the decks should just be loaded in order as I've coded. With 2, it's obvious that they are left and right. 4 decks is where you see this CABD stuff, and when I've spun at middlesex they definitely had the "outside/inside" method of pairing decks. It's odd, but the way 4 decks are actually used justifies the code. |
Pushed changes. Untested, but it builds. |
On May 21, 2013 9:29 AM, "Owen Williams" [email protected] wrote:
Hmm you're right. I agree we shouldn't show decks that don't have a ui But maybe we should instead fix the issue where mixxx can't remove a deck It wouldn't fix midi controllers that will just break when they have been |
I agree that we should be able to remove decks. In fact I tried to do that at first and ran into race conditions if I tried to delete a deck while it was playing. Maybe decks should be able to receive a "die()" signal so they can safely eject tracks and shut themselves down? I'm not sure what the proper multithreaded OO way of doing this is. |
I think deck ordering is a good idea but I think the implementation should
|
true, I have a three-deck mixer actually, though the use-case is more for two-decks and an mp3 player. I don't know how to programatically generate sane orderings. e.g., no one is going to want DACB, right? I guess all I can think of is a drag-reorderable list of decks. Which seems like overkill. But now that I think about use-cases, what if someone wants to use Mixxx as a kind of mixing board for a whole band? Maybe they have two turntables, and a mic, and a guitar, and a synth. Who knows where the turntables are. |
Yea - The UI could be hard to make general. The preferences could be 4deck
|
How about making deckorderings a hash of int to lists of strings? QHash < QList < QString > > >. Or maybe a small class that has that structure internally, but externally just has convenience functions like .begin and .end for easy enumeration. (That would also solve the translation issue between the visual ordering, eg CABD, and the load ordering, eg 1,2,0,3. the generic code would be: if number_of_decks in deckorderings.keys: so for now we'd only prepopulate hashvalue of 4. later if we want to add something for 3 deck, we just push a string into the list for hash 3. There could even be a UI that would push those values in. |
…-deck skins, since controllers vary
// Make sure the number of internal decks is in sync with the number of decks in the skin. | ||
connect(m_pCOSkinNumDecks, SIGNAL(valueChanged(double)), | ||
this, SLOT(slotNumDecksControlChanged(double)), | ||
Qt::DirectConnection); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Qt::DirectConnection should be removed.
After our atomic changes this is always a Qt::DirectConnection because the signal is resend by the ControlObject itselve.
Direct connections are somehow not supported now because if the signal is from an other thread it is transfered into the current thread by the ControlObject before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, GitHub did a really bad job formatting my reply-via-email. Re-posting:
That's not true -- an AutoConnection decides between direct invocation and queueing based on the emitting thread and the receiver object's thread property alone (if they match, direct. if not, queue). Nothing we did in atomic-co changes this -- a non main thread change made to this control (by looking it up with getControl or in the case of our many shared state multiple thread classes) would queue, not directly invoke. Also queueing is not acceptable here because other parts of Mixxx want this processing to be done immediately (eg so skin processing doesn't have to block while waiting for PlayerManager to get the signal) and this class is designed to be thread safe (locks) because of this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2013/5/22 RJ Ryan [email protected]
In mixxx/src/playermanager.cpp:
@@ -46,6 +50,17 @@
this, SLOT(slotNumPreviewDecksControlChanged(double)),
Qt::DirectConnection);
- // Make sure the number of internal decks is in sync with the number of decks in the skin.
- connect(m_pCOSkinNumDecks, SIGNAL(valueChanged(double)),
this, SLOT(slotNumDecksControlChanged(double)),
Qt::DirectConnection);
Oops, GitHub did a really bad job formatting my reply-via-email.
Re-posting:That's not true -- an AutoConnection decides between direct invocation and
queueing based on the emitting thread and the receiver object's thread
property alone (if they match, direct. if not, queue). Nothing we did in
atomic-co changes this -- a non main thread change made to this control (by
looking it up with getControl or in the case of our many shared state
multiple thread classes) would queue, not directly invoke. Also queueing is
not acceptable here because other parts of Mixxx want this processing to be
done immediately (eg so skin processing doesn't have to block while waiting
for PlayerManager to get the signal) and this class is designed to be
thread safe (locks) because of this.ectHi RJ,
in general, you are right, but in this case we have a double signal, one
with (QObject* sender), which is a queued connection in case of a different
sender and a direct connection else. The final signal without sender is a
direct connection in any case. But isn't the PlayerManager and the
LegacySkin parser in the same thread anyway?
—
Reply to this email directly or view it on GitHubhttps://github.com//pull/6/files#r4343623
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what you mean by double signal? If you are referring to the chain of signals from ControlObject::set() -> ControlDoublePrivate::set() -> ControlDoublePrivate::valueChanged() -> ControlObject::privateValueChanged() -> ControlObject::valueChanged/valueChangedFromEngine then I think you are missing that the ControlNumericPrivate / ControlObject connection is also a direct connection (and must be -- otherwise Qt will take unintended roundtrips through the event queue if the current thread when set() is called does not match the thread property of the object attached to the signal).
Qt signals and slots do not care about the emitter of the signal at all, all they care about is the current thread when emit() is called. If the current thread when emit is called does not match the receiving objects 'thread' property then AutoConnection is queued, otherwise it is a DirectConnection.
isn't the PlayerManager and the LegacySkin parser in the same thread anyway
PlayerManager is thread safe and its methods are invoked by multiple threads in addition to the main thread. LegacySkinParser is totally in the main thread.
For example, MIDI controllers can (and do) set the number of decks. Then the valueChanged signal would come from the controller thread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, Yes, I have overlooked that ControlObject::initialize() sets up a
direct connection.
2013/5/23 RJ Ryan [email protected]
In mixxx/src/playermanager.cpp:
@@ -46,6 +50,17 @@
this, SLOT(slotNumPreviewDecksControlChanged(double)),
Qt::DirectConnection);
- // Make sure the number of internal decks is in sync with the number of decks in the skin.
- connect(m_pCOSkinNumDecks, SIGNAL(valueChanged(double)),
this, SLOT(slotNumDecksControlChanged(double)),
Qt::DirectConnection);
Not sure what you mean by double signal? If you are referring to the chain
of signals from ControlObject::set() -> ControlDoublePrivate::set() ->
ControlDoublePrivate::valueChanged() ->
ControlObject::privateValueChanged() ->
ControlObject::valueChanged/valueChangedFromEngine then I think you are
missing that the ControlNumericPrivate / ControlObject connection is also a
direct connection (and must be -- otherwise Qt will take unintended
roundtrips through the event queue if the current thread when set() is
called does not match the thread property of the object attached to the
signal).Qt signals and slots do not care about the emitter of the signal at all,
all they care about is the current thread when emit() is called. If the
current thread when emit is called does not match the receiving objects
'thread' property then AutoConnection is queued, otherwise it is a
DirectConnection.isn't the PlayerManager and the LegacySkin parser in the same thread anyway
PlayerManager is thread safe and its methods are invoked by multiple
threads in addition to the main thread. LegacySkinParser is totally in the
main thread.For example, MIDI controllers can (and do) set the number of decks. Then
the valueChanged signal would come from the controller thread.—
Reply to this email directly or view it on GitHubhttps://github.com//pull/6/files#r4351458
.
I did not get the point why we need [Master] and [Skin] deck_num. I would like to stay with [Master] deck_num, Because there is IMHO no need for renaming it. I like the Idea to let the skin control the Deck count. Is there a way to avoid others to control the deck count? Will the deck lable be shown in the Skin? |
The reason I added [Skin] deck_num is because [Master] deck_num can never be reduced. So if I go from a skin with 4 decks to a skin with 2 decks, [Master]deck_num still says 4. So I wanted a CO that would keep track of how many decks are actually usable. A better solution to this would be to support the removing of decks so that [Master]deck_num is accurate in that use-case. |
Reimplement reverb effect with newly-ported CAPS Reverb effect.
Fix compile on WIN, use GetSystemTimePreciseAsFileTime() on Windows 8
use QEvent::WindowDeactivate to reset the press state
Mastersyc double / half Bpm Fix.
Hercules DJControl Inpulse 200: Fix some code stye issues
…h sync When loading a track that is not yet present in the library (and thus doesn't have any BPM because it hasn't been analyzed yet) while another deck is playing and both decks have sync enabled, a debug assertion is triggered: DEBUG ASSERT: "isValid()" in function double mixxx::Bpm::value() const at src/track/bpm.h:53 Aborted (core dumped) The backtrace looks as follows: #0 0x00007f175c87234c in __pthread_kill_implementation () at /usr/lib/libc.so.6 #1 0x00007f175c8254b8 in raise () at /usr/lib/libc.so.6 #2 0x00007f175c80f534 in abort () at /usr/lib/libc.so.6 #3 0x00007f175cf05ee4 in qt_assert(char const*, char const*, int) () at /usr/lib/libQt5Core.so.5 #4 0x000055deb2e67e1c in mixxx::(anonymous namespace)::handleMessage(QtMsgType, QMessageLogContext const&, QString const&) (type=<optimized out>, context=<optimized out>, input=<optimized out>) at src/util/logging.cpp:355 #5 0x00007f175cf47128 in () at /usr/lib/libQt5Core.so.5 #6 0x00007f175cf3fd8a in () at /usr/lib/libQt5Core.so.5 #7 0x00007f175cf06526 in QMessageLogger::critical(char const*, ...) const () at /usr/lib/libQt5Core.so.5 #8 0x000055deb2e5c720 in mixxx_debug_assert(char const*, char const*, int, char const*) (assertion=assertion@entry=0x55deb39bd0db "isValid()", file=file@entry=0x55deb39bbf30 "src/track/bpm.h", line=line@entry=53, function=function@entry=0x55deb39bbf08 "double mixxx::Bpm::value() const") at gsrc/util/assert.h:9 #9 0x000055deb2ee7e7e in mixxx_debug_assert_return_true(char const*, char const*, int, char const*) (function=0x55deb39bbf08 "double mixxx::Bpm::value() const", line=53, file=0x55deb39bbf30 "src/track/bpm.h", assertion=0x55deb39bd0db "isValid()") at gsrc/util/assert.h:18 #10 mixxx::Bpm::value() const (this=<synthetic pointer>) at src/track/bpm.h:53 #11 mixxx::operator*(mixxx::Bpm, double) (multiple=1, bpm=...) at src/track/bpm.h:160 #12 SyncControl::setLocalBpm(mixxx::Bpm) (this=<optimized out>, localBpm=...) at src/engine/sync/synccontrol.cpp:567 #13 0x000055deb34c7ba3 in EngineBuffer::postProcess(int) (this=0x55deb56eb060, iBufferSize=2048) at src/engine/enginebuffer.cpp:1318 #14 0x000055deb3139023 in EngineMaster::processChannels(int) (this=0x55deb5449440, iBufferSize=<optimized out>) at src/engine/enginemaster.cpp:383 #15 0x000055deb31394f7 in EngineMaster::process(int) (this=0x55deb5449440, iBufferSize=iBufferSize@entry=2048) at src/engine/enginemaster.cpp:410 #16 0x000055deb2f91d0b in SoundManager::onDeviceOutputCallback(long) (this=<optimized out>, iFramesPerBuffer=iFramesPerBuffer@entry=1024) at src/soundio/soundmanager.cpp:596 #17 0x000055deb32dd794 in SoundDevicePortAudio::callbackProcessClkRef(long, float*, float const*, PaStreamCallbackTimeInfo const*, unsigned long) (this=0x55deb553e6b0, framesPerBuffer=1024, out=<optimized out>, in=<optimized out>, timeInfo=<optimized out>, statusFlags=<optimized out>) at src/soundio/sounddeviceportaudio.cpp:965 This happens because `newLocalBpm` is invalid when `localBpm` is invalid. Trying to do sync decks while no tempo information is available does not make sense, so we only synchronize decks if the local BPM is available.
Silence some float conversion warnings by making conversion explicit
VersionStore: Remove Apple fallback
No description provided.