EngineChannel::~EngineChannel() { DisconnectAudioOutputDevice(); // In case the channel was removed before the instrument was // fully loaded, try to give back instrument again (see bug #113) InstrumentChangeCmd< ::gig::DimensionRegion, ::gig::Instrument>& cmd = ChangeInstrument(NULL); if (cmd.pInstrument) { Engine::instruments.HandBack(cmd.pInstrument, this); } /////// }
/** * Load an instrument from a .gig file. PrepareLoadInstrument() has to * be called first to provide the information which instrument to load. * This method will then actually start to load the instrument and block * the calling thread until loading was completed. * * @see PrepareLoadInstrument() */ void EngineChannel::LoadInstrument() { InstrumentResourceManager* pInstrumentManager = dynamic_cast<InstrumentResourceManager*>(pEngine->GetInstrumentManager()); // make sure we don't trigger any new notes with an old // instrument InstrumentChangeCmd< ::gig::DimensionRegion, ::gig::Instrument>& cmd = ChangeInstrument(0); if (cmd.pInstrument) { // give old instrument back to instrument manager, but // keep the dimension regions and samples that are in use pInstrumentManager->HandBackInstrument(cmd.pInstrument, this, cmd.pRegionsInUse); } if (cmd.pScript) { // give old instrument script back to instrument resource manager cmd.pScript->resetAll(); } cmd.pRegionsInUse->clear(); // delete all key groups DeleteGroupEventLists(); // request gig instrument from instrument manager ::gig::Instrument* newInstrument; try { InstrumentManager::instrument_id_t instrid; instrid.FileName = InstrumentFile; instrid.Index = InstrumentIdx; newInstrument = pInstrumentManager->Borrow(instrid, this); if (!newInstrument) { throw InstrumentManagerException("resource was not created"); } if (newInstrument->ScriptSlotCount() > 1) { std::cerr << "WARNING: Executing more than one real-time instrument script slot is not implemented yet!\n"; } ::gig::Script* script = newInstrument->GetScriptOfSlot(0); if (script) { String sourceCode = script->GetScriptAsText(); LoadInstrumentScript(sourceCode); } } catch (RIFF::Exception e) { InstrumentStat = -2; StatusChanged(true); String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message; throw Exception(msg); } catch (InstrumentManagerException e) { InstrumentStat = -3; StatusChanged(true); String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message(); throw Exception(msg); } catch (...) { InstrumentStat = -4; StatusChanged(true); throw Exception("gig::Engine error: Failed to load instrument, cause: Unknown exception while trying to parse gig file."); } RoundRobinIndex = 0; for (int i = 0 ; i < 128 ; i++) pMIDIKeyInfo[i].pRoundRobinIndex = NULL; // rebuild ActiveKeyGroups map with key groups of current // instrument and set the round robin pointers to use one // counter for each region int region = 0; for (::gig::Region* pRegion = newInstrument->GetFirstRegion(); pRegion; pRegion = newInstrument->GetNextRegion()) { AddGroup(pRegion->KeyGroup); RoundRobinIndexes[region] = 0; for (int iKey = pRegion->KeyRange.low; iKey <= pRegion->KeyRange.high; iKey++) { pMIDIKeyInfo[iKey].pRoundRobinIndex = &RoundRobinIndexes[region]; } region++; } InstrumentIdxName = newInstrument->pInfo->Name; InstrumentStat = 100; { InstrumentChangeCmd< ::gig::DimensionRegion, ::gig::Instrument>& cmd = ChangeInstrument(newInstrument); if (cmd.pScript) { // give old instrument script back to instrument resource manager cmd.pScript->resetAll(); } } StatusChanged(true); }
OSStatus ComboBoxHandler(EventHandlerCallRef next, EventRef event, void *data) { WindowRef window; HIViewRef combo; CFIndex index; UInt32 id; // Get the window window = ActiveNonFloatingWindow(); // Get the control GetEventParameter(event, kEventParamDirectObject, typeControlRef, NULL, sizeof(combo), NULL, &combo); // Get the index GetEventParameter(event, kEventParamComboBoxListSelectedItemIndex, typeCFIndex, NULL, sizeof(index), NULL, &index); // Get the command id HIViewGetCommandID(combo, &id); // Switch on the command id switch (id) { // Instrument case kCommandInst: instrument = index; ChangeInstrument(instrument); break; // Key case kCommandKey: key = index; type = types[key]; ChangeDisplay(); break; // Something else default: return eventNotHandledErr; } // Clear the keyboard focus, otherwise the focus stays on the // combo box and makes it drop down when the user presses a key ClearKeyboardFocus(window); // Report success return noErr; }
int main(int argc, char *argv[]) { WindowRef window; HIViewRef content; HIViewRef combo; HIViewRef group; HIViewRef check; HIViewRef text; HIViewRef slider; HIViewRef quit; MenuRef menu; HIRect rect; // Window bounds Rect bounds = {0, 0, 436, 590}; // Create window CreateNewWindow(kDocumentWindowClass, kWindowStandardFloatingAttributes | kWindowStandardHandlerAttribute | kWindowInWindowMenuAttribute | kWindowCompositingAttribute, &bounds, &window); // Set the title SetWindowTitleWithCFString(window, CFSTR("Accordion")); // Create an application menu CreateNewMenu(0, 0, &menu); // Set menu title SetMenuTitleWithCFString(menu, CFStringCreateWithPascalString(kCFAllocatorDefault, "\p\024", kCFStringEncodingMacRoman)); // Create an about item InsertMenuItemTextWithCFString(menu, CFSTR("About Accordion"), 0, 0, kHICommandAbout); // Insert the menu InsertMenu(menu, 0); // Create a standard window menu CreateStandardWindowMenu(0, &menu); // Insert the menu InsertMenu(menu, 0); // Show and position the window ShowWindow(window); RepositionWindow(window, NULL, kWindowCascadeOnMainScreen); // Find the window content HIViewFindByID(HIViewGetRoot(window), kHIViewWindowContentID, &content); // Set bounds for group box bounds.bottom = 92; bounds.right = 550; // Create group box CreateGroupBoxControl(window, &bounds, NULL, true, &group); // Place in the window HIViewAddSubview(content, group); HIViewPlaceInSuperviewAt(group, 20, 20); // Bounds of text bounds.bottom = 16; bounds.right = 74; // Create static text CreateStaticTextControl(window, &bounds, CFSTR("Instrument:"), NULL, &text); // Place in the group box HIViewAddSubview(group, text); HIViewPlaceInSuperviewAt(text, 16, 18); // Bounds of combo box rect.size.height = 20; rect.size.width = 168; // Create combo box HIComboBoxCreate(&rect, CFSTR(" Accordion"), NULL, NULL, kHIComboBoxStandardAttributes, &combo); // Set visible and set command ID HIViewSetVisible(combo, true); HIViewSetCommandID(combo, kCommandInst); // Add the instruments for (int i = 0; i < Length(instruments); i++) { HIComboBoxAppendTextItem(combo, CFStringCreateWithCString(kCFAllocatorDefault, instruments[i], kCFStringEncodingMacRoman), NULL); // Set the current instrument if (strcmp(instruments[i], " Accordion") == 0) instrument = i; } // Place in the group box HIViewAddSubview(group, combo); HIViewPlaceInSuperviewAt(combo, 102, 16); // Bounds of check box bounds.bottom = 18; bounds.right = 121; // Create check box CreateCheckBoxControl(window, &bounds, CFSTR("Reverse"), false, true, &check); // Set the control ID and the command ID HIViewSetID(check, kHIViewIDReverse); HIViewSetCommandID(check, kCommandReverse); // Place in the group box HIViewAddSubview(group, check); HIViewPlaceInSuperviewAt(check, 286, 17); // Bounds of text bounds.bottom = 16; bounds.right = 32; // Create static text CreateStaticTextControl(window, &bounds, CFSTR("Key:"), NULL, &text); // Place in the group box HIViewAddSubview(group, text); HIViewPlaceInSuperviewAt(text, 400, 18); // Bounds of combo box rect.size.width = 90; // Create combo box HIComboBoxCreate(&rect, CFSTR(" A/D/G"), NULL, NULL, kHIComboBoxStandardAttributes, &combo); // Set visible and set command ID HIViewSetVisible(combo, true); HIViewSetID(combo, kHIViewIDKey); HIViewSetCommandID(combo, kCommandKey); // Add keys for (int i = 0; i < Length(keys); i++) { HIComboBoxAppendTextItem(combo, CFStringCreateWithCString(kCFAllocatorDefault, keys[i], kCFStringEncodingMacRoman), NULL); // Set current key if (strcmp(keys[i], " A/D/G") == 0) key = i; } // Place in the group box HIViewAddSubview(group, combo); HIViewPlaceInSuperviewAt(combo, 440, 16); // Bounds of text bounds.bottom = 16; bounds.right = 54; // Create static text CreateStaticTextControl(window, &bounds, CFSTR("Volume:"), NULL, &text); // Place in the group box HIViewAddSubview(group, text); HIViewPlaceInSuperviewAt(text, 16, 56); // Bounds of slider bounds.bottom = 16; bounds.right = 168; // Create slider CreateSliderControl(window, &bounds, MAXVOL, 0, MAXVOL, kControlSliderDoesNotPoint, 0, false, NULL, &slider); // Set command ID HIViewSetCommandID(slider, kCommandVolume); // Place in the group box HIViewAddSubview(group, slider); HIViewPlaceInSuperviewAt(slider, 100, 58); // Bounds of check box bounds.bottom = 18; bounds.right = 121; // Create check box CreateCheckBoxControl(window, &bounds, CFSTR("Notes"), false, true, &check); // Set the control ID and the command ID HIViewSetID(check, kHIViewIDNote); HIViewSetCommandID(check, kCommandNote); // Place in the group box HIViewAddSubview(group, check); HIViewPlaceInSuperviewAt(check, 286, 56); // Bounds of push button bounds.bottom = 20; bounds.right = 90; // Create push button CreatePushButtonControl(window, &bounds, CFSTR("Quit"), &quit); // Set command ID HIViewSetCommandID(quit, kHICommandQuit); // Place in the group box HIViewAddSubview(group, quit); HIViewPlaceInSuperviewAt(quit, 440, 54); // Group box bounds bounds.bottom = 48; bounds.right = 550; // Create group box CreateGroupBoxControl(window, &bounds, NULL, true, &group); // Place in the window HIViewAddSubview(content, group); HIViewPlaceInSuperviewAt(group, 20, 132); // Font style ControlFontStyleRec style; style.flags = kControlUseFontMask|kControlUseJustMask; style.font = kControlFontBigSystemFont; style.just = teCenter; // Bounds of text bounds.bottom = 16; bounds.right = 550; // Create static text CreateStaticTextControl(window, &bounds, CFSTR("Accordion"), &style, &text); // Place in the group box HIViewAddSubview(group, text); HIViewPlaceInSuperviewAt(text, 0, 8); // Bounds of text bounds.bottom = 16; bounds.right = 550; // Create static text CreateStaticTextControl(window, &bounds, CFSTR("Play accordion on your keyboard"), &style, &text); // Place in the group box HIViewAddSubview(group, text); HIViewPlaceInSuperviewAt(text, 0, 24); // Group box bounds bounds.bottom = 196; bounds.right = 550; // Create group box CreateGroupBoxControl(window, &bounds, NULL, true, &group); // Place in the window HIViewAddSubview(content, group); HIViewPlaceInSuperviewAt(group, 20, 200); // Button bounds bounds.bottom = SIZE; bounds.right = SIZE; // Create row of bass buttons for (int i = 0; i < Length(bassdisplay); i++) { int x = 15 + 44 * i; int y = 15; // Create button CreateBevelButtonControl(window, &bounds, NULL, kControlBevelButtonNormalBevel, kControlBehaviorPushbutton, NULL, 0, 0, 0, &bassdisplay[i]); // Place in the group box HIViewAddSubview(group, bassdisplay[i]); HIViewPlaceInSuperviewAt(bassdisplay[i], x, y); } // Create three rows of buttons for (int i = 0; i < Length(display); i++) { for (int j = 0; j < ((i == 1)? Length(display[i]): Length(display[i]) - 1); j++) { int x = (i == 1)? 37 + 44 * j: 59 + 44 * j; int y = 59 + 44 * i; // Create button CreateBevelButtonControl(window, &bounds, NULL, kControlBevelButtonNormalBevel, kControlBehaviorPushbutton, NULL, 0, 0, 0, &display[i][j]); // Place in the group box HIViewAddSubview(group, display[i][j]); HIViewPlaceInSuperviewAt(display[i][j], x, y); } } // Create spacebar button CreateBevelButtonControl(window, &bounds, NULL, kControlBevelButtonNormalBevel, kControlBehaviorPushbutton, NULL, 0, 0, 0, &spacebar); // Place in the group box HIViewAddSubview(group, spacebar); HIViewPlaceInSuperviewAt(spacebar, 16, 147); // Group box bounds, wider than the window to hide rounded corners bounds.bottom = 20; bounds.right = 598; // Create group box for fake status bar CreateGroupBoxControl(window, &bounds, NULL, false, &group); // Place in window at negative offset to hide rounded corners HIViewAddSubview(content, group); HIViewPlaceInSuperviewAt(group, -4, 416); // Text bounds bounds.bottom = 16; bounds.right = 590; // Font style style.flags = kControlUseFontMask|kControlUseJustMask; style.font = kControlFontSmallSystemFont; style.just = teCenter; // Create static text CreateStaticTextControl(window, &bounds, CFSTR("Press the keyboard keys as accordion buttons " "and the space bar as the bellows. 3rd button start."), &style, &text); // Place in group box HIViewAddSubview(group, text); HIViewPlaceInSuperviewAt(text, 0, 2); // Application events type spec EventTypeSpec applicationEvents[] = {{kEventClassApplication, kEventAppFrontSwitched}}; // Install event handler InstallApplicationEventHandler(NewEventHandlerUPP(ApplicationHandler), Length(applicationEvents), applicationEvents, NULL, NULL); // Mouse events type spec EventTypeSpec mouseEvents[] = {{kEventClassMouse, kEventMouseDown}}; // Install event handler on the event dispatcher, so that we can // see mouse events before the default handler gets them InstallEventHandler(GetEventDispatcherTarget(), NewEventHandlerUPP(MouseHandler), Length(mouseEvents), mouseEvents, NULL, NULL); // Window events type spec EventTypeSpec windowEvents[] = {{kEventClassWindow, kEventWindowClose}}; // Install event handler InstallWindowEventHandler(window, NewEventHandlerUPP(WindowHandler), Length(windowEvents), windowEvents, NULL, NULL); // Combo box events type spec EventTypeSpec comboBoxEvents[] = {{kEventClassHIComboBox, kEventComboBoxListItemSelected}}; // Install event handler InstallApplicationEventHandler(NewEventHandlerUPP(ComboBoxHandler), Length(comboBoxEvents), comboBoxEvents, NULL, NULL); // Command events type spec EventTypeSpec commandEvents[] = {{kEventClassCommand, kEventCommandProcess}}; // Install event handler InstallApplicationEventHandler(NewEventHandlerUPP(CommandHandler), Length(commandEvents), commandEvents, NULL, NULL); // Keyboard events type spec EventTypeSpec keyboardEvents[] = {{kEventClassKeyboard, kEventRawKeyDown}, {kEventClassKeyboard, kEventRawKeyUp}, {kEventClassKeyboard, kEventRawKeyModifiersChanged}}; // Install event handler on the event dispatcher InstallEventHandler(GetEventDispatcherTarget(), NewEventHandlerUPP(KeyboardHandler), Length(keyboardEvents), keyboardEvents, NULL, NULL); // Audio Unit graph AUGraph graph; // Audio Unit synthesizer and output node AUNode synthNode; AUNode outNode; // Component description ComponentDescription cd; cd.componentManufacturer = kAudioUnitManufacturer_Apple; cd.componentFlags = 0; cd.componentFlagsMask = 0; do { // New AU graph OSStatus status = NewAUGraph(&graph); if (status != noErr) { DisplayAlert(CFSTR("NewAUGraph"), CFSTR("Can't create a new AUGraph"), status); break; } // Synthesizer cd.componentType = kAudioUnitType_MusicDevice; cd.componentSubType = kAudioUnitSubType_DLSSynth; // New synthesizer node status = AUGraphNewNode(graph, &cd, 0, NULL, &synthNode); if (status != noErr) { DisplayAlert(CFSTR("AUGraphNewNode"), CFSTR("Can't create a new AUGraph node"), status); break; } // Output cd.componentType = kAudioUnitType_Output; cd.componentSubType = kAudioUnitSubType_DefaultOutput; // New output node status = AUGraphNewNode(graph, &cd, 0, NULL, &outNode); if (status != noErr) { DisplayAlert(CFSTR("AUGraphNewNode"), CFSTR("Can't create a new AUGraph node"), status); break; } // Open graph status = AUGraphOpen(graph); if (status != noErr) { DisplayAlert(CFSTR("AUGraphOpen"), CFSTR("Can't open AUGraph"), status); break; } // Connect synthesizer node to output node status = AUGraphConnectNodeInput(graph, synthNode, 0, outNode, 0); if (status != noErr) { DisplayAlert(CFSTR("AUGraphConnectNodeInput"), CFSTR("Can't connect AUGraph input node"), status); break; } // Get a synthesizer unit status = AUGraphGetNodeInfo(graph, synthNode, NULL, 0, NULL, &synthUnit); if (status != noErr) { DisplayAlert(CFSTR("AUGraphGetNodeInfo"), CFSTR("Can't get AUGraph node info"), status); break; } // Initialise status = AUGraphInitialize(graph); if (status != noErr) { DisplayAlert(CFSTR("AUGraphInitialize"), CFSTR("Can't initialize AUGraph"), status); break; } // Start status = AUGraphStart(graph); if (status != noErr) { DisplayAlert(CFSTR("AUGraphStart"), CFSTR("Can't start AUGraph"), status); break; } // Show the graph // CAShow(graph); } while (false); // Change instrument ChangeInstrument(instrument); // Run the application event loop RunApplicationEventLoop(); // Stop the graph AUGraphStop(graph); // Dispose of the graph DisposeAUGraph(graph); // Exit return 0; }
/** * Load an instrument from a .sf2 file. PrepareLoadInstrument() has to * be called first to provide the information which instrument to load. * This method will then actually start to load the instrument and block * the calling thread until loading was completed. * * @see PrepareLoadInstrument() */ void EngineChannel::LoadInstrument() { InstrumentResourceManager* pInstrumentManager = dynamic_cast<InstrumentResourceManager*>(pEngine->GetInstrumentManager()); // make sure we don't trigger any new notes with an old // instrument InstrumentChangeCmd< ::sf2::Region, ::sf2::Preset>& cmd = ChangeInstrument(0); if (cmd.pInstrument) { // give old instrument back to instrument manager, but // keep the dimension regions and samples that are in use pInstrumentManager->HandBackInstrument(cmd.pInstrument, this, cmd.pRegionsInUse); } cmd.pRegionsInUse->clear(); // delete all key groups DeleteGroupEventLists(); // request sf2 instrument from instrument manager ::sf2::Preset* newInstrument; try { InstrumentManager::instrument_id_t instrid; instrid.FileName = InstrumentFile; instrid.Index = InstrumentIdx; newInstrument = pInstrumentManager->Borrow(instrid, this); if (!newInstrument) { throw InstrumentManagerException("resource was not created"); } } catch (InstrumentManagerException e) { InstrumentStat = -3; StatusChanged(true); String msg = "sf2::Engine error: Failed to load instrument, cause: " + e.Message(); throw Exception(msg); } catch (::sf2::Exception e) { InstrumentStat = -3; StatusChanged(true); String msg = "sf2::Engine error: Failed to load instrument, cause: " + e.Message; throw Exception(msg); } catch (::std::runtime_error e) { InstrumentStat = -3; StatusChanged(true); String msg = "sf2::Engine error: Failed to load instrument, cause: "; msg += e.what(); throw Exception(msg); } catch (...) { InstrumentStat = -4; StatusChanged(true); throw Exception("sf2::Engine error: Failed to load instrument, cause: Unknown exception while trying to parse sf2 file."); } // rebuild ActiveKeyGroups map with key groups of current instrument for (int i = 0 ; i < newInstrument->GetRegionCount() ; i++) { ::sf2::Region* pRegion = newInstrument->GetRegion(i); for (int j = 0 ; j < pRegion->pInstrument->GetRegionCount() ; j++) { ::sf2::Region* pSubRegion = pRegion->pInstrument->GetRegion(j); AddGroup(pSubRegion->exclusiveClass); } } InstrumentIdxName = newInstrument->GetName(); InstrumentStat = 100; ChangeInstrument(newInstrument); StatusChanged(true); }