mirror of
https://github.com/Oibaf66/uae-wii.git
synced 2024-11-25 12:06:55 +01:00
425 lines
11 KiB
C
425 lines
11 KiB
C
/*
|
|
* 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 "driveclick.h"
|
|
#include "sounddep/sound.h"
|
|
#include "zfile.h"
|
|
#include "events.h"
|
|
|
|
|
|
#include "fsdb.h"
|
|
|
|
#include "resource/drive_click.c"
|
|
#include "resource/drive_snatch.c"
|
|
#include "resource/drive_spin.c"
|
|
#include "resource/drive_startup.c"
|
|
|
|
|
|
|
|
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;
|
|
#define DS_SHIFT 10
|
|
static int sample_step;
|
|
|
|
static uae_s16 *clickbuffer;
|
|
|
|
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 (len);
|
|
#ifdef WORDS_BIGENDIAN
|
|
{
|
|
int i;
|
|
uae_u8* d = (uae_u8*) dst;
|
|
for (i = 0; i < len; i+= 2) {
|
|
d[i] = s[i + 5];
|
|
d[i+1] = s[i + 4];
|
|
}
|
|
}
|
|
#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 (const char *path, struct drvsample *ds)
|
|
{
|
|
struct zfile *f;
|
|
uae_u8 *buf;
|
|
int size;
|
|
int i;
|
|
|
|
f = zfile_fopen (path, "rb");
|
|
if (!f) {
|
|
write_log ("driveclick: can't open '%s'\n", path);
|
|
return 0;
|
|
}
|
|
// write_log("driveclick: loading '%s'\n", path);
|
|
zfile_fseek (f, 0, SEEK_END);
|
|
size = zfile_ftell (f);
|
|
buf = malloc (size);
|
|
zfile_fseek (f, 0, SEEK_SET);
|
|
zfile_fread (buf, size, 1, f);
|
|
zfile_fclose (f);
|
|
|
|
/*
|
|
printf("size=%i \n", size);
|
|
for (i = 0; i < size; i++) {
|
|
printf("0x%02x,", buf[i]);
|
|
if (i % 20 == 19) {
|
|
printf("\n");
|
|
}
|
|
}
|
|
printf("\n");
|
|
flush(NULL);
|
|
}
|
|
*/
|
|
|
|
ds->len = size;
|
|
ds->p = decodewav (buf, &ds->len);
|
|
|
|
free (buf);
|
|
return 1;
|
|
}
|
|
|
|
//The same function as load sample, but the wav data is already in memory.
|
|
//No read, just decode.
|
|
static int loadsample_resource(int resId, struct drvsample *ds) {
|
|
uae_u8* buf = NULL;
|
|
int size;
|
|
switch (resId) {
|
|
case DS_CLICK: {
|
|
buf = res_drive_click;
|
|
size = res_drive_click_size;
|
|
} break;
|
|
case DS_SPIN :
|
|
case DS_SPINND: {
|
|
buf = res_drive_spin;
|
|
size = res_drive_spin_size;
|
|
} break;
|
|
case DS_START: {
|
|
buf = res_drive_startup;
|
|
size = res_drive_startup_size;
|
|
} break;
|
|
case DS_SNATCH: {
|
|
buf = res_drive_snatch;
|
|
size = res_drive_snatch_size;
|
|
} break;
|
|
|
|
default: return 0;
|
|
} //end of switch
|
|
|
|
|
|
//write_log("loading click resource %i \n", resId);
|
|
ds->len = size;
|
|
ds->p = decodewav (buf, &ds->len);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
static void freesample (struct drvsample *s)
|
|
{
|
|
free (s->p);
|
|
s->p = 0;
|
|
}
|
|
|
|
extern char *start_path;
|
|
|
|
void driveclick_init (void)
|
|
{
|
|
int v, vv, i, j;
|
|
static char tmp_path[1024];
|
|
|
|
driveclick_free ();
|
|
vv = 0;
|
|
|
|
write_log("driveclick init...\n");
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (currprefs.dfxclick[i]) {
|
|
/* TODO: Implement location of sample data */
|
|
//load from resource
|
|
if (currprefs.dfxclick[i] > 0) { // > 0
|
|
v = loadsample_resource(DS_CLICK, &drvs[i][DS_CLICK]);
|
|
v += loadsample_resource(DS_SPIN, &drvs[i][DS_SPIN]);
|
|
v += loadsample_resource(DS_SPINND, &drvs[i][DS_SPINND]);
|
|
v += loadsample_resource(DS_SNATCH, &drvs[i][DS_SNATCH]);
|
|
v += loadsample_resource(DS_START, &drvs[i][DS_START]);
|
|
|
|
} else
|
|
//load from file
|
|
if (currprefs.dfxclick[i] == -1) {
|
|
#ifdef GEKKO //currprefs.dfxclickexternal[i] is the path to the wav directory (path contains trailing separator)
|
|
sprintf (tmp_path, "%sdrive_click.wav", currprefs.dfxclickexternal[i]);
|
|
v = loadsample (tmp_path, &drvs[i][DS_CLICK]);
|
|
sprintf (tmp_path, "%sdrive_spin.wav", currprefs.dfxclickexternal[i]);
|
|
v += loadsample (tmp_path, &drvs[i][DS_SPIN]);
|
|
sprintf (tmp_path, "%sdrive_spinnd.wav", currprefs.dfxclickexternal[i]);
|
|
v += loadsample (tmp_path, &drvs[i][DS_SPINND]);
|
|
sprintf (tmp_path, "%sdrive_startup.wav", currprefs.dfxclickexternal[i]);
|
|
v += loadsample (tmp_path, &drvs[i][DS_START]);
|
|
sprintf (tmp_path, "%sdrive_snatch.wav", currprefs.dfxclickexternal[i]);
|
|
v += loadsample (tmp_path, &drvs[i][DS_SNATCH]);
|
|
#else
|
|
char * start_path = "."; //TODO - ??? set correct path
|
|
sprintf (tmp_path, "%suae_data%cdrive_click_%s", start_path, FSDB_DIR_SEPARATOR, currprefs.dfxclickexternal[i]);
|
|
v = loadsample (tmp_path, &drvs[i][DS_CLICK]);
|
|
sprintf (tmp_path, "%suae_data%cdrive_spin_%s", start_path, FSDB_DIR_SEPARATOR, currprefs.dfxclickexternal[i]);
|
|
v += loadsample (tmp_path, &drvs[i][DS_SPIN]);
|
|
sprintf (tmp_path, "%suae_data%cdrive_spinnd_%s", start_path, FSDB_DIR_SEPARATOR, currprefs.dfxclickexternal[i]);
|
|
v += loadsample (tmp_path, &drvs[i][DS_SPINND]);
|
|
sprintf (tmp_path, "%suae_data%cdrive_startup_%s", start_path, FSDB_DIR_SEPARATOR, currprefs.dfxclickexternal[i]);
|
|
v += loadsample (tmp_path, &drvs[i][DS_START]);
|
|
sprintf (tmp_path, "%suae_data%cdrive_snatch_%s", start_path, FSDB_DIR_SEPARATOR, currprefs.dfxclickexternal[i]);
|
|
v += loadsample (tmp_path, &drvs[i][DS_SNATCH]);
|
|
#endif /* GEKKO */
|
|
}
|
|
if (v == 0) {
|
|
int j;
|
|
for (j = 0; j < DS_END; j++) {
|
|
freesample (&drvs[i][j]);
|
|
}
|
|
currprefs.dfxclick[i] = changed_prefs.dfxclick[i] = 0;
|
|
}
|
|
for (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;
|
|
vv += abs (currprefs.dfxclick[i]);
|
|
|
|
}
|
|
}
|
|
if (vv > 0) {
|
|
write_log("reset driveclick \n");
|
|
driveclick_reset ();
|
|
click_initialized = 1;
|
|
}
|
|
}
|
|
|
|
void driveclick_reset (void)
|
|
{
|
|
free (clickbuffer);
|
|
clickbuffer = xmalloc (sndbufsize);
|
|
sample_step = (freq << DS_SHIFT) / currprefs.sound_freq;
|
|
}
|
|
|
|
void driveclick_free (void)
|
|
{
|
|
int i, j;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
for (j = 0; j < DS_END; j++)
|
|
freesample (&drvs[i][j]);
|
|
}
|
|
memset (drvs, 0, sizeof (drvs));
|
|
free (clickbuffer);
|
|
clickbuffer = 0;
|
|
click_initialized = 0;
|
|
}
|
|
|
|
STATIC_INLINE uae_s16 getsample (void)
|
|
{
|
|
uae_s32 smp = 0;
|
|
int div = 0, i;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (currprefs.dfxclick[i]) {
|
|
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];
|
|
div += 2;
|
|
if (drv_spinning[i] || drv_starting[i]) {
|
|
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];
|
|
ds_click->pos += sample_step;
|
|
}
|
|
}
|
|
}
|
|
if (!div)
|
|
return 0;
|
|
return smp / div;
|
|
}
|
|
|
|
static int clickcnt;
|
|
|
|
static void mix (void)
|
|
{
|
|
int total = ((uae_u8*)sndbufpt - (uae_u8*)sndbuffer) / (currprefs.sound_stereo ? 4 : 2);
|
|
|
|
if (currprefs.dfxclickvolume > 0) {
|
|
while (clickcnt < total) {
|
|
clickbuffer[clickcnt++] = getsample() * (100 - currprefs.dfxclickvolume) / 100;
|
|
}
|
|
} else {
|
|
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 i;
|
|
|
|
if (!click_initialized)
|
|
return;
|
|
mix();
|
|
clickcnt = 0;
|
|
if (currprefs.sound_stereo) {
|
|
for (i = 0; i < size / 2; i++) {
|
|
uae_s16 s = clickbuffer[i];
|
|
sndbuffer[0] = limit(((sndbuffer[0] + s) * 2) / 3);
|
|
sndbuffer[1] = limit(((sndbuffer[1] + s) * 2) / 3);
|
|
sndbuffer += 2;
|
|
}
|
|
} else {
|
|
for (i = 0; i < size; i++) {
|
|
sndbuffer[0] = limit(((sndbuffer[0] + clickbuffer[i]) * 2) / 3);
|
|
sndbuffer++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void driveclick_click (int drive, int startOffset)
|
|
{
|
|
if (!click_initialized)
|
|
return;
|
|
if (!currprefs.dfxclick[drive])
|
|
return;
|
|
mix ();
|
|
drvs[drive][DS_CLICK].pos = (startOffset * 4) << DS_SHIFT;
|
|
if (drvs[drive][DS_CLICK].pos > drvs[drive][DS_CLICK].len / 2)
|
|
drvs[drive][DS_CLICK].pos = drvs[drive][DS_CLICK].len / 2;
|
|
}
|
|
|
|
void driveclick_motor (int drive, int running)
|
|
{
|
|
if (!click_initialized)
|
|
return;
|
|
if (!currprefs.dfxclick[drive])
|
|
return;
|
|
mix();
|
|
if (running == 0) {
|
|
drv_starting[drive] = 0;
|
|
drv_spinning[drive] = 0;
|
|
} else {
|
|
if (drv_spinning[drive] == 0) {
|
|
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 (!currprefs.dfxclick[drive])
|
|
return;
|
|
if (eject)
|
|
drv_has_spun[drive] = 0;
|
|
drv_has_disk[drive] = !eject;
|
|
}
|
|
|
|
void driveclick_check_prefs (void)
|
|
{
|
|
int i;
|
|
|
|
if (currprefs.dfxclickvolume != changed_prefs.dfxclickvolume ||
|
|
currprefs.dfxclick[0] != changed_prefs.dfxclick[0] ||
|
|
currprefs.dfxclick[1] != changed_prefs.dfxclick[1] ||
|
|
currprefs.dfxclick[2] != changed_prefs.dfxclick[2] ||
|
|
currprefs.dfxclick[3] != changed_prefs.dfxclick[3] ||
|
|
strcmp (currprefs.dfxclickexternal[0], changed_prefs.dfxclickexternal[0]) ||
|
|
strcmp (currprefs.dfxclickexternal[1], changed_prefs.dfxclickexternal[1]) ||
|
|
strcmp (currprefs.dfxclickexternal[2], changed_prefs.dfxclickexternal[2]) ||
|
|
strcmp (currprefs.dfxclickexternal[3], changed_prefs.dfxclickexternal[3]))
|
|
{
|
|
currprefs.dfxclickvolume = changed_prefs.dfxclickvolume;
|
|
for (i = 0; i < 4; i++) {
|
|
currprefs.dfxclick[i] = changed_prefs.dfxclick[i];
|
|
strcpy (currprefs.dfxclickexternal[i], changed_prefs.dfxclickexternal[i]);
|
|
}
|
|
driveclick_init ();
|
|
}
|
|
}
|
|
|
|
#endif
|