| 1 | /* Copyright � 2007 Apple Inc. All Rights Reserved. |
|---|
| 2 | |
|---|
| 3 | Disclaimer: IMPORTANT: This Apple software is supplied to you by |
|---|
| 4 | Apple Inc. ("Apple") in consideration of your agreement to the |
|---|
| 5 | following terms, and your use, installation, modification or |
|---|
| 6 | redistribution of this Apple software constitutes acceptance of these |
|---|
| 7 | terms. If you do not agree with these terms, please do not use, |
|---|
| 8 | install, modify or redistribute this Apple software. |
|---|
| 9 | |
|---|
| 10 | In consideration of your agreement to abide by the following terms, and |
|---|
| 11 | subject to these terms, Apple grants you a personal, non-exclusive |
|---|
| 12 | license, under Apple's copyrights in this original Apple software (the |
|---|
| 13 | "Apple Software"), to use, reproduce, modify and redistribute the Apple |
|---|
| 14 | Software, with or without modifications, in source and/or binary forms; |
|---|
| 15 | provided that if you redistribute the Apple Software in its entirety and |
|---|
| 16 | without modifications, you must retain this notice and the following |
|---|
| 17 | text and disclaimers in all such redistributions of the Apple Software. |
|---|
| 18 | Neither the name, trademarks, service marks or logos of Apple Inc. |
|---|
| 19 | may be used to endorse or promote products derived from the Apple |
|---|
| 20 | Software without specific prior written permission from Apple. Except |
|---|
| 21 | as expressly stated in this notice, no other rights or licenses, express |
|---|
| 22 | or implied, are granted by Apple herein, including but not limited to |
|---|
| 23 | any patent rights that may be infringed by your derivative works or by |
|---|
| 24 | other works in which the Apple Software may be incorporated. |
|---|
| 25 | |
|---|
| 26 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE |
|---|
| 27 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION |
|---|
| 28 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS |
|---|
| 29 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND |
|---|
| 30 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. |
|---|
| 31 | |
|---|
| 32 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL |
|---|
| 33 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|---|
| 34 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|---|
| 35 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, |
|---|
| 36 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED |
|---|
| 37 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), |
|---|
| 38 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE |
|---|
| 39 | POSSIBILITY OF SUCH DAMAGE. |
|---|
| 40 | */ |
|---|
| 41 | |
|---|
| 42 | // This is a simple test case of making an simple graph with a DLSSynth, Limiter and Ouput unit |
|---|
| 43 | // we're going to use a graph because its easier for it to just handle the setup and connections, etc... |
|---|
| 44 | |
|---|
| 45 | #include <CoreServices/CoreServices.h> //for file stuff |
|---|
| 46 | #include <AudioUnit/AudioUnit.h> |
|---|
| 47 | #include <AudioToolbox/AudioToolbox.h> //for AUGraph |
|---|
| 48 | #include <unistd.h> // used for usleep... |
|---|
| 49 | #include <sys/time.h> |
|---|
| 50 | #include <iostream> |
|---|
| 51 | #include <vector> |
|---|
| 52 | #include <gainer.h> |
|---|
| 53 | #include "filter.h" |
|---|
| 54 | |
|---|
| 55 | // This call creates the Graph and the Synth unit... |
|---|
| 56 | OSStatus CreateAUGraph (AUGraph &outGraph, AudioUnit &outSynth) |
|---|
| 57 | { |
|---|
| 58 | OSStatus result; |
|---|
| 59 | //create the nodes of the graph |
|---|
| 60 | AUNode synthNode, limiterNode, outNode; |
|---|
| 61 | |
|---|
| 62 | ComponentDescription cd; |
|---|
| 63 | cd.componentManufacturer = kAudioUnitManufacturer_Apple; |
|---|
| 64 | cd.componentFlags = 0; |
|---|
| 65 | cd.componentFlagsMask = 0; |
|---|
| 66 | |
|---|
| 67 | require_noerr (result = NewAUGraph (&outGraph), home); |
|---|
| 68 | |
|---|
| 69 | cd.componentType = kAudioUnitType_MusicDevice; |
|---|
| 70 | cd.componentSubType = kAudioUnitSubType_DLSSynth; |
|---|
| 71 | |
|---|
| 72 | require_noerr (result = AUGraphAddNode (outGraph, &cd, &synthNode), home); |
|---|
| 73 | |
|---|
| 74 | cd.componentType = kAudioUnitType_Effect; |
|---|
| 75 | cd.componentSubType = kAudioUnitSubType_PeakLimiter; |
|---|
| 76 | |
|---|
| 77 | require_noerr (result = AUGraphAddNode (outGraph, &cd, &limiterNode), home); |
|---|
| 78 | |
|---|
| 79 | cd.componentType = kAudioUnitType_Output; |
|---|
| 80 | cd.componentSubType = kAudioUnitSubType_DefaultOutput; |
|---|
| 81 | require_noerr (result = AUGraphAddNode (outGraph, &cd, &outNode), home); |
|---|
| 82 | |
|---|
| 83 | require_noerr (result = AUGraphOpen (outGraph), home); |
|---|
| 84 | |
|---|
| 85 | require_noerr (result = AUGraphConnectNodeInput (outGraph, synthNode, 0, limiterNode, 0), home); |
|---|
| 86 | require_noerr (result = AUGraphConnectNodeInput (outGraph, limiterNode, 0, outNode, 0), home); |
|---|
| 87 | |
|---|
| 88 | // ok we're good to go - get the Synth Unit... |
|---|
| 89 | require_noerr (result = AUGraphNodeInfo(outGraph, synthNode, 0, &outSynth), home); |
|---|
| 90 | |
|---|
| 91 | home: |
|---|
| 92 | return result; |
|---|
| 93 | } |
|---|
| 94 | |
|---|
| 95 | // some MIDI constants: |
|---|
| 96 | enum { |
|---|
| 97 | kMidiMessage_ControlChange = 0xB, |
|---|
| 98 | kMidiMessage_ProgramChange = 0xC, |
|---|
| 99 | kMidiMessage_BankMSBControl = 0, |
|---|
| 100 | kMidiMessage_BankLSBControl = 32, |
|---|
| 101 | kMidiMessage_NoteOn = 0x9 |
|---|
| 102 | }; |
|---|
| 103 | |
|---|
| 104 | const int OCTAVE[2] = {64, 74}; |
|---|
| 105 | const int OCTAVE_INTERVAL(1); |
|---|
| 106 | const int FINGERS[4] = {0, 2, 4, 5}; |
|---|
| 107 | const int OCTAVE_RANGE(7); |
|---|
| 108 | |
|---|
| 109 | int main (int argc, const char * argv[]) { |
|---|
| 110 | AUGraph graph = 0; |
|---|
| 111 | AudioUnit synthUnit; |
|---|
| 112 | OSStatus result; |
|---|
| 113 | char* bankPath = 0; |
|---|
| 114 | |
|---|
| 115 | UInt8 midiChannelInUse = 0; //we're using midi channel 1... |
|---|
| 116 | |
|---|
| 117 | // this is the only option to main that we have... |
|---|
| 118 | // just the full path of the sample bank... |
|---|
| 119 | |
|---|
| 120 | // On OS X there are known places were sample banks can be stored |
|---|
| 121 | // Library/Audio/Sounds/Banks - so you could scan this directory and give the user options |
|---|
| 122 | // about which sample bank to use... |
|---|
| 123 | if (argc > 2) |
|---|
| 124 | bankPath = const_cast<char*>(argv[2]); |
|---|
| 125 | |
|---|
| 126 | Gainer gainer(argv[1]); |
|---|
| 127 | std::vector <bool> prev(gainer.digital_inputs.size(), false); |
|---|
| 128 | MovingAverageFilter filter(4); |
|---|
| 129 | int octave(0); |
|---|
| 130 | struct timeval start, stop; |
|---|
| 131 | gettimeofday(&start, NULL); |
|---|
| 132 | |
|---|
| 133 | gainer.continuous_digital_inputs(); |
|---|
| 134 | gainer.continuous_analog_inputs(); |
|---|
| 135 | |
|---|
| 136 | require_noerr (result = CreateAUGraph (graph, synthUnit), home); |
|---|
| 137 | |
|---|
| 138 | // if the user supplies a sound bank, we'll set that before we initialize and start playing |
|---|
| 139 | if (bankPath) |
|---|
| 140 | { |
|---|
| 141 | FSRef fsRef; |
|---|
| 142 | require_noerr (result = FSPathMakeRef ((const UInt8*)bankPath, &fsRef, 0), home); |
|---|
| 143 | |
|---|
| 144 | printf ("Setting Sound Bank:%s\n", bankPath); |
|---|
| 145 | |
|---|
| 146 | require_noerr (result = AudioUnitSetProperty (synthUnit, |
|---|
| 147 | kMusicDeviceProperty_SoundBankFSRef, |
|---|
| 148 | kAudioUnitScope_Global, 0, |
|---|
| 149 | &fsRef, sizeof(fsRef)), home); |
|---|
| 150 | |
|---|
| 151 | } |
|---|
| 152 | |
|---|
| 153 | // ok we're set up to go - initialize and start the graph |
|---|
| 154 | require_noerr (result = AUGraphInitialize (graph), home); |
|---|
| 155 | |
|---|
| 156 | //set our bank |
|---|
| 157 | require_noerr (result = MusicDeviceMIDIEvent(synthUnit, |
|---|
| 158 | kMidiMessage_ControlChange << 4 | midiChannelInUse, |
|---|
| 159 | kMidiMessage_BankMSBControl, 0, |
|---|
| 160 | 0/*sample offset*/), home); |
|---|
| 161 | |
|---|
| 162 | require_noerr (result = MusicDeviceMIDIEvent(synthUnit, |
|---|
| 163 | kMidiMessage_ProgramChange << 4 | midiChannelInUse, |
|---|
| 164 | 0/*prog change num*/, 0, |
|---|
| 165 | 0/*sample offset*/), home); |
|---|
| 166 | |
|---|
| 167 | CAShow (graph); // prints out the graph so we can see what it looks like... |
|---|
| 168 | |
|---|
| 169 | require_noerr (result = AUGraphStart (graph), home); |
|---|
| 170 | |
|---|
| 171 | // we're going to play an octave of MIDI notes: one a second |
|---|
| 172 | while (true) { |
|---|
| 173 | |
|---|
| 174 | //UInt32 noteNum = i + 60; |
|---|
| 175 | |
|---|
| 176 | bool moved(false); |
|---|
| 177 | int x(filter.filter(gainer.analog_inputs[0]-126)); |
|---|
| 178 | if (x < -OCTAVE[0]) { |
|---|
| 179 | std::cout << x << std::endl; |
|---|
| 180 | gettimeofday(&stop, NULL); |
|---|
| 181 | if (stop.tv_sec - start.tv_sec > OCTAVE_INTERVAL) { |
|---|
| 182 | octave++; |
|---|
| 183 | start = stop; |
|---|
| 184 | } |
|---|
| 185 | moved = true; |
|---|
| 186 | } else if (x > OCTAVE[1]) { |
|---|
| 187 | std::cout << x << std::endl; |
|---|
| 188 | gettimeofday(&stop, NULL); |
|---|
| 189 | if (stop.tv_sec - start.tv_sec > OCTAVE_INTERVAL) { |
|---|
| 190 | octave--; |
|---|
| 191 | start = stop; |
|---|
| 192 | } |
|---|
| 193 | moved = true; |
|---|
| 194 | } |
|---|
| 195 | |
|---|
| 196 | for (size_t j(0); j<prev.size(); j++) { |
|---|
| 197 | //std::cout << gainer.digital_inputs[j] << std::endl; |
|---|
| 198 | if (gainer.digital_inputs[j] and not prev[j]) { |
|---|
| 199 | if (moved) |
|---|
| 200 | std::cout << prev[j] << std::endl; |
|---|
| 201 | |
|---|
| 202 | UInt32 noteNum = 60 + FINGERS[j] + octave*OCTAVE_RANGE; |
|---|
| 203 | UInt32 onVelocity = 127; |
|---|
| 204 | UInt32 noteOnCommand = kMidiMessage_NoteOn << 4 | midiChannelInUse; |
|---|
| 205 | |
|---|
| 206 | require_noerr (result = MusicDeviceMIDIEvent(synthUnit, noteOnCommand, noteNum, 0, 0), home); |
|---|
| 207 | printf ("Playing Note: Status: 0x%lX, Note: %ld, Vel: %ld\n", noteOnCommand, noteNum, onVelocity); |
|---|
| 208 | require_noerr (result = MusicDeviceMIDIEvent(synthUnit, noteOnCommand, noteNum, onVelocity, 0), home); |
|---|
| 209 | |
|---|
| 210 | } |
|---|
| 211 | prev[j] = gainer.digital_inputs[j]; |
|---|
| 212 | } |
|---|
| 213 | |
|---|
| 214 | usleep (1 * 10 * 1000); |
|---|
| 215 | } |
|---|
| 216 | |
|---|
| 217 | // ok we're done now |
|---|
| 218 | |
|---|
| 219 | home: |
|---|
| 220 | if (graph) { |
|---|
| 221 | AUGraphStop (graph); // stop playback - AUGraphDispose will do that for us but just showing you what to do |
|---|
| 222 | DisposeAUGraph (graph); |
|---|
| 223 | } |
|---|
| 224 | return result; |
|---|
| 225 | } |
|---|