void CTrackList::refresh() { int chan; int rowCount = 0; m_trackQtList.clear(); for (chan = 0; chan < MAX_MIDI_CHANNELS; chan++) { if (m_midiActiveChannels[chan] == true) { CTrackListItem trackItem; trackItem.midiChannel = chan; m_trackQtList.append(trackItem); rowCount++; } } if (pianoPartConvetionTest()) { if (CNote::bothHandsChan() == -2 ) // -2 for not set -1 for not used CNote::setChannelHands(CONVENTION_LEFT_HAND_CHANNEL, CONVENTION_RIGHT_HAND_CHANNEL); m_song->setActiveChannel(CNote::bothHandsChan()); ppLogInfo("Active both"); } else { if (m_trackQtList.count() > 0) { m_song->setActiveChannel(m_trackQtList[0].midiChannel); } } if (CStavePos::getKeySignature() == NOT_USED) CStavePos::setKeySignature(guessKeySignature(CNote::rightHandChan(),CNote::leftHandChan()), 0); int goodChan = -1; // Find an unused channel that we can use for the keyboard for (chan = 0; chan < MAX_MIDI_CHANNELS; chan++) { if (m_midiActiveChannels[chan] == false) { if (goodChan != -1) { m_song->setPianistChannels(goodChan,chan); ppLogInfo("Using Pianist Channels %d + %d", goodChan +1, chan +1); return; } goodChan = chan; } } // As we have not returned we have not found to empty channels to use if (goodChan == -1) goodChan = 15 -1; m_song->setPianistChannels(goodChan,16-1); }
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(); }
// reads the real midi event CMidiEvent CMidiDeviceRt::readMidiInput() { CMidiEvent midiEvent; unsigned int channel; if (Cfg::midiInputDump) { QString str; for (unsigned int i = 0; i < m_inputMessage.size(); i++) str += " 0x" + QString::number(m_inputMessage[i], 16) + ','; ppLogInfo("midi input %s", qPrintable(str)); } channel = m_inputMessage[0] & 0x0f; switch (m_inputMessage[0] & 0xf0 ) { case MIDI_NOTE_ON: if (m_inputMessage[2] != 0 ) midiEvent.noteOnEvent(0, channel, m_inputMessage[1], m_inputMessage[2]); else midiEvent.noteOffEvent(0,channel, m_inputMessage[1], m_inputMessage[2]); break; case MIDI_NOTE_OFF: midiEvent.noteOffEvent(0, channel, m_inputMessage[1], m_inputMessage[2]); break; case MIDI_NOTE_PRESSURE: //MIDI_CMD_NOTE_PRESSURE: //POLY_AFTERTOUCH: // fixme fill in the blanks //midi_input_bytes[midi_input_length++] = channel | MIDI_CMD_NOTE_PRESSURE; //midi_input_bytes[midi_input_length++] = ev->data.note.note; //midi_input_bytes[midi_input_length++] = ev->data.note.velocity; break; case MIDI_CONTROL_CHANGE: //CONTROL_CHANGE: midiEvent.controlChangeEvent(0, channel, m_inputMessage[1], m_inputMessage[2]); break; case MIDI_PROGRAM_CHANGE: //PROGRAM_CHANGE: //midiEvent.programChangeEvent(0, ev->data.control.channel, ev->data.control.value); break; case MIDI_CHANNEL_PRESSURE: //AFTERTOUCH: // fixme fill in the blanks //midi_input_bytes[midi_input_length++] = ev->data.control.channel | MIDI_CMD_CHANNEL_PRESSURE; //midi_input_bytes[midi_input_length++] = ev->data.control.value; break; case MIDI_PITCH_BEND: //PITCH_BEND: // fixme fill in the blanks //midi_input_bytes[midi_input_length++] = ev->data.control.channel | MIDI_CMD_CHANNEL_PRESSURE; //midi_input_bytes[midi_input_length++] = ev->data.control.value; break; } m_inputMessage.clear(); return midiEvent; }
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(); } }
QtWindow::QtWindow() { QCoreApplication::setOrganizationName("Instrument-Trainer"); QCoreApplication::setOrganizationDomain("github.com/joshelser/Instrument-Trainer"); QCoreApplication::setApplicationName("Instrument Trainer"); m_settings = new CSettings(this); setWindowIcon(QIcon(":/images/Logo32x32.png")); setWindowTitle(tr("Instrument Trainer")); decodeCommandLine(); if (Cfg::experimentalSwapInterval != -1) { QGLFormat fmt; fmt.setSwapInterval(Cfg::experimentalSwapInterval); int value = fmt.swapInterval(); ppLogInfo("Open GL Swap Interval %d", value); QGLFormat::setDefaultFormat(fmt); } #if USE_REALTIME_PRIORITY int rt_prio = sched_get_priority_max(SCHED_FIFO); set_realtime_priority(SCHED_FIFO, rt_prio); #endif m_glWidget = new CGLView(this, m_settings); m_song = m_glWidget->getSongObject(); m_score = m_glWidget->getScoreObject(); QHBoxLayout *mainLayout = new QHBoxLayout; QVBoxLayout *columnLayout = new QVBoxLayout; m_sidePanel = new GuiSidePanel(this, m_settings); m_topBar = new GuiTopBar(this, m_settings); m_settings->init(m_song, m_sidePanel, m_topBar); mainLayout->addWidget(m_sidePanel); columnLayout->addWidget(m_topBar); columnLayout->addWidget(m_glWidget); mainLayout->addLayout(columnLayout); m_song->init(m_score, m_settings); m_glWidget->init(); m_sidePanel->init(m_song, m_song->getTrackList(), m_topBar); m_topBar->init(m_song, m_song->getTrackList()); createActions(); createMenus(); readSettings(); QWidget *centralWin = new QWidget(); centralWin->setLayout(mainLayout); setCentralWidget(centralWin); m_glWidget->setFocus(Qt::ActiveWindowFocusReason); m_song->setPianoSoundPatches(m_settings->value("Keyboard/RightSound", Cfg::defaultRightPatch()).toInt() - 1, m_settings->value("Keyboard/WrongSound", Cfg::defaultWrongPatch()).toInt() - 1, true); QString midiInputName = m_settings->value("Midi/Input").toString(); if (midiInputName.startsWith("None")) CChord::setPianoRange(PC_KEY_LOWEST_NOTE, PC_KEY_HIGHEST_NOTE); else CChord::setPianoRange(m_settings->value("Keyboard/LowestNote", 0).toInt(), m_settings->value("Keyboard/HighestNote", 127).toInt()); m_song->setLatencyFix(m_settings->value("Midi/Latency", 0).toInt()); #ifdef _WIN32 m_glWidget->m_cfg_openGlOptimise = true; // don't default to true on windows #else m_glWidget->m_cfg_openGlOptimise = true; // changed to default to false on platforms #endif m_glWidget->m_cfg_openGlOptimise = m_settings->value("Display/OpenGlOptimise", m_glWidget->m_cfg_openGlOptimise ).toBool(); m_song->cfg_timingMarkersFlag = m_settings->value("Score/TimingMarkers", m_song->cfg_timingMarkersFlag ).toBool(); m_song->cfg_stopPointMode = static_cast<stopPointMode_t> (m_settings->value("Score/StopPointMode", m_song->cfg_stopPointMode ).toInt()); m_song->openMidiPort(CMidiDevice::MIDI_INPUT, midiInputName); m_song->openMidiPort(CMidiDevice::MIDI_OUTPUT,m_settings->value("midi/output").toString()); m_settings->loadSettings(); show(); }