/[svn]/linuxsampler/trunk/src/engines/gig/EngineChannel.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/engines/gig/EngineChannel.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2594 - (show annotations) (download)
Thu Jun 5 00:16:25 2014 UTC (9 years, 10 months ago) by schoenebeck
File size: 7914 byte(s)
* ScriptVM (WIP): started to integrate real-time instrument script
  support into the sampler engine implementations. The code is
  shared among all sampler engines, however currently only the gig
  file format supports storing instrument scripts (as LinuxSampler
  extension to the original GigaStudio 4 file format).
* gig engine: Added support for loading instrument scripts from .gig
  files.
* ScriptVM (WIP): Implemented built-in script variables %CC, $CC_NUM,
  $EVENT_NOTE, $EVENT_VELOCITY, $VCC_MONO_AT, $VCC_PITCH_BEND.
* ScriptVM (WIP): Implemented execution of script event handler "init".
* ScriptVM (WIP): Implemented execution of script event handler
  "controller".
* Bumped version (1.0.0.svn42).

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

  ViewVC Help
Powered by ViewVC