ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/Solaris/audio_solaris.cpp
Revision: 1.8
Committed: 2002-01-15T14:58:40Z (22 years, 10 months ago) by cebix
Branch: MAIN
CVS Tags: snapshot-15012002
Changes since 1.7: +1 -1 lines
Log Message:
- documentation updates
- 2001 -> 2002
- version 0.9 -> 1.0

File Contents

# Content
1 /*
2 * audio_solaris.cpp - Audio support, Solaris implementation
3 *
4 * Adapted from Frodo's Solaris sound routines by Marc Chabanas
5 *
6 * Basilisk II (C) 1997-2002 Christian Bauer
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23 #include "sysdeps.h"
24
25 #include <sys/ioctl.h>
26 #include <sys/audioio.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <pthread.h>
30 #include <semaphore.h>
31
32 #include "cpu_emulation.h"
33 #include "main.h"
34 #include "prefs.h"
35 #include "user_strings.h"
36 #include "audio.h"
37 #include "audio_defs.h"
38
39 #define DEBUG 0
40 #include "debug.h"
41
42
43 // Global variables
44 static int fd = -1; // fd of /dev/audio
45 static sem_t audio_irq_done_sem; // Signal from interrupt to streaming thread: data block read
46 static pthread_t stream_thread; // Audio streaming thread
47 static pthread_attr_t stream_thread_attr; // Streaming thread attributes
48 static bool stream_thread_active = false;
49 static int sound_buffer_size; // Size of sound buffer in bytes
50
51 // Prototypes
52 static void *stream_func(void *arg);
53
54
55 /*
56 * Initialization
57 */
58
59 // Set AudioStatus to reflect current audio stream format
60 static void set_audio_status_format(void)
61 {
62 AudioStatus.sample_rate = audio_sample_rates[0];
63 AudioStatus.sample_size = audio_sample_sizes[0];
64 AudioStatus.channels = audio_channel_counts[0];
65 }
66
67 void AudioInit(void)
68 {
69 char str[256];
70
71 // Init audio status and feature flags
72 audio_sample_rates.push_back(44100 << 16);
73 audio_sample_sizes.push_back(16);
74 audio_channel_counts.push_back(2);
75 set_audio_status_format();
76 AudioStatus.mixer = 0;
77 AudioStatus.num_sources = 0;
78 audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut;
79
80 // Sound disabled in prefs? Then do nothing
81 if (PrefsFindBool("nosound"))
82 return;
83
84 // Init semaphore
85 if (sem_init(&audio_irq_done_sem, 0, 0) < 0)
86 return;
87
88 // Open /dev/audio
89 fd = open("/dev/audio", O_WRONLY | O_NDELAY);
90 if (fd < 0) {
91 sprintf(str, GetString(STR_NO_AUDIO_DEV_WARN), "/dev/audio", strerror(errno));
92 WarningAlert(str);
93 sem_destroy(&audio_irq_done_sem);
94 return;
95 }
96
97 // Set audio parameters
98 struct audio_info info;
99 AUDIO_INITINFO(&info);
100 info.play.sample_rate = AudioStatus.sample_rate >> 16;
101 info.play.channels = AudioStatus.channels;
102 info.play.precision = AudioStatus.sample_size;
103 info.play.encoding = AUDIO_ENCODING_LINEAR;
104 info.play.port = AUDIO_SPEAKER;
105 if (ioctl(fd, AUDIO_SETINFO, &info)) {
106 WarningAlert(GetString(STR_AUDIO_FORMAT_WARN));
107 close(fd);
108 fd = -1;
109 sem_destroy(&audio_irq_done_sem);
110 return;
111 }
112
113 // 2048 frames per buffer
114 audio_frames_per_block = 2048;
115 sound_buffer_size = (AudioStatus.sample_size>>3) * AudioStatus.channels * audio_frames_per_block;
116
117 // Start audio thread
118 pthread_attr_init(&stream_thread_attr);
119 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
120 pthread_attr_setinheritsched(&stream_thread_attr, PTHREAD_EXPLICIT_SCHED);
121 pthread_attr_setschedpolicy(&stream_thread_attr, SCHED_FIFO);
122 struct sched_param fifo_param;
123 fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2;
124 pthread_attr_setschedparam(&stream_thread_attr, &fifo_param);
125 #endif
126 stream_thread_active = (pthread_create(&stream_thread, &stream_thread_attr, stream_func, NULL) == 0);
127
128 // Everything OK
129 audio_open = true;
130 }
131
132
133 /*
134 * Deinitialization
135 */
136
137 void AudioExit(void)
138 {
139 // Stop audio thread
140 if (stream_thread_active) {
141 pthread_cancel(stream_thread);
142 pthread_join(stream_thread, NULL);
143 sem_destroy(&audio_irq_done_sem);
144 stream_thread_active = false;
145 }
146
147 // Close /dev/audio
148 if (fd > 0) {
149 ioctl(fd, AUDIO_DRAIN);
150 close(fd);
151 }
152 }
153
154
155 /*
156 * First source added, start audio stream
157 */
158
159 void audio_enter_stream()
160 {
161 }
162
163
164 /*
165 * Last source removed, stop audio stream
166 */
167
168 void audio_exit_stream()
169 {
170 }
171
172
173 /*
174 * Streaming function
175 */
176
177 static uint32 apple_stream_info; // Mac address of SoundComponentData struct describing next buffer
178
179 static void *stream_func(void *arg)
180 {
181 int16 *silent_buffer = new int16[sound_buffer_size / 2];
182 int16 *last_buffer = new int16[sound_buffer_size / 2];
183 memset(silent_buffer, 0, sound_buffer_size);
184
185 uint_t sent = 0, delta;
186 struct audio_info status;
187
188 for (;;) {
189 if (AudioStatus.num_sources) {
190
191 // Trigger audio interrupt to get new buffer
192 D(bug("stream: triggering irq\n"));
193 SetInterruptFlag(INTFLAG_AUDIO);
194 TriggerInterrupt();
195 D(bug("stream: waiting for ack\n"));
196 sem_wait(&audio_irq_done_sem);
197 D(bug("stream: ack received\n"));
198
199 // Get size of audio data
200 uint32 apple_stream_info = ReadMacInt32(audio_data + adatStreamInfo);
201 if (apple_stream_info) {
202 int work_size = ReadMacInt32(apple_stream_info + scd_sampleCount) * (AudioStatus.sample_size >> 3) * AudioStatus.channels;
203 D(bug("stream: work_size %d\n", work_size));
204 if (work_size > sound_buffer_size)
205 work_size = sound_buffer_size;
206 if (work_size == 0)
207 goto silence;
208
209 // Send data to audio port
210 if (work_size == sound_buffer_size)
211 write(fd, Mac2HostAddr(ReadMacInt32(apple_stream_info + scd_buffer)), sound_buffer_size);
212 else {
213 // Last buffer
214 Mac2Host_memcpy(last_buffer, ReadMacInt32(apple_stream_info + scd_buffer), work_size);
215 memset((uint8 *)last_buffer + work_size, 0, sound_buffer_size - work_size);
216 write(fd, last_buffer, sound_buffer_size);
217 }
218 D(bug("stream: data written\n"));
219 } else
220 goto silence;
221
222 } else {
223
224 // Audio not active, play silence
225 silence: write(fd, silent_buffer, sound_buffer_size);
226 }
227
228 // We allow a maximum of three buffers to be sent
229 sent += audio_frames_per_block;
230 ioctl(fd, AUDIO_GETINFO, &status);
231 while ((delta = sent - status.play.samples) > (audio_frames_per_block * 3)) {
232 unsigned int sl = 1000000 * (delta - audio_frames_per_block * 3) / (AudioStatus.sample_rate >> 16);
233 usleep(sl);
234 ioctl(fd, AUDIO_GETINFO, &status);
235 }
236 }
237 return NULL;
238 }
239
240
241 /*
242 * MacOS audio interrupt, read next data block
243 */
244
245 void AudioInterrupt(void)
246 {
247 D(bug("AudioInterrupt\n"));
248
249 // Get data from apple mixer
250 if (AudioStatus.mixer) {
251 M68kRegisters r;
252 r.a[0] = audio_data + adatStreamInfo;
253 r.a[1] = AudioStatus.mixer;
254 Execute68k(audio_data + adatGetSourceData, &r);
255 D(bug(" GetSourceData() returns %08lx\n", r.d[0]));
256 } else
257 WriteMacInt32(audio_data + adatStreamInfo, 0);
258
259 // Signal stream function
260 sem_post(&audio_irq_done_sem);
261 D(bug("AudioInterrupt done\n"));
262 }
263
264
265 /*
266 * Set sampling parameters
267 * "index" is an index into the audio_sample_rates[] etc. arrays
268 * It is guaranteed that AudioStatus.num_sources == 0
269 */
270
271 bool audio_set_sample_rate(int index)
272 {
273 return true;
274 }
275
276 bool audio_set_sample_size(int index)
277 {
278 return true;
279 }
280
281 bool audio_set_channels(int index)
282 {
283 return true;
284 }
285
286
287 /*
288 * Get/set volume controls (volume values received/returned have the left channel
289 * volume in the upper 16 bits and the right channel volume in the lower 16 bits;
290 * both volumes are 8.8 fixed point values with 0x0100 meaning "maximum volume"))
291 */
292
293 bool audio_get_main_mute(void)
294 {
295 return false;
296 }
297
298 uint32 audio_get_main_volume(void)
299 {
300 return 0x01000100;
301 }
302
303 bool audio_get_speaker_mute(void)
304 {
305 return false;
306 }
307
308 uint32 audio_get_speaker_volume(void)
309 {
310 return 0x01000100;
311 }
312
313 void audio_set_main_mute(bool mute)
314 {
315 }
316
317 void audio_set_main_volume(uint32 vol)
318 {
319 }
320
321 void audio_set_speaker_mute(bool mute)
322 {
323 }
324
325 void audio_set_speaker_volume(uint32 vol)
326 {
327 }