Results 1 to 5 of 5

Thread: Replacing "busy wait" with QTimer

  1. #1
    Join Date
    Sep 2011
    Posts
    19
    Qt products
    Qt4
    Platforms
    Windows

    Default Replacing "busy wait" with QTimer

    Using the RtMidi library, I'm setting up a loop to play multiple notes and voices. However the examples in RTMidi use a "busy wait" SLEEP to keep the sound sustained until the note ends which makes it impossible to play, say, quarter notes and whole notes together, as the quarter notes have to wait until the whole note has "SLEPT" until they can play.

    I've tried using QTimer::singleShot and I've tried offloading the SLEEP with QtConcurrent::run to a different thread, and tried combining them. My working theory is that using either a timer or a thread or a combination can give the notes time to play without causing the other notes to have to wait.

    Each QT call has worked as they are supposed to but don't achieve the desired effect of playing one note after another in the case of the quarter notes. They all sound at once. So far I haven't even gotten to the point of multi-voices but that is essential, too.

    What is wrong with this code that I can't get the desired effect?
    Qt Code:
    1. ...
    2. foreach (Note* tn, noteList) {
    3. // Note On: 144, 64, 90
    4. message[0] = 144;
    5. message[1] = tn->midiNumber;
    6. message[2] = tn->velocity;
    7. midiout->sendMessage( &message );
    8.  
    9. // setup params in globals for now
    10. mNum = tn->midiNumber;
    11. int ticks = (tn->ticks * 125);
    12.  
    13. QTimer::singleShot(ticks , this, SLOT(noteOff())); // can't do parameters
    14.  
    15. /*
    16.   SLEEP (tn->ticks * 125); ////////////////////// original example code with SLEEP
    17.   // Note Off: 128, 64, 40
    18.   message[0] = 128;
    19.   message[1] = mNum; // tn->midiNumber;
    20.   message[2] = 100; //tn->velocity;
    21.   midiout->sendMessage( &message );
    22.   */
    23. }
    24. ...
    To copy to clipboard, switch view to plain text mode 
    Qt Code:
    1. void AMidi_Rt::noteOff()
    2. {
    3. // should fire accurately after each QTimer::singleShot timer times out
    4. // this routine stops a specific note after a specific amount of time
    5. message[0] = 128;
    6. message[1] = mNum; // tn->midiNumber;
    7. message[2] = 100; //tn->velocity;
    8. midiout->sendMessage( &message );
    9. }
    To copy to clipboard, switch view to plain text mode 

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,013 Times in 4,791 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Replacing "busy wait" with QTimer

    So what causes the notes to start playing? The code looks like all notes will start playing at the same time (at the moment when you do the foreach loop) and will cause the noteOff() slot to be called multiple times with mNum set to the last note on the list.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  3. #3
    Join Date
    Sep 2011
    Posts
    19
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Replacing "busy wait" with QTimer

    The foreach loop sends the note -on message (// Note On: 144, 64, 90 - message[0] = 144 then I have a singleshot timer which repeatedly calls a routine that turns the notes off one at a time according to the ticks variable in the singleShot timer.


    Added after 1 8 minutes:


    I see what you mean now about the notes starting at the same time with the singleShot. With the SLEEP in place, it buffers the notes so that they play separately. I didn't take that into account. Your help in replacing this SLEEP function is appreciated. I've tried double timers staggered by the ticks variable but the starting problem remains. I found that you can't put a timer into a slot to call a slot, or at least I couldn't make it work. Is that possible? If it were possible to cascade the timers it would work I think.
    Last edited by devdon; 20th January 2012 at 00:28.

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,013 Times in 4,791 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Replacing "busy wait" with QTimer

    Do you want notes to play one after the other? If so then the most trivial approach would be:

    Qt Code:
    1. void X::startPlaying(QList<Note*> noteList) {
    2. m_notes = noteList;
    3. m_currentlyPlaying = 0;
    4. QTimer::singleShot(0, this, SLOT(playNextNote()));
    5.  
    6. }
    7.  
    8. void X::playNextNote() {
    9. if(m_currentlyPlaying) {
    10. // stop playing that note
    11. message[0] = 128;
    12. message[1] = m_currentlyPlaying->midiNumber;
    13. message[2] = 100; //tn->velocity;
    14. midiout->sendMessage( &message );
    15. delete m_currentlyPlaying;
    16. }
    17. // check if anything left to play
    18. if(m_notes.isEmpty()) {
    19. m_currentlyPlaying = 0;
    20. return;
    21. }
    22. // play next note
    23. m_currentlyPlaying = m_notes.first();
    24. m_notes.removeFirst();
    25. message[0] = 144;
    26. message[1] = m_currentlyPlaying->midiNumber;
    27. message[2] = m_currentlyPlaying->velocity;
    28. midiout->sendMessage( &message );
    29.  
    30. // schedule next note
    31. int ticks = m_currentlyPlaying->ticks * 125;
    32. QTimer::singleShot(ticks, this, SLOT(playNextNote()));
    33. }
    To copy to clipboard, switch view to plain text mode 

    If you want to introduce pauses, just make them special cases of Note and treat them properly in "play next note" part of the code (that is don't send the message).
    If you want multiple sounds at the same time then either have separate lists for each instrument or add a parameter to the structure that will differentiate between the finish offset of the current sound and beginning time of the next sound (e.g. setting it to 0 will make it play immediately).
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  5. #5
    Join Date
    Sep 2011
    Posts
    19
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Replacing "busy wait" with QTimer

    wysota,

    This looks interesting and I very much want to pursue it but my development computer crashed and I'm going to go ahead and wipe and reinstall on it so I'll have to get back to you later with results. Thanks for your help, I'll be back.

Similar Threads

  1. Replies: 1
    Last Post: 7th April 2010, 22:46
  2. Replies: 3
    Last Post: 15th February 2010, 18:27
  3. Replies: 3
    Last Post: 8th July 2008, 20:37
  4. Translation QFileDialog standart buttons ("Open"/"Save"/"Cancel")
    By victor.yacovlev in forum Qt Programming
    Replies: 4
    Last Post: 24th January 2008, 20:05
  5. QFile Problem~ "Unknow error" in "open(QIODevice::ReadWrite)"
    By fengtian.we in forum Qt Programming
    Replies: 3
    Last Post: 23rd May 2007, 16:58

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.