void Synthesiser::handleMidiEvent (const MidiMessage& m) { if (m.isNoteOn()) { noteOn (m.getChannel(), m.getNoteNumber(), m.getFloatVelocity()); } else if (m.isNoteOff()) { noteOff (m.getChannel(), m.getNoteNumber(), true); } else if (m.isAllNotesOff() || m.isAllSoundOff()) { allNotesOff (m.getChannel(), true); } else if (m.isPitchWheel()) { const int channel = m.getChannel(); const int wheelPos = m.getPitchWheelValue(); lastPitchWheelValues [channel - 1] = wheelPos; handlePitchWheel (channel, wheelPos); } else if (m.isController()) { handleController (m.getChannel(), m.getControllerNumber(), m.getControllerValue()); } }
void ISynth::sysexSoundFont(SfOp op, const char* data) { char c = 'x'; allNotesOff(); switch(op) { case SF_REMOVE: break; case SF_REPLACE: case SF_ADD: if (sfont && (strcmp(sfont, data) == 0)) { #ifdef FS_DEBUG fprintf(stderr, "fluid: font already loaded\n"); #endif break; } if (_busy) { //#ifdef FS_DEBUG fprintf(stderr, "fluid: busy!\n"); //#endif break; } _busy = true; if (sfont) delete[] sfont; sfont = new char[strlen(data)+1]; strcpy(sfont, data); _busy = true; write(writeFd, &c, 1); break; } }
bool MidiParser::setTrack(int track) { if (track < 0 || track >= _num_tracks) return false; // We allow restarting the track via setTrack when // it isn't playing anymore. This allows us to reuse // a MidiParser when a track has finished and will // be restarted via setTrack by the client again. // This isn't exactly how setTrack behaved before though, // the old MidiParser code did not allow setTrack to be // used to restart a track, which was already finished. // // TODO: Check if any engine has problem with this // handling, if so we need to find a better way to handle // track restarts. (KYRA relies on this working) else if (track == _active_track && isPlaying()) return true; if (_smartJump) hangAllActiveNotes(); else allNotesOff(); resetTracking(); memset(_active_notes, 0, sizeof(_active_notes)); _active_track = track; _position._play_pos = _tracks[track]; parseNextEvent(_next_event); return true; }
void MidiSequencer::stop() { m_midiSequencerOutputThread->stop(); m_midiSequencerOutputThread->resetPosition(); emit allNotesOff(); emit timeLabelChanged("00:00.00"); }
//============================================================================== void Synthesiser::setCurrentPlaybackSampleRate (const double newRate) { if (sampleRate != newRate) { const ScopedLock sl (lock); allNotesOff (0, false); sampleRate = newRate; for (auto* voice : voices) voice->setCurrentPlaybackSampleRate (newRate); } }
//============================================================================== void Synthesiser::setCurrentPlaybackSampleRate (const double newRate) { if (sampleRate != newRate) { const ScopedLock sl (lock); allNotesOff (0, false); sampleRate = newRate; for (int i = voices.size(); --i >= 0;) voices.getUnchecked (i)->setCurrentPlaybackSampleRate (newRate); } }
void MidiKeyboardState::allNotesOff (const int midiChannel) { const ScopedLock sl (lock); if (midiChannel <= 0) { for (int i = 1; i <= 16; ++i) allNotesOff (i); } else { for (int i = 0; i < 128; ++i) noteOff (midiChannel, i, 0.0f); } }
void PlayerHandler::process(const jack_nframes_t nframes) { void* outPortBuf = jack_port_get_buffer(m_outputPort, nframes); jack_midi_clear_buffer(outPortBuf); jack_position_t pos; const jack_transport_state_t state = jack_transport_query(m_client, &pos); switch (state) { case JackTransportStopped: { if (m_previousState != state) { // stop them all now allNotesOff(outPortBuf, 0); // reset position m_position = 0; } break; } case JackTransportRolling: { const jack_nframes_t framesAtStart = jack_last_frame_time(m_client); const jack_nframes_t lastFrame = framesAtStart + nframes; const jack_nframes_t startFrame = framesAtStart - pos.frame; while (m_position < m_master.size() && startFrame + m_master[m_position].m_time >= framesAtStart && startFrame + m_master[m_position].m_time < lastFrame) { const MidiEvent & event = m_master[m_position]; const jack_nframes_t newOffset = event.m_time - pos.frame; jack_midi_event_write(outPortBuf, newOffset, event.m_data, event.m_size); noteChange(event.m_data); ++m_position; } break; } default: { break; } } m_previousState = state; }
void MidiParser::unloadMusic() { resetTracking(); allNotesOff(); _num_tracks = 0; _active_track = 255; _abort_parse = true; if (_centerPitchWheelOnUnload) { // Center the pitch wheels in preparation for the next piece of // music. It's not safe to do this from within allNotesOff(), // and might not even be safe here, so we only do it if the // client has explicitly asked for it. if (_driver) { for (int i = 0; i < 16; ++i) { sendToDriver(0xE0 | i, 0, 0x40); } } } }
void MidiInputController::setModePolyphonic(int maxPolyphony) { // First turn off any notes in the current mode allNotesOff(); removeAllOscListeners(); // Register a callback for touchkey data. When we get a note-on message, // we request this callback occur once touch data is available. In this mode, // we know the eventual channel before any touch data ever occurs: thus, we // only listen to the MIDI onset itself, which happens after all the touch // data is sent out. addOscListener("/midi/noteon"); mode_ = ModePolyphonic; retransmitMaxPolyphony_ = maxPolyphony; if(retransmitMaxPolyphony_ > 16) retransmitMaxPolyphony_ = 16; // Limit polyphony to 16 (number of MIDI channels for(int i = 0; i < retransmitMaxPolyphony_; i++) retransmitChannelsAvailable_.insert(i); retransmitChannelForNote_.clear(); }
void Synthesiser::handleMidiEvent (const MidiMessage& m) { const int channel = m.getChannel(); if (m.isNoteOn()) { noteOn (channel, m.getNoteNumber(), m.getFloatVelocity()); } else if (m.isNoteOff()) { noteOff (channel, m.getNoteNumber(), m.getFloatVelocity(), true); } else if (m.isAllNotesOff() || m.isAllSoundOff()) { allNotesOff (channel, true); } else if (m.isPitchWheel()) { const int wheelPos = m.getPitchWheelValue(); lastPitchWheelValues [channel - 1] = wheelPos; handlePitchWheel (channel, wheelPos); } else if (m.isAftertouch()) { handleAftertouch (channel, m.getNoteNumber(), m.getAfterTouchValue()); } else if (m.isChannelPressure()) { handleChannelPressure (channel, m.getChannelPressureValue()); } else if (m.isController()) { handleController (channel, m.getControllerNumber(), m.getControllerValue()); } else if (m.isProgramChange()) { handleProgramChange (channel, m.getProgramChangeNumber()); } }
void MidiInputController::setModeChannelSelect(int switchType, int numDivisions, int defaultChannel) { // First turn off any notes in the current mode allNotesOff(); removeAllOscListeners(); // Register a callback for touchkey data. When we get a note-on message, // we request this callback occur once touch data is available. In this mode, we // need to know about the touch before we can decide the channel, so we listen to both // pre-onset and onset messages addOscListener("/touchkeys/preonset"); addOscListener("/midi/noteon"); mode_ = ModeChannelSelect; channelSelectSwitchType_ = switchType; channelSelectNumberOfDivisions_ = numDivisions; channelSelectDefaultChannel_ = defaultChannel; if(channelSelectNumberOfDivisions_ < 1) channelSelectNumberOfDivisions_ = 1; if(channelSelectDefaultChannel_ >= channelSelectNumberOfDivisions_) channelSelectDefaultChannel_ = channelSelectNumberOfDivisions_ - 1; retransmitChannelForNote_.clear(); channelSelectLastOnsetChannel_ = 0; }
void MidiInputController::setModePassThrough() { allNotesOff(); removeAllOscListeners(); mode_ = ModePassThrough; }
bool MidiParser::jumpToTick(uint32 tick, bool fireEvents, bool stopNotes, bool dontSendNoteOn) { if (_active_track >= _num_tracks) return false; Tracker currentPos(_position); EventInfo currentEvent(_next_event); resetTracking(); _position._play_pos = _tracks[_active_track]; parseNextEvent(_next_event); if (tick > 0) { while (true) { EventInfo &info = _next_event; if (_position._last_event_tick + info.delta >= tick) { _position._play_time += (tick - _position._last_event_tick) * _psec_per_tick; _position._play_tick = tick; break; } _position._last_event_tick += info.delta; _position._last_event_time += info.delta * _psec_per_tick; _position._play_tick = _position._last_event_tick; _position._play_time = _position._last_event_time; if (info.event == 0xFF) { if (info.ext.type == 0x2F) { // End of track _position = currentPos; _next_event = currentEvent; return false; } else { if (info.ext.type == 0x51 && info.length >= 3) // Tempo setTempo(info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2]); if (fireEvents) _driver->metaEvent(info.ext.type, info.ext.data, (uint16) info.length); } } else if (fireEvents) { if (info.event == 0xF0) { if (info.ext.data[info.length-1] == 0xF7) _driver->sysEx(info.ext.data, (uint16)info.length-1); else _driver->sysEx(info.ext.data, (uint16)info.length); } else { // The note on sending code is used by the SCUMM engine. Other engine using this code // (such as SCI) have issues with this, as all the notes sent can be heard when a song // is fast-forwarded. Thus, if the engine requests it, don't send note on events. if (info.command() == 0x9 && dontSendNoteOn) { // Don't send note on; doing so creates a "warble" with some instruments on the MT-32. // Refer to patch #3117577 } else { sendToDriver(info.event, info.basic.param1, info.basic.param2); } } } parseNextEvent(_next_event); } } if (stopNotes) { if (!_smartJump || !currentPos._play_pos) { allNotesOff(); } else { EventInfo targetEvent(_next_event); Tracker targetPosition(_position); _position = currentPos; _next_event = currentEvent; hangAllActiveNotes(); _next_event = targetEvent; _position = targetPosition; } } _abort_parse = true; return true; }
void MidiParser::stopPlaying() { allNotesOff(); resetTracking(); }
int OscController::handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *data) { bool matched = false; #ifdef DEBUG_MESSAGES_EXTRA cout << "Received OSC message " << path << " [" << types << "]\n"; #endif if(useOscMidi_) // OSC MIDI emulation. Also the most time-sensitive & frequent message so do this first. { if(!strcmp(path, "/mrp/midi") && argc >= 1) { if(types[0] == 'm') return handleMidi(argv[0]->m[1], argv[0]->m[2], argv[0]->m[3]); if(argc >= 3) if(types[0] == 'i' && types[1] == 'i' && types[2] == 'i') return handleMidi((unsigned char)argv[0]->i, (unsigned char)argv[1]->i, (unsigned char)argv[2]->i); } if(!strcmp(path, "/mrp/quality/brightness") && argc >= 3) { if(types[0] == 'i' && types[1] == 'i' && types[2] == 'f') return handleRtBrightness(argv); } if(!strcmp(path, "/mrp/quality/intensity") && argc >= 3) { if(types[0] == 'i' && types[1] == 'i' && types[2] == 'f') return handleRtIntensity(argv); } if(!strcmp(path, "/mrp/quality/pitch") && argc >= 3) { if(types[0] == 'i' && types[1] == 'i' && types[2] == 'f') return handleRtPitch(argv); } if(!strcmp(path, "/mrp/quality/pitch/vibrato") && argc >= 3) { if(types[0] == 'i' && types[1] == 'i' && types[2] == 'f') return handleRtPitchVibrato(argv); } if(!strcmp(path, "/mrp/quality/harmonic") && argc >= 3) { if(types[0] == 'i' && types[1] == 'i' && types[2] == 'f') return handleRtHarmonic(argv); } if(!strcmp(path, "/mrp/quality/harmonics/raw") && argc >= 3) { if(types[0] == 'i' && types[1] == 'i' && types[2] == 'f') return handleRtHarmonicsRaw(argc, types, argv); } if(!strcmp(path, "/mrp/volume") && argc >= 1) { if(types[0] == 'f') { cout << "setting volume to " << argv[0]->f << endl; midiController_->render_->setGlobalAmplitude(argv[0]->f); return 0; } } if(!strcmp(path, "/mrp/global/harmonics") && argc == 2) { if(types[0] == 'i' || types[1] == 'f') midiController_->oscHandleGlobalParameters(path, types, 2, argv, data); } if(!strcmp(path, "/mrp/allnotesoff")) { allNotesOff(); } } string pathString(path); if(useThru_) { // Rebroadcast any matching messages if(!pathString.compare(0, thruPrefix_.length(), thruPrefix_)) lo_send_message(thruAddress_, path, msg); } // Check if the incoming message matches the global prefix for this program. If not, discard it. if(pathString.compare(0, globalPrefix_.length(), globalPrefix_)) { cout << "OSC message '" << path << "' received\n"; return 1; } // Lock the mutex so the list of listeners doesn't change midway through pthread_mutex_lock(&oscListenerMutex_); // Now remove the global prefix and compare the rest of the message to the registered handlers. multimap<string, OscHandler*>::iterator it; pair<multimap<string, OscHandler*>::iterator,multimap<string, OscHandler*>::iterator> ret; string truncatedPath = pathString.substr(globalPrefix_.length(), pathString.length() - globalPrefix_.length()); ret = noteListeners_.equal_range(truncatedPath); it = ret.first; while(it != ret.second) { OscHandler *object = (*it++).second; #ifdef DEBUG_MESSAGES_EXTRA cout << "Matched OSC path '" << path << "' to handler " << object << endl; #endif object->oscHandlerMethod(truncatedPath.c_str(), types, argc, argv, data); matched = true; } pthread_mutex_unlock(&oscListenerMutex_); if(matched) // This message has been handled return 0; printf("Unhandled OSC path: <%s>\n", path); /*#ifdef DEBUG_MESSAGES for (i=0; i<argc; i++) { printf("arg %d '%c' ", i, types[i]); lo_arg_pp((lo_type)types[i], argv[i]); printf("\n"); } #endif*/ return 1; }
bool MidiParser::jumpToTick(uint32 tick, bool fireEvents) { if (_active_track >= _num_tracks) return false; Tracker currentPos(_position); EventInfo currentEvent(_next_event); resetTracking(); _position._play_pos = _tracks[_active_track]; parseNextEvent(_next_event); if (tick > 0) { while (true) { EventInfo &info = _next_event; if (_position._last_event_tick + info.delta >= tick) { _position._play_time += (tick - _position._last_event_tick) * _psec_per_tick; _position._play_tick = tick; break; } _position._last_event_tick += info.delta; _position._last_event_time += info.delta * _psec_per_tick; _position._play_tick = _position._last_event_tick; _position._play_time = _position._last_event_time; if (info.event == 0xFF) { if (info.ext.type == 0x2F) { // End of track _position = currentPos; _next_event = currentEvent; return false; } else { if (info.ext.type == 0x51 && info.length >= 3) // Tempo setTempo(info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2]); if (fireEvents) _driver->metaEvent(info.ext.type, info.ext.data, (uint16) info.length); } } else if (fireEvents) { if (info.event == 0xF0) { if (info.ext.data[info.length-1] == 0xF7) _driver->sysEx(info.ext.data, (uint16)info.length-1); else _driver->sysEx(info.ext.data, (uint16)info.length); } else _driver->send(info.event, info.basic.param1, info.basic.param2); } parseNextEvent(_next_event); } } if (!_smartJump || !currentPos._play_pos) { allNotesOff(); } else { EventInfo targetEvent(_next_event); Tracker targetPosition(_position); _position = currentPos; _next_event = currentEvent; hangAllActiveNotes(); _next_event = targetEvent; _position = targetPosition; } _abort_parse = true; return true; }
void MidiInputController::setModeOff() { allNotesOff(); removeAllOscListeners(); mode_ = ModeOff; }
void MidiSequencer::setPitchShift(unsigned int value) { m_midiSequencerOutputThread->setPitchShift(value); emit allNotesOff(); emit pitchChanged(value); }
void MidiParser_SH::parseNextEvent(EventInfo &info) { Common::StackLock lock(_mutex); // warning("parseNextEvent"); // there is no delta right at the start of the music data // this order is essential, otherwise notes will get delayed or even go missing if (_position._playPos != _tracks[0]) { info.delta = *(_position._playPos++); } else { info.delta = 0; } info.start = _position._playPos; info.event = *_position._playPos++; //warning("Event %x", info.event); _position._runningStatus = info.event; switch (info.command()) { case 0xC: { // program change int idx = *_position._playPos++; info.basic.param1 = idx & 0x7f; info.basic.param2 = 0; } break; case 0xD: info.basic.param1 = *_position._playPos++; info.basic.param2 = 0; break; case 0xB: info.basic.param1 = *_position._playPos++; info.basic.param2 = *_position._playPos++; info.length = 0; break; case 0x8: case 0x9: case 0xA: case 0xE: info.basic.param1 = *(_position._playPos++); info.basic.param2 = *(_position._playPos++); if (info.command() == 0x9 && info.basic.param2 == 0) { // NoteOn with param2==0 is a NoteOff info.event = info.channel() | 0x80; } info.length = 0; break; case 0xF: if (info.event == 0xFF) { error("SysEx META event 0xFF"); byte type = *(_position._playPos++); switch(type) { case 0x2F: // End of Track allNotesOff(); stopPlaying(); unloadMusic(); return; case 0x51: warning("TODO: 0xFF / 0x51"); return; default: warning("TODO: 0xFF / %x Unknown", type); break; } } else if (info.event == 0xFC) { // Official End-Of-Track signal debugC(kDebugLevelMusic, "Music: System META event 0xFC"); byte type = *(_position._playPos++); switch (type) { case 0x80: // end of track, triggers looping debugC(kDebugLevelMusic, "Music: META event triggered looping"); jumpToTick(0, true, true, false); break; case 0x81: // end of track, stop playing debugC(kDebugLevelMusic, "Music: META event triggered music stop"); stopPlaying(); unloadMusic(); break; default: error("MidiParser_SH::parseNextEvent: Unknown META event 0xFC type %x", type); break; } } else { warning("TODO: %x / Unknown", info.event); break; } break; default: warning("MidiParser_SH::parseNextEvent: Unsupported event code %x", info.event); break; }// switch (info.command()) }
void VPiano::slotPanic() { allNotesOff(); }
void Zerberus::allSoundsOff(int channel) { allNotesOff(channel); }
void ISynth::gmOn(bool flag) { _gmMode = flag; allNotesOff(); }