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