mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2024-12-27 19:51:48 +01:00
289 lines
7.7 KiB
C
289 lines
7.7 KiB
C
|
|
#include "osd.h"
|
|
|
|
int seal_sample_rate = 44100;
|
|
int seal_sound_card = -1;
|
|
|
|
HAC hVoice[NUMVOICES];
|
|
LPAUDIOWAVE lpWave[NUMVOICES];
|
|
AUDIOINFO info;
|
|
AUDIOCAPS caps;
|
|
int c[MAX_STREAM_CHANNELS];
|
|
int nominal_sample_rate;
|
|
static int attenuation = 0;
|
|
static int master_volume = 256;
|
|
|
|
|
|
void osd_update_audio(void)
|
|
{
|
|
if (seal_sample_rate == 0) return;
|
|
AUpdateAudio();
|
|
}
|
|
|
|
|
|
/* attenuation in dB */
|
|
void osd_set_mastervolume(int _attenuation)
|
|
{
|
|
float volume;
|
|
|
|
attenuation = _attenuation;
|
|
|
|
volume = 256.0; /* range is 0-256 */
|
|
while (_attenuation++ < 0)
|
|
volume /= 1.122018454; /* = (10 ^ (1/20)) = 1dB */
|
|
|
|
master_volume = volume;
|
|
|
|
ASetAudioMixerValue(AUDIO_MIXER_MASTER_VOLUME,master_volume);
|
|
}
|
|
|
|
|
|
int msdos_init_sound(int *rate, int card)
|
|
{
|
|
int i;
|
|
|
|
seal_sample_rate = *rate;
|
|
seal_sound_card = card;
|
|
|
|
if (AInitialize() != AUDIO_ERROR_NONE)
|
|
return 1;
|
|
|
|
/* Ask the user if no sound card was chosen */
|
|
if (seal_sound_card == -1)
|
|
{
|
|
unsigned int k;
|
|
|
|
printf("\n SELECT YOUR AUDIO DEVICE :\n\n"
|
|
" AWE32/64 playback requires onboard DRAM,\n"
|
|
" Sound Blaster playback is the most compatible & better for emulation\n\n");
|
|
|
|
for (k = 0;k < AGetAudioNumDevs();k++)
|
|
{
|
|
if (AGetAudioDevCaps(k,&caps) == AUDIO_ERROR_NONE)
|
|
printf(" %2d. %s\n",k,caps.szProductName);
|
|
}
|
|
printf("\n");
|
|
|
|
if (k < 10)
|
|
{
|
|
i = getch();
|
|
seal_sound_card = i - '0';
|
|
}
|
|
else
|
|
scanf("%d",&seal_sound_card);
|
|
}
|
|
|
|
/* initialize SEAL audio library */
|
|
if (seal_sound_card == 0) /* silence */
|
|
{
|
|
/* update the Machine structure to show that sound is disabled */
|
|
seal_sample_rate = 0;
|
|
exit(0);
|
|
return 0;
|
|
}
|
|
|
|
/* open audio device */
|
|
/* info.nDeviceId = AUDIO_DEVICE_MAPPER;*/
|
|
info.nDeviceId = seal_sound_card;
|
|
/* always use 16 bit mixing if possible - better quality and same speed of 8 bit */
|
|
info.wFormat = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO | AUDIO_FORMAT_RAW_SAMPLE;
|
|
|
|
info.nSampleRate = seal_sample_rate;
|
|
if (AOpenAudio(&info) != AUDIO_ERROR_NONE)
|
|
{
|
|
return (1);
|
|
}
|
|
|
|
AGetAudioDevCaps(info.nDeviceId,&caps);
|
|
printf("Using `%s' at %d-bit %s %u Hz\n",
|
|
caps.szProductName,
|
|
info.wFormat & AUDIO_FORMAT_16BITS ? 16 : 8,
|
|
info.wFormat & AUDIO_FORMAT_STEREO ? "stereo" : "mono",
|
|
info.nSampleRate);
|
|
|
|
/* open and allocate voices, allocate waveforms */
|
|
if (AOpenVoices(NUMVOICES) != AUDIO_ERROR_NONE)
|
|
{
|
|
printf("voices initialization failed\n");
|
|
return 1;
|
|
}
|
|
|
|
for (i = 0; i < NUMVOICES; i++)
|
|
{
|
|
if (ACreateAudioVoice(&hVoice[i]) != AUDIO_ERROR_NONE)
|
|
{
|
|
printf("voice #%d creation failed\n",i);
|
|
return 1;
|
|
}
|
|
|
|
ASetVoicePanning(hVoice[i],128);
|
|
|
|
lpWave[i] = 0;
|
|
}
|
|
|
|
/* update the Machine structure to reflect the actual sample rate */
|
|
*rate = seal_sample_rate = info.nSampleRate;
|
|
|
|
{
|
|
uclock_t a,b;
|
|
LONG start,end;
|
|
|
|
|
|
if ((lpWave[0] = (LPAUDIOWAVE)malloc(sizeof(AUDIOWAVE))) == 0)
|
|
return 1;
|
|
|
|
lpWave[0]->wFormat = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO;
|
|
lpWave[0]->nSampleRate = seal_sample_rate;
|
|
lpWave[0]->dwLength = 3*seal_sample_rate;
|
|
lpWave[0]->dwLoopStart = 0;
|
|
lpWave[0]->dwLoopEnd = 3*seal_sample_rate;
|
|
if (ACreateAudioData(lpWave[0]) != AUDIO_ERROR_NONE)
|
|
{
|
|
free(lpWave[0]);
|
|
lpWave[0] = 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
memset(lpWave[0]->lpData,0,3*seal_sample_rate);
|
|
/* upload the data to the audio DRAM local memory */
|
|
AWriteAudioData(lpWave[0],0,3*seal_sample_rate);
|
|
APrimeVoice(hVoice[0],lpWave[0]);
|
|
ASetVoiceFrequency(hVoice[0],seal_sample_rate);
|
|
ASetVoiceVolume(hVoice[0],0);
|
|
AStartVoice(hVoice[0]);
|
|
|
|
a = uclock();
|
|
/* wait some time to let everything stabilize */
|
|
do
|
|
{
|
|
osd_update_audio();
|
|
b = uclock();
|
|
} while (b-a < UCLOCKS_PER_SEC/10);
|
|
|
|
a = uclock();
|
|
AGetVoicePosition(hVoice[0],&start);
|
|
do
|
|
{
|
|
osd_update_audio();
|
|
b = uclock();
|
|
} while (b-a < UCLOCKS_PER_SEC);
|
|
AGetVoicePosition(hVoice[0],&end);
|
|
|
|
nominal_sample_rate = seal_sample_rate;
|
|
seal_sample_rate = end - start;
|
|
|
|
AStopVoice(hVoice[0]);
|
|
ADestroyAudioData(lpWave[0]);
|
|
free(lpWave[0]);
|
|
lpWave[0] = 0;
|
|
}
|
|
|
|
osd_set_mastervolume(0); /* start at maximum volume */
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void msdos_shutdown_sound(void)
|
|
{
|
|
if (seal_sample_rate != 0)
|
|
{
|
|
int n;
|
|
|
|
/* stop and release voices */
|
|
for (n = 0; n < NUMVOICES; n++)
|
|
{
|
|
AStopVoice(hVoice[n]);
|
|
ADestroyAudioVoice(hVoice[n]);
|
|
if (lpWave[n])
|
|
{
|
|
ADestroyAudioData(lpWave[n]);
|
|
free(lpWave[n]);
|
|
lpWave[n] = 0;
|
|
}
|
|
}
|
|
ACloseVoices();
|
|
ACloseAudio();
|
|
}
|
|
}
|
|
|
|
|
|
void playstreamedsample(int channel,signed char *data,int len,int freq,int volume,int pan,int bits)
|
|
{
|
|
static int playing[NUMVOICES];
|
|
static int c[NUMVOICES];
|
|
|
|
/* backwards compatibility with old 0-255 volume range */
|
|
if (volume > 100) volume = volume * 25 / 255;
|
|
|
|
if (seal_sample_rate == 0 || channel >= NUMVOICES) return;
|
|
|
|
if (!playing[channel])
|
|
{
|
|
if (lpWave[channel])
|
|
{
|
|
AStopVoice(hVoice[channel]);
|
|
ADestroyAudioData(lpWave[channel]);
|
|
free(lpWave[channel]);
|
|
lpWave[channel] = 0;
|
|
}
|
|
|
|
if ((lpWave[channel] = (LPAUDIOWAVE)malloc(sizeof(AUDIOWAVE))) == 0)
|
|
return;
|
|
|
|
lpWave[channel]->wFormat = (bits == 8 ? AUDIO_FORMAT_8BITS : AUDIO_FORMAT_16BITS)
|
|
| AUDIO_FORMAT_MONO | AUDIO_FORMAT_LOOP;
|
|
lpWave[channel]->nSampleRate = nominal_sample_rate;
|
|
lpWave[channel]->dwLength = 3*len;
|
|
lpWave[channel]->dwLoopStart = 0;
|
|
lpWave[channel]->dwLoopEnd = 3*len;
|
|
if (ACreateAudioData(lpWave[channel]) != AUDIO_ERROR_NONE)
|
|
{
|
|
free(lpWave[channel]);
|
|
lpWave[channel] = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
memset(lpWave[channel]->lpData,0,3*len);
|
|
memcpy(lpWave[channel]->lpData,data,len);
|
|
/* upload the data to the audio DRAM local memory */
|
|
AWriteAudioData(lpWave[channel],0,3*len);
|
|
APrimeVoice(hVoice[channel],lpWave[channel]);
|
|
/* need to cast to double because freq*nominal_sample_rate can exceed the size of an int */
|
|
ASetVoiceFrequency(hVoice[channel],(double)freq*nominal_sample_rate/seal_sample_rate);
|
|
AStartVoice(hVoice[channel]);
|
|
playing[channel] = 1;
|
|
c[channel] = 1;
|
|
}
|
|
else
|
|
{
|
|
LONG pos;
|
|
|
|
for(;;)
|
|
{
|
|
AGetVoicePosition(hVoice[channel],&pos);
|
|
if (c[channel] == 0 && pos >= len) break;
|
|
if (c[channel] == 1 && (pos < len || pos >= 2*len)) break;
|
|
if (c[channel] == 2 && pos < 2*len) break;
|
|
osd_update_audio();
|
|
}
|
|
|
|
memcpy(&lpWave[channel]->lpData[len * c[channel]],data,len);
|
|
AWriteAudioData(lpWave[channel],len*c[channel],len);
|
|
c[channel]++;
|
|
if (c[channel] == 3) c[channel] = 0;
|
|
}
|
|
|
|
|
|
ASetVoiceVolume(hVoice[channel],volume * 64 / 100);
|
|
ASetVoicePanning(hVoice[channel],(pan + 100) * 255 / 200);
|
|
}
|
|
|
|
void osd_play_streamed_sample_16(int channel,signed short *data,int len,int freq,int volume,int pan)
|
|
{
|
|
playstreamedsample(channel,(signed char *)data,len,freq,volume,pan,16);
|
|
}
|
|
|