ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SIDPlayer/src/main_beos.cpp
Revision: 1.6
Committed: 2003-04-11T20:23:02Z (21 years, 6 months ago) by cebix
Branch: MAIN
Changes since 1.5: +22 -2 lines
Log Message:
- added support for Catweasel SID
- replay timing is now based on CIA timer value, removed replayfreq

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * main_beos.cpp - SIDPlayer BeOS main program
3     *
4 cebix 1.6 * SIDPlayer (C) Copyright 1996-2003 Christian Bauer
5 cebix 1.1 *
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 cebix 1.4 #include "sid.h"
33 cebix 1.1
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 cebix 1.3 if (argc < 2)
191     return;
192    
193     for (int i=1; i<argc; i++) {
194     if (argv[i][0] == '-')
195     continue;
196 cebix 1.1 player.Stop();
197 cebix 1.3 LoadPSIDFile(argv[i]);
198 cebix 1.1 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 cebix 1.4 if (IsPSIDLoaded())
302 cebix 1.1 main_window->PostMessage(MSG_NEW_MODULE);
303     }
304    
305    
306     /*
307     * Show About window
308     */
309    
310     void AboutWindow(void)
311     {
312     BAlert *theAlert = new BAlert("",
313 cebix 1.2 "SIDPlayer\nVersion " VERSION "\n\n"
314 cebix 1.6 "Copyright " B_UTF8_COPYRIGHT " 1996-2003 Christian Bauer\n"
315 cebix 1.1 "E-mail: Christian.Bauer@uni-mainz.de\n"
316 cebix 1.5 "http://www.uni-mainz.de/~bauec002/SPMain.html\n\n"
317 cebix 1.1 "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 cebix 1.6 }
642    
643    
644     /*
645     * Get current value of microsecond timer
646     */
647    
648     uint64 GetTicks_usec(void)
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 cebix 1.1 }
662    
663    
664     /*
665     * Main program
666     */
667    
668     int main(int argc, char **argv)
669     {
670 cebix 1.3 InitAll(argc, argv);
671 cebix 1.1 SIDPlayer *the_app = new SIDPlayer();
672     the_app->Run();
673     delete the_app;
674     ExitAll();
675     return 0;
676     }