Rewrote sound and audio handling, implemented driveclick

WIP, performance is still slower
This commit is contained in:
Dimitris Panokostas 2020-08-14 22:07:43 +02:00
parent 71a5994822
commit cce84daaf8
30 changed files with 3416 additions and 923 deletions

View file

@ -114,7 +114,7 @@
<GenerateCtrlBreakInsteadOfCtrlC>false</GenerateCtrlBreakInsteadOfCtrlC>
<SuppressArgumentVariablesCheck>false</SuppressArgumentVariablesCheck>
<DeploymentTargetPath>/home/pi/projects/amiberry/$(TargetFileName)</DeploymentTargetPath>
<X11WindowMode>Local</X11WindowMode>
<X11WindowMode>Remote</X11WindowMode>
<KeepConsoleAfterExit>false</KeepConsoleAfterExit>
<RunGDBUnderSudo>false</RunGDBUnderSudo>
<DeploymentMode>Auto</DeploymentMode>

View file

@ -114,7 +114,7 @@
<GenerateCtrlBreakInsteadOfCtrlC>false</GenerateCtrlBreakInsteadOfCtrlC>
<SuppressArgumentVariablesCheck>false</SuppressArgumentVariablesCheck>
<DeploymentTargetPath>/home/pi/projects/amiberry/$(TargetFileName)</DeploymentTargetPath>
<X11WindowMode>Local</X11WindowMode>
<X11WindowMode>Remote</X11WindowMode>
<KeepConsoleAfterExit>false</KeepConsoleAfterExit>
<RunGDBUnderSudo>false</RunGDBUnderSudo>
<DeploymentMode>Auto</DeploymentMode>

View file

@ -222,6 +222,7 @@
<ClCompile Include="..\..\src\diskutil.cpp" />
<ClCompile Include="..\..\src\dlopen.cpp" />
<ClCompile Include="..\..\src\drawing.cpp" />
<ClCompile Include="..\..\src\driveclick.cpp" />
<ClCompile Include="..\..\src\events.cpp" />
<ClCompile Include="..\..\src\expansion.cpp" />
<ClCompile Include="..\..\src\fdi2raw.cpp" />
@ -403,6 +404,7 @@
<ClInclude Include="..\..\src\include\disk.h" />
<ClInclude Include="..\..\src\include\diskutil.h" />
<ClInclude Include="..\..\src\include\drawing.h" />
<ClInclude Include="..\..\src\include\driveclick.h" />
<ClInclude Include="..\..\src\include\events.h" />
<ClInclude Include="..\..\src\include\execio.h" />
<ClInclude Include="..\..\src\include\execlib.h" />

View file

@ -649,6 +649,9 @@
<ClCompile Include="..\..\src\osdep\gui\PanelPrio.cpp">
<Filter>Source files\osdep\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\src\driveclick.cpp">
<Filter>Source files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\threaddep\thread.h">
@ -1065,5 +1068,8 @@
<ClInclude Include="..\..\src\osdep\amiberry_filesys.hpp">
<Filter>Source files\osdep</Filter>
</ClInclude>
<ClInclude Include="..\..\src\include\driveclick.h">
<Filter>Source files\include</Filter>
</ClInclude>
</ItemGroup>
</Project>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -438,23 +438,23 @@ static void audio_unpack (struct cdunit *cdu, struct cdtoc *t)
sleep_millis(10);
}
//static void next_cd_audio_buffer_callback(int bufnum, void *params)
//{
// struct cdunit *cdu = (struct cdunit*)params;
// uae_sem_wait(&play_sem);
// if (bufnum >= 0) {
// cdu->cda_bufon[bufnum] = 0;
// bufnum = 1 - bufnum;
// if (cdu->cda_bufon[bufnum])
// audio_cda_new_buffer(&cdu->cas, (uae_s16*)cdu->cda->buffers[bufnum], CDDA_BUFFERS * 2352 / 4, bufnum, next_cd_audio_buffer_callback, cdu);
// else
// bufnum = -1;
// }
// if (bufnum < 0) {
// audio_cda_new_buffer(&cdu->cas, NULL, -1, 0, NULL, cdu);
// }
// uae_sem_post(&play_sem);
//}
static void next_cd_audio_buffer_callback(int bufnum, void *params)
{
struct cdunit *cdu = (struct cdunit*)params;
uae_sem_wait(&play_sem);
if (bufnum >= 0) {
cdu->cda_bufon[bufnum] = 0;
bufnum = 1 - bufnum;
if (cdu->cda_bufon[bufnum])
audio_cda_new_buffer(&cdu->cas, (uae_s16*)cdu->cda->buffers[bufnum], CDDA_BUFFERS * 2352 / 4, bufnum, next_cd_audio_buffer_callback, cdu);
else
bufnum = -1;
}
if (bufnum < 0) {
audio_cda_new_buffer(&cdu->cas, NULL, -1, 0, NULL, cdu);
}
uae_sem_post(&play_sem);
}
static bool cdda_play_func2 (struct cdunit *cdu, int *outpos)
{
@ -479,7 +479,7 @@ static bool cdda_play_func2 (struct cdunit *cdu, int *outpos)
cdu->cda_bufon[0] = cdu->cda_bufon[1] = 0;
bufnum = 0;
cdu->cda = new cda_audio (CDDA_BUFFERS, 2352, 44100);
cdu->cda = new cda_audio (CDDA_BUFFERS, 2352, 44100, mode != 0);
while (cdu->cdda_play > 0) {
@ -583,7 +583,17 @@ static bool cdda_play_func2 (struct cdunit *cdu, int *outpos)
}
}
cdu->cda->wait(bufnum);
if (mode) {
while (cdu->cda_bufon[bufnum] && cdu->cdda_play > 0) {
if (cd_audio_mode_changed) {
restart = true;
goto end;
}
sleep_millis(10);
}
} else {
cdu->cda->wait(bufnum);
}
cdu->cda_bufon[bufnum] = 0;
if (cdu->cdda_play <= 0)
@ -682,13 +692,22 @@ static bool cdda_play_func2 (struct cdunit *cdu, int *outpos)
if (idleframes <= 0)
cdu->cd_last_pos = cdda_pos;
cdu->cda_bufon[bufnum] = 1;
cdu->cda->setvolume (cdu->cdda_volume[0], cdu->cdda_volume[1]);
if (!cdu->cda->play (bufnum)) {
if (cdu->cdda_play > 0)
setstate (cdu, AUDIO_STATUS_PLAY_ERROR, -1);
goto end;
}
if (mode) {
if (cdu->cda_bufon[0] == 0 && cdu->cda_bufon[1] == 0) {
cdu->cda_bufon[bufnum] = 1;
next_cd_audio_buffer_callback(1 - bufnum, cdu);
}
audio_cda_volume(&cdu->cas, cdu->cdda_volume[0], cdu->cdda_volume[1]);
cdu->cda_bufon[bufnum] = 1;
} else {
cdu->cda_bufon[bufnum] = 1;
cdu->cda->setvolume (cdu->cdda_volume[0], cdu->cdda_volume[1]);
if (!cdu->cda->play (bufnum)) {
if (cdu->cdda_play > 0)
setstate (cdu, AUDIO_STATUS_PLAY_ERROR, -1);
goto end;
}
}
if (first) {
first = false;
@ -719,8 +738,14 @@ static bool cdda_play_func2 (struct cdunit *cdu, int *outpos)
end:
*outpos = cdda_pos;
cdu->cda->wait (0);
cdu->cda->wait (1);
if (mode) {
next_cd_audio_buffer_callback(-1, cdu);
if (restart)
audio_cda_new_buffer(&cdu->cas, NULL, -1, -1, NULL, NULL);
} else {
cdu->cda->wait (0);
cdu->cda->wait (1);
}
while (cdimage_unpack_active == 1)
sleep_millis(10);
@ -1955,12 +1980,15 @@ static int parsenrg(struct cdunit *cdu, struct zfile *znrg, const TCHAR *img, co
} else {
tracknum = frombcd(trk);
int index = frombcd(buf[2]);
if (index == 0 && tracknum >= 1 && tracknum <= 99) {
uae_u32 address = get_long_host(buf + 4);
if (tracknum >= 1 && tracknum <= 99) {
struct cdtoc *t = &cdu->toc[tracknum - 1];
t->address = get_long_host(buf + 4);
t->ctrl = buf[0] >> 4;
t->adr = buf[0] & 15;
t->track = tracknum;
if (index == 0) {
t->address = address;
t->ctrl = buf[0] >> 4;
t->adr = buf[0] & 15;
t->track = tracknum;
}
}
}
size -= 8;

View file

@ -379,11 +379,11 @@ static void l64111_setvolume(void)
return;
write_log(_T("L64111 mute %d\n"), volume ? 0 : 1);
if (cda) {
//if (audio_mode) {
// audio_cda_volume(&cas, volume, volume);
//} else {
if (audio_mode) {
audio_cda_volume(&cas, volume, volume);
} else {
cda->setvolume(volume, volume);
//}
}
}
}
@ -1302,22 +1302,22 @@ void cd32_fmv_set_sync(double svpos, double adjust)
fmv_syncadjust = adjust;
}
//static void fmv_next_cd_audio_buffer_callback(int bufnum, void *param)
//{
// uae_sem_wait(&play_sem);
// if (bufnum >= 0) {
// fmv_bufon[bufnum] = 0;
// bufnum = 1 - bufnum;
// if (fmv_bufon[bufnum])
// audio_cda_new_buffer(&cas, (uae_s16*)cda->buffers[bufnum], PCM_SECTORS * KJMP2_SAMPLES_PER_FRAME, bufnum, fmv_next_cd_audio_buffer_callback, param);
// else
// bufnum = -1;
// }
// if (bufnum < 0) {
// audio_cda_new_buffer(&cas, NULL, 0, -1, NULL, NULL);
// }
// uae_sem_post(&play_sem);
//}
static void fmv_next_cd_audio_buffer_callback(int bufnum, void *param)
{
uae_sem_wait(&play_sem);
if (bufnum >= 0) {
fmv_bufon[bufnum] = 0;
bufnum = 1 - bufnum;
if (fmv_bufon[bufnum])
audio_cda_new_buffer(&cas, (uae_s16*)cda->buffers[bufnum], PCM_SECTORS * KJMP2_SAMPLES_PER_FRAME, bufnum, fmv_next_cd_audio_buffer_callback, param);
else
bufnum = -1;
}
if (bufnum < 0) {
audio_cda_new_buffer(&cas, NULL, 0, -1, NULL, NULL);
}
uae_sem_post(&play_sem);
}
void cd32_fmv_vsync_handler(void)
{
@ -1335,13 +1335,13 @@ static void cd32_fmv_audio_handler(void)
if (cd_audio_mode_changed || (cl450_play && !cda)) {
cd_audio_mode_changed = false;
if (cl450_play) {
//if (audio_mode) {
// audio_cda_new_buffer(&cas, NULL, -1, -1, NULL, NULL);
//}
if (audio_mode) {
audio_cda_new_buffer(&cas, NULL, -1, -1, NULL, NULL);
}
audio_mode = currprefs.sound_cdaudio;
fmv_bufon[0] = fmv_bufon[1] = 0;
delete cda;
cda = new cda_audio(PCM_SECTORS, KJMP2_SAMPLES_PER_FRAME * 4, 44100);
cda = new cda_audio(PCM_SECTORS, KJMP2_SAMPLES_PER_FRAME * 4, 44100, audio_mode != 0);
l64111_setvolume();
}
}
@ -1357,13 +1357,13 @@ static void cd32_fmv_audio_handler(void)
if (!cda || !(l64111_regs[A_CONTROL1] & 1))
return;
//if (audio_mode) {
// play0 = fmv_bufon[0];
// play1 = fmv_bufon[1];
//} else {
if (audio_mode) {
play0 = fmv_bufon[0];
play1 = fmv_bufon[1];
} else {
play0 = cda->isplaying(0);
play1 = cda->isplaying(1);
//}
}
needsectors = PCM_SECTORS;
if (!play0 && !play1) {
needsectors *= 2;
@ -1387,15 +1387,15 @@ static void cd32_fmv_audio_handler(void)
memcpy(cda->buffers[bufnum] + i * KJMP2_SAMPLES_PER_FRAME * 4, pcmaudio[offset2].pcm, KJMP2_SAMPLES_PER_FRAME * 4);
pcmaudio[offset2].ready = false;
}
//if (audio_mode) {
// if (!play0 && !play1) {
// fmv_bufon[bufnum] = 1;
// fmv_next_cd_audio_buffer_callback(1 - bufnum, NULL);
// }
// fmv_bufon[bufnum] = 1;
//} else {
if (audio_mode) {
if (!play0 && !play1) {
fmv_bufon[bufnum] = 1;
fmv_next_cd_audio_buffer_callback(1 - bufnum, NULL);
}
fmv_bufon[bufnum] = 1;
} else {
cda->play(bufnum);
//}
}
offset += PCM_SECTORS;
offset &= l64111_cb_mask;
l64111_regs[A_CB_READ] = offset;
@ -1469,12 +1469,12 @@ static void cd32_fmv_free(void)
xfree(videoram);
videoram = NULL;
if (cda) {
//if (audio_mode) {
// fmv_next_cd_audio_buffer_callback(-1, NULL);
//} else {
if (audio_mode) {
fmv_next_cd_audio_buffer_callback(-1, NULL);
} else {
cda->wait(0);
cda->wait(1);
//}
}
delete cda;
}
cda = NULL;

View file

@ -30,6 +30,9 @@
#include "gensound.h"
#include "gui.h"
#include "drawing.h"
#ifdef DRIVESOUND
#include "driveclick.h"
#endif
#include "statusline.h"
#include "uaeexe.h"
#ifdef JIT
@ -257,6 +260,7 @@ void devices_rethink(void)
void devices_update_sound(double clk, double syncadjust)
{
update_sound(clk);
update_cda_sound(clk / syncadjust);
}
void devices_update_sync(double svpos, double syncadjust)

View file

@ -34,6 +34,9 @@ int disk_debug_track = -1;
#ifdef FDI2RAW
#include "fdi2raw.h"
#endif
#ifdef DRIVESOUND
#include "driveclick.h"
#endif
#ifdef CAPS
#include "uae/caps.h"
#endif

600
src/driveclick.cpp Normal file
View file

@ -0,0 +1,600 @@
/*
* UAE - The Un*x Amiga Emulator
*
* Drive Click Emulation Support Functions
*
* Copyright 2004 James Bagg, Toni Wilen
*/
#include "sysconfig.h"
#include "sysdeps.h"
#ifdef DRIVESOUND
#include "uae.h"
#include "options.h"
#include "audio.h"
#include "sounddep/sound.h"
#include "zfile.h"
#include "fsdb.h"
#include "events.h"
#include "driveclick.h"
#ifdef AMIBERRY
SDL_AudioSpec wav_spec;
Uint32 wav_length;
Uint8* wav_buffer;
#endif
static struct drvsample drvs[4][DS_END];
static int freq = 44100;
static int drv_starting[4], drv_spinning[4], drv_has_spun[4], drv_has_disk[4];
static int click_initialized, wave_initialized;
#define DS_SHIFT 10
static int sample_step;
static uae_s16* clickbuffer;
static int clickcnt;
uae_s16* decodewav(uae_u8* s, int* lenp)
{
uae_s16* dst;
uae_u8* src = s;
int len;
if (memcmp(s, "RIFF", 4))
return 0;
if (memcmp(s + 8, "WAVE", 4))
return 0;
s += 12;
len = *lenp;
while (s < src + len) {
if (!memcmp(s, "fmt ", 4))
freq = s[8 + 4] | (s[8 + 5] << 8);
if (!memcmp(s, "data", 4)) {
s += 4;
len = s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24);
dst = xmalloc(uae_s16, len / 2);
#ifdef WORDS_BIGENDIAN
int8_t* dst8 = (int8_t*)dst;
for (int i = 0; i < len; i += 2) {
dst8[i] = s[i + 1];
dst8[i + 1] = s[i];
}
#else
memcpy(dst, s + 4, len);
#endif
* lenp = len / 2;
return dst;
}
s += 8 + (s[4] | (s[5] << 8) | (s[6] << 16) | (s[7] << 24));
}
return 0;
}
static int loadsample(TCHAR* path, struct drvsample* ds)
{
struct zfile* f;
uae_u8* buf;
int size;
TCHAR name[MAX_DPATH];
f = zfile_fopen(path, _T("rb"), ZFD_NORMAL);
if (!f) {
_tcscpy(name, path);
_tcscat(name, _T(".wav"));
f = zfile_fopen(name, _T("rb"), ZFD_NORMAL);
if (!f) {
write_log(_T("driveclick: can't open '%s' (or '%s')\n"), path, name);
return 0;
}
}
zfile_fseek(f, 0, SEEK_END);
size = zfile_ftell(f);
buf = xmalloc(uae_u8, size);
zfile_fseek(f, 0, SEEK_SET);
zfile_fread(buf, size, 1, f);
zfile_fclose(f);
ds->len = size;
ds->p = decodewav(buf, &ds->len);
xfree(buf);
return 1;
}
static void freesample(struct drvsample* s)
{
xfree(s->p);
s->p = nullptr;
}
static void processclicks(struct drvsample* ds)
{
unsigned int nClick = 0;
for (int n = 0; n < CLICK_TRACKS; n++) {
ds->indexes[n] = 0;
ds->lengths[n] = 0;
}
for (int n = 0; n < ds->len; n++) {
uae_s16 smp = ds->p[n];
if (smp > 0x6ff0 && nClick < CLICK_TRACKS) {
ds->indexes[nClick] = n - 128;
ds->lengths[nClick] = 2800;
nClick++;
n += 3000;
}
}
if (nClick == 0) {
for (int n = 0; n < CLICK_TRACKS; n++) {
ds->indexes[n] = 0;
ds->lengths[n] = ds->len;
}
}
else {
if (nClick == 1) {
ds->lengths[0] = ds->len - ds->indexes[0];
for (int n = 1; n < CLICK_TRACKS; n++) {
ds->indexes[n] = ds->indexes[0];
ds->lengths[n] = ds->lengths[0];
}
}
else {
for (int n = nClick; n < CLICK_TRACKS; n++) {
ds->indexes[n] = ds->indexes[nClick - 1];
ds->lengths[n] = ds->lengths[nClick - 1];
}
}
}
}
static void driveclick_close(void)
{
driveclick_fdrawcmd_close(0);
driveclick_fdrawcmd_close(1);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < DS_END; j++)
freesample(&drvs[i][j]);
}
memset(drvs, 0, sizeof(drvs));
click_initialized = 0;
wave_initialized = 0;
driveclick_reset();
}
void driveclick_free(void)
{
driveclick_close();
}
void driveclick_init(void)
{
int v, vv;
TCHAR tmp[MAX_DPATH];
driveclick_fdrawcmd_detect();
driveclick_close();
vv = 0;
for (int i = 0; i < 4; i++) {
struct floppyslot* fs = &currprefs.floppyslots[i];
for (int j = 0; j < CLICK_TRACKS; j++) {
drvs[i][DS_CLICK].indexes[j] = 0;
drvs[i][DS_CLICK].lengths[j] = 0;
}
if (fs->dfxclick) {
v = 0;
if (fs->dfxclick > 0) {
switch (fs->dfxclick)
{
case 1:
if (driveclick_loadresource(drvs[i], fs->dfxclick))
v = 3;
for (int j = 0; j < CLICK_TRACKS; j++)
drvs[i][DS_CLICK].lengths[j] = drvs[i][DS_CLICK].len;
wave_initialized = 1;
break;
default:
if (driveclick_fdrawcmd_open(fs->dfxclick - 2))
v = 1;
break;
}
} else if (fs->dfxclick == -1) {
TCHAR path2[MAX_DPATH];
wave_initialized = 1;
for (int j = 0; j < CLICK_TRACKS; j++)
drvs[i][DS_CLICK].lengths[j] = drvs[i][DS_CLICK].len;
get_plugin_path (path2, sizeof path2 / sizeof (TCHAR), _T("floppysounds"));
_stprintf (tmp, _T("%sdrive_click_%s"),
path2, fs->dfxclickexternal);
v = loadsample (tmp, &drvs[i][DS_CLICK]);
if (v)
processclicks (&drvs[i][DS_CLICK]);
_stprintf (tmp, _T("%sdrive_spin_%s"),
path2, fs->dfxclickexternal);
v += loadsample (tmp, &drvs[i][DS_SPIN]);
_stprintf (tmp, _T("%sdrive_spinnd_%s"),
path2, fs->dfxclickexternal);
v += loadsample (tmp, &drvs[i][DS_SPINND]);
_stprintf (tmp, _T("%sdrive_startup_%s"),
path2, fs->dfxclickexternal);
v += loadsample (tmp, &drvs[i][DS_START]);
_stprintf (tmp, _T("%sdrive_snatch_%s"),
path2, fs->dfxclickexternal);
v += loadsample (tmp, &drvs[i][DS_SNATCH]);
}
if (v == 0) {
for (int j = 0; j < DS_END; j++)
freesample(&drvs[i][j]);
fs->dfxclick = changed_prefs.floppyslots[i].dfxclick = 0;
} else {
vv++;
}
for (int j = 0; j < DS_END; j++)
drvs[i][j].len <<= DS_SHIFT;
drvs[i][DS_CLICK].pos = drvs[i][DS_CLICK].len;
drvs[i][DS_SNATCH].pos = drvs[i][DS_SNATCH].len;
}
}
if (vv > 0) {
click_initialized = 1;
}
driveclick_reset();
}
void driveclick_reset (void)
{
xfree (clickbuffer);
clickbuffer = NULL;
clickcnt = 0;
for (int i = 0; i < 4; i++) {
drv_starting[i] = 0;
drv_spinning[i] = 0;
drv_has_spun[i] = 0;
drv_has_disk[i] = 0;
if (currprefs.floppyslots[i].df[0])
driveclick_insert(i, 0);
}
if (!wave_initialized)
return;
clickbuffer = xcalloc (uae_s16, paula_sndbufsize / 2);
sample_step = (freq << DS_SHIFT) / currprefs.sound_freq;
}
static int driveclick_active (void)
{
for (int i = 0; i < 4; i++) {
if (currprefs.floppyslots[i].dfxclick) {
if (drv_spinning[i] || drv_starting[i])
return 1;
}
}
return 0;
}
static uae_s16 getsample (void)
{
uae_s32 total_sample = 0;
int total_div = 0;
for (int i = 0; i < 4; i++) {
int div = 0;
if (currprefs.floppyslots[i].dfxclick) {
uae_s32 smp = 0;
struct drvsample* ds_start = &drvs[i][DS_START];
struct drvsample* ds_spin = drv_has_disk[i] ? &drvs[i][DS_SPIN] : &drvs[i][DS_SPINND];
struct drvsample* ds_click = &drvs[i][DS_CLICK];
struct drvsample* ds_snatch = &drvs[i][DS_SNATCH];
if (drv_spinning[i] || drv_starting[i]) {
div++;
if (drv_starting[i] && drv_has_spun[i]) {
if (ds_start->p && ds_start->pos < ds_start->len) {
smp = ds_start->p[ds_start->pos >> DS_SHIFT];
ds_start->pos += sample_step;
} else {
drv_starting[i] = 0;
}
} else if (drv_starting[i] && drv_has_spun[i] == 0) {
if (ds_snatch->p && ds_snatch->pos < ds_snatch->len) {
smp = ds_snatch->p[ds_snatch->pos >> DS_SHIFT];
ds_snatch->pos += sample_step;
} else {
drv_starting[i] = 0;
ds_start->pos = ds_start->len;
drv_has_spun[i] = 1;
}
}
if (ds_spin->p && drv_starting[i] == 0) {
if (ds_spin->pos >= ds_spin->len)
ds_spin->pos -= ds_spin->len;
smp = ds_spin->p[ds_spin->pos >> DS_SHIFT];
ds_spin->pos += sample_step;
}
}
if (ds_click->p && ds_click->pos < ds_click->len) {
smp += ds_click->p[ds_click->pos >> DS_SHIFT];
div++;
ds_click->pos += sample_step;
}
if (div) {
int vol;
if (drv_has_disk[i])
vol = currprefs.dfxclickvolume_disk[i];
else
vol = currprefs.dfxclickvolume_empty[i];
total_sample += (smp * (100 - vol) / 100) / div;
total_div++;
}
}
}
if (!total_div)
return 0;
return total_sample / total_div;
}
static void mix(void)
{
int total = ((uae_u8*)paula_sndbufpt - (uae_u8*)paula_sndbuffer) / (get_audio_nativechannels(currprefs.sound_stereo) * 2);
while (clickcnt < total) {
clickbuffer[clickcnt++] = getsample();
}
}
STATIC_INLINE uae_s16 limit(uae_s32 v)
{
if (v < -32768)
v = -32768;
if (v > 32767)
v = 32767;
return v;
}
void driveclick_mix(uae_s16* sndbuffer, int size, int channelmask)
{
if (!wave_initialized)
return;
mix();
clickcnt = 0;
switch (get_audio_nativechannels(currprefs.sound_stereo))
{
case 6:
for (int i = 0; i < size / 6; i++) {
uae_s16 s = clickbuffer[i];
if (channelmask & 1)
sndbuffer[0] = limit(((sndbuffer[0] + s) * 2) / 3);
else
sndbuffer[0] = sndbuffer[0] * 2 / 3;
if (channelmask & 2)
sndbuffer[1] = limit(((sndbuffer[1] + s) * 2) / 3);
else
sndbuffer[1] = sndbuffer[1] * 2 / 3;
if (channelmask & 4)
sndbuffer[2] = limit(((sndbuffer[2] + s) * 2) / 3);
else
sndbuffer[2] = sndbuffer[2] * 2 / 3;
if (channelmask & 8)
sndbuffer[3] = limit(((sndbuffer[3] + s) * 2) / 3);
else
sndbuffer[3] = sndbuffer[3] * 2 / 3;
if (channelmask & 16)
sndbuffer[4] = limit(((sndbuffer[4] + s) * 2) / 3);
else
sndbuffer[4] = sndbuffer[4] * 2 / 3;
if (channelmask & 32)
sndbuffer[5] = limit(((sndbuffer[5] + s) * 2) / 3);
else
sndbuffer[5] = sndbuffer[5] * 2 / 3;
sndbuffer += 6;
}
break;
case 4:
for (int i = 0; i < size / 4; i++) {
uae_s16 s = clickbuffer[i];
if (channelmask & 1)
sndbuffer[0] = limit(((sndbuffer[0] + s) * 2) / 3);
else
sndbuffer[0] = sndbuffer[0] * 2 / 3;
if (channelmask & 2)
sndbuffer[1] = limit(((sndbuffer[1] + s) * 2) / 3);
else
sndbuffer[1] = sndbuffer[1] * 2 / 3;
if (channelmask & 4)
sndbuffer[2] = limit(((sndbuffer[2] + s) * 2) / 3);
else
sndbuffer[2] = sndbuffer[2] * 2 / 3;
if (channelmask & 8)
sndbuffer[3] = limit(((sndbuffer[3] + s) * 2) / 3);
else
sndbuffer[3] = sndbuffer[3] * 2 / 3;
sndbuffer += 4;
}
break;
case 2:
for (int i = 0; i < size / 2; i++) {
uae_s16 s = clickbuffer[i];
if (channelmask & 1)
sndbuffer[0] = limit(((sndbuffer[0] + s) * 2) / 3);
else
sndbuffer[0] = sndbuffer[0] * 2 / 3;
if (channelmask & 2)
sndbuffer[1] = limit(((sndbuffer[1] + s) * 2) / 3);
else
sndbuffer[1] = sndbuffer[1] * 2 / 3;
sndbuffer += 2;
}
break;
case 1:
for (int i = 0; i < size; i++) {
uae_s16 s = clickbuffer[i];
if (channelmask & 1)
sndbuffer[0] = limit(((sndbuffer[0] + s) * 2) / 3);
else
sndbuffer[0] = sndbuffer[0] * 2 / 3;
sndbuffer++;
}
break;
}
}
static void dr_audio_activate(void)
{
if (audio_activate())
clickcnt = 0;
}
void driveclick_click(int drive, int cyl)
{
static int prevcyl[4];
if (!click_initialized)
return;
if (!currprefs.floppyslots[drive].dfxclick)
return;
if (prevcyl[drive] == 0 && cyl == 0) // "noclick" check
return;
dr_audio_activate();
prevcyl[drive] = cyl;
if (!wave_initialized) {
driveclick_fdrawcmd_seek(currprefs.floppyslots[drive].dfxclick - 2, cyl);
return;
}
mix();
drvs[drive][DS_CLICK].pos = drvs[drive][DS_CLICK].indexes[cyl] << DS_SHIFT;
drvs[drive][DS_CLICK].len = (drvs[drive][DS_CLICK].indexes[cyl] + (drvs[drive][DS_CLICK].lengths[cyl] / 2)) << DS_SHIFT;
}
void driveclick_motor(int drive, int running)
{
if (!click_initialized)
return;
if (!currprefs.floppyslots[drive].dfxclick)
return;
if (!wave_initialized) {
driveclick_fdrawcmd_motor(currprefs.floppyslots[drive].dfxclick - 2, running);
return;
}
mix();
if (running == 0) {
drv_starting[drive] = 0;
drv_spinning[drive] = 0;
} else {
if (drv_spinning[drive] == 0) {
dr_audio_activate();
drv_starting[drive] = 1;
drv_spinning[drive] = 1;
if (drv_has_disk[drive] && drv_has_spun[drive] == 0 && drvs[drive][DS_SNATCH].pos >= drvs[drive][DS_SNATCH].len)
drvs[drive][DS_SNATCH].pos = 0;
if (running == 2)
drvs[drive][DS_START].pos = 0;
drvs[drive][DS_SPIN].pos = 0;
}
}
}
void driveclick_insert(int drive, int eject)
{
if (!click_initialized)
return;
if (!wave_initialized)
return;
if (!currprefs.floppyslots[drive].dfxclick)
return;
if (eject)
drv_has_spun[drive] = 0;
if (drv_has_disk[drive] == 0 && !eject)
dr_audio_activate ();
drv_has_disk[drive] = !eject;
}
void driveclick_check_prefs(void)
{
if (!config_changed)
return;
driveclick_fdrawcmd_vsync();
if (driveclick_active())
dr_audio_activate();
if (
currprefs.dfxclickvolume_disk[0] != changed_prefs.dfxclickvolume_disk[0] ||
currprefs.dfxclickvolume_disk[1] != changed_prefs.dfxclickvolume_disk[1] ||
currprefs.dfxclickvolume_disk[2] != changed_prefs.dfxclickvolume_disk[2] ||
currprefs.dfxclickvolume_disk[3] != changed_prefs.dfxclickvolume_disk[3] ||
currprefs.dfxclickvolume_empty[0] != changed_prefs.dfxclickvolume_empty[0] ||
currprefs.dfxclickvolume_empty[1] != changed_prefs.dfxclickvolume_empty[1] ||
currprefs.dfxclickvolume_empty[2] != changed_prefs.dfxclickvolume_empty[2] ||
currprefs.dfxclickvolume_empty[3] != changed_prefs.dfxclickvolume_empty[3] ||
currprefs.floppyslots[0].dfxclick != changed_prefs.floppyslots[0].dfxclick ||
currprefs.floppyslots[1].dfxclick != changed_prefs.floppyslots[1].dfxclick ||
currprefs.floppyslots[2].dfxclick != changed_prefs.floppyslots[2].dfxclick ||
currprefs.floppyslots[3].dfxclick != changed_prefs.floppyslots[3].dfxclick ||
_tcscmp(currprefs.floppyslots[0].dfxclickexternal, changed_prefs.floppyslots[0].dfxclickexternal) ||
_tcscmp(currprefs.floppyslots[1].dfxclickexternal, changed_prefs.floppyslots[1].dfxclickexternal) ||
_tcscmp(currprefs.floppyslots[2].dfxclickexternal, changed_prefs.floppyslots[2].dfxclickexternal) ||
_tcscmp(currprefs.floppyslots[3].dfxclickexternal, changed_prefs.floppyslots[3].dfxclickexternal))
{
for (int i = 0; i < 4; i++) {
currprefs.floppyslots[i].dfxclick = changed_prefs.floppyslots[i].dfxclick;
_tcscpy(currprefs.floppyslots[i].dfxclickexternal, changed_prefs.floppyslots[i].dfxclickexternal);
currprefs.dfxclickvolume_empty[i] = changed_prefs.dfxclickvolume_empty[i];
currprefs.dfxclickvolume_disk[i] = changed_prefs.dfxclickvolume_disk[i];
}
driveclick_init();
}
}
int driveclick_loadresource(struct drvsample* sp, int drivetype)
{
auto ok = 1;
for (auto type = 0; type < DS_END; type++) {
auto* s = sp + type;
switch (type) {
case 0:
ok = loadsample("data/floppy_sounds/drive_click.wav", s);
break;
case 1:
ok = loadsample("data/floppy_sounds/drive_spin.wav", s);
break;
case 2:
ok = loadsample("data/floppy_sounds/drive_spinnd.wav", s);
break;
case 3:
ok = loadsample("data/floppy_sounds/drive_startup.wav", s);
break;
case 4:
ok = loadsample("data/floppy_sounds/drive_snatch.wav", s);
break;
default:
continue;
}
}
return ok;
}
void driveclick_fdrawcmd_close(int drive)
{
}
int driveclick_fdrawcmd_open(int drive)
{
return 0;
}
void driveclick_fdrawcmd_detect(void)
{
}
void driveclick_fdrawcmd_seek(int drive, int cyl)
{
}
void driveclick_fdrawcmd_motor(int drive, int running)
{
}
void driveclick_fdrawcmd_vsync(void)
{
}
#endif

View file

@ -75,9 +75,9 @@ static bool event_check_vsync(void)
if (v < 0)
{
if (currprefs.cachesize)
regs.pissoff = pissoff_value;
pissoff = pissoff_value;
else
regs.pissoff = pissoff_nojit_value;
pissoff = pissoff_nojit_value;
return true;
}
//}
@ -95,9 +95,9 @@ static bool event_check_vsync(void)
}
if (v < 0 && v2 < 0) {
if (currprefs.cachesize)
regs.pissoff = pissoff_value;
pissoff = pissoff_value;
else
regs.pissoff = pissoff_nojit_value;
pissoff = pissoff_nojit_value;
return true;
}
//}
@ -108,11 +108,11 @@ static bool event_check_vsync(void)
void do_cycles_cpu_fastest(uae_u32 cycles_to_add)
{
if ((regs.pissoff -= cycles_to_add) > 0)
if ((pissoff -= cycles_to_add) > 0)
return;
cycles_to_add = -regs.pissoff;
regs.pissoff = 0;
cycles_to_add = -pissoff;
pissoff = 0;
if (is_syncline)
{

57
src/include/driveclick.h Normal file
View file

@ -0,0 +1,57 @@
/*
* UAE - The Un*x Amiga Emulator
*
* Drive Click emulation stuff
*
* Copyright 2004 James Bagg, Toni Wilen
*/
#ifndef UAE_DRIVECLICK_H
#define UAE_DRIVECLICK_H
#include "uae/types.h"
#define CLICK_TRACKS 84
struct drvsample {
int len;
int pos;
uae_s16* p;
int indexes[CLICK_TRACKS];
int lengths[CLICK_TRACKS];
};
#define DS_CLICK 0
#define DS_SPIN 1
#define DS_SPINND 2
#define DS_START 3
#define DS_SNATCH 4
#define DS_END 5
extern void driveclick_click(int drive, int startOffset);
extern void driveclick_motor(int drive, int running);
extern void driveclick_insert(int drive, int eject);
extern void driveclick_init(void);
extern void driveclick_free(void);
extern void driveclick_reset(void);
extern void driveclick_mix(uae_s16*, int, int);
extern int driveclick_loadresource(struct drvsample*, int);
extern void driveclick_check_prefs(void);
extern uae_s16* decodewav(uae_u8* s, int* len);
#define DS_BUILD_IN_SOUNDS 1
#define DS_NAME_CLICK _T("drive_click_")
#define DS_NAME_SPIN _T("drive_spin_")
#define DS_NAME_SPIN_ND _T("drive_spinnd_")
#define DS_NAME_START _T("drive_start_")
#define DS_NAME_SNATCH _T("drive_snatch_")
extern int driveclick_fdrawcmd_open(int);
extern void driveclick_fdrawcmd_close(int);
extern void driveclick_fdrawcmd_detect(void);
extern void driveclick_fdrawcmd_seek(int, int);
extern void driveclick_fdrawcmd_motor(int, int);
extern void driveclick_fdrawcmd_vsync(void);
extern int driveclick_pcdrivemask, driveclick_pcdrivenum;
#endif /* UAE_DRIVECLICK_H */

View file

@ -69,8 +69,9 @@ enum {
};
extern int pissoff_value;
extern uae_s32 pissoff;
#define countdown (regs.pissoff)
#define countdown (pissoff)
extern struct ev eventtab[ev_max];
extern struct ev2 eventtab2[ev2_max];
@ -82,19 +83,19 @@ STATIC_INLINE void cycles_do_special(void)
{
#ifdef JIT
if (currprefs.cachesize) {
if (regs.pissoff >= 0)
regs.pissoff = -1;
if (pissoff >= 0)
pissoff = -1;
}
else
#endif
{
regs.pissoff = 0;
pissoff = 0;
}
}
STATIC_INLINE void do_extra_cycles (unsigned long cycles_to_add)
{
regs.pissoff -= cycles_to_add;
pissoff -= cycles_to_add;
}
STATIC_INLINE unsigned long int get_cycles (void)

View file

@ -12,6 +12,7 @@
#include "uae/types.h"
#include "readcpu.h"
#include "machdep/m68k.h"
#include "events.h"
extern const int areg_byteinc[];
extern const int imm8_table[];
@ -172,7 +173,6 @@ struct regstruct
uae_u32 pcr;
uae_u32 address_space_mask;
uae_s32 pissoff;
uae_u8* natmem_offset;
#ifdef JIT

View file

@ -10,4 +10,7 @@ void uae_clipboard_put_text(const char* text);
typedef const char * (*amiga_plugin_lookup_function)(const char *name);
void amiga_set_plugin_lookup_function(amiga_plugin_lookup_function function);
typedef int (*audio_callback)(int type, int16_t* buffer, int size);
int amiga_set_cd_audio_callback(audio_callback func);
#endif // LIBAMIGA_LIBAMIGA_H_

View file

@ -31,6 +31,8 @@
/* Need to have these somewhere */
bool check_prefs_changed_comp (bool checkonly) { return false; }
#endif
/* For faster JIT cycles handling */
uae_s32 pissoff = 0;
/* Opcode of faulting instruction */
static uae_u32 last_op_for_exception_3;
@ -1158,7 +1160,7 @@ static void m68k_reset(bool hardreset)
{
uae_u32 v;
regs.pissoff = 0;
pissoff = 0;
cpu_cycles = 0;
regs.halted = 0;

View file

@ -134,6 +134,7 @@ static char rp9_path[MAX_DPATH];
static char controllers_path[MAX_DPATH];
static char retroarch_file[MAX_DPATH];
static char logfile_path[MAX_DPATH];
static char floppy_sounds_dir[MAX_DPATH];
char last_loaded_config[MAX_DPATH] = {'\0'};
@ -529,6 +530,11 @@ void target_default_options(struct uae_prefs* p, int type)
p->cr[0].locked = true;
p->cr[0].rtg = true;
_tcscpy(p->cr[0].label, _T("RTG"));
for (auto& floppyslot : p->floppyslots)
{
floppyslot.dfxclick = 1;
}
}
void target_save_options(struct zfile* f, struct uae_prefs* p)
@ -1209,6 +1215,7 @@ void load_amiberry_settings(void)
#endif
snprintf(rp9_path, MAX_DPATH, "%s/rp9/", start_path_data);
snprintf(path, MAX_DPATH, "%s/conf/amiberry.conf", start_path_data);
snprintf(floppy_sounds_dir, MAX_DPATH, "%s/data/floppy_sounds/", start_path_data);
auto* const fh = zfile_fopen(path, _T("r"), ZFD_NORMAL);
if (fh)
@ -2067,3 +2074,22 @@ bool handle_events()
return pause_emulation != 0;
}
bool get_plugin_path(TCHAR* out, int len, const TCHAR* path)
{
if (strcmp(path, "floppysounds") == 0) {
if (floppy_sounds_dir) {
strncpy(out, floppy_sounds_dir, len);
}
else {
strncpy(out, "floppy_sounds", len);
}
// make sure out is null-terminated in any case
out[len - 1] = '\0';
}
else {
write_log("\n-----------------> STUB: get_plugin_path, "
"size: %d, path: %s\n", len, path);
out[0] = '\0';
}
return TRUE;
}

View file

@ -31,6 +31,7 @@
#include "statusline.h"
#include "sounddep/sound.h"
#include "threaddep/thread.h"
static uae_thread_id display_tid = nullptr;
static smp_comm_pipe *volatile display_pipe = nullptr;
static uae_sem_t display_sem = nullptr;

View file

@ -424,7 +424,7 @@ int gui_init()
void gui_exit()
{
sync();
stop_sound();
close_sound();
save_amiberry_settings();
ClearConfigFileList();
ClearAvailableROMList();

View file

@ -1,78 +1,120 @@
#include "sysconfig.h"
#include "sysdeps.h"
#include "audio.h"
#include "cda_play.h"
#include "audio.h"
#include "options.h"
#include "sounddep/sound.h"
#include "uae/uae.h"
cda_audio::~cda_audio()
{
cdaudio_active = false;
if (active) {
wait(0);
wait(1);
}
for (int i = 0; i < 2; i++) {
xfree (buffers[i]);
buffers[i] = NULL;
}
static int (*g_audio_callback)(int type, int16_t* buffer, int size) = NULL;
int amiga_set_cd_audio_callback(audio_callback func) {
g_audio_callback = func;
return 1;
}
cda_audio::cda_audio(int num_sectors, int sectorsize, int samplerate)
cda_audio::~cda_audio()
{
active = false;
playing = false;
volume[0] = volume[1] = 0;
currBuf = 1;
wait(0);
wait(1);
for (auto& buffer : buffers)
{
xfree(buffer);
buffer = nullptr;
}
}
bufsize = num_sectors * sectorsize;
cda_audio::cda_audio(int num_sectors, int sectorsize, int samplerate, bool internalmode)
{
active = false;
playing = false;
volume[0] = volume[1] = 0;
bufsize = num_sectors * sectorsize;
this->sectorsize = sectorsize;
for (int i = 0; i < 2; i++) {
buffers[i] = xcalloc (uae_u8, num_sectors * ((bufsize + 4095) & ~4095));
}
this->num_sectors = num_sectors;
active = true;
playing = true;
cdaudio_active = true;
for (int i = 0; i < 2; i++)
{
buffer_ids[i] = 0;
buffers[i] = xcalloc(uae_u8, num_sectors * ((bufsize + 4095) & ~4095));
}
this->num_sectors = num_sectors;
if (internalmode)
return;
active = true;
playing = true;
}
void cda_audio::setvolume(int left, int right)
void cda_audio::setvolume(int left, int right)
{
for (int j = 0; j < 2; j++) {
volume[j] = j == 0 ? left : right;
for (int j = 0; j < 2; j++)
{
volume[j] = j == 0 ? left : right;
volume[j] = sound_cd_volume[j] * volume[j] / 32768;
if (volume[j])
volume[j]++;
if (volume[j] >= 32768)
volume[j] = 32768;
}
if (volume[j])
volume[j]++;
volume[j] = volume[j] * (100 - currprefs.sound_volume_master) / 100;
if (volume[j] >= 32768)
volume[j] = 32768;
}
}
bool cda_audio::play(int bufnum)
bool cda_audio::play(int bufnum)
{
if (!active) {
return false;
}
if (!active)
return false;
currBuf = bufnum;
uae_s16 *p = (uae_s16*)(buffers[bufnum]);
for (int i = 0; i < num_sectors * sectorsize / 4; i++) {
PUT_CDAUDIO_WORD_STEREO(p[i * 2 + 0] * volume[0] / 32768, p[i * 2 + 1] * volume[1] / 32768);
check_cdaudio_buffers();
}
uae_s16* p = (uae_s16*)(buffers[bufnum]);
for (int i = 0; i < num_sectors * sectorsize / 4; i++) {
p[i * 2 + 0] = p[i * 2 + 0] * volume[0] / 32768;
p[i * 2 + 1] = p[i * 2 + 1] * volume[1] / 32768;
}
return cdaudio_catchup();
if (g_audio_callback) {
int len = num_sectors * sectorsize;
#ifdef WORDS_BIGENDIAN
int8_t* d = (int8_t*)p;
int8_t temp = 0;
for (int i = 0; i < len; i += 2) {
temp = d[i + 1];
d[i + 1] = d[i];
d[i] = temp;
}
#endif
buffer_ids[bufnum] = g_audio_callback(3, p, len);
}
else {
buffer_ids[bufnum] = 0;
}
return true;
}
void cda_audio::wait(int bufnum)
void cda_audio::wait(int bufnum)
{
if (!active || !playing)
return;
if (!active || !playing)
return;
if (buffer_ids[bufnum] == 0) {
return;
}
// calling g_audio_callback with NULL parameter to check status
while (!g_audio_callback(3, NULL, buffer_ids[bufnum])) {
Sleep(10);
}
}
bool cda_audio::isplaying(int bufnum)
{
if (!active || !playing)
return false;
return bufnum != currBuf;
if (buffer_ids[bufnum] == 0) {
return false;
}
return g_audio_callback(3, NULL, buffer_ids[bufnum]);
}

View file

@ -1,26 +1,28 @@
#pragma once
#include "audio.h"
extern volatile bool cd_audio_mode_changed;
class cda_audio
class cda_audio
{
private:
int bufsize;
int sectorsize;
int volume[2];
bool playing;
bool active;
int currBuf;
int num_sectors;
int bufsize;
int volume[2];
bool playing;
bool active;
int buffer_ids[2];
public:
uae_u8 *buffers[2];
cda_audio(int num_sectors, int sectorsize, int samplerate);
~cda_audio();
void setvolume(int left, int right);
bool play(int bufnum);
void wait(void);
void wait(int bufnum);
uae_u8 *buffers[2];
int num_sectors;
int sectorsize;
cda_audio(int num_sectors, int sectorsize, int samplerate, bool internalmode);
~cda_audio();
void setvolume(int left, int right);
bool play(int bufnum);
void wait(void);
void wait(int bufnum);
bool isplaying(int bufnum);
};

View file

@ -9,7 +9,7 @@
#define MAX_DPATH 4096
#endif
/* #define DRIVESOUND */
#define DRIVESOUND
/* #define GFXFILTER */
//#define USE_SOFT_LONG_DOUBLE
#define PACKAGE_STRING "AMIBERRY"

View file

@ -57,8 +57,6 @@ void update_display(struct uae_prefs*);
void black_screen_now(void);
void graphics_subshutdown(void);
void stop_sound();
void keyboard_settrans();
void set_mouse_grab(bool grab);
@ -221,3 +219,12 @@ void restore_host_fp_regs(void* buf);
}
#endif
#endif
#define MAX_SOUND_DEVICES 100
#define SOUND_DEVICE_DS 1
#define SOUND_DEVICE_AL 2
#define SOUND_DEVICE_PA 3
#define SOUND_DEVICE_WASAPI 4
#define SOUND_DEVICE_WASAPI_EXCLUSIVE 5
#define SOUND_DEVICE_XAUDIO2 6
#define SOUND_DEVICE_SDL2 7

View file

@ -2,245 +2,385 @@
* Sdl sound.c implementation
* (c) 2015
*/
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include "sysconfig.h"
#include "sysdeps.h"
#include "uae.h"
#include "options.h"
#include "audio.h"
#include "gensound.h"
#include "sounddep/sound.h"
#include "events.h"
#include "custom.h"
#include "threaddep/thread.h"
#include "gui.h"
#include "savestate.h"
#ifdef DRIVESOUND
#include "driveclick.h"
#endif
#include "gensound.h"
#include "xwin.h"
#include "sounddep/sound.h"
#ifdef ANDROID
#include <android/log.h>
#endif
// "consumer" means the actual SDL sound output, as opposed to
#define SOUND_CONSUMER_BUFFER_LENGTH (SNDBUFFER_LEN * SOUND_BUFFERS_COUNT / 4)
struct sound_dp
{
int sndbufsize;
int framesperbuffer;
int sndbuf;
int pullmode;
uae_u8* pullbuffer;
int pullbufferlen;
int pullbuffermaxlen;
double avg_correct;
double cnt_correct;
};
uae_u16 sndbuffer[SOUND_BUFFERS_COUNT][(SNDBUFFER_LEN + 32) * DEFAULT_SOUND_CHANNELS];
uae_u16* sndbufpt = sndbuffer[0];
uae_u16* render_sndbuff = sndbuffer[0];
uae_u16* finish_sndbuff = sndbuffer[0] + SNDBUFFER_LEN * DEFAULT_SOUND_CHANNELS;
#define SND_STATUSCNT 10
uae_u16 cdaudio_buffer[CDAUDIO_BUFFERS][(CDAUDIO_BUFFER_LEN + 32) * DEFAULT_SOUND_CHANNELS];
uae_u16* cdbufpt = cdaudio_buffer[0];
uae_u16* render_cdbuff = cdaudio_buffer[0];
uae_u16* finish_cdbuff = cdaudio_buffer[0] + CDAUDIO_BUFFER_LEN * DEFAULT_SOUND_CHANNELS;
bool cdaudio_active = false;
static int cdwrcnt = 0;
static int cdrdcnt = 0;
#define ADJUST_SIZE 20
#define EXP 1.9
#define ADJUST_VSSIZE 12
#define EXPVS 1.6
static int have_sound = 0;
static int statuscnt;
void update_sound(double clk)
#define SND_MAX_BUFFER2 524288
#define SND_MAX_BUFFER 65536
//uae_u16 paula_sndbuffer[SND_MAX_BUFFER];
uae_u16 paula_sndbuffer[SND_MAX_BUFFER];
uae_u16* paula_sndbufpt;
int paula_sndbufsize;
SDL_AudioSpec want, have;
SDL_AudioDeviceID dev;
void sdl2_audio_callback(void* userdata, Uint8* stream, int len);
struct sound_device* sound_devices[MAX_SOUND_DEVICES];
struct sound_device* record_devices[MAX_SOUND_DEVICES];
static struct sound_data sdpaula;
static struct sound_data* sdp = &sdpaula;
static uae_u8* extrasndbuf;
static int extrasndbufsize;
static int extrasndbuffered;
int setup_sound(void)
{
const auto evtime = clk * CYCLE_UNIT / double(currprefs.sound_freq);
scaled_sample_evtime = evtime;
}
static int s_oldrate = 0, s_oldbits = 0, s_oldstereo = 0;
static int sound_thread_active = 0, sound_thread_exit = 0;
static int rdcnt = 0;
static int wrcnt = 0;
static void sound_copy_produced_block(void* ud, Uint8* stream, int len)
{
if (currprefs.sound_stereo)
{
if (cdaudio_active && currprefs.sound_freq == 44100 && cdrdcnt < cdwrcnt)
{
for (auto i = 0; i < SNDBUFFER_LEN * 2; ++i)
sndbuffer[rdcnt & SOUND_BUFFERS_COUNT - 1][i] += cdaudio_buffer[cdrdcnt & CDAUDIO_BUFFERS - 1][i];
cdrdcnt++;
}
memcpy(stream, sndbuffer[rdcnt & SOUND_BUFFERS_COUNT - 1], len);
}
else
memcpy(stream, sndbuffer[rdcnt & SOUND_BUFFERS_COUNT - 1], len);
if (wrcnt - rdcnt >= SOUND_BUFFERS_COUNT / 2)
{
rdcnt++;
}
}
static void sound_thread_mixer(void* ud, Uint8* stream, int len)
{
if (sound_thread_exit)
return;
sound_thread_active = 1;
const auto sample_size = currprefs.sound_stereo ? 4 : 2;
while (len > 0)
{
int l = len < SNDBUFFER_LEN * sample_size ? len : SNDBUFFER_LEN * sample_size;
sound_copy_produced_block(ud, stream, l);
stream += l;
len -= l;
}
}
static void init_soundbuffer_usage()
{
sndbufpt = sndbuffer[0];
render_sndbuff = sndbuffer[0];
finish_sndbuff = sndbuffer[0] + SNDBUFFER_LEN * 2;
rdcnt = 0;
wrcnt = 0;
cdbufpt = cdaudio_buffer[0];
render_cdbuff = cdaudio_buffer[0];
finish_cdbuff = cdaudio_buffer[0] + CDAUDIO_BUFFER_LEN * 2;
cdrdcnt = 0;
cdwrcnt = 0;
}
static int start_sound(int rate, int bits, int stereo)
{
int frag = 0, buffers, ret;
unsigned int bsize;
if (SDL_GetAudioStatus() == SDL_AUDIO_STOPPED)
{
init_soundbuffer_usage();
s_oldrate = 0;
s_oldbits = 0;
s_oldstereo = 0;
sound_thread_exit = 0;
}
// if no settings change, we don't need to do anything
if (rate == s_oldrate && s_oldbits == bits && s_oldstereo == stereo)
return 0;
SDL_AudioSpec as;
memset(&as, 0, sizeof(as));
as.freq = rate;
as.format = (bits == 8 ? AUDIO_S8 : AUDIO_S16);
as.channels = (stereo ? 2 : 1);
as.samples = SOUND_CONSUMER_BUFFER_LENGTH;
as.callback = sound_thread_mixer;
if (SDL_OpenAudio(&as, nullptr))
write_log("Error when opening SDL audio !\n");
s_oldrate = rate;
s_oldbits = bits;
s_oldstereo = stereo;
clear_sound_buffers();
clear_cdaudio_buffers();
SDL_PauseAudio(0);
return 0;
}
void stop_sound()
{
if (sound_thread_exit == 0)
{
SDL_PauseAudio(1);
sound_thread_exit = 1;
SDL_CloseAudio();
}
}
void finish_sound_buffer()
{
wrcnt++;
sndbufpt = render_sndbuff = sndbuffer[wrcnt & SOUND_BUFFERS_COUNT - 1];
if (currprefs.sound_stereo)
finish_sndbuff = sndbufpt + SNDBUFFER_LEN * 2;
else
finish_sndbuff = sndbufpt + SNDBUFFER_LEN;
while ((wrcnt & SOUND_BUFFERS_COUNT - 1) == (rdcnt & SOUND_BUFFERS_COUNT - 1))
{
usleep(500);
}
}
void pause_sound_buffer()
{
reset_sound();
}
void restart_sound_buffer()
{
sndbufpt = render_sndbuff = sndbuffer[wrcnt & (SOUND_BUFFERS_COUNT - 1)];
if (currprefs.sound_stereo)
finish_sndbuff = sndbufpt + SNDBUFFER_LEN * 2;
else
finish_sndbuff = sndbufpt + SNDBUFFER_LEN;
cdbufpt = render_cdbuff = cdaudio_buffer[cdwrcnt & (CDAUDIO_BUFFERS - 1)];
finish_cdbuff = cdbufpt + CDAUDIO_BUFFER_LEN * 2;
}
void finish_cdaudio_buffer()
{
cdwrcnt++;
cdbufpt = render_cdbuff = cdaudio_buffer[cdwrcnt & (CDAUDIO_BUFFERS - 1)];
finish_cdbuff = cdbufpt + CDAUDIO_BUFFER_LEN * 2;
audio_activate();
}
bool cdaudio_catchup()
{
while (cdwrcnt > cdrdcnt + CDAUDIO_BUFFERS - 10 && sound_thread_active != 0 && quit_program == 0)
{
sleep_millis(10);
}
return sound_thread_active != 0;
}
/* Try to determine whether sound is available. This is only for GUI purposes. */
int setup_sound()
{
if (start_sound(currprefs.sound_freq, 16, currprefs.sound_stereo) != 0)
return 0;
sound_available = 1;
return 1;
}
float sound_sync_multiplier = 1.0;
float scaled_sample_evtime_orig;
// Originally from sampler.cpp
float sampler_evtime;
void update_sound(double clk)
{
if (!have_sound)
return;
scaled_sample_evtime_orig = clk * CYCLE_UNIT * sound_sync_multiplier / sdp->obtainedfreq;
scaled_sample_evtime = scaled_sample_evtime_orig;
sampler_evtime = clk * CYCLE_UNIT * sound_sync_multiplier;
}
extern int vsynctimebase_orig;
#define ADJUST_LIMIT 6
#define ADJUST_LIMIT2 1
void sound_setadjust(double v)
{
float mult;
if (v < -ADJUST_LIMIT)
v = -ADJUST_LIMIT;
if (v > ADJUST_LIMIT)
v = ADJUST_LIMIT;
mult = 1000.0 + v;
if (isvsync_chipset()) {
vsynctimebase = vsynctimebase_orig;
scaled_sample_evtime = scaled_sample_evtime_orig * mult / 1000.0;
}
else if (currprefs.cachesize || currprefs.m68k_speed != 0) {
vsynctimebase = (int)(((double)vsynctimebase_orig) * mult / 1000.0);
scaled_sample_evtime = scaled_sample_evtime_orig;
}
else {
vsynctimebase = (int)(((double)vsynctimebase_orig) * mult / 1000.0);
scaled_sample_evtime = scaled_sample_evtime_orig;
}
}
static void docorrection(struct sound_dp* s, int sndbuf, double sync, int granulaty)
{
static int tfprev;
s->avg_correct += sync;
s->cnt_correct++;
if (granulaty < 10)
granulaty = 10;
if (tfprev != timeframes) {
double skipmode, avgskipmode;
double avg = s->avg_correct / s->cnt_correct;
skipmode = sync / 100.0;
avgskipmode = avg / (10000.0 / granulaty);
gui_data.sndbuf = sndbuf;
if (skipmode > ADJUST_LIMIT2)
skipmode = ADJUST_LIMIT2;
if (skipmode < -ADJUST_LIMIT2)
skipmode = -ADJUST_LIMIT2;
sound_setadjust(skipmode + avgskipmode);
tfprev = timeframes;
}
}
static double sync_sound(double m)
{
double skipmode;
if (isvsync()) {
skipmode = pow(m < 0 ? -m : m, EXPVS) / 2;
if (m < 0)
skipmode = -skipmode;
if (skipmode < -ADJUST_VSSIZE)
skipmode = -ADJUST_VSSIZE;
if (skipmode > ADJUST_VSSIZE)
skipmode = ADJUST_VSSIZE;
}
else if (1) {
skipmode = pow(m < 0 ? -m : m, EXP) / 2;
if (m < 0)
skipmode = -skipmode;
if (skipmode < -ADJUST_SIZE)
skipmode = -ADJUST_SIZE;
if (skipmode > ADJUST_SIZE)
skipmode = ADJUST_SIZE;
}
return skipmode;
}
static void clearbuffer_sdl2(struct sound_data *sd)
{
SDL_LockAudioDevice(dev);
SDL_memset(paula_sndbuffer, 0, sizeof paula_sndbuffer);
SDL_UnlockAudioDevice(dev);
}
static void clearbuffer(struct sound_data* sd)
{
struct sound_dp* s = sd->data;
clearbuffer_sdl2(sd);
if (s->pullbuffer) {
memset(s->pullbuffer, 0, s->pullbuffermaxlen);
}
}
static void set_reset(struct sound_data* sd)
{
sd->reset = true;
sd->resetcnt = 10;
sd->resetframecnt = 0;
}
static void pause_audio_sdl2(struct sound_data* sd)
{
sd->waiting_for_buffer = 0;
SDL_PauseAudioDevice(dev, 1);
clearbuffer(sd);
}
static void resume_audio_sdl2(struct sound_data* sd)
{
struct sound_dp* s = sd->data;
sd->paused = 0;
clearbuffer(sd);
sd->waiting_for_buffer = 1;
s->avg_correct = 0;
s->cnt_correct = 0;
SDL_PauseAudioDevice(dev, 0);
}
static void close_audio_sdl2(struct sound_data* sd)
{
struct sound_dp* s = sd->data;
SDL_PauseAudioDevice(dev, 1);
// shut everything down
SDL_CloseAudioDevice(dev);
xfree(s->pullbuffer);
s->pullbuffer = NULL;
s->pullbufferlen = 0;
}
void set_volume_sound_device(struct sound_data* sd, int volume, int mute)
{
//todo
}
void set_volume(int volume, int mute)
{
set_volume_sound_device(sdp, volume, mute);
//setvolume_ahi(volume);
config_changed = 1;
}
static void finish_sound_buffer_pull(struct sound_data* sd, uae_u16* sndbuffer)
{
struct sound_dp* s = sd->data;
if (s->pullbufferlen + sd->sndbufsize > s->pullbuffermaxlen) {
write_log(_T("pull overflow! %d %d %d\n"), s->pullbufferlen, sd->sndbufsize, s->pullbuffermaxlen);
s->pullbufferlen = 0;
}
memcpy(s->pullbuffer + s->pullbufferlen, sndbuffer, sd->sndbufsize);
s->pullbufferlen += sd->sndbufsize;
}
static int open_audio_sdl2(struct sound_data* sd, int index)
{
struct sound_dp* s = sd->data;
int freq = sd->freq;
int ch = sd->channels;
int size;
sd->devicetype = SOUND_DEVICE_SDL2;
if (sd->sndbufsize < 0x80)
sd->sndbufsize = 0x80;
s->framesperbuffer = sd->sndbufsize;
s->sndbufsize = s->framesperbuffer;
sd->sndbufsize = s->sndbufsize * ch * 2;
if (sd->sndbufsize > SND_MAX_BUFFER)
sd->sndbufsize = SND_MAX_BUFFER;
SDL_memset(&want, 0, sizeof want);
want.freq = freq;
want.format = AUDIO_S16;
want.channels = ch;
want.samples = s->framesperbuffer;
want.callback = sdl2_audio_callback;
want.userdata = sd;
sd->samplesize = ch * 16 / 8;
s->pullmode = 1;
dev = SDL_OpenAudioDevice(nullptr, 0, &want, &have, 0);
if (dev == 0)
SDL_Log("Failed to open audio: %s", SDL_GetError());
s->pullbuffermaxlen = sd->sndbufsize * 2;
s->pullbuffer = xcalloc(uae_u8, s->pullbuffermaxlen);
s->pullbufferlen = 0;
clear_sound_buffers();
SDL_PauseAudioDevice(dev, 0);
return 1;
}
int open_sound_device(struct sound_data* sd, int index, int bufsize, int freq, int channels)
{
int ret = 0;
struct sound_dp* sdp = xcalloc(struct sound_dp, 1);
sd->data = sdp;
sd->sndbufsize = bufsize;
sd->freq = freq;
sd->channels = channels;
sd->paused = 1;
sd->index = index;
ret = open_audio_sdl2(sd, index);
sd->samplesize = sd->channels * 2;
sd->sndbufframes = sd->sndbufsize / sd->samplesize;
return ret;
}
void close_sound_device(struct sound_data* sd)
{
pause_sound_device(sd);
close_audio_sdl2(sd);
xfree(sd->data);
sd->data = NULL;
sd->index = -1;
}
void pause_sound_device(struct sound_data* sd)
{
struct sound_dp* s = sd->data;
sd->paused = 1;
gui_data.sndbuf_status = 0;
gui_data.sndbuf = 0;
pause_audio_sdl2(sd);
}
void resume_sound_device(struct sound_data* sd)
{
struct sound_dp* s = sd->data;
resume_audio_sdl2(sd);
sd->paused = 0;
}
static int open_sound()
{
config_changed = 1;
if (start_sound(currprefs.sound_freq, 16, currprefs.sound_stereo) != 0)
int ret = 0, ch;
int size = currprefs.sound_maxbsiz;
if (!currprefs.produce_sound) {
return 0;
}
config_changed = 1;
/* Always interpret buffer size as number of samples, not as actual
buffer size. Of course, since 8192 is the default, we'll have to
scale that to a sane value (assuming that otherwise 16 bits and
stereo would have been enabled and we'd have done the shift by
two anyway). */
size >>= 2;
size &= ~63;
sdp->softvolume = -1;
ch = get_audio_nativechannels(currprefs.sound_stereo);
ret = open_sound_device(sdp, 0, size, currprefs.sound_freq, ch);
if (!ret)
return 0;
currprefs.sound_freq = changed_prefs.sound_freq = sdp->freq;
if (ch != sdp->channels)
currprefs.sound_stereo = changed_prefs.sound_stereo = get_audio_stereomode(sdp->channels);
set_volume(currprefs.sound_volume_master, sdp->mute);
if (get_audio_amigachannels(currprefs.sound_stereo) == 4)
sample_handler = sample16ss_handler;
else
sample_handler = get_audio_ismono(currprefs.sound_stereo) ? sample16_handler : sample16s_handler;
sdp->obtainedfreq = currprefs.sound_freq;
have_sound = 1;
sound_available = 1;
gui_data.sndbuf_avail = true;
if (currprefs.sound_stereo)
sample_handler = sample16s_handler;
else
sample_handler = sample16_handler;
gui_data.sndbuf_avail = audio_is_pull() == 0;
paula_sndbufsize = sdp->sndbufsize;
paula_sndbufpt = paula_sndbuffer;
#ifdef DRIVESOUND
driveclick_init();
#endif
return 1;
}
@ -253,9 +393,42 @@ void close_sound()
if (!have_sound)
return;
stop_sound();
close_sound_device(sdp);
have_sound = 0;
extrasndbufsize = 0;
extrasndbuffered = 0;
xfree(extrasndbuf);
extrasndbuf = NULL;
}
bool sound_paused(void)
{
return sdp->paused != 0;
}
void pause_sound()
{
if (sdp->paused)
return;
if (!have_sound)
return;
pause_sound_device(sdp);
}
void resume_sound()
{
if (!sdp->paused)
return;
if (!have_sound)
return;
resume_sound_device(sdp);
}
void reset_sound()
{
if (!have_sound)
return;
clearbuffer(sdp);
}
int init_sound()
@ -263,33 +436,304 @@ int init_sound()
gui_data.sndbuf_status = 3;
gui_data.sndbuf = 0;
gui_data.sndbuf_avail = false;
have_sound = open_sound();
return have_sound;
if (!sound_available)
return 0;
if (currprefs.produce_sound <= 1)
return 0;
if (have_sound)
return 1;
if (!open_sound())
return 0;
sdp->paused = 1;
#ifdef DRIVESOUND
driveclick_reset();
#endif
reset_sound();
resume_sound();
return 1;
}
void pause_sound()
static void disable_sound(void)
{
SDL_PauseAudio(1);
close_sound();
currprefs.produce_sound = changed_prefs.produce_sound = 1;
}
void resume_sound()
static int reopen_sound(void)
{
SDL_PauseAudio(0);
bool paused = sdp->paused != 0;
close_sound();
int v = open_sound();
if (v && !paused)
resume_sound_device(sdp);
return v;
}
void reset_sound()
void pause_sound_buffer(void)
{
sdp->deactive = true;
reset_sound();
}
void restart_sound_buffer(void)
{
sdp->deactive = false;
//restart_sound_buffer2(sdp);
}
static void channelswap(uae_s16* sndbuffer, int len)
{
for (int i = 0; i < len; i += 2) {
uae_s16 t;
t = sndbuffer[i];
sndbuffer[i] = sndbuffer[i + 1];
sndbuffer[i + 1] = t;
}
}
static void channelswap6(uae_s16* sndbuffer, int len)
{
for (int i = 0; i < len; i += 6) {
uae_s16 t;
t = sndbuffer[i + 0];
sndbuffer[i + 0] = sndbuffer[i + 1];
sndbuffer[i + 1] = t;
t = sndbuffer[i + 4];
sndbuffer[i + 4] = sndbuffer[i + 5];
sndbuffer[i + 5] = t;
}
}
static void send_sound(struct sound_data* sd, uae_u16* sndbuffer)
{
if (savestate_state)
return;
if (sd->paused)
return;
if (sd->softvolume >= 0) {
uae_s16* p = (uae_s16*)sndbuffer;
for (int i = 0; i < sd->sndbufsize / 2; i++) {
p[i] = p[i] * sd->softvolume / 32768;
}
}
finish_sound_buffer_pull(sd, sndbuffer);
}
bool audio_is_event_frame_possible(int)
{
return false;
}
int audio_is_pull(void)
{
if (sdp->reset)
return 0;
struct sound_dp* s = sdp->data;
if (s && s->pullmode) {
return sdp->paused || sdp->deactive ? -1 : 1;
}
return 0;
}
int audio_pull_buffer(void)
{
int cnt = 0;
if (sdp->paused || sdp->deactive || sdp->reset)
return 0;
struct sound_dp* s = sdp->data;
if (s->pullbufferlen > 0) {
cnt++;
int size = (uae_u8*)paula_sndbufpt - (uae_u8*)paula_sndbuffer;
if (size > sdp->sndbufsize * 2 / 3)
cnt++;
}
return cnt;
}
bool audio_is_pull_event(void)
{
return false;
}
bool audio_finish_pull(void)
{
return false;
}
static void handle_reset(void)
{
if (sdp->resetframe == timeframes)
return;
sdp->resetframe = timeframes;
sdp->resetframecnt--;
if (sdp->resetframecnt > 0)
return;
sdp->resetframecnt = 20;
sdp->reset = false;
if (!reopen_sound() || sdp->reset) {
if (sdp->resetcnt <= 0) {
write_log(_T("Reopen sound failed. Retrying with default device.\n"));
close_sound();
//int type = sound_devices[currprefs.win32_soundcard]->type;
//int max = enumerate_sound_devices();
//for (int i = 0; i < max; i++) {
// if (sound_devices[i]->alname == NULL && sound_devices[i]->type == type) {
// currprefs.win32_soundcard = changed_prefs.win32_soundcard = i;
// if (open_sound())
// return;
// break;
// }
//}
currprefs.produce_sound = changed_prefs.produce_sound = 1;
}
else {
write_log(_T("Retrying sound.. %d..\n"), sdp->resetcnt);
sdp->resetcnt--;
sdp->reset = true;
}
}
else {
resume_sound_device(sdp);
}
}
void finish_sound_buffer()
{
static unsigned long tframe;
int bufsize = (uae_u8*)paula_sndbufpt - (uae_u8*)paula_sndbuffer;
if (sdp->reset) {
handle_reset();
paula_sndbufpt = paula_sndbuffer;
return;
}
if (currprefs.turbo_emulation) {
paula_sndbufpt = paula_sndbuffer;
return;
}
if (currprefs.sound_stereo_swap_paula) {
if (get_audio_nativechannels(currprefs.sound_stereo) == 2 || get_audio_nativechannels(currprefs.sound_stereo) == 4)
channelswap((uae_s16*)paula_sndbuffer, bufsize / 2);
else if (get_audio_nativechannels(currprefs.sound_stereo) == 6)
channelswap6((uae_s16*)paula_sndbuffer, bufsize / 2);
}
#ifdef DRIVESOUND
driveclick_mix((uae_s16*)paula_sndbuffer, bufsize / 2, currprefs.dfxclickchannelmask);
#endif
// must be after driveclick_mix
paula_sndbufpt = paula_sndbuffer;
if (!have_sound)
return;
init_soundbuffer_usage();
// we got buffer that was not full (recording active). Need special handling.
if (bufsize < sdp->sndbufsize && !extrasndbuf) {
extrasndbufsize = sdp->sndbufsize;
extrasndbuf = xcalloc(uae_u8, sdp->sndbufsize);
extrasndbuffered = 0;
}
clear_sound_buffers();
clear_cdaudio_buffers();
if (statuscnt > 0 && tframe != timeframes) {
tframe = timeframes;
statuscnt--;
if (statuscnt == 0)
gui_data.sndbuf_status = 0;
}
if (gui_data.sndbuf_status == 3)
gui_data.sndbuf_status = 0;
if (extrasndbuf) {
int size = extrasndbuffered + bufsize;
int copied = 0;
if (size > extrasndbufsize) {
copied = extrasndbufsize - extrasndbuffered;
memcpy(extrasndbuf + extrasndbuffered, paula_sndbuffer, copied);
send_sound(sdp, (uae_u16*)extrasndbuf);
extrasndbuffered = 0;
}
memcpy(extrasndbuf + extrasndbuffered, (uae_u8*)paula_sndbuffer + copied, bufsize - copied);
extrasndbuffered += bufsize - copied;
}
else {
send_sound(sdp, paula_sndbuffer);
}
}
static int set_master_volume(int volume, int mute)
{
//todo set volume using SDL2
}
static int get_master_volume(int* volume, int* mute)
{
//todo get volume using SDL2
}
void sound_mute(int newmute)
{
if (newmute < 0)
sdp->mute = sdp->mute ? 0 : 1;
else
sdp->mute = newmute;
set_volume(currprefs.sound_volume_master, sdp->mute);
config_changed = 1;
}
void sound_volume(int dir)
{
currprefs.sound_volume_master -= dir * 10;
currprefs.sound_volume_cd -= dir * 10;
if (currprefs.sound_volume_master < 0)
currprefs.sound_volume_master = 0;
if (currprefs.sound_volume_master > 100)
currprefs.sound_volume_master = 100;
changed_prefs.sound_volume_master = currprefs.sound_volume_master;
if (currprefs.sound_volume_cd < 0)
currprefs.sound_volume_cd = 0;
if (currprefs.sound_volume_cd > 100)
currprefs.sound_volume_cd = 100;
changed_prefs.sound_volume_cd = currprefs.sound_volume_cd;
set_volume(currprefs.sound_volume_master, sdp->mute);
config_changed = 1;
}
void master_sound_volume(int dir)
{
int vol, mute, r;
r = get_master_volume(&vol, &mute);
if (!r)
return;
if (dir == 0)
mute = mute ? 0 : 1;
vol += dir * (65536 / 10);
if (vol < 0)
vol = 0;
if (vol > 65535)
vol = 65535;
set_master_volume(vol, mute);
config_changed = 1;
}
// Audio callback function
void sdl2_audio_callback(void* userdata, Uint8* stream, int len)
{
struct sound_data* sd = (struct sound_data*)userdata;
struct sound_dp* s = sd->data;
int bytestocopy;
if (s->pullbufferlen <= 0)
return;
bytestocopy = s->framesperbuffer * sd->samplesize;
if (bytestocopy > 0) {
memcpy(stream, s->pullbuffer, bytestocopy);
}
if (bytestocopy < s->pullbufferlen) {
memmove(s->pullbuffer, s->pullbuffer + bytestocopy, s->pullbufferlen - bytestocopy);
}
s->pullbufferlen -= bytestocopy;
}

View file

@ -7,43 +7,136 @@
*/
#pragma once
#define DEFAULT_SOUND_CHANNELS 2
#include "audio.h"
#define SOUNDSTUFF 1
#define SOUND_BUFFERS_COUNT 4
#define SNDBUFFER_LEN 1024
extern uae_u16 sndbuffer[SOUND_BUFFERS_COUNT][(SNDBUFFER_LEN + 32) * DEFAULT_SOUND_CHANNELS];
extern uae_u16* sndbufpt;
extern uae_u16* render_sndbuff;
extern uae_u16* finish_sndbuff;
extern int sndbufsize;
extern uae_u16 paula_sndbuffer[];
extern uae_u16* paula_sndbufpt;
extern int paula_sndbufsize;
extern void finish_sound_buffer(void);
extern void restart_sound_buffer(void);
extern void pause_sound_buffer(void);
extern void finish_cdaudio_buffer(void);
extern bool cdaudio_catchup(void);
extern int init_sound(void);
extern void close_sound(void);
extern int setup_sound(void);
extern void resume_sound(void);
extern void pause_sound(void);
extern void reset_sound(void);
extern void sound_volume(int);
extern void stop_sound(void);
extern bool sound_paused(void);
extern void sound_setadjust(double);
#define check_sound_buffers() { if (sndbufpt >= finish_sndbuff) finish_sound_buffer (); }
extern int drivesound_init(void);
extern void drivesound_free(void);
extern void sound_mute(int);
extern void sound_volume(int);
extern void set_volume(int, int);
extern void master_sound_volume(int);
struct sound_dp;
struct sound_data
{
int waiting_for_buffer;
int deactive;
int devicetype;
int obtainedfreq;
int paused;
int mute;
int channels;
int freq;
int samplesize;
int sndbufsize;
int sndbufframes;
int softvolume;
struct sound_dp* data;
int index;
bool reset;
int resetcnt;
int resetframe;
int resetframecnt;
};
int open_sound_device(struct sound_data* sd, int index, int exclusive, int bufsize, int freq, int channels);
void close_sound_device(struct sound_data* sd);
void pause_sound_device(struct sound_data* sd);
void resume_sound_device(struct sound_data* sd);
void set_volume_sound_device(struct sound_data* sd, int volume, int mute);
static uae_u16* paula_sndbufpt_prev, * paula_sndbufpt_start;
STATIC_INLINE void set_sound_buffers(void)
{
#if SOUNDSTUFF > 1
paula_sndbufpt_prev = paula_sndbufpt_start;
paula_sndbufpt_start = paula_sndbufpt;
#endif
}
STATIC_INLINE void check_sound_buffers()
{
#if SOUNDSTUFF > 1
int len;
#endif
if (currprefs.sound_stereo == SND_4CH_CLONEDSTEREO) {
((uae_u16*)paula_sndbufpt)[0] = ((uae_u16*)paula_sndbufpt)[-2];
((uae_u16*)paula_sndbufpt)[1] = ((uae_u16*)paula_sndbufpt)[-1];
paula_sndbufpt = (uae_u16*)(((uae_u8*)paula_sndbufpt) + 2 * 2);
}
else if (currprefs.sound_stereo == SND_6CH_CLONEDSTEREO) {
uae_s16* p = ((uae_s16*)paula_sndbufpt);
uae_s32 sum;
p[2] = p[-2];
p[3] = p[-1];
sum = (uae_s32)(p[-2]) + (uae_s32)(p[-1]) + (uae_s32)(p[2]) + (uae_s32)(p[3]);
p[0] = sum / 8;
p[1] = sum / 8;
paula_sndbufpt = (uae_u16*)(((uae_u8*)paula_sndbufpt) + 4 * 2);
}
#if SOUNDSTUFF > 1
if (outputsample == 0)
return;
len = paula_sndbufpt - paula_sndbufpt_start;
if (outputsample < 0) {
int i;
uae_s16* p1 = (uae_s16*)paula_sndbufpt_prev;
uae_s16* p2 = (uae_s16*)paula_sndbufpt_start;
for (i = 0; i < len; i++) {
*p1 = (*p1 + *p2) / 2;
}
paula_sndbufpt = paula_sndbufpt_start;
}
#endif
if ((uae_u8*)paula_sndbufpt - (uae_u8*)paula_sndbuffer >= paula_sndbufsize) {
finish_sound_buffer();
paula_sndbufpt = paula_sndbuffer;
}
#if SOUNDSTUFF > 1
while (doublesample-- > 0) {
memcpy(paula_sndbufpt, paula_sndbufpt_start, len * 2);
paula_sndbufpt += len;
if ((uae_u8*)paula_sndbufpt - (uae_u8*)paula_sndbuffer >= paula_sndbufsize) {
finish_sound_buffer();
paula_sndbufpt = paula_sndbuffer;
}
}
#endif
}
STATIC_INLINE void clear_sound_buffers(void)
{
memset(sndbuffer, 0, sizeof(sndbuffer));
memset(paula_sndbuffer, 0, paula_sndbufsize);
paula_sndbufpt = paula_sndbuffer;
}
#define PUT_SOUND_WORD(b) do { *sndbufpt = b; sndbufpt = sndbufpt + 1; } while (0)
#define PUT_SOUND_WORD_STEREO(l,r) do { *((uae_u32 *)sndbufpt) = (r << 16) | (l & 0xffff); sndbufpt = sndbufpt + 2; } while (0)
#define DEFAULT_SOUND_BITS 16
#define DEFAULT_SOUND_FREQ 44100
#define HAVE_STEREO_SUPPORT
#define PUT_SOUND_WORD(b) do { *(uae_u16 *)paula_sndbufpt = b; paula_sndbufpt = (uae_u16 *)(((uae_u8 *)paula_sndbufpt) + 2); } while (0)
#define PUT_SOUND_WORD_MONO(b) PUT_SOUND_WORD(b)
#define SOUND16_BASE_VAL 0
#define SOUND8_BASE_VAL 128
#define DEFAULT_SOUND_MAXB 16384
#define DEFAULT_SOUND_MINB 16384
@ -56,22 +149,4 @@ STATIC_INLINE void clear_sound_buffers(void)
#define FILTER_SOUND_ON 2
#define FILTER_SOUND_TYPE_A500 0
#define FILTER_SOUND_TYPE_A1200 1
#define CDAUDIO_BUFFERS 16
#define CDAUDIO_BUFFER_LEN 1024
extern uae_u16 cdaudio_buffer[CDAUDIO_BUFFERS][(CDAUDIO_BUFFER_LEN + 32) * DEFAULT_SOUND_CHANNELS];
extern uae_u16* cdbufpt;
extern uae_u16* render_cdbuff;
extern uae_u16* finish_cdbuff;
extern bool cdaudio_active;
#define check_cdaudio_buffers() { if (cdbufpt >= finish_cdbuff) finish_cdaudio_buffer (); }
STATIC_INLINE void clear_cdaudio_buffers(void)
{
memset(cdaudio_buffer, 0, sizeof(cdaudio_buffer));
}
#define PUT_CDAUDIO_WORD_STEREO(l,r) do { *((uae_u32 *)cdbufpt) = (r << 16) | (l & 0xffff); cdbufpt = cdbufpt + 2; } while (0)
#define FILTER_SOUND_TYPE_A1200 1