2023-03-23 21:53:43 +00:00
|
|
|
/*****************************************************************************\
|
|
|
|
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
|
|
|
|
This file is licensed under the Snes9x License.
|
|
|
|
For further information, consult the LICENSE file in the root directory.
|
|
|
|
\*****************************************************************************/
|
|
|
|
|
|
|
|
#include "s9x_sound_driver_cubeb.hpp"
|
|
|
|
#include <cstdio>
|
|
|
|
|
2023-06-28 22:58:00 +00:00
|
|
|
bool S9xCubebSoundDriver::write_samples(int16_t *data, int samples)
|
2023-03-23 21:53:43 +00:00
|
|
|
{
|
2023-06-28 22:58:00 +00:00
|
|
|
bool retval = true;
|
2023-07-03 20:35:11 +00:00
|
|
|
auto empty = buffer.space_empty();
|
|
|
|
if (samples > empty)
|
2023-06-28 22:58:00 +00:00
|
|
|
{
|
|
|
|
retval = false;
|
2023-07-03 20:35:11 +00:00
|
|
|
buffer.dump(buffer.buffer_size / 2 - empty);
|
2023-06-28 22:58:00 +00:00
|
|
|
}
|
2023-07-03 20:35:11 +00:00
|
|
|
|
2023-03-23 21:53:43 +00:00
|
|
|
buffer.push(data, samples);
|
2023-06-28 22:58:00 +00:00
|
|
|
|
|
|
|
return retval;
|
2023-03-23 21:53:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
S9xCubebSoundDriver::S9xCubebSoundDriver()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
S9xCubebSoundDriver::~S9xCubebSoundDriver()
|
|
|
|
{
|
|
|
|
deinit();
|
|
|
|
}
|
|
|
|
|
|
|
|
void S9xCubebSoundDriver::init()
|
|
|
|
{
|
|
|
|
if (!context)
|
|
|
|
cubeb_init(&context, "Snes9x", nullptr);
|
|
|
|
stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
void S9xCubebSoundDriver::deinit()
|
|
|
|
{
|
|
|
|
stop();
|
|
|
|
if (stream)
|
|
|
|
{
|
|
|
|
cubeb_stream_destroy(stream);
|
|
|
|
stream = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (context)
|
|
|
|
{
|
|
|
|
cubeb_destroy(context);
|
|
|
|
context = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void S9xCubebSoundDriver::start()
|
|
|
|
{
|
|
|
|
if (stream)
|
|
|
|
cubeb_stream_start(stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
void S9xCubebSoundDriver::stop()
|
|
|
|
{
|
|
|
|
if (stream)
|
|
|
|
cubeb_stream_stop(stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
void state_callback(cubeb_stream *stream, void *user_ptr, cubeb_state state)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
long data_callback(cubeb_stream *stream, void *user_ptr,
|
|
|
|
void const *input_buffer,
|
|
|
|
void *output_buffer, long nframes)
|
|
|
|
{
|
|
|
|
return ((S9xCubebSoundDriver *)user_ptr)->data_callback(stream, input_buffer, output_buffer, nframes);
|
|
|
|
}
|
|
|
|
|
|
|
|
long S9xCubebSoundDriver::data_callback(cubeb_stream *stream, void const *input_buffer, void *output_buffer, long nframes)
|
|
|
|
{
|
2023-06-27 20:33:52 +00:00
|
|
|
auto avail = buffer.avail();
|
|
|
|
if (avail < nframes * 2)
|
|
|
|
{
|
|
|
|
auto zeroed_samples = nframes * 2 - avail;
|
|
|
|
memset(output_buffer, 0, zeroed_samples);
|
|
|
|
buffer.read((int16_t *)output_buffer + zeroed_samples, nframes * 2 - zeroed_samples);
|
2023-07-03 20:35:11 +00:00
|
|
|
buffer.add_silence(buffer.buffer_size / 2);
|
2023-06-27 20:33:52 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
buffer.read((int16_t *)output_buffer, nframes * 2);
|
|
|
|
}
|
2023-03-23 21:53:43 +00:00
|
|
|
return nframes;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool S9xCubebSoundDriver::open_device(int playback_rate, int buffer_size)
|
|
|
|
{
|
|
|
|
cubeb_stream_params params{};
|
|
|
|
params.channels = 2;
|
|
|
|
params.format = CUBEB_SAMPLE_S16LE;
|
|
|
|
params.layout = CUBEB_LAYOUT_UNDEFINED;
|
|
|
|
params.rate = playback_rate;
|
|
|
|
params.prefs = CUBEB_STREAM_PREF_NONE;
|
|
|
|
|
2023-06-28 22:58:00 +00:00
|
|
|
uint32_t suggested_latency = playback_rate * buffer_size / 1000;
|
2023-03-23 21:53:43 +00:00
|
|
|
uint32_t min_latency;
|
|
|
|
cubeb_get_min_latency(context, ¶ms, &min_latency);
|
|
|
|
|
|
|
|
auto retval = cubeb_stream_init(context, &stream, "Snes9x",
|
|
|
|
nullptr, nullptr,
|
|
|
|
nullptr, ¶ms,
|
2023-07-16 00:14:44 +00:00
|
|
|
min_latency,
|
2023-03-23 21:53:43 +00:00
|
|
|
&::data_callback,
|
|
|
|
&state_callback,
|
|
|
|
this);
|
|
|
|
|
|
|
|
if (retval != CUBEB_OK)
|
|
|
|
{
|
|
|
|
printf("Failed to start stream. Error: %d!\n", retval);
|
|
|
|
stream = nullptr;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-07-16 00:14:44 +00:00
|
|
|
buffer.resize(suggested_latency * 2);
|
2023-03-23 21:53:43 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int S9xCubebSoundDriver::space_free()
|
|
|
|
{
|
|
|
|
return buffer.space_empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<int, int> S9xCubebSoundDriver::buffer_level()
|
|
|
|
{
|
|
|
|
return { buffer.space_empty(), buffer.buffer_size };
|
|
|
|
}
|