mirror of
https://github.com/holub/mame
synced 2025-10-07 09:25:34 +03:00
Merge pull request #2001 from intealls/pa-cc
Some PortAudio-related changes and fixes
This commit is contained in:
commit
51081d26e4
@ -131,7 +131,7 @@ const options_entry osd_options::s_option_entries[] =
|
|||||||
{ nullptr, nullptr, OPTION_HEADER, "PORTAUDIO OPTIONS" },
|
{ nullptr, nullptr, OPTION_HEADER, "PORTAUDIO OPTIONS" },
|
||||||
{ OSDOPTION_PA_API, OSDOPTVAL_NONE, OPTION_STRING, "PortAudio API" },
|
{ OSDOPTION_PA_API, OSDOPTVAL_NONE, OPTION_STRING, "PortAudio API" },
|
||||||
{ OSDOPTION_PA_DEVICE, OSDOPTVAL_NONE, OPTION_STRING, "PortAudio device" },
|
{ OSDOPTION_PA_DEVICE, OSDOPTVAL_NONE, OPTION_STRING, "PortAudio device" },
|
||||||
{ OSDOPTION_PA_LATENCY "(0.001-0.25)", "0", OPTION_FLOAT, "suggested latency in seconds, 0 for default" },
|
{ OSDOPTION_PA_LATENCY "(0-0.25)", "0", OPTION_FLOAT, "suggested latency in seconds, 0 for default" },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SDLMAME_MACOSX
|
#ifdef SDLMAME_MACOSX
|
||||||
|
@ -49,78 +49,75 @@ public:
|
|||||||
virtual void set_mastervolume(int attenuation);
|
virtual void set_mastervolume(int attenuation);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* Lock free SPSC ring buffer */
|
// Lock free SPSC ring buffer
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct audio_buffer {
|
struct audio_buffer {
|
||||||
T* buf;
|
T* buf;
|
||||||
int size;
|
int size;
|
||||||
int reserve;
|
int reserve;
|
||||||
std::atomic<int> rd_pos, wr_pos;
|
std::atomic<int> playpos, writepos;
|
||||||
|
|
||||||
audio_buffer(int size, int reserve) : size(size), reserve(reserve) {
|
audio_buffer(int size, int reserve) : size(size + reserve), reserve(reserve) {
|
||||||
rd_pos = wr_pos = 0;
|
playpos = writepos = 0;
|
||||||
buf = new T[size]();
|
buf = new T[size]();
|
||||||
}
|
}
|
||||||
|
|
||||||
~audio_buffer() { delete[] buf; }
|
~audio_buffer() { delete[] buf; }
|
||||||
|
|
||||||
int count() {
|
int count() {
|
||||||
int diff;
|
int diff = writepos - playpos;
|
||||||
diff = wr_pos - rd_pos;
|
return diff < 0 ? size + diff : diff;
|
||||||
diff = diff < 0 ? size + diff : diff;
|
|
||||||
diff -= reserve;
|
|
||||||
return diff < 0 ? 0 : diff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void increment_wrpos(int n) {
|
void increment_writepos(int n) {
|
||||||
wr_pos = (wr_pos + n) % size;
|
writepos.store((writepos + n) % size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int write(const T* src, int n, int attenuation) {
|
int write(const T* src, int n, int attenuation) {
|
||||||
n = std::min<int>(n, size - count());
|
n = std::min<int>(n, size - reserve - count());
|
||||||
|
|
||||||
if (wr_pos + n > size) {
|
if (writepos + n > size) {
|
||||||
att_memcpy(buf + wr_pos, src, sizeof(T) * (size - wr_pos), attenuation);
|
att_memcpy(buf + writepos, src, sizeof(T) * (size - writepos), attenuation);
|
||||||
att_memcpy(buf, src + (size - wr_pos), sizeof(T) * (n - (size - wr_pos)), attenuation);
|
att_memcpy(buf, src + (size - writepos), sizeof(T) * (n - (size - writepos)), attenuation);
|
||||||
} else {
|
} else {
|
||||||
att_memcpy(buf + wr_pos, src, sizeof(T) * n, attenuation);
|
att_memcpy(buf + writepos, src, sizeof(T) * n, attenuation);
|
||||||
}
|
}
|
||||||
|
|
||||||
increment_wrpos(n);
|
increment_writepos(n);
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void increment_rdpos(int n) {
|
void increment_playpos(int n) {
|
||||||
rd_pos = (rd_pos + n) % size;
|
playpos.store((playpos + n) % size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int read(T* dst, int n) {
|
int read(T* dst, int n) {
|
||||||
n = std::min<int>(n, count());
|
n = std::min<int>(n, count());
|
||||||
|
|
||||||
if (rd_pos + n > size) {
|
if (playpos + n > size) {
|
||||||
std::memcpy(dst, buf + rd_pos, sizeof(T) * (size - rd_pos));
|
std::memcpy(dst, buf + playpos, sizeof(T) * (size - playpos));
|
||||||
std::memcpy(dst + (size - rd_pos), buf, sizeof(T) * (n - (size - rd_pos)));
|
std::memcpy(dst + (size - playpos), buf, sizeof(T) * (n - (size - playpos)));
|
||||||
} else {
|
} else {
|
||||||
std::memcpy(dst, buf + rd_pos, sizeof(T) * n);
|
std::memcpy(dst, buf + playpos, sizeof(T) * n);
|
||||||
}
|
}
|
||||||
|
|
||||||
increment_rdpos(n);
|
increment_playpos(n);
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
int clear(int n) {
|
int clear(int n) {
|
||||||
n = std::min<int>(n, size - count());
|
n = std::min<int>(n, size - reserve - count());
|
||||||
|
|
||||||
if (wr_pos + n > size) {
|
if (writepos + n > size) {
|
||||||
std::memset(buf + wr_pos, 0, sizeof(T) * (size - wr_pos));
|
std::memset(buf + writepos, 0, sizeof(T) * (size - writepos));
|
||||||
std::memset(buf, 0, sizeof(T) * (n - (size - wr_pos)));
|
std::memset(buf, 0, sizeof(T) * (n - (size - writepos)));
|
||||||
} else {
|
} else {
|
||||||
std::memset(buf + wr_pos, 0, sizeof(T) * n);
|
std::memset(buf + writepos, 0, sizeof(T) * n);
|
||||||
}
|
}
|
||||||
|
|
||||||
increment_wrpos(n);
|
increment_writepos(n);
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@ -185,7 +182,10 @@ int sound_pa::init(osd_options const &options)
|
|||||||
m_overflows = 0;
|
m_overflows = 0;
|
||||||
m_has_overflowed = false;
|
m_has_overflowed = false;
|
||||||
m_has_underflowed = false;
|
m_has_underflowed = false;
|
||||||
|
m_osd_ticks = 0;
|
||||||
m_skip_threshold_ticks = 0;
|
m_skip_threshold_ticks = 0;
|
||||||
|
m_osd_tps = osd_ticks_per_second();
|
||||||
|
m_buffer_min_ct = INT_MAX;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
m_ab = new audio_buffer<s16>(m_sample_rate, 2);
|
m_ab = new audio_buffer<s16>(m_sample_rate, 2);
|
||||||
@ -194,8 +194,6 @@ int sound_pa::init(osd_options const &options)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_osd_tps = osd_ticks_per_second();
|
|
||||||
|
|
||||||
err = Pa_Initialize();
|
err = Pa_Initialize();
|
||||||
|
|
||||||
if (err != paNoError) goto pa_error;
|
if (err != paNoError) goto pa_error;
|
||||||
@ -342,7 +340,7 @@ int sound_pa::callback(s16* output_buffer, size_t number_of_samples)
|
|||||||
|
|
||||||
// if adjustment is less than two milliseconds, don't bother
|
// if adjustment is less than two milliseconds, don't bother
|
||||||
if (adjust / 2 > sample_rate() / 500) {
|
if (adjust / 2 > sample_rate() / 500) {
|
||||||
m_ab->increment_rdpos(adjust);
|
m_ab->increment_playpos(adjust);
|
||||||
m_has_overflowed = true;
|
m_has_overflowed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,9 +353,8 @@ int sound_pa::callback(s16* output_buffer, size_t number_of_samples)
|
|||||||
m_ab->read(output_buffer, buf_ct);
|
m_ab->read(output_buffer, buf_ct);
|
||||||
std::memset(output_buffer + buf_ct, 0, (number_of_samples - buf_ct) * sizeof(s16));
|
std::memset(output_buffer + buf_ct, 0, (number_of_samples - buf_ct) * sizeof(s16));
|
||||||
|
|
||||||
// rd_pos == wr_pos only happens when buffer hasn't received any samples,
|
// if update_audio_stream has been called, note the underflow
|
||||||
// i.e. before update_audio_stream has been called
|
if (m_osd_ticks)
|
||||||
if (m_ab->rd_pos != m_ab->wr_pos)
|
|
||||||
m_has_underflowed = true;
|
m_has_underflowed = true;
|
||||||
|
|
||||||
m_skip_threshold_ticks = m_osd_ticks;
|
m_skip_threshold_ticks = m_osd_ticks;
|
||||||
@ -371,9 +368,6 @@ void sound_pa::update_audio_stream(bool is_throttled, const s16 *buffer, int sam
|
|||||||
if (!sample_rate())
|
if (!sample_rate())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// for determining buffer overflows, take the sample here instead of in the callback
|
|
||||||
m_osd_ticks = osd_ticks();
|
|
||||||
|
|
||||||
#if LOG_BUFCNT
|
#if LOG_BUFCNT
|
||||||
if (m_log.good())
|
if (m_log.good())
|
||||||
m_log << m_ab->count() << std::endl;
|
m_log << m_ab->count() << std::endl;
|
||||||
@ -394,6 +388,9 @@ void sound_pa::update_audio_stream(bool is_throttled, const s16 *buffer, int sam
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_ab->write(buffer, samples_this_frame * 2, m_attenuation);
|
m_ab->write(buffer, samples_this_frame * 2, m_attenuation);
|
||||||
|
|
||||||
|
// for determining buffer overflows, take the sample here instead of in the callback
|
||||||
|
m_osd_ticks = osd_ticks();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sound_pa::set_mastervolume(int attenuation)
|
void sound_pa::set_mastervolume(int attenuation)
|
||||||
|
Loading…
Reference in New Issue
Block a user