fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/arch/macplus/sound.c *
7 * Created: 2008-04-18 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2008-2020 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include "main.h"
24#include "sound.h"
25
26#include <stdlib.h>
27#include <string.h>
28
29#include <drivers/sound/sound.h>
30
31
32#define MAC_SOUND_CLK 352
33
34#define MAC_SOUND_SILENCE 60
35
36#ifndef DEBUG_SOUND
37#define DEBUG_SOUND 0
38#endif
39
40
41void mac_sound_init (mac_sound_t *ms)
42{
43 ms->drv = NULL;
44
45 ms->sbuf = NULL;
46
47 ms->idx = 0;
48 ms->cnt = 0;
49 ms->clk = 0;
50
51 ms->enable = 0;
52 ms->volume = 0;
53
54 ms->lowpass_freq = 8000;
55
56 snd_iir2_init (&ms->iir);
57
58 ms->last_val = 0x8000;
59 ms->changed = 0;
60 ms->silence_cnt = MAC_SOUND_SILENCE;
61}
62
63mac_sound_t *mac_sound_new (void)
64{
65 mac_sound_t *ms;
66
67 ms = malloc (sizeof (mac_sound_t));
68
69 if (ms == NULL) {
70 return (NULL);
71 }
72
73 mac_sound_init (ms);
74
75 return (ms);
76}
77
78void mac_sound_free (mac_sound_t *ms)
79{
80 if (ms->drv != NULL) {
81 snd_close (ms->drv);
82 }
83}
84
85void mac_sound_del (mac_sound_t *ms)
86{
87 if (ms != NULL) {
88 mac_sound_free (ms);
89 free (ms);
90 }
91}
92
93void mac_sound_set_sbuf (mac_sound_t *ms, const unsigned char *sbuf)
94{
95 ms->sbuf = sbuf;
96}
97
98void mac_sound_set_lowpass (mac_sound_t *ms, unsigned freq)
99{
100 ms->lowpass_freq = freq;
101
102 snd_iir2_set_lowpass (&ms->iir, freq, 22255);
103}
104
105void mac_sound_set_volume (mac_sound_t *ms, unsigned vol)
106{
107#if DEBUG_SOUND >= 1
108 mac_log_deb ("sound: volume=%u\n", vol);
109#endif
110
111 ms->volume = vol;
112}
113
114void mac_sound_set_enable (mac_sound_t *ms, int val)
115{
116 val = (val != 0);
117
118 if (ms->enable == val) {
119 return;
120 }
121
122#if DEBUG_SOUND >= 1
123 mac_log_deb ("sound: enable=%d\n", val);
124#endif
125
126 ms->enable = val;
127}
128
129int mac_sound_set_driver (mac_sound_t *ms, const char *driver)
130{
131 if (ms->drv != NULL) {
132 snd_close (ms->drv);
133 }
134
135 ms->drv = snd_open (driver);
136
137 if (ms->drv == NULL) {
138 return (1);
139 }
140
141 if (snd_set_params (ms->drv, 1, 22255, 0)) {
142 snd_close (ms->drv);
143 ms->drv = NULL;
144 return (1);
145 }
146
147 return (0);
148}
149
150static
151void mac_sound_get_bytes (mac_sound_t *ms, unsigned cnt)
152{
153 unsigned val, div;
154
155 if (ms->cnt >= 370) {
156 return;
157 }
158
159 if (ms->sbuf == NULL) {
160 return;
161 }
162
163 div = 8 - ms->volume;
164
165 while ((cnt > 0) && (ms->cnt < 370)) {
166 if (ms->enable) {
167 val = ms->sbuf[2 * ms->idx];
168 val = val << 8;
169
170 if (val < 32768) {
171 val = 32768 - (32768 - val) / div;
172 }
173 else {
174 val = 32768 + (val - 32768) / div;
175 }
176 }
177 else {
178 val = 0x8000;
179 }
180
181 ms->idx += 1;
182 if (ms->idx >= 370) {
183 ms->idx = 0;
184 }
185
186 if (val != ms->last_val) {
187 ms->last_val = val;
188 ms->changed = 1;
189 }
190
191 ms->buf[ms->cnt] = val;
192
193 ms->cnt += 1;
194 cnt -= 1;
195 }
196}
197
198static
199void mac_sound_fill (mac_sound_t *ms, unsigned cnt)
200{
201 if ((cnt == 0) || (ms->cnt >= 370)) {
202 return;
203 }
204
205 if (ms->last_val != 0x8000) {
206 ms->changed = 1;
207 }
208
209 while ((cnt > 0) && (ms->cnt < 370)) {
210 ms->buf[ms->cnt] = 0x8000;
211
212 ms->idx += 1;
213 if (ms->idx >= 370) {
214 ms->idx = 0;
215 }
216
217 ms->cnt += 1;
218 cnt -= 1;
219 }
220
221 ms->last_val = 0x8000;
222}
223
224static
225void mac_sound_speaker_on (mac_sound_t *ms)
226{
227 unsigned i;
228 uint16_t buf[1024];
229
230#if DEBUG_SOUND >= 1
231 mac_log_deb ("sound: output on\n");
232#endif
233
234 for (i = 0; i < 1024; i++) {
235 buf[i] = 0x8000;
236 }
237
238 for (i = 0; i < 4; i++) {
239 snd_write (ms->drv, buf, 1024);
240 }
241}
242
243static
244void mac_sound_speaker_off (mac_sound_t *ms)
245{
246#if DEBUG_SOUND >= 1
247 mac_log_deb ("sound: output off\n");
248#endif
249}
250
251void mac_sound_vbl (mac_sound_t *ms)
252{
253 if (ms->sbuf == NULL) {
254 return;
255 }
256
257 if (ms->drv == NULL) {
258 return;
259 }
260
261 if (ms->cnt < 370) {
262 if (ms->enable) {
263 mac_sound_get_bytes (ms, 370 - ms->cnt);
264 }
265 else if ((ms->silence_cnt < MAC_SOUND_SILENCE) || (ms->cnt > 0)) {
266 mac_sound_fill (ms, 370 - ms->cnt);
267 }
268 }
269
270 if (ms->changed) {
271 if (ms->silence_cnt >= MAC_SOUND_SILENCE) {
272 mac_sound_speaker_on (ms);
273 }
274
275 ms->silence_cnt = 0;
276 }
277 else {
278 if (ms->silence_cnt < MAC_SOUND_SILENCE) {
279 ms->silence_cnt += 1;
280
281 if (ms->silence_cnt == MAC_SOUND_SILENCE) {
282 mac_sound_speaker_off (ms);
283 }
284 }
285 }
286
287 if (ms->silence_cnt < MAC_SOUND_SILENCE) {
288 if (ms->lowpass_freq > 0) {
289 snd_iir2_filter (&ms->iir, ms->buf, ms->buf, ms->cnt, 1, 0);
290 }
291
292 snd_write (ms->drv, ms->buf, ms->cnt);
293 }
294
295 ms->changed = 0;
296
297 ms->idx = 16;
298 ms->cnt = 0;
299 ms->clk = 0;
300}
301
302void mac_sound_clock (mac_sound_t *ms, unsigned long n)
303{
304 unsigned cnt;
305
306 if (ms->enable == 0) {
307 return;
308 }
309
310 if (ms->sbuf == NULL) {
311 return;
312 }
313
314 if (ms->cnt >= 370) {
315 return;
316 }
317
318 ms->clk += n;
319
320 if (ms->clk >= MAC_SOUND_CLK) {
321 cnt = ms->clk / MAC_SOUND_CLK;
322 ms->clk %= MAC_SOUND_CLK;
323
324 mac_sound_get_bytes (ms, cnt);
325 }
326}