void CSong::loadSong(const QString & filename) { CNote::setChannelHands(-2, -2); // -2 for not set -1 for none m_songTitle = filename; int index = m_songTitle.lastIndexOf("/"); if (index >= 0) m_songTitle = m_songTitle.right( m_songTitle.length() - index - 1); QString fn = filename; #ifdef _WIN32 fn = fn.replace('/','\\'); #endif m_midiFile->setLogLevel(3); m_midiFile->openMidiFile(string(fn.toLatin1())); ppLogInfo("Opening song %s", string(fn.toLatin1()).c_str()); transpose(0); midiFileInfo(); m_midiFile->setLogLevel(99); playMusic(false); rewind(); setPlayFromBar(0.0); setLoopingBars(0.0); setEventBits(EVENT_BITS_playingStopped); if (!m_midiFile->getSongTitle().isEmpty()) m_songTitle = m_midiFile->getSongTitle(); }
void CConductor::followPlaying() { if ( m_playMode == PB_PLAY_MODE_listen ) return; if (m_wantedChord.length() == 0) fetchNextChord(); if (m_wantedChord.length() == 0) return; if (seekingBarNumber()) { if (deltaAdjust(m_chordDeltaTime) > -m_stopPoint ) fetchNextChord(); } else if ( m_playMode == PB_PLAY_MODE_followYou || m_playMode == PB_PLAY_MODE_rhythmTapping ) { if (deltaAdjust(m_chordDeltaTime) > -m_cfg_earlyNotesPoint ) m_followState = PB_FOLLOW_earlyNotes; if (deltaAdjust(m_chordDeltaTime) > -m_stopPoint ) { m_followState = PB_FOLLOW_waiting; // Throw away the time past the stop point (by adding a negative ticks) addDeltaTime( -m_stopPoint*SPEED_ADJUST_FACTOR - m_chordDeltaTime); } } else // m_playMode == PB_PLAY_MODE_playAlong { if (m_chordDeltaTime > m_cfg_playZoneLate ) { missedNotesColour(Cfg::playedStoppedColour()); fetchNextChord(); m_rating.lateNotes(m_wantedChord.length() - m_goodPlayedNotes.length()); setEventBits( EVENT_BITS_forceRatingRedraw); } } }
void CConductor::realTimeEngine(int mSecTicks) { int type; int ticks; // Midi ticks //mSecTicks = 2; // for debugging only ticks = m_tempo.mSecToTicks(mSecTicks); if (!m_followPlayingTimeOut) m_pianistTiming += ticks; while (checkMidiInput() > 0) expandPianistInput(readMidiInput()); if (getfollowState() == PB_FOLLOW_waiting ) { if (m_silenceTimeOut > 0) { m_silenceTimeOut -= mSecTicks; if (m_silenceTimeOut <= 0) { allSoundOff(); m_silenceTimeOut = 0; } } m_tempo.insertPlayingTicks(ticks); if (m_pianistTiming > m_cfg_playZoneLate) { if (m_followPlayingTimeOut == false) { m_followPlayingTimeOut = true; m_tempo.clearPlayingTicks(); m_rating.lateNotes(m_wantedChord.length() - m_goodPlayedNotes.length()); setEventBits( EVENT_BITS_forceRatingRedraw); missedNotesColour(Cfg::playedStoppedColour()); findImminentNotesOff(); // Don't keep any saved notes off if there are no notes down if (m_piano->pianistAllNotesDown() == 0) outputSavedNotesOff(); m_silenceTimeOut = Cfg::silenceTimeOut(); } } return; } m_silenceTimeOut = 0; if (m_playing == false) return; if (seekingBarNumber()) ticks = 0; m_tempo.adjustTempo(&ticks); ticks = m_bar.addDeltaTime(ticks); if (seekingBarNumber()) ticks = m_bar.goToBarNumer(); setEventBits( m_bar.readEventBits()); #if OPTION_DEBUG_CONDUCTOR if (m_realTimeEventBits | EVENT_BITS_newBarNumber) { ppDEBUG_CONDUCTOR(("m_savedNoteQueue %d m_playingDeltaTime %d",m_savedNoteQueue->space() , m_playingDeltaTime )); ppDEBUG_CONDUCTOR(("getfollowState() %d %d %d",getfollowState() , m_leadLagAdjust, m_songEventQueue->length() )); } #endif addDeltaTime(ticks); followPlaying(); while ( m_playingDeltaTime >= m_leadLagAdjust) { type = m_nextMidiEvent.type(); if (m_songEventQueue->length() == 0 && type == MIDI_PB_EOF) { ppLogInfo("The End of the song"); setEventBits(EVENT_BITS_playingStopped); m_playing = false; break; } if (type == MIDI_PB_tempo) { m_tempo.setMidiTempo(m_nextMidiEvent.data1()); m_leadLagAdjust = m_tempo.mSecToTicks( -getLatencyFix() ); } else if (type == MIDI_PB_timeSignature) { m_bar.setTimeSig(m_nextMidiEvent.data1(), m_nextMidiEvent.data2()); ppLogDebug("Midi Time Signature %d/%d", m_nextMidiEvent.data1(),m_nextMidiEvent.data2()); } else if ( type != MIDI_NONE ) // this marks the end of the piece of music { int channel = m_nextMidiEvent.channel(); // Is this this channel_muted if (!hasPianistKeyboardChannel(channel)) { if (getfollowState() >= PB_FOLLOW_earlyNotes && (m_playMode == PB_PLAY_MODE_followYou || m_playMode == PB_PLAY_MODE_rhythmTapping) && !seekingBarNumber() && m_followSkillAdvanced == false) { // Save up the notes until the pianist presses the right key if (m_savedNoteQueue->space()>0) m_savedNoteQueue->push(m_nextMidiEvent); else ppLogWarn("Warning the m_savedNoteQueue is full"); if (type == MIDI_NOTE_OFF) { if (m_savedNoteOffQueue->space()>0) m_savedNoteOffQueue->push(m_nextMidiEvent); else ppLogDebug("Warning the m_savedNoteOffQueue is full"); } } else { playTransposeEvent(m_nextMidiEvent); // Play the midi note or event ppDEBUG_CONDUCTOR(("playEvent() chan %d type %d note %d", m_nextMidiEvent.channel() , m_nextMidiEvent.type() , m_nextMidiEvent.note(), m_songEventQueue->length() )); } } } if (m_songEventQueue->length() > 0) m_nextMidiEvent = m_songEventQueue->pop(); else { ppDEBUG_CONDUCTOR(("no data in song queue")); m_nextMidiEvent.clear(); break; } m_playingDeltaTime -= m_nextMidiEvent.deltaTime() * SPEED_ADJUST_FACTOR; followPlaying(); } }
void CConductor::pianistInput(CMidiEvent inputNote) { bool goodSound = true; // inputNote.transpose(+12); fixme if (m_testWrongNoteSound) goodSound = false; whichPart_t hand; hand = (inputNote.note() >= m_pianistSplitPoint)? PB_PART_right : PB_PART_left; // for rhythm tapping if ( inputNote.channel() == MIDI_DRUM_CHANNEL) hand = (inputNote.note() >= MIDDLE_C) ? PB_PART_right : PB_PART_left; if (inputNote.type() == MIDI_NOTE_ON) { if ( validatePianistNote(inputNote) == true) { m_goodPlayedNotes.addNote(hand, inputNote.note()); m_piano->addPianistNote(hand, inputNote,true); int pianistTiming; if ( ( cfg_timingMarkersFlag && m_followSkillAdvanced ) || m_playMode == PB_PLAY_MODE_rhythmTapping ) pianistTiming = m_pianistTiming; else pianistTiming = NOT_USED; m_scoreWin->setPlayedNoteColour(inputNote.note(), (!m_followPlayingTimeOut)? Cfg::playedGoodColour():Cfg::playedBadColour(), m_chordDeltaTime, pianistTiming); if (validatePianistChord() == true) { if (m_chordDeltaTime < 0) m_tempo.removePlayingTicks(-m_chordDeltaTime); m_goodPlayedNotes.clear(); fetchNextChord(); // count the good notes so that the live percentage looks OK m_rating.totalNotes(m_wantedChord.length()); m_rating.calculateAccuracy(); m_settings->pianistActive(); if (m_rating.isAccuracyGood() || m_playMode == PB_PLAY_MODE_playAlong) setFollowSkillAdvanced(true); // change the skill level only when they are good enough else setFollowSkillAdvanced(false); setEventBits( EVENT_BITS_forceRatingRedraw); } } else { if (m_playing == true) { goodSound = false; m_piano->addPianistNote(hand, inputNote, false); m_rating.wrongNotes(1); } else m_piano->addPianistNote(hand, inputNote, true); } } else if (inputNote.type() == MIDI_NOTE_OFF) { if (m_piano->removePianistNote(inputNote.note()) == true) goodSound = false; bool hasNote = m_goodPlayedNotes.removeNote(inputNote.note()); if (hasNote) m_scoreWin->setPlayedNoteColour(inputNote.note(), (!m_followPlayingTimeOut)? Cfg::noteColour():Cfg::playedStoppedColour(), m_chordDeltaTime); outputSavedNotesOff(); } if ( inputNote.velocity() == -1 ) return; if (goodSound == true || m_cfg_wrongNoteSound < 0) { if (m_cfg_rightNoteSound >= 0) // don't play anything if the sound is set to -1 (none) { bool playDrumBeat = false; if ( inputNote.channel() != MIDI_DRUM_CHANNEL) { if (cfg_rhythmTapping != PB_RHYTHM_TAP_drumsOnly || m_playMode != PB_PLAY_MODE_rhythmTapping) { inputNote.setChannel(m_pianistGoodChan); playTrackEvent( inputNote ); } } else { playDrumBeat = true; } if (cfg_rhythmTapping != PB_RHYTHM_TAP_mellodyOnly && m_playMode == PB_PLAY_MODE_rhythmTapping) playDrumBeat = true; if (playDrumBeat) { inputNote.setChannel(MIDI_DRUM_CHANNEL); ppLogTrace("note %d", inputNote.note()); inputNote.setNote((hand == PB_PART_right)? m_cfg_rhythmTapRightHandDrumSound : m_cfg_rhythmTapLeftHandDrumSound); playTrackEvent( inputNote ); } } } else { inputNote.setChannel(m_pianistBadChan); if (m_playMode == PB_PLAY_MODE_rhythmTapping) { inputNote.setChannel(MIDI_DRUM_CHANNEL); ppLogTrace("note %d", inputNote.note()); inputNote.setNote((hand == PB_PART_right)? m_cfg_rhythmTapRightHandDrumSound : m_cfg_rhythmTapLeftHandDrumSound); } playTrackEvent( inputNote ); } /* // use the same channel for the right and wrong note int pianoSound = (goodSound == true) ? m_cfg_rightNoteSound : m_cfg_wrongNoteSound; if (pianoSound != m_lastSound) { m_lastSound = pianoSound; CMidiEvent midiSound; midiSound.programChangeEvent(0,inputNote.channel(),pianoSound); playTrackEvent( midiSound ); } */ }
void CConductor::pianistInput(CMidiEvent inputNote) { bool goodSound = true; if (m_testWrongNoteSound) goodSound = false; if (inputNote.type() == MIDI_NOTE_ON) { whichPart_t hand; hand = (inputNote.note() >= m_pianistSplitPoint)? PB_PART_right : PB_PART_left; if ( validatePianistNote(inputNote) == true) { m_goodPlayedNotes.addNote(hand, inputNote.note()); m_piano->addPianistNote(hand, inputNote.note(),true); int pianistTiming = ( cfg_timingMarkersFlag && m_followSkillAdvanced) ? m_pianistTiming : NOT_USED; m_scoreWin->setPlayedNoteColour(inputNote.note(), (!m_followPlayingTimeOut)? Cfg::playedGoodColour():Cfg::playedBadColour(), m_chordDeltaTime, pianistTiming); if (validatePianistChord() == true) { if (m_chordDeltaTime < 0) m_tempo.removePlayingTicks(-m_chordDeltaTime); m_goodPlayedNotes.clear(); fetchNextChord(); // count the good notes so that the live percentage looks OK m_rating.totalNotes(m_wantedChord.length()); m_rating.calculateAccuracy(); m_settings->pianistActive(); if (m_rating.isAccuracyGood() || m_playMode == PB_PLAY_MODE_playAlong) setFollowSkillAdvanced(true); // change the skill level only when they are good enough else setFollowSkillAdvanced(false); setEventBits( EVENT_BITS_forceRatingRedraw); } } else { if (m_playing == true) { goodSound = false; m_piano->addPianistNote(hand, inputNote.note(), false); m_rating.wrongNotes(1); } else m_piano->addPianistNote(hand, inputNote.note(), true); } } else if (inputNote.type() == MIDI_NOTE_OFF) { if (m_piano->removePianistNote(inputNote.note()) == true) goodSound = false; bool hasNote = m_goodPlayedNotes.removeNote(inputNote.note()); if (hasNote) m_scoreWin->setPlayedNoteColour(inputNote.note(), (!m_followPlayingTimeOut)? Cfg::noteColour():Cfg::playedStoppedColour(), m_chordDeltaTime); outputSavedNotesOff(); } if (goodSound == true || m_cfg_wrongNoteSound < 0) { if (m_cfg_rightNoteSound >= 0) // don't play anything if the sound is set to -1 (none) { inputNote.setChannel(m_pianistGoodChan); playMidiEvent( inputNote ); } } else { inputNote.setChannel(m_pianistBadChan); playMidiEvent( inputNote ); } /* // use the same channel for the right and wrong note int pianoSound = (goodSound == true) ? m_cfg_rightNoteSound : m_cfg_wrongNoteSound; if (pianoSound != m_lastSound) { m_lastSound = pianoSound; CMidiEvent midiSound; midiSound.programChangeEvent(0,inputNote.channel(),pianoSound); playMidiEvent( midiSound ); } */ }