1 /*
2  * soundbeos.cc - Implementation of the BeOS sound device.
3  *
4  * Written by
5  *  Andreas Matthies <andreas.matthies@gmx.net>
6  *
7  * This file is part of VICE, the Versatile Commodore Emulator.
8  * See README for copyright notice.
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23  *  02111-1307  USA.
24  *
25  */
26 
27 #include "vice.h"
28 
29 #ifdef BEOS_COMPILE
30 
31 #ifdef __HAIKU__
32 /* Workaround an issue in the Haiku headers. */
33 #include <List.h>
34 #endif
35 #include <PushGameSound.h>
36 #include <SoundPlayer.h>
37 #include <stdio.h>
38 #include <string.h>
39 
40 extern "C" {
41 #include "log.h"
42 #include "sound.h"
43 #include "util.h"
44 }
45 /* ------------------------------------------------------------------------- */
46 
47 /* the BeOS soundplayer node */
48 static BPushGameSound *game_sound;
49 
50 /* the cyclic buffer */
51 static int16_t *soundbuffer;
52 
53 /* the buffer's length */
54 static size_t bufferlength;
55 
56 /* the next position to write */
57 static size_t write_position;
58 
59 /* Size of fragment (bytes).  */
60 static unsigned int fragment_size;
61 
62 /* Number of channels */
63 static unsigned int num_of_channels;
64 
65 /* ------------------------------------------------------------------------- */
66 
beos_init(const char * param,int * speed,int * fragsize,int * fragnr,int * channels)67 static int beos_init(const char *param, int *speed,
68                                                 int *fragsize, int *fragnr, int *channels)
69 {
70         gs_audio_format audio_format;
71 
72         fragment_size = *fragsize;
73         num_of_channels = *channels;
74 
75         audio_format.frame_rate = (float)*speed;
76         audio_format.channel_count = *channels;
77         audio_format.format = gs_audio_format::B_GS_S16;
78         audio_format.byte_order = B_MEDIA_LITTLE_ENDIAN;
79         audio_format.buffer_size = (size_t) *fragsize * *fragnr * *channels;
80 
81         game_sound = new BPushGameSound(*fragsize,
82                                         &audio_format, *fragnr);
83         if (game_sound->InitCheck() != B_OK) {
84                 log_error(LOG_DEFAULT, "sound (beos_init): Failed to initialize Be's PushGameSound");
85                 return -1;
86         }
87 
88         if (game_sound->LockForCyclic((void **)&soundbuffer, &bufferlength)
89                         == BPushGameSound::lock_failed) {
90                         log_error(LOG_DEFAULT, "sound (beos_init): LockForCyclic failed");
91                         return -1;
92         }
93         memset(soundbuffer, 0, bufferlength);
94         game_sound->StartPlaying();
95 
96         write_position = game_sound->CurrentPosition();
97 
98     return 0;
99 }
100 
101 extern CLOCK clk;
102 
beos_write(int16_t * pbuf,size_t nr)103 static int beos_write(int16_t *pbuf, size_t nr)
104 {
105         int i,count;
106         int16_t *p;
107 
108         count = nr / fragment_size;
109 #if 0
110         while (game_sound->CurrentPosition()*num_of_channels == write_position);
111 #endif
112         for (i=0; i<count; i++) {
113                 p = (int16_t *) (soundbuffer+write_position);
114                 memcpy(p,pbuf,fragment_size*2);
115                 write_position += fragment_size;
116                 if (write_position*2 >= bufferlength)
117                         write_position = 0;
118                 pbuf+=fragment_size;
119         }
120 
121         return 0;
122 }
123 
beos_bufferspace(void)124 static int beos_bufferspace(void)
125 {
126         int ret;
127         int current = game_sound->CurrentPosition();
128 
129         ret = current - (write_position / num_of_channels);
130         if (ret < 0)
131                 ret += (bufferlength/(2*num_of_channels));
132 
133         return ret;
134 }
135 
beos_close(void)136 static void beos_close(void)
137 {
138         delete game_sound;
139 }
140 
beos_suspend(void)141 static int beos_suspend(void)
142 {
143     game_sound->StopPlaying();
144     game_sound->UnlockCyclic();
145     return 0;
146 }
147 
beos_resume(void)148 static int beos_resume(void)
149 {
150         if (game_sound->LockForCyclic((void **)&soundbuffer, &bufferlength)
151                         == BPushGameSound::lock_failed) {
152                         log_error(LOG_DEFAULT, "sound (beos_resume): LockForCyclic failed");
153                         return -1;
154         }
155         memset(soundbuffer, 0, bufferlength);
156         game_sound->StartPlaying();
157     return 0;
158 }
159 
160 static sound_device_t beos_device =
161 {
162     "beos",
163     beos_init,
164     beos_write,
165     NULL,
166     NULL,
167     beos_bufferspace,
168     beos_close,
169     beos_suspend,
170     beos_resume,
171     1,
172     2
173 };
174 
sound_init_beos_device(void)175 int sound_init_beos_device(void)
176 {
177     return sound_register_device(&beos_device);
178 }
179 #endif
180