fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 326 lines 5.8 kB view raw
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}