mirror of
https://github.com/holub/mame
synced 2025-05-18 11:39:29 +03:00

Sent: Thursday, December 11, 2008 6:52 PM To: submit@mamedev.org Cc: atariace@hotmail.com Subject: [patch] deprecat.h cpu cleanup Hi mamedev, This patch purges the last few uses of deprecat.h from the cpu cores, plus a handful of other Machine cases elsewhere that were found by script inspection. ~aa -- Hi mamedev, This patch eliminates most uses of deprecat.h in the sound cores by attaching the device to the state object and using it where appropriate. Given that all the cpu objects use this convention, and three sound cores already do this, this seemed an appropriate approach. ~aa
615 lines
15 KiB
C
615 lines
15 KiB
C
#include "driver.h"
|
|
#include "streams.h"
|
|
#include "samples.h"
|
|
|
|
|
|
struct sample_channel
|
|
{
|
|
sound_stream *stream;
|
|
const INT16 *source;
|
|
INT32 source_length;
|
|
INT32 source_num;
|
|
UINT32 pos;
|
|
UINT32 frac;
|
|
UINT32 step;
|
|
UINT32 basefreq;
|
|
UINT8 loop;
|
|
UINT8 paused;
|
|
};
|
|
|
|
struct samples_info
|
|
{
|
|
const device_config *device;
|
|
int numchannels; /* how many channels */
|
|
struct sample_channel *channel;/* array of channels */
|
|
struct loaded_samples *samples;/* array of samples */
|
|
};
|
|
|
|
|
|
|
|
#define FRAC_BITS 24
|
|
#define FRAC_ONE (1 << FRAC_BITS)
|
|
#define FRAC_MASK (FRAC_ONE - 1)
|
|
#define MAX_CHANNELS 100
|
|
|
|
|
|
/*-------------------------------------------------
|
|
read_wav_sample - read a WAV file as a sample
|
|
-------------------------------------------------*/
|
|
|
|
#ifdef LSB_FIRST
|
|
#define intelLong(x) (x)
|
|
#else
|
|
#define intelLong(x) (((x << 24) | (((unsigned long) x) >> 24) | (( x & 0x0000ff00) << 8) | (( x & 0x00ff0000) >> 8)))
|
|
#endif
|
|
|
|
static int read_wav_sample(mame_file *f, struct loaded_sample *sample)
|
|
{
|
|
unsigned long offset = 0;
|
|
UINT32 length, rate, filesize;
|
|
UINT16 bits, temp16;
|
|
char buf[32];
|
|
#ifndef LSB_FIRST
|
|
UINT32 sindex;
|
|
#endif
|
|
|
|
/* read the core header and make sure it's a WAVE file */
|
|
offset += mame_fread(f, buf, 4);
|
|
if (offset < 4)
|
|
return 0;
|
|
if (memcmp(&buf[0], "RIFF", 4) != 0)
|
|
return 0;
|
|
|
|
/* get the total size */
|
|
offset += mame_fread(f, &filesize, 4);
|
|
if (offset < 8)
|
|
return 0;
|
|
filesize = intelLong(filesize);
|
|
|
|
/* read the RIFF file type and make sure it's a WAVE file */
|
|
offset += mame_fread(f, buf, 4);
|
|
if (offset < 12)
|
|
return 0;
|
|
if (memcmp(&buf[0], "WAVE", 4) != 0)
|
|
return 0;
|
|
|
|
/* seek until we find a format tag */
|
|
while (1)
|
|
{
|
|
offset += mame_fread(f, buf, 4);
|
|
offset += mame_fread(f, &length, 4);
|
|
length = intelLong(length);
|
|
if (memcmp(&buf[0], "fmt ", 4) == 0)
|
|
break;
|
|
|
|
/* seek to the next block */
|
|
mame_fseek(f, length, SEEK_CUR);
|
|
offset += length;
|
|
if (offset >= filesize)
|
|
return 0;
|
|
}
|
|
|
|
/* read the format -- make sure it is PCM */
|
|
offset += mame_fread(f, &temp16, 2);
|
|
temp16 = LITTLE_ENDIANIZE_INT16(temp16);
|
|
if (temp16 != 1)
|
|
return 0;
|
|
|
|
/* number of channels -- only mono is supported */
|
|
offset += mame_fread(f, &temp16, 2);
|
|
temp16 = LITTLE_ENDIANIZE_INT16(temp16);
|
|
if (temp16 != 1)
|
|
return 0;
|
|
|
|
/* sample rate */
|
|
offset += mame_fread(f, &rate, 4);
|
|
rate = intelLong(rate);
|
|
|
|
/* bytes/second and block alignment are ignored */
|
|
offset += mame_fread(f, buf, 6);
|
|
|
|
/* bits/sample */
|
|
offset += mame_fread(f, &bits, 2);
|
|
bits = LITTLE_ENDIANIZE_INT16(bits);
|
|
if (bits != 8 && bits != 16)
|
|
return 0;
|
|
|
|
/* seek past any extra data */
|
|
mame_fseek(f, length - 16, SEEK_CUR);
|
|
offset += length - 16;
|
|
|
|
/* seek until we find a data tag */
|
|
while (1)
|
|
{
|
|
offset += mame_fread(f, buf, 4);
|
|
offset += mame_fread(f, &length, 4);
|
|
length = intelLong(length);
|
|
if (memcmp(&buf[0], "data", 4) == 0)
|
|
break;
|
|
|
|
/* seek to the next block */
|
|
mame_fseek(f, length, SEEK_CUR);
|
|
offset += length;
|
|
if (offset >= filesize)
|
|
return 0;
|
|
}
|
|
|
|
/* if there was a 0 length data block, we're done */
|
|
if (length == 0)
|
|
return 0;
|
|
|
|
/* fill in the sample data */
|
|
sample->length = length;
|
|
sample->frequency = rate;
|
|
|
|
/* read the data in */
|
|
if (bits == 8)
|
|
{
|
|
unsigned char *tempptr;
|
|
int sindex;
|
|
|
|
sample->data = auto_malloc(sizeof(*sample->data) * length);
|
|
mame_fread(f, sample->data, length);
|
|
|
|
/* convert 8-bit data to signed samples */
|
|
tempptr = (unsigned char *)sample->data;
|
|
for (sindex = length - 1; sindex >= 0; sindex--)
|
|
sample->data[sindex] = (INT8)(tempptr[sindex] ^ 0x80) * 256;
|
|
}
|
|
else
|
|
{
|
|
/* 16-bit data is fine as-is */
|
|
sample->data = auto_malloc(sizeof(*sample->data) * (length/2));
|
|
mame_fread(f, sample->data, length);
|
|
sample->length /= 2;
|
|
#ifndef LSB_FIRST
|
|
for (sindex = 0; sindex < sample->length; sindex++)
|
|
sample->data[sindex] = LITTLE_ENDIANIZE_INT16(sample->data[sindex]);
|
|
#endif
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
readsamples - load all samples
|
|
-------------------------------------------------*/
|
|
|
|
struct loaded_samples *readsamples(const char *const *samplenames, const char *basename)
|
|
{
|
|
struct loaded_samples *samples;
|
|
int skipfirst = 0;
|
|
int i;
|
|
|
|
/* if the user doesn't want to use samples, bail */
|
|
if (!options_get_bool(mame_options(), OPTION_SAMPLES))
|
|
return NULL;
|
|
if (samplenames == 0 || samplenames[0] == 0)
|
|
return NULL;
|
|
|
|
/* if a name begins with '*', we will also look under that as an alternate basename */
|
|
if (samplenames[0][0] == '*')
|
|
skipfirst = 1;
|
|
|
|
/* count the samples */
|
|
for (i = 0; samplenames[i+skipfirst] != 0; i++) ;
|
|
if (i == 0)
|
|
return NULL;
|
|
|
|
/* allocate the array */
|
|
samples = auto_malloc(sizeof(struct loaded_samples) + (i-1) * sizeof(struct loaded_sample));
|
|
memset(samples, 0, sizeof(struct loaded_samples) + (i-1) * sizeof(struct loaded_sample));
|
|
samples->total = i;
|
|
|
|
/* load the samples */
|
|
for (i = 0; i < samples->total; i++)
|
|
if (samplenames[i+skipfirst][0])
|
|
{
|
|
file_error filerr;
|
|
mame_file *f;
|
|
astring *fname;
|
|
|
|
fname = astring_assemble_3(astring_alloc(), basename, PATH_SEPARATOR, samplenames[i+skipfirst]);
|
|
filerr = mame_fopen(SEARCHPATH_SAMPLE, astring_c(fname), OPEN_FLAG_READ, &f);
|
|
|
|
if (filerr != FILERR_NONE && skipfirst)
|
|
{
|
|
astring_assemble_3(fname, samplenames[0] + 1, PATH_SEPARATOR, samplenames[i+skipfirst]);
|
|
filerr = mame_fopen(SEARCHPATH_SAMPLE, astring_c(fname), OPEN_FLAG_READ, &f);
|
|
}
|
|
if (filerr == FILERR_NONE)
|
|
{
|
|
read_wav_sample(f, &samples->sample[i]);
|
|
mame_fclose(f);
|
|
}
|
|
|
|
astring_free(fname);
|
|
}
|
|
|
|
return samples;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Start one of the samples loaded from disk. Note: channel must be in the range */
|
|
/* 0 .. Samplesinterface->channels-1. It is NOT the discrete channel to pass to */
|
|
/* mixer_play_sample() */
|
|
void sample_start_n(int num,int channel,int samplenum,int loop)
|
|
{
|
|
struct samples_info *info = sndti_token(SOUND_SAMPLES, num);
|
|
struct sample_channel *chan;
|
|
struct loaded_sample *sample;
|
|
|
|
/* if samples are disabled, just return quietly */
|
|
if (info->samples == NULL)
|
|
return;
|
|
|
|
assert( samplenum < info->samples->total );
|
|
assert( channel < info->numchannels );
|
|
|
|
chan = &info->channel[channel];
|
|
|
|
/* force an update before we start */
|
|
stream_update(chan->stream);
|
|
|
|
/* update the parameters */
|
|
sample = &info->samples->sample[samplenum];
|
|
chan->source = sample->data;
|
|
chan->source_length = sample->length;
|
|
chan->source_num = sample->data ? samplenum : -1;
|
|
chan->pos = 0;
|
|
chan->frac = 0;
|
|
chan->basefreq = sample->frequency;
|
|
chan->step = ((INT64)chan->basefreq << FRAC_BITS) / info->device->machine->sample_rate;
|
|
chan->loop = loop;
|
|
}
|
|
|
|
void sample_start(int channel,int samplenum,int loop)
|
|
{
|
|
sample_start_n(0,channel,samplenum,loop);
|
|
}
|
|
|
|
|
|
void sample_start_raw_n(int num,int channel,const INT16 *sampledata,int samples,int frequency,int loop)
|
|
{
|
|
struct samples_info *info = sndti_token(SOUND_SAMPLES, num);
|
|
struct sample_channel *chan;
|
|
|
|
assert( channel < info->numchannels );
|
|
|
|
chan = &info->channel[channel];
|
|
|
|
/* force an update before we start */
|
|
stream_update(chan->stream);
|
|
|
|
/* update the parameters */
|
|
chan->source = sampledata;
|
|
chan->source_length = samples;
|
|
chan->source_num = -1;
|
|
chan->pos = 0;
|
|
chan->frac = 0;
|
|
chan->basefreq = frequency;
|
|
chan->step = ((INT64)chan->basefreq << FRAC_BITS) / info->device->machine->sample_rate;
|
|
chan->loop = loop;
|
|
}
|
|
|
|
void sample_start_raw(int channel,const INT16 *sampledata,int samples,int frequency,int loop)
|
|
{
|
|
sample_start_raw_n(0,channel,sampledata,samples,frequency,loop);
|
|
}
|
|
|
|
|
|
void sample_set_freq_n(int num,int channel,int freq)
|
|
{
|
|
struct samples_info *info = sndti_token(SOUND_SAMPLES, num);
|
|
struct sample_channel *chan;
|
|
|
|
assert( channel < info->numchannels );
|
|
|
|
chan = &info->channel[channel];
|
|
|
|
/* force an update before we start */
|
|
stream_update(chan->stream);
|
|
|
|
chan->step = ((INT64)freq << FRAC_BITS) / info->device->machine->sample_rate;
|
|
}
|
|
|
|
void sample_set_freq(int channel,int freq)
|
|
{
|
|
sample_set_freq_n(0,channel,freq);
|
|
}
|
|
|
|
|
|
void sample_set_volume_n(int num,int channel,float volume)
|
|
{
|
|
struct samples_info *info = sndti_token(SOUND_SAMPLES, num);
|
|
struct sample_channel *chan;
|
|
|
|
assert( channel < info->numchannels );
|
|
|
|
chan = &info->channel[channel];
|
|
|
|
stream_set_output_gain(chan->stream, 0, volume);
|
|
}
|
|
|
|
void sample_set_volume(int channel,float volume)
|
|
{
|
|
sample_set_volume_n(0,channel,volume);
|
|
}
|
|
|
|
|
|
void sample_set_pause_n(int num,int channel,int pause)
|
|
{
|
|
struct samples_info *info = sndti_token(SOUND_SAMPLES, num);
|
|
struct sample_channel *chan;
|
|
|
|
assert( channel < info->numchannels );
|
|
|
|
chan = &info->channel[channel];
|
|
|
|
/* force an update before we start */
|
|
stream_update(chan->stream);
|
|
|
|
chan->paused = pause;
|
|
}
|
|
|
|
void sample_set_pause(int channel,int pause)
|
|
{
|
|
sample_set_pause_n(0,channel,pause);
|
|
}
|
|
|
|
|
|
void sample_stop_n(int num,int channel)
|
|
{
|
|
struct samples_info *info = sndti_token(SOUND_SAMPLES, num);
|
|
struct sample_channel *chan;
|
|
|
|
assert( channel < info->numchannels );
|
|
|
|
chan = &info->channel[channel];
|
|
|
|
/* force an update before we start */
|
|
stream_update(chan->stream);
|
|
chan->source = NULL;
|
|
chan->source_num = -1;
|
|
}
|
|
|
|
void sample_stop(int channel)
|
|
{
|
|
sample_stop_n(0,channel);
|
|
}
|
|
|
|
|
|
int sample_get_base_freq_n(int num,int channel)
|
|
{
|
|
struct samples_info *info = sndti_token(SOUND_SAMPLES, num);
|
|
struct sample_channel *chan;
|
|
|
|
assert( channel < info->numchannels );
|
|
|
|
chan = &info->channel[channel];
|
|
|
|
/* force an update before we start */
|
|
stream_update(chan->stream);
|
|
return chan->basefreq;
|
|
}
|
|
|
|
int sample_get_base_freq(int channel)
|
|
{
|
|
return sample_get_base_freq_n(0,channel);
|
|
}
|
|
|
|
|
|
int sample_playing_n(int num,int channel)
|
|
{
|
|
struct samples_info *info = sndti_token(SOUND_SAMPLES, num);
|
|
struct sample_channel *chan;
|
|
|
|
assert( channel < info->numchannels );
|
|
|
|
chan = &info->channel[channel];
|
|
|
|
/* force an update before we start */
|
|
stream_update(chan->stream);
|
|
return (chan->source != NULL);
|
|
}
|
|
|
|
int sample_playing(int channel)
|
|
{
|
|
return sample_playing_n(0,channel);
|
|
}
|
|
|
|
|
|
int sample_loaded_n(int num,int samplenum)
|
|
{
|
|
int ret = 0;
|
|
struct samples_info *info = sndti_token(SOUND_SAMPLES, num);
|
|
|
|
if (info->samples != NULL)
|
|
{
|
|
assert( samplenum < info->samples->total );
|
|
|
|
ret = (info->samples->sample[samplenum].data != NULL);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int sample_loaded(int samplenum)
|
|
{
|
|
return sample_loaded_n(0,samplenum);
|
|
}
|
|
|
|
|
|
static void sample_update_sound(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
|
|
{
|
|
struct sample_channel *chan = param;
|
|
stream_sample_t *buffer = _buffer[0];
|
|
|
|
if (chan->source && !chan->paused)
|
|
{
|
|
/* load some info locally */
|
|
UINT32 pos = chan->pos;
|
|
UINT32 frac = chan->frac;
|
|
UINT32 step = chan->step;
|
|
const INT16 *sample = chan->source;
|
|
UINT32 sample_length = chan->source_length;
|
|
|
|
while (length--)
|
|
{
|
|
/* do a linear interp on the sample */
|
|
INT32 sample1 = sample[pos];
|
|
INT32 sample2 = sample[(pos + 1) % sample_length];
|
|
INT32 fracmult = frac >> (FRAC_BITS - 14);
|
|
*buffer++ = ((0x4000 - fracmult) * sample1 + fracmult * sample2) >> 14;
|
|
|
|
/* advance */
|
|
frac += step;
|
|
pos += frac >> FRAC_BITS;
|
|
frac = frac & ((1 << FRAC_BITS) - 1);
|
|
|
|
/* handle looping/ending */
|
|
if (pos >= sample_length)
|
|
{
|
|
if (chan->loop)
|
|
pos %= sample_length;
|
|
else
|
|
{
|
|
chan->source = NULL;
|
|
chan->source_num = -1;
|
|
if (length > 0)
|
|
memset(buffer, 0, length * sizeof(*buffer));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* push position back out */
|
|
chan->pos = pos;
|
|
chan->frac = frac;
|
|
}
|
|
else
|
|
memset(buffer, 0, length * sizeof(*buffer));
|
|
}
|
|
|
|
|
|
static STATE_POSTLOAD( samples_postload )
|
|
{
|
|
struct samples_info *info = param;
|
|
int i;
|
|
|
|
/* loop over channels */
|
|
for (i = 0; i < info->numchannels; i++)
|
|
{
|
|
struct sample_channel *chan = &info->channel[i];
|
|
|
|
/* attach any samples that were loaded and playing */
|
|
if (chan->source_num >= 0 && chan->source_num < info->samples->total)
|
|
{
|
|
struct loaded_sample *sample = &info->samples->sample[chan->source_num];
|
|
chan->source = sample->data;
|
|
chan->source_length = sample->length;
|
|
if (!sample->data)
|
|
chan->source_num = -1;
|
|
}
|
|
|
|
/* validate the position against the length in case the sample is smaller */
|
|
if (chan->source && chan->pos >= chan->source_length)
|
|
{
|
|
if (chan->loop)
|
|
chan->pos %= chan->source_length;
|
|
else
|
|
{
|
|
chan->source = NULL;
|
|
chan->source_num = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static SND_START( samples )
|
|
{
|
|
int i;
|
|
const samples_interface *intf = config;
|
|
struct samples_info *info;
|
|
|
|
info = auto_malloc(sizeof(*info));
|
|
memset(info, 0, sizeof(*info));
|
|
info->device = device;
|
|
sndintrf_register_token(info);
|
|
|
|
/* read audio samples */
|
|
if (intf->samplenames)
|
|
info->samples = readsamples(intf->samplenames,device->machine->gamedrv->name);
|
|
|
|
/* allocate channels */
|
|
info->numchannels = intf->channels;
|
|
assert(info->numchannels < MAX_CHANNELS);
|
|
info->channel = auto_malloc(sizeof(*info->channel) * info->numchannels);
|
|
for (i = 0; i < info->numchannels; i++)
|
|
{
|
|
info->channel[i].stream = stream_create(device, 0, 1, device->machine->sample_rate, &info->channel[i], sample_update_sound);
|
|
|
|
info->channel[i].source = NULL;
|
|
info->channel[i].source_num = -1;
|
|
info->channel[i].step = 0;
|
|
info->channel[i].loop = 0;
|
|
info->channel[i].paused = 0;
|
|
|
|
/* register with the save state system */
|
|
state_save_register_device_item(device, i, info->channel[i].source_length);
|
|
state_save_register_device_item(device, i, info->channel[i].source_num);
|
|
state_save_register_device_item(device, i, info->channel[i].pos);
|
|
state_save_register_device_item(device, i, info->channel[i].frac);
|
|
state_save_register_device_item(device, i, info->channel[i].step);
|
|
state_save_register_device_item(device, i, info->channel[i].loop);
|
|
state_save_register_device_item(device, i, info->channel[i].paused);
|
|
}
|
|
state_save_register_postload(device->machine, samples_postload, info);
|
|
|
|
/* initialize any custom handlers */
|
|
if (intf->start)
|
|
(*intf->start)(device);
|
|
|
|
return info;
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
* Generic get_info
|
|
**************************************************************************/
|
|
|
|
static SND_SET_INFO( samples )
|
|
{
|
|
switch (state)
|
|
{
|
|
/* no parameters to set */
|
|
}
|
|
}
|
|
|
|
|
|
SND_GET_INFO( samples )
|
|
{
|
|
switch (state)
|
|
{
|
|
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
|
|
|
/* --- the following bits of info are returned as pointers to data or functions --- */
|
|
case SNDINFO_PTR_SET_INFO: info->set_info = SND_SET_INFO_NAME( samples ); break;
|
|
case SNDINFO_PTR_START: info->start = SND_START_NAME( samples ); break;
|
|
case SNDINFO_PTR_STOP: /* Nothing */ break;
|
|
case SNDINFO_PTR_RESET: /* Nothing */ break;
|
|
|
|
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
|
case SNDINFO_STR_NAME: info->s = "Samples"; break;
|
|
case SNDINFO_STR_CORE_FAMILY: info->s = "Big Hack"; break;
|
|
case SNDINFO_STR_CORE_VERSION: info->s = "1.1"; break;
|
|
case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
|
|
case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright Nicola Salmoria and the MAME Team"; break;
|
|
}
|
|
}
|
|
|