Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/Classes/MyMIDISequence.m

Parent Directory Parent Directory | Revision Log Revision Log


Revision 183 - (show annotations) (download)
Wed Mar 4 13:15:43 2020 UTC (4 years, 1 month ago) by toshinagata1964
File size: 18507 byte(s)
Internal errors during SMF saving are reported to the user
1 //
2 // MyMIDISequence.m
3 //
4 // Created by Toshi Nagata on Sun Jun 03 2001.
5 /*
6 Copyright (c) 2000-2016 Toshi Nagata. All rights reserved.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation version 2 of the License.
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
18 #import "MyMIDISequence.h"
19 #import "MyDocument.h"
20 #import "MDObjects.h"
21
22 NSString
23 *MyRecordingInfoSourceDeviceKey = @"sourceDevice",
24 *MyRecordingInfoDestinationDeviceKey = @"destinationDevice",
25 *MyRecordingInfoSourceAudioDeviceKey = @"sourceAudioDevice",
26 *MyRecordingInfoDestinationAudioDeviceKey = @"destinationAudioDevice",
27 *MyRecordingInfoFolderNameKey = @"folderName",
28 *MyRecordingInfoFileNameKey = @"fileName",
29 *MyRecordingInfoOverwriteExistingFileFlagKey = @"overwriteExistingFile",
30 *MyRecordingInfoMultiFileNamesKey = @"multiFileNames",
31 *MyRecordingInfoTrackSelectionsKey = @"trackSelections",
32 *MyRecordingInfoIsAudioKey = @"isAudio",
33 *MyRecordingInfoAudioPlayThroughKey = @"audioPlayThru",
34 *MyRecordingInfoDestinationChannelKey = @"destinationChannel",
35 *MyRecordingInfoTargetTrackKey = @"trackNumber",
36 *MyRecordingInfoReplaceFlagKey = @"replaceFlag",
37 *MyRecordingInfoStartTickKey = @"startTick",
38 *MyRecordingInfoStopTickKey = @"stopTick",
39 *MyRecordingInfoStopFlagKey = @"stopFlag",
40 *MyRecordingInfoRecordingModeKey = @"recordingMode",
41 *MyRecordingInfoCountOffNumberKey = @"countOffNumber",
42 *MyRecordingInfoBarBeatFlagKey = @"barBeatFlag",
43 *MyRecordingInfoMIDITransposeKey = @"MIDItranspose",
44 *MyRecordingInfoAudioRecordingFormatKey = @"audioRecordingFormat",
45 *MyRecordingInfoAudioBitRateKey = @"audioBitRate",
46 *MyRecordingInfoAudioChannelFormatKey = @"audioChannelFormat";
47
48 @implementation MyMIDISequence
49
50 - (id)init {
51 return [self initWithDocument:nil];
52 }
53
54 - (id)initWithDocument:(MyDocument *)document {
55 self = [super init];
56 if (self != nil) {
57 MDTrack *track;
58 int i;
59 myDocument = document;
60 mySequence = MDSequenceNew();
61 if (mySequence == NULL)
62 return nil;
63 /* Create conductor track and one empty track */
64 for (i = 0; i < 2; i++) {
65 track = MDTrackNew();
66 if (track == NULL) {
67 MDSequenceRelease(mySequence);
68 mySequence = NULL;
69 return nil;
70 }
71 if (MDSequenceInsertTrack(mySequence, i, track) < 0) {
72 MDTrackRelease(track);
73 MDSequenceRelease(mySequence);
74 mySequence = NULL;
75 return nil;
76 } else MDTrackRelease(track); /* track is retained by mySequence */
77 }
78 myPlayer = MDPlayerNew(mySequence);
79 if (myPlayer == NULL) {
80 MDSequenceRelease(mySequence);
81 mySequence = NULL;
82 return nil;
83 }
84 /* Initialize shared calibrator */
85 calib = MDCalibratorNew(mySequence, NULL, kMDEventTimeSignature, -1);
86 if (calib == NULL) {
87 MDSequenceRelease(mySequence);
88 mySequence = NULL;
89 return nil;
90 }
91 MDCalibratorAppend(calib, NULL, kMDEventTempo, -1);
92
93 /* Initialize MyRecordingInfo */
94 {
95 recordingInfo = [NSDictionary dictionaryWithObjectsAndKeys:
96 [NSNumber numberWithBool: NO], MyRecordingInfoIsAudioKey,
97 [NSNumber numberWithBool: NO], MyRecordingInfoAudioPlayThroughKey,
98 [NSNumber numberWithBool: NO], MyRecordingInfoOverwriteExistingFileFlagKey,
99 [NSNumber numberWithInt: 0], MyRecordingInfoDestinationChannelKey,
100 [NSNumber numberWithInt: -1], MyRecordingInfoTargetTrackKey,
101 [NSNumber numberWithBool: NO], MyRecordingInfoReplaceFlagKey,
102 [NSNumber numberWithDouble: 0.0], MyRecordingInfoStartTickKey,
103 [NSNumber numberWithDouble: 0.0], MyRecordingInfoStopTickKey,
104 [NSNumber numberWithBool: NO], MyRecordingInfoStopFlagKey,
105 [NSNumber numberWithInt: 0], MyRecordingInfoRecordingModeKey,
106 [NSNumber numberWithInt: 0], MyRecordingInfoCountOffNumberKey,
107 [NSNumber numberWithBool: NO], MyRecordingInfoBarBeatFlagKey,
108 [NSNumber numberWithInt: 0], MyRecordingInfoMIDITransposeKey,
109 [NSNumber numberWithInt: kAudioRecordingAIFFFormat], MyRecordingInfoAudioRecordingFormatKey,
110 [NSNumber numberWithFloat: 44100.0f], MyRecordingInfoAudioBitRateKey,
111 [NSNumber numberWithInt: kAudioRecordingStereoFormat], MyRecordingInfoAudioChannelFormatKey,
112 nil];
113 [recordingInfo retain];
114 }
115 }
116 return self;
117 }
118
119 - (void)dealloc {
120 if (myPlayer != NULL)
121 MDPlayerRelease(myPlayer);
122 if (mySequence != NULL)
123 MDSequenceRelease(mySequence);
124 [recordingInfo release];
125 [super dealloc];
126 }
127
128 #pragma mark ====== Access to sequence/track info ======
129
130 - (MyDocument *)myDocument {
131 return myDocument;
132 }
133
134 - (MDSequence *)mySequence {
135 return mySequence;
136 }
137
138 - (int32_t)lookUpTrack:(MDTrack *)track {
139 int32_t count;
140 if (mySequence != NULL) {
141 for (count = MDSequenceGetNumberOfTracks(mySequence) - 1; count >= 0; count--) {
142 if (MDSequenceGetTrack(mySequence, count) == track)
143 return count;
144 }
145 }
146 return -1;
147 }
148
149 - (MDTrack *)getTrackAtIndex: (int)index {
150 if (mySequence != NULL)
151 return MDSequenceGetTrack(mySequence, index);
152 else return NULL;
153 }
154
155 - (int32_t)trackCount {
156 if (mySequence != NULL)
157 return MDSequenceGetNumberOfTracks(mySequence);
158 else return 0;
159 }
160
161 - (MDTickType)sequenceDuration {
162 if (mySequence != NULL) {
163 MDTickType duration = MDSequenceGetDuration(mySequence);
164 if (recordTrack != NULL) {
165 /* Recording */
166 MDTickType rduration = MDPlayerGetTick(myPlayer);
167 /* MDTickType rduration = MDTrackGetDuration(recordTrack); */
168 if (duration < rduration)
169 return rduration;
170 }
171 return duration;
172 } else return 0;
173 }
174
175 /*
176 - (void)updateTrackName:(int32_t)index {
177 if (mySequence != NULL) {
178 MDTrack *track = MDSequenceGetTrack(mySequence, index);
179 if (track != NULL) {
180 char buf[256];
181 MDTrackGuessName(track, buf, sizeof buf);
182 MDTrackSetName(track, buf);
183 }
184 }
185 }
186 */
187
188 - (NSString *)trackName:(int32_t)index {
189 if (mySequence != NULL) {
190 MDTrack *track;
191 char buf[256];
192 track = MDSequenceGetTrack(mySequence, index);
193 if (track != NULL) {
194 MDTrackGetName(track, buf, sizeof buf);
195 return [NSString stringWithUTF8String:buf];
196 }
197 }
198 return nil;
199 }
200
201 - (NSString *)deviceName:(int32_t)index {
202 if (mySequence != NULL) {
203 MDTrack *track;
204 char buf[256];
205 track = MDSequenceGetTrack(mySequence, index);
206 if (track != NULL) {
207 // if (MDTrackGetNumberOfChannelEvents(track, -1) + MDTrackGetNumberOfSysexEvents(track) > 0) {
208 // MDTrackGuessDeviceName(track, buf, sizeof buf);
209 // int32_t dev = MDTrackGetDevice(track);
210 // if (dev < 0 || MDPlayerGetDestinationName(dev, buf, sizeof buf) != kMDNoError)
211 MDTrackGetDeviceName(track, buf, sizeof buf);
212 return [NSString stringWithUTF8String: buf];
213 // }
214 }
215 }
216 return nil;
217 }
218
219 - (int)trackChannel:(int32_t)index {
220 if (mySequence != NULL) {
221 MDTrack *track = MDSequenceGetTrack(mySequence, index);
222 if (track != NULL) {
223 // if (MDTrackGetNumberOfChannelEvents(track, -1) > 0)
224 return MDTrackGetTrackChannel(track);
225 }
226 }
227 return -1;
228 }
229
230 - (MDTrackAttribute)trackAttributeAtIndex: (int32_t)index
231 {
232 if (mySequence != NULL) {
233 MDTrack *track = MDSequenceGetTrack(mySequence, index);
234 if (track != NULL) {
235 return MDTrackGetAttribute(track);
236 }
237 }
238 return 0;
239 }
240
241 - (void)setTrackAttribute: (MDTrackAttribute)attribute atIndex: (int32_t)index
242 {
243 if (mySequence != NULL) {
244 MDTrack *track = MDSequenceGetTrack(mySequence, index);
245 if (track != NULL) {
246 MDTrackAttribute oldAttr = MDTrackGetAttribute(track);
247 MDTrackSetAttribute(track, attribute);
248 if ((oldAttr & kMDTrackAttributeSolo) != (attribute & kMDTrackAttributeSolo))
249 MDSequenceUpdateMuteBySoloFlag(mySequence);
250 }
251 }
252 }
253
254 - (MDCalibrator *)sharedCalibrator
255 {
256 return calib;
257 }
258
259 #pragma mark ====== File I/O ======
260
261 - (MDStatus)readSMFFromFile:(NSString *)fileName withCallback: (MDSequenceCallback)callback andData: (void *)data
262 {
263 MDSequence *sequence;
264 MDStatus sts;
265 STREAM stream;
266 sequence = MDSequenceNew();
267
268 if (sequence == NULL) {
269 return kMDErrorOutOfMemory;
270 } else {
271 stream = MDStreamOpenFile([fileName fileSystemRepresentation], "rb");
272 if (stream != NULL) {
273 sts = MDSequenceReadSMF(sequence, stream, callback, data);
274 FCLOSE(stream);
275 } else sts = kMDErrorCannotOpenFile;
276 if (sts == kMDNoError)
277 sts = MDSequenceSingleChannelMode(sequence, 1);
278 if (sts != kMDNoError) {
279 MDSequenceRelease(sequence);
280 sequence = NULL;
281 }
282 }
283 if (sts != kMDNoError)
284 return sts;
285
286 if (calib != NULL) {
287 MDCalibratorRelease(calib);
288 calib = NULL;
289 }
290 if (mySequence != NULL)
291 MDSequenceRelease(mySequence);
292 mySequence = sequence;
293 if (mySequence != NULL) {
294 calib = MDCalibratorNew(mySequence, NULL, kMDEventTimeSignature, -1);
295 if (calib == NULL)
296 sts = kMDErrorOutOfMemory;
297 else
298 sts = MDCalibratorAppend(calib, NULL, kMDEventTempo, -1);
299 if (sts != kMDNoError)
300 return sts;
301 myPlayer = MDPlayerNew(mySequence);
302 if (myPlayer == NULL)
303 sts = kMDErrorOutOfMemory;
304 }
305 return sts;
306 }
307
308 - (MDStatus)writeSMFToFile:(NSString *)fileName withCallback: (MDSequenceCallback)callback andData: (void *)data errorMessage: (char **)errorMessage
309 {
310 MDStatus sts;
311 STREAM stream, err_stream;
312 if (mySequence != NULL) {
313 stream = MDStreamOpenFile([fileName fileSystemRepresentation], "wb");
314 if (stream != NULL) {
315 char *errdata;
316 size_t errsize;
317 if (errorMessage != NULL) {
318 err_stream = MDStreamOpenData(NULL, 0);
319 *errorMessage= NULL;
320 } else
321 err_stream = NULL;
322 sts = MDSequenceWriteSMF(mySequence, stream, callback, data, err_stream);
323 FCLOSE(stream);
324 if (err_stream != NULL) {
325 MDStreamGetData(err_stream, (void **)(&errdata), &errsize);
326 if (errsize > 0) {
327 errdata = (char *)realloc(errdata, errsize + 1);
328 errdata[errsize] = 0; /* Be sure that the message is null-terminated */
329 *errorMessage = errdata;
330 }
331 }
332 } else sts = kMDErrorCannotCreateFile;
333 } else sts = kMDErrorInternalError;
334 return sts;
335 }
336
337 #pragma mark ====== Player support ======
338
339 - (MDPlayer *)myPlayer {
340 return myPlayer;
341 }
342
343 /*
344 - (id)startPlay:(id)sender {
345 // if (myPlayer == NULL && mySequence != NULL)
346 // myPlayer = MDPlayerNew(mySequence);
347 if (myPlayer != NULL)
348 MDPlayerStart(myPlayer);
349 return self;
350 }
351
352 - (id)stopPlay:(id)sender {
353 if (myPlayer != NULL)
354 MDPlayerStop(myPlayer);
355 return self;
356 }
357 */
358
359 - (BOOL)isPlaying
360 {
361 MDPlayerStatus status;
362 if (myPlayer != NULL) {
363 status = MDPlayerGetStatus(myPlayer);
364 return (status == kMDPlayer_playing || status == kMDPlayer_exhausted);
365 }
366 return NO;
367 }
368
369 - (BOOL)isSuspended
370 {
371 MDPlayerStatus status;
372 if (myPlayer != NULL) {
373 status = MDPlayerGetStatus(myPlayer);
374 return (status == kMDPlayer_suspended);
375 }
376 return NO;
377 }
378
379 - (float)playingTime
380 {
381 if (myPlayer != NULL) {
382 return (float)MDPlayerGetTime(myPlayer);
383 } else return -1.0f;
384 }
385
386 //- (float)playingBeat
387 //{
388 // if (myPlayer != NULL) {
389 // return (float)MDPlayerGetTick(myPlayer) / MDSequenceGetTimebase(mySequence);
390 // } else return -1.0;
391 //}
392
393 #pragma mark ====== MIDI/Audio Recording ======
394
395 NSString *
396 MyRecordingInfoFileExtensionForFormat(int format)
397 {
398 switch (format) {
399 case kAudioRecordingAIFFFormat: return @"aiff";
400 case kAudioRecordingWAVFormat: return @"wav";
401 default: return @"";
402 }
403 }
404
405 - (NSDictionary *)recordingInfo
406 {
407 return recordingInfo;
408 }
409
410 - (void)setRecordingInfo: (NSDictionary *)anInfo
411 {
412 [recordingInfo autorelease];
413 recordingInfo = [anInfo retain];
414 }
415
416 - (MDStatus)startMIDIRecording
417 {
418 int32_t dev;
419 int ch, trans;
420 MDTickType tick;
421 NSString *destDevice;
422 if (mySequence == NULL || myPlayer == NULL)
423 return kMDErrorInternalError;
424 recordTrack = MDTrackNew();
425 if (recordTrack == NULL)
426 return kMDErrorOutOfMemory;
427 if ((destDevice = [recordingInfo valueForKey: MyRecordingInfoDestinationDeviceKey]) != nil)
428 dev = MDPlayerGetDestinationNumberFromName([destDevice UTF8String]);
429 else dev = -1;
430 ch = [[recordingInfo valueForKey: MyRecordingInfoDestinationChannelKey] intValue];
431 MDPlayerSetMIDIThruDeviceAndChannel(dev, ch);
432 trans = [[recordingInfo valueForKey: MyRecordingInfoMIDITransposeKey] intValue];
433 MDPlayerSetMIDIThruTranspose(trans);
434 tick = (MDTickType)[[recordingInfo valueForKey: MyRecordingInfoStartTickKey] doubleValue];
435 if (tick >= 0 && tick < kMDMaxTick)
436 MDPlayerJumpToTick(myPlayer, tick);
437 if ([[recordingInfo valueForKey: MyRecordingInfoStopFlagKey] boolValue]) {
438 tick = (MDTickType)[[recordingInfo valueForKey: MyRecordingInfoStopTickKey] doubleValue];
439 MDPlayerSetRecordingStopTick(myPlayer, tick);
440 }
441 MDPlayerStartRecording(myPlayer);
442 return kMDNoError;
443 }
444
445 - (int32_t)collectRecordedEvents
446 {
447 MDEvent *eventBuf;
448 int eventBufSize;
449 MDStatus result = kMDNoError;
450 MDPointer *lastPendingNoteOn;
451 int count;
452 int32_t n = 0;
453 // if (recordTrack == NULL || recordNoteOffTrack == NULL)
454 // return kMDErrorInternalError;
455 if (recordTrack == NULL)
456 return -2;
457 eventBuf = NULL;
458 eventBufSize = 0;
459 lastPendingNoteOn = MDPointerNew(recordTrack);
460 while ((count = MDPlayerGetRecordedEvents(myPlayer, &eventBuf, &eventBufSize)) > 0) {
461 MDEvent *ep;
462 for (ep = eventBuf; ep < eventBuf + count; ep++) {
463 if (MDGetKind(ep) == kMDEventInternalNoteOff) {
464 result = MDTrackMatchNoteOff(recordTrack, ep, lastPendingNoteOn);
465 } else {
466 if (MDTrackAppendEvents(recordTrack, ep, 1) < 1)
467 result = kMDErrorOutOfMemory;
468 MDEventClear(ep);
469 }
470 if (result != kMDNoError)
471 break;
472 n++;
473 }
474 }
475 MDPointerRelease(lastPendingNoteOn);
476 if (result != kMDNoError)
477 return -1; /* Error */
478
479 /* Update the track duration */
480 if (n > 0) {
481 MDTrackSetDuration(recordTrack, MDTrackGetLargestTick(recordTrack) + 1);
482 }
483
484 return n;
485 }
486
487 //- (MDStatus)finishMIDIRecordingAndGetTrack: (MDTrackObject **)outTrack andTrackIndex: (int32_t *)outIndex
488
489 - (MDTrackObject *)finishMIDIRecording
490 {
491 // MDStatus result;
492 int32_t n;
493 MDTrackObject *trackObj;
494 if (mySequence == NULL || myPlayer == NULL)
495 return nil;
496 MDPlayerStopRecording(myPlayer);
497 // if (recordTrack == NULL || recordNoteOffTrack == NULL)
498 if (recordTrack == NULL)
499 return nil;
500 n = [self collectRecordedEvents];
501 // result = MDTrackMatchNoteOffInTrack(recordTrack, recordNoteOffTrack);
502
503 // if (n >= 0) {
504 trackObj = [[[MDTrackObject allocWithZone: [self zone]] initWithMDTrack: recordTrack] autorelease];
505 // if (outTrack != NULL)
506 // *outTrack = [[[MDTrackObject allocWithZone: [self zone]] initWithMDTrack: recordTrack] autorelease];
507 // if (outIndex != NULL)
508 // *outIndex = MDSequenceGetIndexOfRecordingTrack(mySequence);
509 // } else trackObj = nil;
510
511 MDTrackRelease(recordTrack);
512 recordTrack = NULL;
513
514 // MDTrackRelease(recordNoteOffTrack);
515 // recordTrack = recordNoteOffTrack = NULL;
516
517 return trackObj;
518 }
519
520 - (MDTrack *)recordTrack
521 {
522 return recordTrack;
523 }
524
525 - (MDStatus)startAudioRecordingWithName: (NSString *)filename
526 {
527 // NSString *sourceAudioDevice;
528 // MDAudioDeviceID deviceID;
529 // MDAudioDeviceInfo *infop;
530 MDTickType tick, stopTick;
531 UInt64 duration;
532 MDStatus result;
533 // MDAudio *myAudio;
534 MDAudioFormat audioFormat;
535 int fileFormat, channelFormat, mdAudioFileFormat;
536
537 if (mySequence == NULL || myPlayer == NULL)
538 return kMDErrorInternalError;
539 // sourceAudioDevice = [recordingInfo valueForKey: MyRecordingInfoSourceAudioDeviceKey];
540 // if (sourceAudioDevice == nil || (infop = MDAudioDeviceInfoWithName([sourceAudioDevice UTF8String], 1, NULL)) == NULL || (deviceID = infop->deviceID) == kMDAudioDeviceUnknown)
541 // return kMDErrorCannotSetupAudio;
542 // myAudio = MDPlayerGetAudioPlayer(myPlayer);
543 tick = (MDTickType)[[recordingInfo valueForKey: MyRecordingInfoStartTickKey] doubleValue];
544 if (tick >= 0 && tick < kMDMaxTick)
545 MDPlayerJumpToTick(myPlayer, tick);
546 tick = MDPlayerGetTick(myPlayer);
547 fileFormat = [[recordingInfo valueForKey: MyRecordingInfoAudioRecordingFormatKey] intValue];
548 channelFormat = [[recordingInfo valueForKey: MyRecordingInfoAudioChannelFormatKey] intValue];
549 audioFormat.mSampleRate = [[recordingInfo valueForKey: MyRecordingInfoAudioBitRateKey] floatValue];
550 audioFormat.mFormatID = kAudioFormatLinearPCM;
551 switch (fileFormat) {
552 case kAudioRecordingWAVFormat:
553 audioFormat.mFormatFlags = (kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked);
554 mdAudioFileFormat = kMDAudioFileWAVType;
555 break;
556 case kAudioRecordingAIFFFormat:
557 default:
558 audioFormat.mFormatFlags = (kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked);
559 mdAudioFileFormat = kMDAudioFileAIFFType;
560 break;
561 }
562 switch (channelFormat) {
563 case kAudioRecordingMonoFormat: audioFormat.mChannelsPerFrame = 1; break;
564 case kAudioRecordingStereoFormat: audioFormat.mChannelsPerFrame = 2; break;
565 default: audioFormat.mChannelsPerFrame = 2; break;
566 }
567 audioFormat.mBitsPerChannel = 24;
568 audioFormat.mBytesPerFrame = (audioFormat.mBitsPerChannel / 8) * audioFormat.mChannelsPerFrame;
569 audioFormat.mFramesPerPacket = 1;
570 audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame * audioFormat.mFramesPerPacket;
571 audioFormat.mReserved = 0;
572 // MDAudioFormatSetCanonical(&audioFormat, 44100, 2, YES);
573
574 /* #error "Maybe need to set up audio thru device here" */
575
576 duration = 0;
577 if ([[recordingInfo valueForKey: MyRecordingInfoStopFlagKey] boolValue]) {
578 MDTimeType durationTime;
579 stopTick = (MDTickType)[[recordingInfo valueForKey: MyRecordingInfoStopTickKey] doubleValue];
580 MDPlayerSetRecordingStopTick(myPlayer, stopTick);
581 durationTime = MDCalibratorTickToTime(calib, stopTick) - MDCalibratorTickToTime(calib, tick);
582 if (durationTime > 0)
583 duration = ConvertMDTimeTypeToHostTime(durationTime);
584 }
585
586 result = MDAudioPrepareRecording([filename fileSystemRepresentation], &audioFormat, mdAudioFileFormat, duration);
587 if (result != kMDNoError)
588 return result;
589
590 MDPlayerStart(myPlayer);
591 MDAudioStartRecording();
592
593 return kMDNoError;
594 }
595
596 - (MDStatus)finishAudioRecordingByMIDISequence
597 {
598 if (mySequence == NULL || myPlayer == NULL)
599 return kMDErrorInternalError;
600 return MDAudioStopRecording();
601 }
602
603 @end

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26