Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/Classes/PlayingPanelController.m

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (show annotations) (download)
Sat Sep 3 06:22:57 2011 UTC (12 years, 7 months ago) by toshinagata1964
File size: 16721 byte(s)
initial import
1 //
2 // PlayingPanelCotroller.m
3 //
4 // Created by Toshi Nagata.
5 /*
6 Copyright (c) 2000-2011 Toshi Nagata. All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
9
10 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
12
13 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14 */
15
16 #import "PlayingPanelController.h"
17 #import "MyDocument.h"
18 #import "MyMIDISequence.h"
19
20 @implementation PlayingPanelController
21
22 static PlayingPanelController *sharedPlayingPanelController = nil;
23
24 + (PlayingPanelController *)sharedPlayingPanelController
25 {
26 return sharedPlayingPanelController;
27 }
28
29 - (id)init
30 {
31 self = [super initWithWindowNibName:@"PlayingPanel"];
32 sharedPlayingPanelController = self;
33 activeIndex = -1;
34 status = kMDPlayer_idle;
35 docArray = [[NSMutableArray allocWithZone: [self zone]] initWithCapacity: 16];
36 tickArray = [[NSMutableArray allocWithZone: [self zone]] initWithCapacity: 16];
37 calibrator = NULL;
38 totalTime = currentTime = 0;
39 timer = nil;
40 // resumeTimer = nil;
41 // shouldContinuePlay = NO;
42 isRecording = NO;
43 MDPlayerInitMIDIDevices();
44 [[self window] makeKeyAndOrderFront: self];
45 return self;
46 }
47
48 - (void)dealloc
49 {
50 if (calibrator != NULL)
51 MDCalibratorRelease(calibrator);
52 // [timer autorelease];
53 [tickArray release];
54 [docArray release];
55 [[NSNotificationCenter defaultCenter]
56 removeObserver:self];
57 [super dealloc];
58 }
59
60 - (void)windowDidLoad
61 {
62 NSFont *font;
63 [markerPopup removeAllItems];
64 [tunePopup removeAllItems];
65 [markerPopup setEnabled: NO];
66 [tunePopup setEnabled: NO];
67 font = [NSFont userFixedPitchFontOfSize: -1.0];
68 [timeField setFont: font];
69 [countField setFont: font];
70 [[NSNotificationCenter defaultCenter]
71 addObserver:self
72 selector:@selector(trackModified:)
73 name:MyDocumentTrackModifiedNotification
74 object:nil];
75 [self refreshTimeDisplay];
76 }
77
78 - (void)refreshTimeDisplay
79 {
80 MDPlayer *player;
81 MDTickType tick;
82 MDTimeType time;
83 double d, slider;
84 long bar, beat, count, marker, ntime;
85 int hour, min, sec;
86 NSString *countString, *timeString;
87
88 if (activeIndex < 0) {
89 currentTime = 0;
90 countString = @"----:--:----";
91 timeString = @"--:--:--";
92 marker = -1;
93 slider = 0.0;
94 status = kMDPlayer_idle;
95 [recordButton setEnabled: NO];
96 [stopButton setEnabled: NO];
97 [playButton setEnabled: NO];
98 [pauseButton setEnabled: NO];
99 [ffButton setEnabled: NO];
100 [rewindButton setEnabled: NO];
101 } else {
102 MyDocument *doc = [docArray objectAtIndex: activeIndex];
103 [stopButton setEnabled: YES];
104 [playButton setEnabled: YES];
105 [pauseButton setEnabled: YES];
106 [ffButton setEnabled: YES];
107 [rewindButton setEnabled: YES];
108 if (status == kMDPlayer_playing) {
109 player = [[doc myMIDISequence] myPlayer];
110 if (player != NULL)
111 currentTime = MDPlayerGetTime(player); /* Update the current time */
112 }
113
114 if (MDSequenceGetIndexOfRecordingTrack([[doc myMIDISequence] mySequence]) < 0)
115 [recordButton setEnabled: NO];
116 else [recordButton setEnabled: YES];
117
118 /* [playButton hilite: (status == kMDPlayer_playing)];
119 [pauseButton hilite: (status == kMDPlayer_suspended)];
120 [recordButton hilite: isRecording]; */
121
122 // if (resumeTimer != nil)
123 // time = currentTime; /* During FF/Rew/Slider actions, time should come from the controls */
124 // else
125 // time = currentTime = MDPlayerGetTime(player);
126 /* Display tick and time */
127 if (currentTime == 0) {
128 time = totalTime;
129 countString = @"----:--:----";
130 marker = -1;
131 slider = 0.0;
132 } else {
133 time = currentTime;
134 tick = MDCalibratorTimeToTick(calibrator, time);
135 MDCalibratorTickToMeasure(calibrator, tick, &bar, &beat, &count);
136 countString = [NSString stringWithFormat: @"%4ld:%2ld:%4ld", bar, beat, count];
137 if (totalTime > 0) {
138 slider = (double)time / totalTime * 100.0;
139 } else slider = 0.0;
140 marker = [tickArray count];
141 if (marker >= 1) {
142 d = (double)tick;
143 while (--marker >= 0) {
144 if ([[tickArray objectAtIndex: marker] doubleValue] <= d)
145 break;
146 }
147 if (marker < 0)
148 marker = 0;
149 } else marker = -1;
150 }
151 ntime = (long)(time / 1000000);
152 hour = ntime / 3600;
153 min = (ntime / 60) % 60;
154 sec = ntime % 60;
155 timeString = [NSString stringWithFormat: @"%02d:%02d:%02d", hour, min, sec];
156 [doc postPlayPositionNotification: (status == kMDPlayer_playing ? MDCalibratorTimeToTick(calibrator, currentTime) : -1.0)];
157 }
158 [timeField setStringValue: timeString];
159 [countField setStringValue: countString];
160 [positionSlider setDoubleValue: slider];
161 if (marker >= 0)
162 [markerPopup selectItemAtIndex: marker];
163 }
164
165 /*
166 - (void)resumeTimerCallback: (NSTimer *)timer
167 {
168 MDPlayer *player;
169 if (activeIndex >= 0) {
170 player = [[[docArray objectAtIndex: activeIndex] myMIDISequence] myPlayer];
171 MDPlayerPreroll(player, MDCalibratorTimeToTick(calibrator, currentTime));
172 status = kMDPlayer_suspended;
173 if (shouldContinuePlay)
174 [self pressPlayButton: self];
175 else {
176 [playButton setState: NSOffState];
177 [pauseButton setState: NSOnState];
178 }
179 }
180 [resumeTimer invalidate];
181 [resumeTimer release];
182 resumeTimer = nil;
183 [timeField setBackgroundColor: [NSColor whiteColor]];
184 shouldContinuePlay = NO;
185 }
186
187 - (void)setResumeTimer
188 {
189 if (resumeTimer == nil)
190 [timeField setBackgroundColor: [NSColor lightGrayColor]];
191 else
192 [resumeTimer invalidate];
193
194 // For better user experience, the play button is left pressed during
195 // FF/Rew/Slider action
196 if (shouldContinuePlay)
197 [playButton setState: NSOnState];
198
199 resumeTimer = [[NSTimer scheduledTimerWithTimeInterval: 0.5 target: self selector:@selector(resumeTimerCallback:) userInfo:nil repeats:NO] retain];
200 }
201 */
202
203 - (void)updateMarkerList
204 {
205 MDPointer *pos;
206 MDTrack *track;
207 MDSequence *sequence;
208
209 [markerPopup removeAllItems];
210 [markerPopup setEnabled: NO];
211 [tickArray removeAllObjects];
212 // totalTime = currentTime = 0;
213
214 if (activeIndex < 0)
215 return;
216
217 sequence = [[[docArray objectAtIndex: activeIndex] myMIDISequence] mySequence];
218 if (sequence == NULL)
219 return;
220
221 /* Total playing time */
222 totalTime = MDCalibratorTickToTime(calibrator, MDSequenceGetDuration(sequence));
223
224 /* The marker list */
225 track = MDSequenceGetTrack(sequence, 0);
226 pos = MDPointerNew(track);
227 if (pos != NULL) {
228 /* Search all the markers in the conductor track */
229 int n;
230 MDEvent *ep;
231 MDTickType tick;
232 NSString *name;
233 long length;
234 n = 0;
235 while ((ep = MDPointerForward(pos)) != NULL) {
236 if (MDIsTextMetaEvent(ep) && MDGetCode(ep) == kMDMetaMarker) {
237 tick = MDGetTick(ep);
238 name = [NSString stringWithFormat: @"%09d: %s", n++, MDGetMessageConstPtr(ep, &length)]; /* Prefix the name with a serial number to ensure uniqueness of the titles */
239 [tickArray addObject: [NSNumber numberWithDouble: (double)tick]];
240 [markerPopup addItemWithTitle: name];
241 }
242 }
243 while (--n >= 0) {
244 /* Remove the serial numbers from the menu titles, and set tag */
245 NSMenuItem *item = [markerPopup itemAtIndex: n];
246 if (item) {
247 [item setTitle: [[item title] substringFromIndex: 11]];
248 [item setTag: n];
249 }
250 }
251 [markerPopup setEnabled: ([markerPopup numberOfItems] > 0)];
252 MDPointerRelease(pos);
253 }
254 }
255
256 - (void)selectTuneAtIndex:(int)index
257 {
258 MDSequence *sequence;
259 MDTrack *track;
260 MDStatus sts = kMDNoError;
261 // MDPointer *pos;
262 // MDEvent *ep;
263 // MDTickType tick;
264 // long length;
265 // NSString *name;
266 // int n;
267
268 if (index < 0 || index >= [tunePopup numberOfItems]) {
269 activeIndex = -1;
270 status = kMDPlayer_idle;
271 sequence = NULL;
272 } else {
273 [tunePopup selectItemAtIndex: index];
274 if (index == activeIndex)
275 return;
276 if (status == kMDPlayer_playing || status == kMDPlayer_suspended)
277 [self pressStopButton: self];
278 status = kMDPlayer_ready;
279 activeIndex = index;
280 sequence = [[[docArray objectAtIndex: index] myMIDISequence] mySequence];
281 }
282 isRecording = NO;
283
284 /* Remove old information */
285 if (calibrator != NULL) {
286 MDCalibratorRelease(calibrator);
287 calibrator = NULL;
288 }
289
290 if (sequence != NULL) {
291 track = MDSequenceGetTrack(sequence, 0); /* the conductor track */
292 calibrator = MDCalibratorNew(sequence, track, kMDEventTempo, -1); /* create a new calibrator */
293 if (calibrator != NULL)
294 sts = MDCalibratorAppend(calibrator, track, kMDEventTimeSignature, -1);
295 if (sts == kMDNoError)
296 sts = MDCalibratorAppend(calibrator, track, kMDEventMetaText, kMDMetaMarker);
297 }
298
299 [self updateMarkerList];
300 [self refreshTimeDisplay];
301 }
302
303 - (int)refreshMIDIDocument: (MyDocument *)document
304 {
305 unsigned int n;
306
307 n = [docArray indexOfObject: document];
308 if (n == NSNotFound) {
309 [docArray addObject: document];
310 n = [docArray count] - 1;
311 /* Create a menu item with a dummy name that is unlikely to conflict with the existing name */
312 [[tunePopup menu] addItemWithTitle: [document tuneName] action: nil keyEquivalent: @""];
313 [tunePopup setEnabled: YES];
314 if (activeIndex == -1)
315 [self selectTuneAtIndex: n];
316 } else {
317 /* Update the item name */
318 [[tunePopup itemAtIndex: n] setTitle: [document tuneName]];
319 // if ([tunePopup indexOfSelectedItem] == n)
320 // [self selectTuneAtIndex: n]; /* Refresh the internal information */
321 }
322 return n;
323 }
324
325 - (void)removeMIDIDocument: (MyDocument *)document
326 {
327 unsigned int n;
328 n = [docArray indexOfObject: document];
329 if (n != NSNotFound) {
330 if (n == activeIndex)
331 [self pressStopButton: self];
332 [docArray removeObjectAtIndex: n];
333 [tunePopup removeItemAtIndex: n];
334 if ([tunePopup numberOfItems] == 0) {
335 [tunePopup setEnabled: NO];
336 [self selectTuneAtIndex: -1];
337 } else {
338 if (n > 0)
339 n--;
340 [self selectTuneAtIndex: n];
341 }
342 }
343 }
344
345 - (void)timerCallback: (NSTimer *)timer
346 {
347 MyDocument *doc;
348 MDPlayer *player;
349 if (activeIndex >= 0 && status == kMDPlayer_playing) {
350 doc = [docArray objectAtIndex: activeIndex];
351 [self refreshTimeDisplay];
352 // [playButton hilite: YES];
353 player = [[doc myMIDISequence] myPlayer];
354 if (player != NULL && MDPlayerGetStatus(player) == kMDPlayer_exhausted)
355 [self pressStopButton: self];
356 }
357 }
358
359 #pragma mark ====== Action methods ======
360
361 - (void)prerollWithFeedback
362 {
363 MDPlayer *player;
364 if (activeIndex >= 0) {
365 player = [[[docArray objectAtIndex: activeIndex] myMIDISequence] myPlayer];
366 if (player != NULL) {
367 [progressIndicator startAnimation: self];
368 MDPlayerPreroll(player, MDCalibratorTimeToTick(calibrator, currentTime), 1);
369 [progressIndicator stopAnimation: self];
370 }
371 }
372 }
373
374 - (void)restartAfterManualMovement
375 {
376 if (status == kMDPlayer_suspended || shouldContinuePlay) {
377 MDPlayer *player = [[[docArray objectAtIndex: activeIndex] myMIDISequence] myPlayer];
378 if (shouldContinuePlay) {
379 /* Note: recording will be stopped and does not recover automatically */
380 MDPlayerJumpToTick(player, MDCalibratorTimeToTick(calibrator, currentTime));
381 [self pressPlayButton: self];
382 } else {
383 [self prerollWithFeedback];
384 }
385 }
386 shouldContinuePlay = NO;
387 }
388
389 - (IBAction)moveSlider:(id)sender
390 {
391 if (activeIndex >= 0) {
392 if (status == kMDPlayer_playing) {
393 [self pressStopButton: self];
394 shouldContinuePlay = YES;
395 }
396 currentTime = totalTime * ([sender doubleValue] / 100.0);
397 [self refreshTimeDisplay];
398 if ([[NSApp currentEvent] type] == NSLeftMouseUp)
399 [self restartAfterManualMovement];
400 }
401 }
402
403 - (IBAction)pressFFButton:(id)sender
404 {
405 // MDPlayer *player;
406 if (activeIndex >= 0) {
407 if (status == kMDPlayer_playing) {
408 [self pressStopButton: self];
409 shouldContinuePlay = YES;
410 }
411 currentTime += 1000000;
412 if (currentTime > totalTime)
413 currentTime = totalTime;
414 [self refreshTimeDisplay];
415 if ([[NSApp currentEvent] type] == NSLeftMouseUp)
416 [self restartAfterManualMovement];
417 }
418 }
419
420 - (IBAction)pressRewindButton:(id)sender
421 {
422 if (activeIndex >= 0) {
423 if (status == kMDPlayer_playing) {
424 [self pressStopButton: self];
425 shouldContinuePlay = YES;
426 }
427 currentTime -= 1000000;
428 if (currentTime < 0)
429 currentTime = 0;
430 [self refreshTimeDisplay];
431 if ([[NSApp currentEvent] type] == NSLeftMouseUp)
432 [self restartAfterManualMovement];
433 }
434 }
435
436 - (IBAction)pressPauseButton:(id)sender
437 {
438 MDPlayer *player;
439 MyDocument *doc;
440 if (activeIndex < 0)
441 return;
442 doc = [docArray objectAtIndex: activeIndex];
443 player = [[doc myMIDISequence] myPlayer];
444 if (status == kMDPlayer_playing) {
445 MDPlayerSuspend(player);
446 status = kMDPlayer_suspended;
447 [playButton setState: NSOffState];
448 } else if (status == kMDPlayer_ready) {
449 /* Jump to the "current" time, send MIDI events before that time, and wait for play */
450 [self prerollWithFeedback];
451 status = kMDPlayer_suspended;
452 } else return;
453 [pauseButton setState: NSOnState];
454 /* [[docArray objectAtIndex: activeIndex] postPlayPositionNotification]; */
455 }
456
457 - (void)pressPlayButtonWithRecording:(BOOL)isRecordButton
458 {
459 MDPlayer *player;
460 MyDocument *doc;
461 if (activeIndex < 0)
462 return;
463 doc = [docArray objectAtIndex: activeIndex];
464 player = [[doc myMIDISequence] myPlayer];
465 [playButton setState: NSOnState];
466 if (status == kMDPlayer_playing)
467 return;
468 else if (status == kMDPlayer_suspended) {
469 [pauseButton setState: NSOffState];
470 } else if (status == kMDPlayer_ready) {
471 MDPlayerJumpToTick(player, MDCalibratorTimeToTick(calibrator, currentTime));
472 }
473 if (isRecordButton)
474 [doc startRecording];
475 else
476 MDPlayerStart(player);
477 timer = [[NSTimer scheduledTimerWithTimeInterval: 0.1 target: self selector:@selector(timerCallback:) userInfo:nil repeats:YES] retain];
478 status = kMDPlayer_playing;
479 }
480
481 - (IBAction)pressPlayButton:(id)sender
482 {
483 [self pressPlayButtonWithRecording: NO];
484 }
485
486 - (IBAction)pressRecordButton:(id)sender
487 {
488 [self pressPlayButtonWithRecording: YES];
489 }
490
491 - (IBAction)pressStopButton:(id)sender
492 {
493 MyDocument *doc;
494 MDPlayer *player;
495 if (activeIndex < 0)
496 return;
497 doc = [docArray objectAtIndex: activeIndex];
498 player = [[doc myMIDISequence] myPlayer];
499 if (status == kMDPlayer_ready) {
500 MDPlayerJumpToTick(player, 0); /* Rewind to the beginning of the tune */
501 currentTime = 0;
502 } else {
503 if (status == kMDPlayer_playing) {
504 [timer invalidate];
505 [timer release];
506 timer = nil;
507 }
508 if (MDPlayerIsRecording(player))
509 [doc finishRecording];
510 MDPlayerStop(player);
511 }
512 status = kMDPlayer_ready;
513 [self refreshTimeDisplay];
514 // [doc postPlayPositionNotification];
515 [playButton setState: NSOffState];
516 [pauseButton setState: NSOffState];
517 [recordButton setState: NSOffState];
518 // [doc postStopPlayingNotification];
519 }
520
521 - (IBAction)selectMarker:(id)sender
522 {
523 MDPlayer *player;
524 int index;
525 MDTickType tick;
526 if (activeIndex >= 0) {
527 player = [[[docArray objectAtIndex: activeIndex] myMIDISequence] myPlayer];
528 index = [sender indexOfSelectedItem];
529 if (index >= 0 && index < [tickArray count]) {
530 if (status == kMDPlayer_playing) {
531 shouldContinuePlay = YES;
532 [self pressStopButton: self];
533 }
534 tick = (MDTimeType)[[tickArray objectAtIndex: index] doubleValue];
535 currentTime = MDCalibratorTickToTime(calibrator, tick);
536 if (shouldContinuePlay)
537 [self pressPlayButton: self];
538 else if (status == kMDPlayer_suspended) {
539 MDPlayerPreroll(player, tick, 1);
540 [pauseButton setState: NSOnState];
541 }
542 [self refreshTimeDisplay];
543 shouldContinuePlay = NO;
544 }
545 }
546 }
547
548 - (IBAction)selectTune:(id)sender
549 {
550 [self selectTuneAtIndex: [tunePopup indexOfSelectedItem]];
551 }
552
553 #pragma mark ====== Notification Handler ======
554
555 - (void)trackModified: (NSNotification *)notification
556 {
557 long trackNo;
558 if ([docArray indexOfObject: [notification object]] != activeIndex)
559 return;
560 [self updateMarkerList];
561 [self refreshTimeDisplay];
562 }
563
564 @end

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