--- linuxsampler/trunk/src/engines/gig/EngineChannel.cpp 2005/09/26 10:17:00 781 +++ linuxsampler/trunk/src/engines/gig/EngineChannel.cpp 2006/11/27 21:34:55 947 @@ -3,7 +3,7 @@ * LinuxSampler - modular, streaming capable sampler * * * * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * - * Copyright (C) 2005 Christian Schoenebeck * + * Copyright (C) 2005, 2006 Christian Schoenebeck * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -48,6 +48,9 @@ pMidiInputPort = NULL; midiChannel = midi_chan_all; ResetControllers(); + SoloMode = false; + PortamentoMode = false; + PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT; } EngineChannel::~EngineChannel() { @@ -108,6 +111,8 @@ pMIDIKeyInfo[i].itSelf = Pool::Iterator(); pMIDIKeyInfo[i].VoiceTheftsQueued = 0; } + SoloKey = -1; // no solo key active yet + PortamentoPos = -1.0f; // no portamento active yet // reset all key groups std::map::iterator iter = ActiveKeyGroups.begin(); @@ -171,9 +176,9 @@ // request gig instrument from instrument manager try { - instrument_id_t instrid; - instrid.FileName = InstrumentFile; - instrid.iInstrument = InstrumentIdx; + InstrumentManager::instrument_id_t instrid; + instrid.FileName = InstrumentFile; + instrid.Index = InstrumentIdx; pInstrument = Engine::instruments.Borrow(instrid, this); if (!pInstrument) { InstrumentStat = -1; @@ -184,16 +189,16 @@ catch (RIFF::Exception e) { InstrumentStat = -2; String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message; - throw LinuxSamplerException(msg); + throw Exception(msg); } catch (InstrumentResourceManagerException e) { InstrumentStat = -3; String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message(); - throw LinuxSamplerException(msg); + throw Exception(msg); } catch (...) { InstrumentStat = -4; - throw LinuxSamplerException("gig::Engine error: Failed to load instrument, cause: Unknown exception while trying to parse gig file."); + throw Exception("gig::Engine error: Failed to load instrument, cause: Unknown exception while trying to parse gig file."); } // rebuild ActiveKeyGroups map with key groups of current instrument @@ -210,7 +215,7 @@ } catch (AudioOutputException e) { String msg = "Audio output device unable to provide 2 audio channels, cause: " + e.Message(); - throw LinuxSamplerException(msg); + throw Exception(msg); } if (pEngine) pEngine->Enable(); @@ -266,6 +271,7 @@ AudioDeviceChannelRight = 1; pOutputLeft = pAudioOut->Channel(0)->Buffer(); pOutputRight = pAudioOut->Channel(1)->Buffer(); + MidiInputPort::AddSysexListener(pEngine); } void EngineChannel::DisconnectAudioOutputDevice() { @@ -348,7 +354,9 @@ /** * Will be called by the MIDIIn Thread to let the audio thread trigger a new - * voice for the given key. + * voice for the given key. This method is meant for real time rendering, + * that is an event will immediately be created with the current system + * time as time stamp. * * @param Key - MIDI key number of the triggered key * @param Velocity - MIDI velocity value of the triggered key @@ -366,8 +374,36 @@ } /** + * Will be called by the MIDIIn Thread to let the audio thread trigger a new + * voice for the given key. This method is meant for offline rendering + * and / or for cases where the exact position of the event in the current + * audio fragment is already known. + * + * @param Key - MIDI key number of the triggered key + * @param Velocity - MIDI velocity value of the triggered key + * @param FragmentPos - sample point position in the current audio + * fragment to which this event belongs to + */ + void EngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, int32_t FragmentPos) { + if (FragmentPos < 0) { + dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!")); + } + else if (pEngine) { + Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos); + event.Type = Event::type_note_on; + event.Param.Note.Key = Key; + event.Param.Note.Velocity = Velocity; + event.pEngineChannel = this; + if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); + else dmsg(1,("EngineChannel: Input event queue full!")); + } + } + + /** * Will be called by the MIDIIn Thread to signal the audio thread to release - * voice(s) on the given key. + * voice(s) on the given key. This method is meant for real time rendering, + * that is an event will immediately be created with the current system + * time as time stamp. * * @param Key - MIDI key number of the released key * @param Velocity - MIDI release velocity value of the released key @@ -385,8 +421,36 @@ } /** + * Will be called by the MIDIIn Thread to signal the audio thread to release + * voice(s) on the given key. This method is meant for offline rendering + * and / or for cases where the exact position of the event in the current + * audio fragment is already known. + * + * @param Key - MIDI key number of the released key + * @param Velocity - MIDI release velocity value of the released key + * @param FragmentPos - sample point position in the current audio + * fragment to which this event belongs to + */ + void EngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, int32_t FragmentPos) { + if (FragmentPos < 0) { + dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!")); + } + else if (pEngine) { + Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos); + event.Type = Event::type_note_off; + event.Param.Note.Key = Key; + event.Param.Note.Velocity = Velocity; + event.pEngineChannel = this; + if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); + else dmsg(1,("EngineChannel: Input event queue full!")); + } + } + + /** * Will be called by the MIDIIn Thread to signal the audio thread to change - * the pitch value for all voices. + * the pitch value for all voices. This method is meant for real time + * rendering, that is an event will immediately be created with the + * current system time as time stamp. * * @param Pitch - MIDI pitch value (-8192 ... +8191) */ @@ -402,8 +466,34 @@ } /** + * Will be called by the MIDIIn Thread to signal the audio thread to change + * the pitch value for all voices. This method is meant for offline + * rendering and / or for cases where the exact position of the event in + * the current audio fragment is already known. + * + * @param Pitch - MIDI pitch value (-8192 ... +8191) + * @param FragmentPos - sample point position in the current audio + * fragment to which this event belongs to + */ + void EngineChannel::SendPitchbend(int Pitch, int32_t FragmentPos) { + if (FragmentPos < 0) { + dmsg(1,("EngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!")); + } + else if (pEngine) { + Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos); + event.Type = Event::type_pitchbend; + event.Param.Pitch.Pitch = Pitch; + event.pEngineChannel = this; + if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); + else dmsg(1,("EngineChannel: Input event queue full!")); + } + } + + /** * Will be called by the MIDIIn Thread to signal the audio thread that a - * continuous controller value has changed. + * continuous controller value has changed. This method is meant for real + * time rendering, that is an event will immediately be created with the + * current system time as time stamp. * * @param Controller - MIDI controller number of the occured control change * @param Value - value of the control change @@ -420,6 +510,32 @@ } } + /** + * Will be called by the MIDIIn Thread to signal the audio thread that a + * continuous controller value has changed. This method is meant for + * offline rendering and / or for cases where the exact position of the + * event in the current audio fragment is already known. + * + * @param Controller - MIDI controller number of the occured control change + * @param Value - value of the control change + * @param FragmentPos - sample point position in the current audio + * fragment to which this event belongs to + */ + void EngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, int32_t FragmentPos) { + if (FragmentPos < 0) { + dmsg(1,("EngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!")); + } + else if (pEngine) { + Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos); + event.Type = Event::type_control_change; + event.Param.CC.Controller = Controller; + event.Param.CC.Value = Value; + event.pEngineChannel = this; + if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); + else dmsg(1,("EngineChannel: Input event queue full!")); + } + } + void EngineChannel::ClearEventLists() { pEvents->clear(); // empty MIDI key specific event lists @@ -437,10 +553,11 @@ SustainPedal = false; SostenutoPedal = false; GlobalVolume = CONFIG_GLOBAL_ATTENUATION; + MidiVolume = 1.0; GlobalPanLeft = 1.0f; GlobalPanRight = 1.0f; // set all MIDI controller values to zero - memset(ControllerTable, 0x00, 128); + memset(ControllerTable, 0x00, 129); } /**