ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/Solaris/audio_solaris.cpp
Revision: 1.3
Committed: 1999-11-03T10:56:32Z (25 years ago) by cebix
Branch: MAIN
CVS Tags: snapshot-22121999, release-0_8-1
Changes since 1.2: +1 -1 lines
Log Message:
- imported UAE CPU 0.8.10 changes
- new utility functions Mac_memset, Mac2Host_memcpy, Host2Mac_memcpu and
  Mac2Mac_memcpy
- extfs.cpp: fixed bug in fs_rename() and fs_cat_move() (auxiliary IOParam
  block was not in Mac address space)
- some provisions for using UAE CPU compiler (doesn't work yet)

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-1999 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 // Supported sample rates, sizes and channels
44 int audio_num_sample_rates = 1;
45 uint32 audio_sample_rates[] = {44100 << 16};
46 int audio_num_sample_sizes = 1;
47 uint16 audio_sample_sizes[] = {16};
48 int audio_num_channel_counts = 1;
49 uint16 audio_channel_counts[] = {2};
50
51 // Global variables
52 static int fd = -1; // fd of /dev/audio
53 static sem_t audio_irq_done_sem; // Signal from interrupt to streaming thread: data block read
54 static pthread_t stream_thread; // Audio streaming thread
55 static pthread_attr_t stream_thread_attr; // Streaming thread attributes
56 static bool stream_thread_active = false;
57 static int sound_buffer_size; // Size of sound buffer in bytes
58
59 // Prototypes
60 static void *stream_func(void *arg);
61
62
63 /*
64 * Initialization
65 */
66
67 void AudioInit(void)
68 {
69 char str[256];
70
71 // Init audio status and feature flags
72 AudioStatus.sample_rate = audio_sample_rates[0];
73 AudioStatus.sample_size = audio_sample_sizes[0];
74 AudioStatus.channels = audio_channel_counts[0];
75 AudioStatus.mixer = 0;
76 AudioStatus.num_sources = 0;
77 audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut;
78
79 // Sound disabled in prefs? Then do nothing
80 if (PrefsFindBool("nosound"))
81 return;
82
83 // Init semaphore
84 if (sem_init(&audio_irq_done_sem, 0, 0) < 0)
85 return;
86
87 // Open /dev/audio
88 fd = open("/dev/audio", O_WRONLY | O_NDELAY);
89 if (fd < 0) {
90 sprintf(str, GetString(STR_NO_AUDIO_DEV_WARN), "/dev/audio", strerror(errno));
91 WarningAlert(str);
92 sem_destroy(&audio_irq_done_sem);
93 return;
94 }
95
96 // Set audio parameters
97 struct audio_info info;
98 AUDIO_INITINFO(&info);
99 info.play.sample_rate = AudioStatus.sample_rate >> 16;
100 info.play.channels = AudioStatus.channels;
101 info.play.precision = AudioStatus.sample_size;
102 info.play.encoding = AUDIO_ENCODING_LINEAR;
103 info.play.port = AUDIO_SPEAKER;
104 if (ioctl(fd, AUDIO_SETINFO, &info)) {
105 WarningAlert(GetString(STR_AUDIO_FORMAT_WARN));
106 close(fd);
107 fd = -1;
108 sem_destroy(&audio_irq_done_sem);
109 return;
110 }
111
112 // 2048 frames per buffer
113 audio_frames_per_block = 2048;
114 sound_buffer_size = (AudioStatus.sample_size>>3) * AudioStatus.channels * audio_frames_per_block;
115
116 // Start audio thread
117 pthread_attr_init(&stream_thread_attr);
118 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
119 pthread_attr_setinheritsched(&stream_thread_attr, PTHREAD_EXPLICIT_SCHED);
120 pthread_attr_setschedpolicy(&stream_thread_attr, SCHED_FIFO);
121 struct sched_param fifo_param;
122 fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2;
123 pthread_attr_setschedparam(&stream_thread_attr, &fifo_param);
124 #endif
125 stream_thread_active = (pthread_create(&stream_thread, &stream_thread_attr, stream_func, NULL) == 0);
126
127 // Everything OK
128 audio_open = true;
129 }
130
131
132 /*
133 * Deinitialization
134 */
135
136 void AudioExit(void)
137 {
138 // Stop audio thread
139 if (stream_thread_active) {
140 pthread_cancel(stream_thread);
141 pthread_join(stream_thread, NULL);
142 sem_destroy(&audio_irq_done_sem);
143 stream_thread_active = false;
144 }
145
146 // Close /dev/audio
147 if (fd > 0) {
148 ioctl(fd, AUDIO_DRAIN);
149 close(fd);
150 }
151 }
152
153
154 /*
155 * First source added, start audio stream
156 */
157
158 void audio_enter_stream()
159 {
160 }
161
162
163 /*
164 * Last source removed, stop audio stream
165 */
166
167 void audio_exit_stream()
168 {
169 }
170
171
172 /*
173 * Streaming function
174 */
175
176 static uint32 apple_stream_info; // Mac address of SoundComponentData struct describing next buffer
177
178 static void *stream_func(void *arg)
179 {
180 int16 *silent_buffer = new int16[sound_buffer_size / 2];
181 int16 *last_buffer = new int16[sound_buffer_size / 2];
182 memset(silent_buffer, 0, sound_buffer_size);
183
184 uint_t sent = 0, delta;
185 struct audio_info status;
186
187 for (;;) {
188 if (AudioStatus.num_sources) {
189
190 // Trigger audio interrupt to get new buffer
191 D(bug("stream: triggering irq\n"));
192 SetInterruptFlag(INTFLAG_AUDIO);
193 TriggerInterrupt();
194 D(bug("stream: waiting for ack\n"));
195 sem_wait(&audio_irq_done_sem);
196 D(bug("stream: ack received\n"));
197
198 // Get size of audio data
199 uint32 apple_stream_info = ReadMacInt32(audio_data + adatStreamInfo);
200 if (apple_stream_info) {
201 int work_size = ReadMacInt32(apple_stream_info + scd_sampleCount) * (AudioStatus.sample_size >> 3) * AudioStatus.channels;
202 D(bug("stream: work_size %d\n", work_size));
203 if (work_size > sound_buffer_size)
204 work_size = sound_buffer_size;
205 if (work_size == 0)
206 goto silence;
207
208 // Send data to audio port
209 if (work_size == sound_buffer_size)
210 write(fd, Mac2HostAddr(ReadMacInt32(apple_stream_info + scd_buffer)), sound_buffer_size);
211 else {
212 // Last buffer
213 Mac2Host_memcpy(last_buffer, ReadMacInt32(apple_stream_info + scd_buffer), work_size);
214 memset((uint8 *)last_buffer + work_size, 0, sound_buffer_size - work_size);
215 write(fd, last_buffer, sound_buffer_size);
216 }
217 D(bug("stream: data written\n"));
218 } else
219 goto silence;
220
221 } else {
222
223 // Audio not active, play silence
224 silence: write(fd, silent_buffer, sound_buffer_size);
225 }
226
227 // We allow a maximum of three buffers to be sent
228 sent += audio_frames_per_block;
229 ioctl(fd, AUDIO_GETINFO, &status);
230 while ((delta = sent - status.play.samples) > (audio_frames_per_block * 3)) {
231 unsigned int sl = 1000000 * (delta - audio_frames_per_block * 3) / (AudioStatus.sample_rate >> 16);
232 usleep(sl);
233 ioctl(fd, AUDIO_GETINFO, &status);
234 }
235 }
236 return NULL;
237 }
238
239
240 /*
241 * MacOS audio interrupt, read next data block
242 */
243
244 void AudioInterrupt(void)
245 {
246 D(bug("AudioInterrupt\n"));
247
248 // Get data from apple mixer
249 if (AudioStatus.mixer) {
250 M68kRegisters r;
251 r.a[0] = audio_data + adatStreamInfo;
252 r.a[1] = AudioStatus.mixer;
253 Execute68k(audio_data + adatGetSourceData, &r);
254 D(bug(" GetSourceData() returns %08lx\n", r.d[0]));
255 } else
256 WriteMacInt32(audio_data + adatStreamInfo, 0);
257
258 // Signal stream function
259 sem_post(&audio_irq_done_sem);
260 D(bug("AudioInterrupt done\n"));
261 }
262
263
264 /*
265 * Set sampling parameters
266 * "index" is an index into the audio_sample_rates[] etc. arrays
267 * It is guaranteed that AudioStatus.num_sources == 0
268 */
269
270 void audio_set_sample_rate(int index)
271 {
272 }
273
274 void audio_set_sample_size(int index)
275 {
276 }
277
278 void audio_set_channels(int index)
279 {
280 }
281
282
283 /*
284 * Get/set volume controls (volume values received/returned have the left channel
285 * volume in the upper 16 bits and the right channel volume in the lower 16 bits;
286 * both volumes are 8.8 fixed point values with 0x0100 meaning "maximum volume"))
287 */
288
289 bool audio_get_main_mute(void)
290 {
291 return false;
292 }
293
294 uint32 audio_get_main_volume(void)
295 {
296 return 0x01000100;
297 }
298
299 bool audio_get_speaker_mute(void)
300 {
301 return false;
302 }
303
304 uint32 audio_get_speaker_volume(void)
305 {
306 return 0x01000100;
307 }
308
309 void audio_set_main_mute(bool mute)
310 {
311 }
312
313 void audio_set_main_volume(uint32 vol)
314 {
315 }
316
317 void audio_set_speaker_mute(bool mute)
318 {
319 }
320
321 void audio_set_speaker_volume(uint32 vol)
322 {
323 }