summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/samples.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/sound/samples.cpp')
-rw-r--r--src/devices/sound/samples.cpp133
1 files changed, 61 insertions, 72 deletions
diff --git a/src/devices/sound/samples.cpp b/src/devices/sound/samples.cpp
index 40ff619cdce..4a1d527a958 100644
--- a/src/devices/sound/samples.cpp
+++ b/src/devices/sound/samples.cpp
@@ -2,23 +2,21 @@
// copyright-holders:Aaron Giles
/***************************************************************************
- samples.c
-
Sound device for sample playback.
****************************************************************************
- Playback of pre-recorded samples. Used for high-level simulation of
- discrete sound circuits where proper low-level simulation isn't
- available. Also used for tape loops and similar.
-
- Current limitations
- - Only supports single channel samples!
+Playback of pre-recorded samples. Used for high-level simulation of discrete
+sound circuits where proper low-level simulation isn't available. Also used
+for tape loops and similar.
- Considerations
- - Maybe this should be part of the presentation layer
- (artwork etc.) with samples specified in .lay files instead of
- in drivers?
+TODO:
+- Only supports single channel samples!
+- When mame.ini samplerate is close to the loaded sample(s) samplerate,
+ (eg. 48000, with 44100Hz samples), things can sound quite bad. This is
+ more an issue in sound.cpp resampler, not this device.
+- Maybe this should be part of the presentation layer (artwork etc.)
+ with samples specified in .lay files instead of in drivers?
***************************************************************************/
@@ -26,6 +24,7 @@
#include "samples.h"
#include "emuopts.h"
+#include "fileio.h"
#include "flac.h"
@@ -55,6 +54,7 @@ samples_device::samples_device(const machine_config &mconfig, const char *tag, d
samples_device::samples_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock)
, device_sound_interface(mconfig, *this)
+ , m_samples_start_cb(*this)
, m_channels(0)
, m_names(nullptr)
{
@@ -85,12 +85,11 @@ void samples_device::start(uint8_t channel, uint32_t samplenum, bool loop)
// update the parameters
sample_t &sample = m_sample[samplenum];
chan.source = (sample.data.size() > 0) ? &sample.data[0] : nullptr;
- chan.source_length = sample.data.size();
- chan.source_num = (chan.source_length > 0) ? samplenum : -1;
+ chan.source_num = (chan.source_len > 0) ? samplenum : -1;
+ chan.source_len = sample.data.size();
chan.pos = 0;
- chan.frac = 0;
chan.basefreq = sample.frequency;
- chan.step = (int64_t(chan.basefreq) << FRAC_BITS) / machine().sample_rate();
+ chan.curfreq = sample.frequency;
chan.loop = loop;
}
@@ -110,12 +109,11 @@ void samples_device::start_raw(uint8_t channel, const int16_t *sampledata, uint3
// update the parameters
chan.source = sampledata;
- chan.source_length = samples;
chan.source_num = -1;
+ chan.source_len = samples;
chan.pos = 0;
- chan.frac = 0;
chan.basefreq = frequency;
- chan.step = (int64_t(chan.basefreq) << FRAC_BITS) / machine().sample_rate();
+ chan.curfreq = frequency;
chan.loop = loop;
}
@@ -132,7 +130,7 @@ void samples_device::set_frequency(uint8_t channel, uint32_t freq)
// force an update before we start
channel_t &chan = m_channel[channel];
chan.stream->update();
- chan.step = (int64_t(freq) << FRAC_BITS) / machine().sample_rate();
+ chan.curfreq = freq;
}
@@ -146,8 +144,7 @@ void samples_device::set_volume(uint8_t channel, float volume)
assert(channel < m_channels);
// force an update before we start
- channel_t &chan = m_channel[channel];
- chan.stream->set_output_gain(0, volume);
+ set_output_gain(channel, volume);
}
@@ -200,11 +197,7 @@ void samples_device::stop_all()
uint32_t samples_device::base_frequency(uint8_t channel) const
{
assert(channel < m_channels);
-
- // force an update before we start
- const channel_t &chan = m_channel[channel];
- chan.stream->update();
- return chan.basefreq;
+ return m_channel[channel].basefreq;
}
@@ -244,25 +237,23 @@ void samples_device::device_start()
{
// initialize channel
channel_t &chan = m_channel[channel];
- chan.stream = stream_alloc(0, 1, machine().sample_rate());
+ chan.stream = stream_alloc(0, 1, SAMPLE_RATE_OUTPUT_ADAPTIVE);
chan.source = nullptr;
chan.source_num = -1;
- chan.step = 0;
+ chan.pos = 0;
chan.loop = 0;
chan.paused = 0;
// register with the save state system
- save_item(NAME(chan.source_length), channel);
save_item(NAME(chan.source_num), channel);
+ save_item(NAME(chan.source_len), channel);
save_item(NAME(chan.pos), channel);
- save_item(NAME(chan.frac), channel);
- save_item(NAME(chan.step), channel);
save_item(NAME(chan.loop), channel);
save_item(NAME(chan.paused), channel);
}
// initialize any custom handlers
- m_samples_start_cb.bind_relative_to(*owner());
+ m_samples_start_cb.resolve();
if (!m_samples_start_cb.isnull())
m_samples_start_cb();
@@ -295,16 +286,21 @@ void samples_device::device_post_load()
{
sample_t &sample = m_sample[chan.source_num];
chan.source = &sample.data[0];
- chan.source_length = sample.data.size();
+ chan.source_len = sample.data.size();
if (sample.data.empty())
chan.source_num = -1;
}
// validate the position against the length in case the sample is smaller
- if (chan.source != nullptr && chan.pos >= chan.source_length)
+ double endpos = chan.source_len;
+ if (chan.source != nullptr && chan.pos >= endpos)
{
if (chan.loop)
- chan.pos %= chan.source_length;
+ {
+ double posfloor = floor(chan.pos);
+ chan.pos -= posfloor;
+ chan.pos += double(int32_t(posfloor) % chan.source_len);
+ }
else
{
chan.source = nullptr;
@@ -319,60 +315,51 @@ void samples_device::device_post_load()
// sound_stream_update - update a sound stream
//-------------------------------------------------
-void samples_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+void samples_device::sound_stream_update(sound_stream &stream)
{
// find the channel with this stream
+ constexpr sound_stream::sample_t sample_scale = 1.0 / 32768.0;
for (int channel = 0; channel < m_channels; channel++)
if (&stream == m_channel[channel].stream)
{
channel_t &chan = m_channel[channel];
- stream_sample_t *buffer = outputs[0];
// process if we still have a source and we're not paused
if (chan.source != nullptr && !chan.paused)
{
// load some info locally
- uint32_t pos = chan.pos;
- uint32_t frac = chan.frac;
- uint32_t step = chan.step;
+ double step = double(chan.curfreq) / double(stream.sample_rate());
+ double endpos = chan.source_len;
const int16_t *sample = chan.source;
- uint32_t sample_length = chan.source_length;
- while (samples--)
+ for (int sampindex = 0; sampindex < stream.samples(); sampindex++)
{
// do a linear interp on the sample
- int32_t sample1 = sample[pos];
- int32_t sample2 = sample[(pos + 1) % sample_length];
- int32_t fracmult = frac >> (FRAC_BITS - 14);
- *buffer++ = ((0x4000 - fracmult) * sample1 + fracmult * sample2) >> 14;
+ double pos_floor = floor(chan.pos);
+ double frac = chan.pos - pos_floor;
+ int32_t ipos = int32_t(pos_floor);
+
+ sound_stream::sample_t sample1 = sound_stream::sample_t(sample[ipos++]);
+ sound_stream::sample_t sample2 = sound_stream::sample_t(sample[(ipos + 1) % chan.source_len]);
+ stream.put(0, sampindex, sample_scale * ((1.0 - frac) * sample1 + frac * sample2));
// advance
- frac += step;
- pos += frac >> FRAC_BITS;
- frac = frac & ((1 << FRAC_BITS) - 1);
+ chan.pos += step;
// handle looping/ending
- if (pos >= sample_length)
+ if (chan.pos >= endpos)
{
if (chan.loop)
- pos %= sample_length;
+ chan.pos -= endpos;
else
{
chan.source = nullptr;
chan.source_num = -1;
- if (samples > 0)
- memset(buffer, 0, samples * sizeof(*buffer));
break;
}
}
}
-
- // push position back out
- chan.pos = pos;
- chan.frac = frac;
}
- else
- memset(buffer, 0, samples * sizeof(*buffer));
break;
}
}
@@ -604,7 +591,7 @@ bool samples_device::load_samples()
return false;
// iterate over ourself
- const char *basename = machine().basename();
+ const std::string &basename = machine().basename();
samples_iterator iter(*this);
const char *altbasename = iter.altbasename();
@@ -613,26 +600,28 @@ bool samples_device::load_samples()
// load the samples
int index = 0;
- for (const char *samplename = iter.first(); samplename != nullptr; index++, samplename = iter.next())
+ for (const char *samplename = iter.first(); samplename; index++, samplename = iter.next())
{
// attempt to open as FLAC first
emu_file file(machine().options().sample_path(), OPEN_FLAG_READ);
- osd_file::error filerr = file.open(basename, PATH_SEPARATOR, samplename, ".flac");
- if (filerr != osd_file::error::NONE && altbasename != nullptr)
- filerr = file.open(altbasename, PATH_SEPARATOR, samplename, ".flac");
+ std::error_condition filerr = file.open(util::string_format("%s" PATH_SEPARATOR "%s.flac", basename, samplename));
+ if (filerr && altbasename)
+ filerr = file.open(util::string_format("%s" PATH_SEPARATOR "%s.flac", altbasename, samplename));
// if not, try as WAV
- if (filerr != osd_file::error::NONE)
- filerr = file.open(basename, PATH_SEPARATOR, samplename, ".wav");
- if (filerr != osd_file::error::NONE && altbasename != nullptr)
- filerr = file.open(altbasename, PATH_SEPARATOR, samplename, ".wav");
+ if (filerr)
+ filerr = file.open(util::string_format("%s" PATH_SEPARATOR "%s.wav", basename, samplename));
+ if (filerr && altbasename)
+ filerr = file.open(util::string_format("%s" PATH_SEPARATOR "%s.wav", altbasename, samplename));
// if opened, read it
- if (filerr == osd_file::error::NONE)
+ if (!filerr)
+ {
read_sample(file, m_sample[index]);
- else if (filerr == osd_file::error::NOT_FOUND)
+ }
+ else
{
- logerror("%s: Sample '%s' NOT FOUND\n", tag(), samplename);
+ logerror("Error opening sample '%s' (%s:%d %s)\n", samplename, filerr.category().name(), filerr.value(), filerr.message());
ok = false;
}
}