ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SIDPlayer/src/main_beos.cpp
Revision: 1.7
Committed: 2003-10-21T16:56:19Z (21 years ago) by cebix
Branch: MAIN
Changes since 1.6: +2 -2 lines
Log Message:
- play_adr is updated from the IRQ vector every time before the replay routine
  is called if it was 0 in the PSID header (this makes some tunes play
  correctly now)
- f(void) -> f() (this is C++, dammit!)

File Contents

# Content
1 /*
2 * main_beos.cpp - SIDPlayer BeOS main program
3 *
4 * SIDPlayer (C) Copyright 1996-2003 Christian Bauer
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "sys.h"
22
23 #include <AppKit.h>
24 #include <InterfaceKit.h>
25 #include <storage/Path.h>
26 #include <media/SoundPlayer.h>
27
28 #include <stdio.h>
29
30 #include "main.h"
31 #include "prefs_window.h"
32 #include "sid.h"
33
34
35 // Message codes
36 const uint32 MSG_NEW_MODULE = 'load';
37 const uint32 MSG_NEW_SONG = 'song';
38 const uint32 MSG_SHOW_PREFS = 'pref';
39 const uint32 MSG_PLAY_PAUSE = 'plpa';
40 const uint32 MSG_STOP = 'stop';
41 const uint32 MSG_NEXT = 'next';
42 const uint32 MSG_PREV = 'prev';
43
44
45 class MainWindow;
46 class SpeedSlider;
47
48 // Application object
49 class SIDPlayer : public BApplication {
50 public:
51 SIDPlayer();
52 virtual ~SIDPlayer();
53 virtual void ArgvReceived(int32 argc, char **argv);
54 virtual void RefsReceived(BMessage *msg);
55 virtual void MessageReceived(BMessage *msg);
56 virtual void ReadyToRun(void);
57 virtual void AboutRequested(void);
58
59 private:
60 static void buffer_proc(void *cookie, void *buffer, size_t size, const media_raw_audio_format &format);
61
62 MainWindow *main_window;
63 PrefsWindow *prefs_window;
64 BSoundPlayer player;
65 bool player_stopped;
66 };
67
68
69 // Main window object
70 class MainWindow : public BWindow {
71 public:
72 MainWindow();
73 virtual bool QuitRequested(void);
74 virtual void MessageReceived(BMessage *msg);
75
76 private:
77 BStringView *make_name_display(BRect frame, char *label_text, BView *parent);
78
79 rgb_color fill_color;
80
81 BStringView *name_view;
82 BStringView *author_view;
83 BStringView *copyright_view;
84 BStringView *position_view;
85 SpeedSlider *speed_slider;
86 };
87
88
89 // Top view object (handles drag&drop)
90 class TopView : public BView {
91 public:
92 TopView(BRect frame, const char *name, uint32 resizingMode, uint32 flags);
93 virtual void MessageReceived(BMessage *msg);
94 virtual void KeyDown(const char *bytes, int32 numBytes);
95 };
96
97
98 // Buttons
99 class PlayPauseButton : public BButton {
100 public:
101 PlayPauseButton(BRect frame, BMessage *msg);
102 virtual void Draw(BRect update);
103 };
104
105 class StopButton : public BButton {
106 public:
107 StopButton(BRect frame, BMessage *msg);
108 virtual void Draw(BRect update);
109 };
110
111 class NextButton : public BButton {
112 public:
113 NextButton(BRect frame, BMessage *msg);
114 virtual void Draw(BRect update);
115 };
116
117 class PrevButton : public BButton {
118 public:
119 PrevButton(BRect frame, BMessage *msg);
120 virtual void Draw(BRect update);
121 };
122
123
124 // Speed slider
125 class SpeedSlider : public BSlider {
126 public:
127 SpeedSlider(BRect frame, const char *name) : BSlider(frame, name, "Speed", NULL, -100, 100, B_TRIANGLE_THUMB)
128 {
129 SetHashMarks(B_HASH_MARKS_TOP);
130 SetHashMarkCount(3);
131 const rgb_color bar_color = {128, 128, 216, 0};
132 SetBarColor(bar_color);
133 SetValue(0);
134 }
135 virtual ~SpeedSlider() {}
136 virtual void SetValue(int32 value)
137 {
138 int percent = value < 0 ? 100 + value / 2 : 100 + value;
139 sprintf(status, "%d%%", percent);
140 SIDAdjustSpeed(percent);
141 BSlider::SetValue(value);
142 }
143 virtual char *UpdateText(void) const
144 {
145 return status;
146 }
147
148 private:
149 mutable char status[32];
150 };
151
152
153 /*
154 * Application constructor
155 */
156
157 #if B_HOST_IS_LENDIAN
158 const media_raw_audio_format audio_format = {44100.0, 2, media_raw_audio_format::B_AUDIO_SHORT, B_MEDIA_LITTLE_ENDIAN, 4096};
159 #else
160 const media_raw_audio_format audio_format = {44100.0, 2, media_raw_audio_format::B_AUDIO_SHORT, B_MEDIA_BIG_ENDIAN, 4096};
161 #endif
162
163 SIDPlayer::SIDPlayer() : BApplication("application/x-vnd.cebix-SIDPlayer"), player(&audio_format, "SIDPlayer", buffer_proc)
164 {
165 main_window = NULL;
166 player.SetHasData(true);
167 player_stopped = true;
168 }
169
170
171 /*
172 * Application destructor
173 */
174
175 SIDPlayer::~SIDPlayer()
176 {
177 main_window = NULL;
178 prefs_window = NULL;
179 player.Stop();
180 player_stopped = true;
181 }
182
183
184 /*
185 * Shell arguments received
186 */
187
188 void SIDPlayer::ArgvReceived(int32 argc, char **argv)
189 {
190 if (argc < 2)
191 return;
192
193 for (int i=1; i<argc; i++) {
194 if (argv[i][0] == '-')
195 continue;
196 player.Stop();
197 LoadPSIDFile(argv[i]);
198 player.Start();
199 player_stopped = false;
200 if (main_window)
201 main_window->PostMessage(MSG_NEW_MODULE);
202 }
203 }
204
205
206 /*
207 * Tracker arguments received
208 */
209
210 void SIDPlayer::RefsReceived(BMessage *msg)
211 {
212 entry_ref the_ref;
213 if (msg->FindRef("refs", &the_ref) == B_NO_ERROR) {
214 BEntry the_entry;
215 if (the_entry.SetTo(&the_ref) == B_NO_ERROR) {
216 if (the_entry.IsFile()) {
217 BPath the_path;
218 the_entry.GetPath(&the_path);
219 player.Stop();
220 LoadPSIDFile(the_path.Path());
221 player.Start();
222 player_stopped = false;
223 if (main_window)
224 main_window->PostMessage(MSG_NEW_MODULE);
225 }
226 }
227 }
228 }
229
230
231 /*
232 * Message received
233 */
234
235 void SIDPlayer::MessageReceived(BMessage *msg)
236 {
237 switch (msg->what) {
238
239 case B_SIMPLE_DATA: // Dropped message
240 RefsReceived(msg);
241 break;
242
243 case MSG_SHOW_PREFS:
244 if (!prefs_window_open)
245 prefs_window = new PrefsWindow();
246 else if (prefs_window)
247 prefs_window->Activate(true);
248 break;
249
250 case MSG_PLAY_PAUSE:
251 if (player_stopped) {
252 player.Start();
253 player_stopped = false;
254 } else {
255 player.Stop();
256 player_stopped = true;
257 }
258 break;
259
260 case MSG_STOP:
261 player.Stop();
262 player_stopped = true;
263 SelectSong(current_song);
264 main_window->PostMessage(MSG_NEW_SONG);
265 break;
266
267 case MSG_NEXT:
268 if (current_song < number_of_songs-1) {
269 player.Stop();
270 SelectSong(current_song + 1);
271 main_window->PostMessage(MSG_NEW_SONG);
272 if (!player_stopped)
273 player.Start();
274 }
275 break;
276
277 case MSG_PREV:
278 if (current_song > 0) {
279 player.Stop();
280 SelectSong(current_song - 1);
281 main_window->PostMessage(MSG_NEW_SONG);
282 if (!player_stopped)
283 player.Start();
284 }
285 break;
286
287 default:
288 BApplication::MessageReceived(msg);
289 break;
290 }
291 }
292
293
294 /*
295 * Arguments processed, open player window
296 */
297
298 void SIDPlayer::ReadyToRun(void)
299 {
300 main_window = new MainWindow();
301 if (IsPSIDLoaded())
302 main_window->PostMessage(MSG_NEW_MODULE);
303 }
304
305
306 /*
307 * Show About window
308 */
309
310 void AboutWindow()
311 {
312 BAlert *theAlert = new BAlert("",
313 "SIDPlayer\nVersion " VERSION "\n\n"
314 "Copyright " B_UTF8_COPYRIGHT " 1996-2003 Christian Bauer\n"
315 "E-mail: Christian.Bauer@uni-mainz.de\n"
316 "http://www.uni-mainz.de/~bauec002/SPMain.html\n\n"
317 "SIDPlayer comes with ABSOLUTELY NO\n"
318 "WARRANTY. This is free software, and\n"
319 "you are welcome to redistribute it\n"
320 "under the terms of the GNU General\n"
321 "Public License.\n",
322 "OK", NULL, NULL, B_WIDTH_FROM_LABEL);
323
324 BTextView *theText = theAlert->TextView();
325 if (theText) {
326 theText->SetStylable(true);
327 theText->Select(0, 9);
328 BFont ourFont;
329 theText->SetFontAndColor(be_bold_font);
330 theText->GetFontAndColor(2, &ourFont, NULL);
331 ourFont.SetSize(24);
332 theText->SetFontAndColor(&ourFont);
333 }
334 theAlert->Go();
335 }
336
337 void SIDPlayer::AboutRequested(void)
338 {
339 AboutWindow();
340 }
341
342
343 /*
344 * SoundPlayer buffer procedure
345 */
346
347 void SIDPlayer::buffer_proc(void *cookie, void *buffer, size_t size, const media_raw_audio_format &format)
348 {
349 SIDCalcBuffer((uint8 *)buffer, size);
350 }
351
352
353 /*
354 * Main window constructor
355 */
356
357 MainWindow::MainWindow() : BWindow(BRect(0, 0, 284, 96), "SIDPlayer", B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS)
358 {
359 fill_color = ui_color(B_PANEL_BACKGROUND_COLOR);
360 BRect b = Bounds();
361
362 // Move window to right position
363 Lock();
364 MoveTo(80, 80);
365
366 // Create menu bar
367 BMenuBar *bar = new BMenuBar(BRect(0, 0, b.right, b.bottom), "menubar");
368 BMenu *menu = new BMenu("File");
369 menu->AddItem(new BMenuItem("About SIDPlayer" B_UTF8_ELLIPSIS, new BMessage(B_ABOUT_REQUESTED)));
370 menu->AddItem(new BSeparatorItem());
371 menu->AddItem(new BMenuItem("Sound Control" B_UTF8_ELLIPSIS, new BMessage(MSG_SHOW_PREFS), 'P'));
372 menu->AddItem(new BSeparatorItem());
373 menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q'));
374 menu->SetTargetForItems(be_app);
375 bar->AddItem(menu);
376 AddChild(bar);
377 SetKeyMenuBar(bar);
378 float menu_height = bar->Bounds().Height();
379
380 // Resize window to fit menu bar
381 ResizeBy(0, menu_height);
382
383 // Light gray background
384 TopView *top = new TopView(BRect(0, menu_height, b.right, b.bottom + menu_height), "main", B_FOLLOW_NONE, B_WILL_DRAW);
385 AddChild(top);
386 top->SetViewColor(fill_color);
387
388 // Name/author/copyright display
389 name_view = make_name_display(BRect(0, 5, 279, 21), "Name", top);
390 author_view = make_name_display(BRect(0, 25, 279, 41), "Author", top);
391 copyright_view = make_name_display(BRect(0, 45, 279, 61), "Copyright", top);
392
393 // Buttons
394 top->AddChild(new PlayPauseButton(BRect(6, 67, 36, 91), new BMessage(MSG_PLAY_PAUSE)));
395 top->AddChild(new StopButton(BRect(37, 67, 67, 91), new BMessage(MSG_STOP)));
396 top->AddChild(new PrevButton(BRect(68, 67, 98, 91), new BMessage(MSG_PREV)));
397 top->AddChild(new NextButton(BRect(99, 67, 129, 91), new BMessage(MSG_NEXT)));
398
399 // Position indicator
400 top->AddChild(position_view = new BStringView(BRect(134, 72, 193, 85), "position", ""));
401 position_view->SetViewColor(fill_color);
402
403 // Speed slider
404 top->AddChild(speed_slider = new SpeedSlider(BRect(194, 62, 279, 63), "speed"));
405
406 // Show window
407 top->MakeFocus();
408 Unlock();
409 Show();
410 }
411
412
413 /*
414 * Create name display field
415 */
416
417 BStringView *MainWindow::make_name_display(BRect frame, char *label_text, BView *parent)
418 {
419 // Label to the left of the display field
420 BRect label_rect = frame;
421 label_rect.right = label_rect.left + 65;
422
423 BStringView *label = new BStringView(label_rect, "", label_text);
424 parent->AddChild(label);
425 label->SetViewColor(fill_color);
426 label->SetLowColor(fill_color);
427 label->SetAlignment(B_ALIGN_RIGHT);
428 label->SetFont(be_bold_font);
429
430 // Box around display field
431 BRect frame_rect = frame;
432 frame_rect.left += 70;
433
434 BBox *box = new BBox(frame_rect);
435 parent->AddChild(box);
436 box->SetViewColor(fill_color);
437 box->SetLowColor(fill_color);
438
439 // The display field
440 BRect textview_rect = frame_rect;
441 textview_rect.OffsetTo(0, 0);
442 textview_rect.InsetBy(4, 2);
443
444 BStringView *text = new BStringView(textview_rect, "", "");
445 box->AddChild(text);
446 text->SetViewColor(fill_color);
447 text->SetLowColor(fill_color);
448 text->SetFont(be_plain_font);
449 return text;
450 }
451
452
453 /*
454 * Main window closed, quit program
455 */
456
457 bool MainWindow::QuitRequested(void)
458 {
459 be_app->PostMessage(B_QUIT_REQUESTED);
460 return true;
461 }
462
463
464 /*
465 * Message received
466 */
467
468 void MainWindow::MessageReceived(BMessage *msg)
469 {
470 switch (msg->what) {
471 case MSG_NEW_MODULE:
472 // Update text views
473 Lock();
474 name_view->SetText(module_name);
475 author_view->SetText(author_name);
476 copyright_view->SetText(copyright_info);
477 Unlock();
478 // falls through
479
480 case MSG_NEW_SONG:
481 // Update position indicator and speed slider
482 if (number_of_songs > 0) {
483 char str[16];
484 sprintf(str, "Song %d/%d", current_song + 1, number_of_songs);
485 position_view->SetText(str);
486 }
487 speed_slider->SetValue(0);
488 break;
489
490 case MSG_SHOW_PREFS:
491 case MSG_PLAY_PAUSE:
492 case MSG_STOP:
493 case MSG_NEXT:
494 case MSG_PREV:
495 be_app->PostMessage(msg);
496 break;
497
498 default:
499 BWindow::MessageReceived(msg);
500 break;
501 }
502 }
503
504
505 /*
506 * TopView handles dropped messages (load new PSID module) and keypresses
507 */
508
509 TopView::TopView(BRect frame, const char *name, uint32 resizingMode, uint32 flags)
510 : BView(frame, name, resizingMode, flags) {}
511
512 void TopView::MessageReceived(BMessage *msg)
513 {
514 if (msg->what == B_SIMPLE_DATA)
515 be_app->PostMessage(msg);
516 else
517 BView::MessageReceived(msg);
518 }
519
520 void TopView::KeyDown(const char *bytes, int32 numBytes)
521 {
522 BMessage *msg = Window()->CurrentMessage();
523 uint32 modifiers = 0;
524 msg->FindInt32("modifiers", (int32 *)&modifiers);
525
526 switch (bytes[0]) {
527 case 'p':
528 case 'P':
529 Window()->PostMessage(MSG_PLAY_PAUSE);
530 break;
531
532 case B_ESCAPE:
533 case B_SPACE:
534 case 's':
535 case 'S':
536 Window()->PostMessage(MSG_STOP);
537 break;
538
539 case B_LEFT_ARROW:
540 Window()->PostMessage(MSG_PREV);
541 break;
542
543 case B_RIGHT_ARROW:
544 case 'n':
545 case 'N':
546 Window()->PostMessage(MSG_NEXT);
547 break;
548
549 case 'q':
550 case 'Q':
551 be_app->PostMessage(B_QUIT_REQUESTED);
552 break;
553 }
554 }
555
556
557 /*
558 * Play/Pause button
559 */
560
561 PlayPauseButton::PlayPauseButton(BRect frame, BMessage *msg) : BButton(frame, "play", "", msg) {};
562
563 void PlayPauseButton::Draw(BRect update)
564 {
565 // First draw normal button
566 BButton::Draw(update);
567
568 // Then draw play/pause image on top of it
569 if (Value())
570 SetHighColor(255, 255, 255);
571 else
572 SetHighColor(0, 0, 0);
573
574 FillRect(BRect(11, 8, 13, 16));
575 FillTriangle(BPoint(16, 8), BPoint(16, 16), BPoint(20, 12));
576 }
577
578
579 /*
580 * Stop button
581 */
582
583 StopButton::StopButton(BRect frame, BMessage *msg) : BButton(frame, "stop", "", msg) {};
584
585 void StopButton::Draw(BRect update)
586 {
587 // First draw normal button
588 BButton::Draw(update);
589
590 // Then draw stop image on top of it
591 if (Value())
592 SetHighColor(255, 255, 255);
593 else
594 SetHighColor(0, 0, 0);
595
596 FillRect(BRect(11, 8, 20, 16));
597 }
598
599
600 /*
601 * "Next" button
602 */
603
604 NextButton::NextButton(BRect frame, BMessage *msg) : BButton(frame, "next", "", msg) {};
605
606 void NextButton::Draw(BRect update)
607 {
608 // First draw normal button
609 BButton::Draw(update);
610
611 // Then draw "next" image on top of it
612 if (Value())
613 SetHighColor(255, 255, 255);
614 else
615 SetHighColor(0, 0, 0);
616
617 FillTriangle(BPoint(12, 8), BPoint(12, 16), BPoint(16, 12));
618 FillRect(BRect(17, 8, 19, 16));
619 }
620
621
622 /*
623 * "Prev" button
624 */
625
626 PrevButton::PrevButton(BRect frame, BMessage *msg) : BButton(frame, "prev", "", msg) {};
627
628 void PrevButton::Draw(BRect update)
629 {
630 // First draw normal button
631 BButton::Draw(update);
632
633 // Then draw "prev" image on top of it
634 if (Value())
635 SetHighColor(255, 255, 255);
636 else
637 SetHighColor(0, 0, 0);
638
639 FillRect(BRect(12, 8, 14, 16));
640 FillTriangle(BPoint(19, 8), BPoint(19, 16), BPoint(15, 12));
641 }
642
643
644 /*
645 * Get current value of microsecond timer
646 */
647
648 uint64 GetTicks_usec()
649 {
650 return system_time();
651 }
652
653
654 /*
655 * Delay by specified number of microseconds (<1 second)
656 */
657
658 void Delay_usec(uint32 usec)
659 {
660 snooze(usec);
661 }
662
663
664 /*
665 * Main program
666 */
667
668 int main(int argc, char **argv)
669 {
670 InitAll(argc, argv);
671 SIDPlayer *the_app = new SIDPlayer();
672 the_app->Run();
673 delete the_app;
674 ExitAll();
675 return 0;
676 }