/[svn]/linuxsampler/trunk/src/hostplugins/au/PluginAU.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/hostplugins/au/PluginAU.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1992 - (show annotations) (download)
Fri Aug 28 07:48:47 2009 UTC (11 years, 6 months ago) by iliev
File size: 13879 byte(s)
* bugfix: AU plugin failed to destroy its audio/MIDI devices

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2009 Grigor Iliev *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
20 * MA 02111-1307 USA *
21 ***************************************************************************/
22
23 #include "PluginAU.h"
24
25 #include "../../drivers/audio/AudioChannel.h"
26
27 #if AU_DEBUG_DISPATCHER
28 #include <AUDebugDispatcher.h>
29 #endif
30
31 COMPONENT_ENTRY(PluginAU)
32
33 //namespace LinuxSampler {
34
35 const midi_chan_t PluginAU::midiChns[16] = {
36 midi_chan_1, midi_chan_2, midi_chan_3, midi_chan_4, midi_chan_5,
37 midi_chan_6, midi_chan_7, midi_chan_8, midi_chan_9, midi_chan_10,
38 midi_chan_11, midi_chan_12, midi_chan_13, midi_chan_14, midi_chan_15,
39 midi_chan_16
40 };
41
42 AUPreset PluginAU::factoryPresets[kFactoryPresetCount] = {
43 { kOneSamplerChannel, CFSTR("LS: 1 Channel") },
44 { k16SamplerChannels, CFSTR("LS: 16 Channels") }
45 };
46
47 PluginAU::PluginAU(ComponentInstance inComponentInstance)
48 : MusicDeviceBase(inComponentInstance, 0, 1), Plugin(false) {
49
50 #if AU_DEBUG_DISPATCHER
51 mDebugDispatcher = new AUDebugDispatcher(this);
52 #endif
53 charBufSize = 512;
54 charBuf = new char[charBufSize];
55 InstallListeners();
56
57 SetAFactoryPresetAsCurrent(factoryPresets[kDefaultPreset]);
58 }
59
60 PluginAU::~PluginAU() {
61 #if AU_DEBUG_DISPATCHER
62 delete mDebugDispatcher;
63 #endif
64 delete [] charBuf;
65 UninstallListeners();
66 }
67
68 void PluginAU::InstallListeners() {
69 AddPropertyListener(kAudioUnitProperty_ContextName, PropertyListenerCallback, this);
70
71 }
72
73 void PluginAU::UninstallListeners() {
74 RemovePropertyListener(kAudioUnitProperty_ContextName, PropertyListenerCallback, this, true);
75 }
76
77 void PluginAU::PropertyListenerCallback (
78 void* inRefCon,
79 AudioUnit ci,
80 AudioUnitPropertyID inID,
81 AudioUnitScope inScope,
82 AudioUnitElement inElement
83 ) {
84 ((PluginAU*)inRefCon)->PropertyChanged(inID, inScope, inElement);
85 }
86
87 void PluginAU::PropertyChanged (
88 AudioUnitPropertyID inID,
89 AudioUnitScope inScope,
90 AudioUnitElement inElement
91 ) {
92 switch (inID) {
93 case kAudioUnitProperty_ContextName:
94 // TODO:
95 //GetStr(mContextName);
96 break;
97 }
98 }
99
100 ComponentResult PluginAU::GetPropertyInfo (
101 AudioUnitPropertyID inID,
102 AudioUnitScope inScope,
103 AudioUnitElement inElement,
104 UInt32& outDataSize,
105 Boolean& outWritable
106 ) {
107 // TODO:
108 return MusicDeviceBase::GetPropertyInfo(inID, inScope, inElement, outDataSize, outWritable);
109 }
110
111 ComponentResult PluginAU::GetProperty (
112 AudioUnitPropertyID inID,
113 AudioUnitScope inScope,
114 AudioUnitElement inElement,
115 void* outData
116 ) {
117 // TODO:
118 return MusicDeviceBase::GetProperty(inID, inScope, inElement, outData);
119 }
120
121 ComponentResult PluginAU::SetProperty (
122 AudioUnitPropertyID inID,
123 AudioUnitScope inScope,
124 AudioUnitElement inElement,
125 const void* inData,
126 UInt32 inDataSize
127 ) {
128 switch (inID) {
129 case kAudioUnitProperty_AUHostIdentifier:
130 if(inData != NULL) {
131 AUHostIdentifier* host = (AUHostIdentifier*)inData;
132 hostName = GetHostNameByID(GetStr(host->hostName));
133 }
134 break;
135 }
136 return MusicDeviceBase::SetProperty(inID, inScope, inElement, inData, inDataSize);
137 }
138
139 ComponentResult PluginAU::GetPresets(CFArrayRef* outData) const {
140 if (outData == NULL) return noErr;
141
142 CFMutableArrayRef presetsArray = CFArrayCreateMutable (
143 NULL, kFactoryPresetCount, NULL
144 );
145
146 for (int i = 0; i < kFactoryPresetCount; i++) {
147 CFArrayAppendValue(presetsArray, &factoryPresets[i] );
148 }
149
150 *outData = (CFArrayRef)presetsArray;
151 return noErr;
152 }
153
154 OSStatus PluginAU::NewFactoryPresetSet(const AUPreset& inNewFactoryPreset) {
155 if(global == NULL) return noErr;
156
157 switch(inNewFactoryPreset.presetNumber) {
158 case kOneSamplerChannel:
159 AddSamplerChannel("GIG", midi_chan_1);
160 break;
161 case k16SamplerChannels:
162 Set16SamplerChannelsPreset();
163 break;
164 default:
165 return kAudioUnitErr_InvalidProperty;
166 }
167
168 SetAFactoryPresetAsCurrent(inNewFactoryPreset);
169 return noErr;
170 }
171
172 UInt32 PluginAU::SupportedNumChannels(const AUChannelInfo** outInfo) {
173 static AUChannelInfo plugChannelInfo = { 0, -1 };
174 if (outInfo != NULL) *outInfo = &plugChannelInfo;
175 return 1;
176 }
177
178 ComponentResult PluginAU::Initialize() {
179 MusicDeviceBase::Initialize();
180
181 // The timeconsuming tasks delayed until the pluging is to be used
182 PreInit();
183
184 if(pAudioDevice) {
185 RemoveChannels();
186 DestroyDevice(pAudioDevice);
187 pAudioDevice = NULL;
188 }
189
190 if(pMidiDevice) {
191 DestroyDevice(pMidiDevice);
192 pMidiDevice = NULL;
193 }
194
195 int srate = (int)GetStreamFormat(kAudioUnitScope_Output, 0).mSampleRate;
196 int chnNum = GetStreamFormat(kAudioUnitScope_Output, 0).NumberChannels();
197
198 Init(srate, GetMaxFramesPerSlice(), chnNum);
199
200 if(hostName.empty()) {
201 hostName = GetHostNameByID(GetHostBundleID());
202 }
203
204 if(!hostName.empty()) {
205 for(int i = 0; i < pMidiDevice->PortCount(); i++) {
206 DeviceRuntimeParameter* param;
207 param = pMidiDevice->GetPort(i)->PortParameters()["NAME"];
208 if(param != NULL) param->SetValue(hostName + " " + ToString(i + 1));
209
210 }
211 }
212
213 if(!hostName.empty()) {
214 for(int i = 0; i < pAudioDevice->ChannelCount(); i++) {
215 DeviceRuntimeParameter* param;
216 param = pAudioDevice->Channel(i)->ChannelParameters()["NAME"];
217 if(param != NULL) param->SetValue(hostName + " " + ToString(i + 1));
218
219 }
220 }
221
222 NewFactoryPresetSet(factoryPresets[kDefaultPreset]);
223
224 /*AudioChannelLayout* pLayout = CAAudioChannelLayout::Create(chnNum);
225 if(pLayout != NULL) {
226 for(int i = 0; i < chnNum; i++) {
227 pLayout->mChannelDescriptions[i].mChannelLabel =
228 }
229 SetAudioChannelLayout(kAudioUnitScope_Output, 0, pLayout);
230 }*/
231
232 return noErr;
233 }
234
235 bool PluginAU::StreamFormatWritable(AudioUnitScope scope, AudioUnitElement element) {
236 return IsInitialized() ? false : true;
237 }
238
239 OSStatus PluginAU::HandleMidiEvent (
240 UInt8 inStatus, UInt8 inChannel,
241 UInt8 inData1, UInt8 inData2,
242 UInt32 inStartFrame
243 ) {
244 if(!IsInitialized()) return kAudioUnitErr_Uninitialized;
245 MidiInputPort* port = pMidiDevice->Port();
246
247 switch (inStatus) {
248 case 0x90:
249 if(inData1 >= 0x80) break;
250
251 if(inData2) {
252 port->DispatchNoteOn (
253 inData1, inData2, inChannel, inStartFrame
254 );
255 } else {
256 port->DispatchNoteOff (
257 inData1, inData2, inChannel, inStartFrame
258 );
259 }
260 break;
261 case 0x80:
262 if(inData1 >= 0x80) break;
263 port->DispatchNoteOff (
264 inData1, inData2, inChannel, inStartFrame
265 );
266 break;
267 case 0xB0:
268 if(inData1 == 0) {
269 port->DispatchBankSelectMsb(inData2, inChannel);
270 } else if(inData1 == 32) {
271 port->DispatchBankSelectLsb(inData2, inChannel);
272 }
273
274 port->DispatchControlChange (
275 inData1, inData2, inChannel, inStartFrame
276 );
277 break;
278 case 0xC0:
279 if(inData1 < 0x80) port->DispatchProgramChange(inData1, inChannel);
280 break;
281 case 0xE0:
282 port->DispatchPitchbend((inData1 | inData2 << 7) - 8192, inChannel, inStartFrame);
283 break;
284 case 0xD0:
285 port->DispatchControlChange(128, inData1, inChannel);
286 break;
287 }
288
289 return noErr;
290 }
291
292 ComponentResult PluginAU::Render (
293 AudioUnitRenderActionFlags& ioActionFlags,
294 const AudioTimeStamp& inTimeStamp,
295 UInt32 inNumberFrames
296 ) {
297 float* buf;
298 int chnCount = GetOutput(0)->GetBufferList().mNumberBuffers;
299 for(int i = 0; i < chnCount; i++) {
300 buf = (float*)GetOutput(0)->GetBufferList().mBuffers[i].mData;
301 pAudioDevice->Channel(i)->SetBuffer(buf);
302 }
303
304 pAudioDevice->Render(inNumberFrames);
305 return noErr;
306 }
307
308 void PluginAU::Set16SamplerChannelsPreset() {
309 RemoveChannels();
310 for(int i = 0; i < 16; i++) {
311 AddSamplerChannel("GIG", midiChns[i]);
312 }
313 }
314
315 void PluginAU::AddSamplerChannel(const char* engine, midi_chan_t midiChn) {
316 SamplerChannel* channel = global->pSampler->AddSamplerChannel();
317 channel->SetEngineType(engine);
318 channel->SetAudioOutputDevice(pAudioDevice);
319 channel->SetMidiInputDevice(pMidiDevice);
320 channel->SetMidiInputChannel(midiChn);
321 }
322
323 OSStatus PluginAU::GetInstrumentCount(UInt32 &outInstCount) const {
324 // TODO:
325 return MusicDeviceBase::GetInstrumentCount(outInstCount);
326 }
327
328 std::string PluginAU::GetHostNameByID(std::string Identifier) {
329 std::string name;
330 if(Identifier == "com.apple.logic.pro") {
331 name = "Logic Pro";
332 } else if(Identifier == "com.apple.garageband") {
333 name = "GarageBand";
334 } else if(Identifier == "com.ableton.live") {
335 name = "Ableton Live";
336 } else if(Identifier == "com.apple.audio.aulab") {
337 name = "AULab";
338 }
339
340 return name;
341 }
342
343 std::string PluginAU::GetHostBundleID() {
344 std::string id;
345 CFStringRef identifier;
346 CFBundleRef mainBundle = CFBundleGetMainBundle();
347 if (mainBundle) {
348 identifier = CFBundleGetIdentifier(mainBundle);
349 id = GetStr(identifier);
350 }
351
352 return id;
353 }
354
355 std::string PluginAU::GetStr(CFStringRef s) {
356 if(s == NULL) return std::string("");
357
358 CFRetain(s);
359 CFIndex len = CFStringGetLength(s) + 1;
360 if(charBufSize < len) {
361 delete [] charBuf;
362 charBufSize *= 2;
363 if(charBufSize < len) charBufSize = len;
364 charBuf = new char[charBufSize];
365 }
366
367 std::string s2;
368 if(CFStringGetCString(s, charBuf, charBufSize, kCFStringEncodingASCII)) {
369 s2 = charBuf;
370 }
371 CFRelease(s);
372
373 return s2;
374 }
375
376 ComponentResult PluginAU::SaveState(CFPropertyListRef* outData) {
377 ComponentResult result = AUBase::SaveState(outData);
378 if(global == NULL || result != noErr) return result;
379
380 void** d = const_cast<void**> (outData);
381 CFMutableDictionaryRef dict = static_cast<CFMutableDictionaryRef> (*d);
382
383 std::string s = GetState();
384 CFStringRef cfsState = CFStringCreateWithCString(NULL, s.c_str(), kCFStringEncodingASCII);
385
386 CFDictionarySetValue(dict, CFSTR("org.linuxsampler.LinuxSamplerPluginAU"), cfsState);
387 CFRelease(cfsState);
388
389 return noErr;
390 }
391
392 ComponentResult PluginAU::RestoreState(CFPropertyListRef inData) {
393 ComponentResult result = AUBase::RestoreState(inData);
394 if(global == NULL || result != noErr) return result;
395
396 CFDictionaryRef dict = static_cast<CFDictionaryRef>(inData);
397
398 const void* d = CFDictionaryGetValue (
399 dict, CFSTR("org.linuxsampler.LinuxSamplerPluginAU")
400 );
401
402 CFStringRef str = static_cast<CFStringRef>(d);
403 if(str != NULL) SetState(GetStr(str));
404
405 return noErr;
406 }
407
408 //} // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC