ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/BeOS/audio_beos.cpp
Revision: 1.10
Committed: 2008-01-01T09:40:32Z (16 years, 11 months ago) by gbeauche
Branch: MAIN
CVS Tags: HEAD
Changes since 1.9: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# Content
1 /*
2 * audio_beos.cpp - Audio support, BeOS implementation
3 *
4 * Basilisk II (C) 1997-2008 Christian Bauer
5 * Portions written by Marc Hellwig
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include "sysdeps.h"
23
24 #include <KernelKit.h>
25 #include <MediaKit.h>
26
27 #include "cpu_emulation.h"
28 #include "main.h"
29 #include "prefs.h"
30 #include "user_strings.h"
31 #include "audio.h"
32 #include "audio_defs.h"
33
34 #define DEBUG 0
35 #include "debug.h"
36
37
38 // Global variables
39 static int audio_irq_done_sem = -1; // Signal from interrupt to streaming thread: data block read
40 static BSoundPlayer *the_player;
41
42 // Prototypes
43 static void playbuffer_func(void *arg, void *buf, size_t size, const media_raw_audio_format &format);
44
45
46 /*
47 * Audio manager thread (for calling media kit functions;
48 * this is not safe under R4 when running on the MacOS stack in kernel space)
49 */
50
51 // Message constants
52 const uint32 MSG_QUIT_AUDIO_MANAGER = 'quit';
53 const uint32 MSG_ENTER_STREAM = 'entr';
54 const uint32 MSG_EXIT_STREAM = 'exit';
55 const uint32 MSG_GET_VOLUME = 'getv';
56 const uint32 MSG_SET_VOLUME = 'setv';
57
58 static thread_id am_thread = -1;
59 static sem_id am_done_sem = -1;
60
61 static volatile float am_volume;
62
63 static status_t audio_manager(void *arg)
64 {
65 for (;;) {
66
67 // Receive message
68 thread_id sender;
69 uint32 code = receive_data(&sender, NULL, 0);
70 D(bug("Audio manager received %08lx\n", code));
71 switch (code) {
72 case MSG_QUIT_AUDIO_MANAGER:
73 return 0;
74
75 case MSG_ENTER_STREAM:
76 the_player->Start();
77 break;
78
79 case MSG_EXIT_STREAM:
80 the_player->Stop();
81 break;
82
83 case MSG_GET_VOLUME:
84 am_volume = the_player->Volume();
85 break;
86
87 case MSG_SET_VOLUME:
88 the_player->SetVolume(am_volume);
89 break;
90 }
91
92 // Acknowledge
93 release_sem(am_done_sem);
94 }
95 }
96
97
98 /*
99 * Initialization
100 */
101
102 // Set AudioStatus to reflect current audio stream format
103 static void set_audio_status_format(void)
104 {
105 AudioStatus.sample_rate = audio_sample_rates[0];
106 AudioStatus.sample_size = audio_sample_sizes[0];
107 AudioStatus.channels = audio_channel_counts[0];
108 }
109
110 void AudioInit(void)
111 {
112 // Init audio status and feature flags
113 audio_sample_rates.push_back(44100 << 16);
114 audio_sample_sizes.push_back(16);
115 audio_channel_counts.push_back(2);
116 set_audio_status_format();
117 AudioStatus.mixer = 0;
118 AudioStatus.num_sources = 0;
119 audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut;
120
121 // Sound disabled in prefs? Then do nothing
122 if (PrefsFindBool("nosound"))
123 return;
124
125 // Init semaphores
126 audio_irq_done_sem = create_sem(0, "Audio IRQ Done");
127 am_done_sem = create_sem(0, "Audio Manager Done");
128
129 // Start audio manager thread
130 am_thread = spawn_thread(audio_manager, "Audio Manager", B_NORMAL_PRIORITY, NULL);
131 resume_thread(am_thread);
132
133 // Start stream
134 media_raw_audio_format format;
135 format.frame_rate = AudioStatus.sample_rate >> 16;
136 format.channel_count = AudioStatus.channels;
137 format.format = media_raw_audio_format::B_AUDIO_SHORT;
138 format.byte_order = B_MEDIA_BIG_ENDIAN;
139 audio_frames_per_block = 4096;
140 size_t block_size = (AudioStatus.sample_size >> 3) * AudioStatus.channels * audio_frames_per_block;
141 D(bug("AudioInit: block size %d\n", block_size));
142 format.buffer_size = block_size;
143 the_player = new BSoundPlayer(&format, "MacOS Audio", playbuffer_func, NULL, NULL);
144 if (the_player->InitCheck() != B_NO_ERROR) {
145 printf("FATAL: Cannot initialize BSoundPlayer\n");
146 delete the_player;
147 the_player = NULL;
148 return;
149 } else
150 the_player->SetHasData(true);
151
152 // Everything OK
153 audio_open = true;
154 }
155
156
157 /*
158 * Deinitialization
159 */
160
161 void AudioExit(void)
162 {
163 // Stop stream
164 if (the_player) {
165 the_player->Stop();
166 delete the_player;
167 the_player = NULL;
168 }
169
170 // Stop audio manager
171 if (am_thread > 0) {
172 status_t l;
173 send_data(am_thread, MSG_QUIT_AUDIO_MANAGER, NULL, 0);
174 wait_for_thread(am_thread, &l);
175 }
176
177 // Delete semaphores
178 delete_sem(am_done_sem);
179 delete_sem(audio_irq_done_sem);
180 }
181
182
183 /*
184 * First source added, start audio stream
185 */
186
187 void audio_enter_stream()
188 {
189 while (send_data(am_thread, MSG_ENTER_STREAM, NULL, 0) == B_INTERRUPTED) ;
190 while (acquire_sem(am_done_sem) == B_INTERRUPTED) ;
191 }
192
193
194 /*
195 * Last source removed, stop audio stream
196 */
197
198 void audio_exit_stream()
199 {
200 while (send_data(am_thread, MSG_EXIT_STREAM, NULL, 0) == B_INTERRUPTED) ;
201 while (acquire_sem(am_done_sem) == B_INTERRUPTED) ;
202 }
203
204
205 /*
206 * Streaming function
207 */
208
209 static uint32 apple_stream_info; // Mac address of SoundComponentData struct describing next buffer
210
211 static void playbuffer_func(void *arg, void *buf, size_t size, const media_raw_audio_format &format)
212 {
213 // Check if new buffer is available
214 if (acquire_sem_etc(audio_irq_done_sem, 1, B_TIMEOUT, 0) == B_NO_ERROR) {
215
216 // Get size of audio data
217 D(bug("stream: new buffer present\n"));
218 uint32 apple_stream_info = ReadMacInt32(audio_data + adatStreamInfo);
219 if (apple_stream_info) {
220 size_t work_size = ReadMacInt32(apple_stream_info + scd_sampleCount) * (AudioStatus.sample_size >> 3) * AudioStatus.channels;
221 D(bug("stream: size %d, work_size %d\n", size, work_size));
222 if (work_size > size)
223 work_size = size;
224
225 if (format.format != media_raw_audio_format::B_AUDIO_SHORT) {
226 D(bug("Wrong audio format %04x\n", format.format));
227 return;
228 }
229
230 // Place data into Media Kit buffer
231 Mac2Host_memcpy(buf, ReadMacInt32(apple_stream_info + scd_buffer), work_size);
232 if (work_size != size)
233 memset((uint8 *)buf + work_size, 0, size - work_size);
234 }
235
236 } else
237 memset(buf, 0, size);
238
239 // Trigger audio interrupt to get new buffer
240 if (AudioStatus.num_sources) {
241 D(bug("stream: triggering irq\n"));
242 SetInterruptFlag(INTFLAG_AUDIO);
243 TriggerInterrupt();
244 }
245 }
246
247
248 /*
249 * MacOS audio interrupt, read next data block
250 */
251
252 void AudioInterrupt(void)
253 {
254 D(bug("AudioInterrupt\n"));
255
256 // Get data from apple mixer
257 if (AudioStatus.mixer) {
258 M68kRegisters r;
259 r.a[0] = audio_data + adatStreamInfo;
260 r.a[1] = AudioStatus.mixer;
261 Execute68k(audio_data + adatGetSourceData, &r);
262 D(bug(" GetSourceData() returns %08lx\n", r.d[0]));
263 } else
264 WriteMacInt32(audio_data + adatStreamInfo, 0);
265
266 // Signal stream function
267 release_sem(audio_irq_done_sem);
268 D(bug("AudioInterrupt done\n"));
269 }
270
271
272 /*
273 * Set sampling parameters
274 * "index" is an index into the audio_sample_rates[] etc. arrays
275 * It is guaranteed that AudioStatus.num_sources == 0
276 */
277
278 bool audio_set_sample_rate(int index)
279 {
280 return true;
281 }
282
283 bool audio_set_sample_size(int index)
284 {
285 return true;
286 }
287
288 bool audio_set_channels(int index)
289 {
290 return true;
291 }
292
293
294 /*
295 * Get/set audio info
296 */
297
298 bool audio_get_main_mute(void)
299 {
300 return false;
301 }
302
303 uint32 audio_get_main_volume(void)
304 {
305 if (audio_open) {
306 while (send_data(am_thread, MSG_GET_VOLUME, NULL, 0) == B_INTERRUPTED) ;
307 while (acquire_sem(am_done_sem) == B_INTERRUPTED) ;
308 return int(am_volume * 256.0) * 0x00010001;
309 } else
310 return 0x01000100;
311 }
312
313 bool audio_get_speaker_mute(void)
314 {
315 return false;
316 }
317
318 uint32 audio_get_speaker_volume(void)
319 {
320 return 0x01000100;
321 }
322
323 void audio_set_main_mute(bool mute)
324 {
325 }
326
327 void audio_set_main_volume(uint32 vol)
328 {
329 if (audio_open) {
330 am_volume = float((vol >> 16) + (vol & 0xffff)) / 512.0;
331 while (send_data(am_thread, MSG_SET_VOLUME, NULL, 0) == B_INTERRUPTED) ;
332 while (acquire_sem(am_done_sem) == B_INTERRUPTED) ;
333 }
334 }
335
336 void audio_set_speaker_mute(bool mute)
337 {
338 }
339
340 void audio_set_speaker_volume(uint32 vol)
341 {
342 }