1 /*************************************************************************** 2 * * 3 * LinuxSampler - modular, streaming capable sampler * 4 * * 5 * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck * 6 * Copyright (C) 2005-2009 Christian Schoenebeck * 7 * Copyright (C) 2009 - 2012 Christian Schoenebeck and Grigor Iliev * 8 * Copyright (C) 2012 - 2016 Christian Schoenebeck and Andreas Persson * 9 * * 10 * This program is free software; you can redistribute it and/or modify * 11 * it under the terms of the GNU General Public License as published by * 12 * the Free Software Foundation; either version 2 of the License, or * 13 * (at your option) any later version. * 14 * * 15 * This program is distributed in the hope that it will be useful, * 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 * GNU General Public License for more details. * 19 * * 20 * You should have received a copy of the GNU General Public License * 21 * along with this program; if not, write to the Free Software * 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * 23 * MA 02111-1307 USA * 24 ***************************************************************************/ 25 26 #include "EngineChannel.h" 27 #include "Engine.h" 28 29 namespace LinuxSampler { namespace sf2 { EngineChannel()30 EngineChannel::EngineChannel() { 31 for(int i = 0; i < 128; i++) PressedKeys[i] = false; 32 LastKey = LastKeySwitch = -1; 33 } 34 ~EngineChannel()35 EngineChannel::~EngineChannel() { 36 DisconnectAudioOutputDevice(); 37 // In case the channel was removed before the instrument was 38 // fully loaded, try to give back instrument again (see bug #113) 39 InstrumentChangeCmd< ::sf2::Region, ::sf2::Preset>& cmd = ChangeInstrument(NULL); 40 if (cmd.pInstrument) { 41 Engine::instruments.HandBack(cmd.pInstrument, this); 42 } 43 /////// 44 } 45 GetEngineFormat()46 AbstractEngine::Format EngineChannel::GetEngineFormat() { return AbstractEngine::SF2; } 47 48 /** This method is not thread safe! */ ResetInternal(bool bResetEngine)49 void EngineChannel::ResetInternal(bool bResetEngine) { 50 CurrentKeyDimension = 0; 51 EngineChannelBase<Voice, ::sf2::Region, ::sf2::Preset>::ResetInternal(bResetEngine); 52 for(int i = 0; i < 128; i++) PressedKeys[i] = false; 53 } 54 55 /** 56 * Will be called by the MIDIIn Thread to signal that a program 57 * change should be performed. As a program change isn't 58 * real-time safe, the actual change is performed by the disk 59 * thread. 60 * 61 * @param Program - MIDI program change number 62 */ SendProgramChange(uint8_t Program)63 void EngineChannel::SendProgramChange(uint8_t Program) { 64 SetMidiProgram(Program); 65 Engine* engine = dynamic_cast<Engine*>(pEngine); 66 if(engine == NULL) return; 67 68 if(engine->GetDiskThread()) { 69 uint32_t merged = (GetMidiBankMsb() << 16) | (GetMidiBankLsb() << 8) | Program; 70 engine->GetDiskThread()->OrderProgramChange(merged, this); 71 } else { 72 // TODO: 73 } 74 } 75 76 /** 77 * Load an instrument from a .sf2 file. PrepareLoadInstrument() has to 78 * be called first to provide the information which instrument to load. 79 * This method will then actually start to load the instrument and block 80 * the calling thread until loading was completed. 81 * 82 * @see PrepareLoadInstrument() 83 */ LoadInstrument()84 void EngineChannel::LoadInstrument() { 85 InstrumentResourceManager* pInstrumentManager = dynamic_cast<InstrumentResourceManager*>(pEngine->GetInstrumentManager()); 86 87 // make sure we don't trigger any new notes with an old 88 // instrument 89 InstrumentChangeCmd< ::sf2::Region, ::sf2::Preset>& cmd = ChangeInstrument(0); 90 if (cmd.pInstrument) { 91 // give old instrument back to instrument manager, but 92 // keep the dimension regions and samples that are in use 93 pInstrumentManager->HandBackInstrument(cmd.pInstrument, this, cmd.pRegionsInUse); 94 } 95 cmd.pRegionsInUse->clear(); 96 97 // delete all key groups 98 DeleteGroupEventLists(); 99 100 // request sf2 instrument from instrument manager 101 ::sf2::Preset* newInstrument; 102 try { 103 InstrumentManager::instrument_id_t instrid; 104 instrid.FileName = InstrumentFile; 105 instrid.Index = InstrumentIdx; 106 107 newInstrument = pInstrumentManager->Borrow(instrid, this); 108 if (!newInstrument) { 109 throw InstrumentManagerException("resource was not created"); 110 } 111 } 112 catch (InstrumentManagerException e) { 113 InstrumentStat = -3; 114 StatusChanged(true); 115 String msg = "sf2::Engine error: Failed to load instrument, cause: " + e.Message(); 116 throw Exception(msg); 117 } 118 catch (::sf2::Exception e) { 119 InstrumentStat = -3; 120 StatusChanged(true); 121 String msg = "sf2::Engine error: Failed to load instrument, cause: " + e.Message; 122 throw Exception(msg); 123 } 124 catch (::std::runtime_error e) { 125 InstrumentStat = -3; 126 StatusChanged(true); 127 String msg = "sf2::Engine error: Failed to load instrument, cause: "; 128 msg += e.what(); 129 throw Exception(msg); 130 } 131 catch (...) { 132 InstrumentStat = -4; 133 StatusChanged(true); 134 throw Exception("sf2::Engine error: Failed to load instrument, cause: Unknown exception while trying to parse sf2 file."); 135 } 136 137 // rebuild ActiveKeyGroups map with key groups of current instrument 138 for (int i = 0 ; i < newInstrument->GetRegionCount() ; i++) { 139 ::sf2::Region* pRegion = newInstrument->GetRegion(i); 140 for (int j = 0 ; j < pRegion->pInstrument->GetRegionCount() ; j++) { 141 ::sf2::Region* pSubRegion = pRegion->pInstrument->GetRegion(j); 142 AddGroup(pSubRegion->exclusiveClass); 143 } 144 } 145 146 InstrumentIdxName = newInstrument->GetName(); 147 InstrumentStat = 100; 148 149 ChangeInstrument(newInstrument); 150 151 StatusChanged(true); 152 } 153 ProcessKeySwitchChange(int key)154 void EngineChannel::ProcessKeySwitchChange(int key) { } 155 156 }} // namespace LinuxSampler::sf2 157