diff -Naur -x *.p* -x *.orig -x *.rej -x *.bak -x neogeo_noslot.c -x arcade.lst -x z80*.c -x hk68*.c --ignore-all-space mame170/src/emu/emuopts.cpp mame170-asio/src/emu/emuopts.cpp --- mame170/src/emu/emuopts.cpp Wed Jan 27 09:15:02 2016 +++ mame170-asio/src/emu/emuopts.cpp Wed Feb 3 18:43:33 2016 @@ -186,6 +186,12 @@ { OPTION_AUTOBOOT_DELAY, "2", OPTION_INTEGER, "timer delay in sec to trigger command execution on autoboot" }, { OPTION_AUTOBOOT_SCRIPT ";script", nullptr, OPTION_STRING, "lua script to execute after machine boot" }, { OPTION_CONSOLE, "0", OPTION_BOOLEAN, "enable emulator LUA console" }, + + // ASIO options + { OPTION_ASIO_LOG ";aslg", "0", OPTION_BOOLEAN, "Generate runtime ASIO log" }, + { OPTION_ASIO_DEVICE ";asd", "0", OPTION_INTEGER, "Use ASIO device number" }, + { OPTION_ASIO_CAL_FREQ ";ascf", "0.0", OPTION_FLOAT, "Value from frequency calibration tool" }, + { nullptr } }; diff -Naur -x *.p* -x *.orig -x *.rej -x *.bak -x neogeo_noslot.c -x arcade.lst -x z80*.c -x hk68*.c --ignore-all-space mame170/src/emu/emuopts.h mame170-asio/src/emu/emuopts.h --- mame170/src/emu/emuopts.h Wed Jan 27 09:15:02 2016 +++ mame170-asio/src/emu/emuopts.h Wed Feb 3 18:44:18 2016 @@ -191,6 +191,11 @@ #define OPTION_CONSOLE "console" +/* ASIO options */ +#define OPTION_ASIO_LOG "asio_log" +#define OPTION_ASIO_DEVICE "asio_device" +#define OPTION_ASIO_CAL_FREQ "asio_cal_freq" + //************************************************************************** // TYPE DEFINITIONS //************************************************************************** @@ -372,6 +377,11 @@ std::string sub_value(const char *name, const char *subname) const; bool add_slot_options(bool isfirst); + // ASIO options + bool asio_log() const { return bool_value(OPTION_ASIO_LOG); } + int asio_device() const { return int_value(OPTION_ASIO_DEVICE); } + float asio_calibration_freq() { return float_value(OPTION_ASIO_CAL_FREQ); } + private: // device-specific option handling void add_device_options(bool isfirst); diff -Naur -x *.p* -x *.orig -x *.rej -x *.bak -x neogeo_noslot.c -x arcade.lst -x z80*.c -x hk68*.c --ignore-all-space mame170/src/emu/sound.cpp mame170-asio/src/emu/sound.cpp --- mame170/src/emu/sound.cpp Wed Jan 27 09:15:02 2016 +++ mame170-asio/src/emu/sound.cpp Wed Feb 3 19:33:32 2016 @@ -844,16 +844,13 @@ machine.add_notifier(MACHINE_NOTIFY_PAUSE, machine_notify_delegate(FUNC(sound_manager::pause), this)); machine.add_notifier(MACHINE_NOTIFY_RESUME, machine_notify_delegate(FUNC(sound_manager::resume), this)); machine.add_notifier(MACHINE_NOTIFY_RESET, machine_notify_delegate(FUNC(sound_manager::reset), this)); + machine.add_notifier(MACHINE_NOTIFY_FRAME, machine_notify_delegate(FUNC(sound_manager::update), this)); // register global states machine.save().save_item(NAME(m_last_update)); // set the starting attenuation set_attenuation(machine.options().volume()); - - // start the periodic update flushing timer - m_update_timer = machine.scheduler().timer_alloc(timer_expired_delegate(FUNC(sound_manager::update), this)); - m_update_timer->adjust(STREAMS_UPDATE_ATTOTIME, 0, STREAMS_UPDATE_ATTOTIME); } @@ -1032,7 +1029,8 @@ // and send it to the OSD layer //------------------------------------------------- -void sound_manager::update(void *ptr, int param) +//void sound_manager::update(void *ptr, int param) +void sound_manager::update() { VPRINTF(("sound_update\n")); @@ -1045,7 +1043,7 @@ speaker->mix(&m_leftmix[0], &m_rightmix[0], samples_this_update, (m_muted & MUTE_REASON_SYSTEM)); // now downmix the final result - UINT32 finalmix_step = machine().video().speed_factor(); + UINT32 finalmix_step = 1000; UINT32 finalmix_offset = 0; INT16 *finalmix = &m_finalmix[0]; int sample; diff -Naur -x *.p* -x *.orig -x *.rej -x *.bak -x neogeo_noslot.c -x arcade.lst -x z80*.c -x hk68*.c --ignore-all-space mame170/src/emu/sound.h mame170-asio/src/emu/sound.h --- mame170/src/emu/sound.h Wed Jan 27 09:15:02 2016 +++ mame170-asio/src/emu/sound.h Wed Feb 3 19:34:40 2016 @@ -225,7 +225,7 @@ void config_load(config_type cfg_type, xml_data_node *parentnode); void config_save(config_type cfg_type, xml_data_node *parentnode); - void update(void *ptr = nullptr, INT32 param = 0); + void update(); // internal state running_machine & m_machine; // reference to our machine diff -Naur -x *.p* -x *.orig -x *.rej -x *.bak -x neogeo_noslot.c -x arcade.lst -x z80*.c -x hk68*.c --ignore-all-space mame170/src/emu/video.h mame170-asio/src/emu/video.h --- mame170/src/emu/video.h Wed Jan 27 09:15:02 2016 +++ mame170-asio/src/emu/video.h Wed Feb 3 20:15:06 2016 @@ -65,6 +65,7 @@ float throttle_rate() const { return m_throttle_rate; } bool fastforward() const { return m_fastforward; } bool is_recording() const { return (m_mng_file != nullptr || m_avi_file != nullptr); } + attotime overall_emutime() { return m_overall_emutime; } // setters void set_frameskip(int frameskip); @@ -82,6 +83,7 @@ // current speed helpers std::string speed_text(); + double target_speed() const { return (double) m_speed / 1000.f; } double speed_percent() const { return m_speed_percent; } // snapshots diff -Naur -x *.p* -x *.orig -x *.rej -x *.bak -x neogeo_noslot.c -x arcade.lst -x z80*.c -x hk68*.c --ignore-all-space mame170/src/osd/modules/lib/osdobj_common.cpp mame170-asio/src/osd/modules/lib/osdobj_common.cpp --- mame170/src/osd/modules/lib/osdobj_common.cpp Wed Jan 27 09:15:10 2016 +++ mame170-asio/src/osd/modules/lib/osdobj_common.cpp Wed Feb 3 18:42:41 2016 @@ -181,6 +181,7 @@ REGISTER_MODULE(m_mod_man, FONT_SDL); REGISTER_MODULE(m_mod_man, FONT_NONE); + REGISTER_MODULE(m_mod_man, SOUND_ASIO); REGISTER_MODULE(m_mod_man, SOUND_DSOUND); REGISTER_MODULE(m_mod_man, SOUND_COREAUDIO); REGISTER_MODULE(m_mod_man, SOUND_JS); @@ -556,6 +557,7 @@ m_sound = select_module_options(options(), OSD_SOUND_PROVIDER); m_sound->m_sample_rate = options().sample_rate(); m_sound->m_audio_latency = options().audio_latency(); + m_sound->set_machine(machine()); m_debugger = select_module_options(options(), OSD_DEBUG_PROVIDER); diff -Naur -x *.p* -x *.orig -x *.rej -x *.bak -x neogeo_noslot.c -x arcade.lst -x z80*.c -x hk68*.c --ignore-all-space mame170/src/osd/modules/sound/asio.cpp mame170-asio/src/osd/modules/sound/asio.cpp --- mame170/src/osd/modules/sound/asio.cpp Thu Jan 1 01:00:00 1970 +++ mame170-asio/src/osd/modules/sound/asio.cpp Wed Feb 3 20:15:24 2016 @@ -0,0 +1,376 @@ +// license:BSD-3-Clause +/*************************************************************************** + + asio.c + + Preliminary ASIO implementation using BASSASIO. + +*******************************************************************c********/ + +#include "emu.h" +#include "asio.h" +#include +#include + +#include + +#undef min +#undef max + +#define ASIO_BUF_CT(c) ((int) ((c)->head <= (c)->tail ? (c)->tail - (c)->head : (c)->buf_size - ((c)->head - (c)->tail))) + +#define D(x) (x) + +#define ASIO_BUF_SIZE 32768 + +DWORD CALLBACK asio_callback(BOOL input, DWORD channel, void *buffer, DWORD length, void *user) +{ + INT16 *buf = (INT16*) buffer; + + asio_buf_t *asio_buf = (asio_buf_t*) user; + + // Collect statistics for calibration frequency fit + { + static const double tps = (double) osd_ticks_per_second(); + static const double time_start = (double) osd_ticks() / tps; + double time_now = (double) osd_ticks() / tps - time_start; + + asio_buf->log.samples_requested += length / 2; + asio_buf->log.time_last_fetch = time_now; + } + + osd_lock_acquire(asio_buf->lock); + + if (ASIO_BUF_CT(asio_buf) < length / 2) { + if (asio_buf->log.samples_received && !asio_buf->log.underrun) + asio_buf->log.underrun++; + + // We can't simply return 0 since it messes with the calibration fit. + memset(buffer, 0, length); + } else { + if (asio_buf->head + (length / 2) > asio_buf->buf_size) { + memcpy(buf, asio_buf->buf + asio_buf->head, sizeof(INT16) * (asio_buf->buf_size - asio_buf->head)); + memcpy(buf + (asio_buf->buf_size - asio_buf->head), asio_buf->buf, length - sizeof(INT16) * (asio_buf->buf_size - asio_buf->head)); + } else { + memcpy(buf, asio_buf->buf + asio_buf->head, length); + } + + asio_buf->head += length / 2; + asio_buf->head %= asio_buf->buf_size; + } + + osd_lock_release(asio_buf->lock); + + return length; +} + +int sound_asio::init(osd_options const &options) +{ + m_audio_updates = 0; + m_rup = 0; + m_rdn = 0; + m_asio_latency = 0; + m_asio_avg_cpu = 0.f; + m_asio_rate = 0.f; + m_asio_rate_compensated = 0.f; + m_asio_running = false; + m_new_rate = 0.f; + m_asio_log = m_machine->options().asio_log(); + + if (!BASS_ASIO_Init(m_machine->options().asio_device(), BASS_ASIO_THREAD | BASS_ASIO_JOINORDER)) { + osd_printf_verbose("ASIO: Unable to initialize device %d\n", m_machine->options().asio_device()); + BASS_ASIO_Free(); + } else { + if (BASS_ASIO_CheckRate((double) m_sample_rate) == BASS_ERROR_NOTAVAIL) { + osd_printf_verbose("ASIO: Requested sample rate %d is not supported by the driver\n", + m_sample_rate); + BASS_ASIO_Free(); + } else { + memset(&m_asio_buf, 0, sizeof(asio_buf_t)); + m_asio_buf.buf_size = ASIO_BUF_SIZE; + m_asio_buf.buf = global_alloc_array_clear(m_asio_buf.buf_size); + m_asio_buf.lock = osd_lock_alloc(); + + BASS_ASIO_SetRate(m_sample_rate); + BASS_ASIO_ChannelEnable(0, 0, &asio_callback, (void*) &m_asio_buf); + BASS_ASIO_ChannelPause(0, 0); + BASS_ASIO_ChannelSetFormat(0, 0, BASS_ASIO_FORMAT_16BIT); + + m_asio_rate = BASS_ASIO_GetRate(); + m_asio_rate_compensated = m_machine->options().asio_calibration_freq() ? + m_machine->options().asio_calibration_freq() : + m_sample_rate; + + m_new_rate = ((double) m_sample_rate + m_asio_rate - m_asio_rate_compensated) * + m_machine->options().speed(); + + BASS_ASIO_ChannelJoin(FALSE, 1, 0); + BASS_ASIO_ChannelSetRate(0, 0, m_new_rate); + + BASS_ASIO_INFO info; + BASS_ASIO_GetInfo(&info); + + if (!BASS_ASIO_IsStarted()) { + if (!BASS_ASIO_Start(info.bufpref, 0)) { + osd_printf_verbose("ASIO: Can't start ASIO output, error code: %lu\n", + BASS_ASIO_ErrorGetCode()); + global_free_array(m_asio_buf.buf); + osd_lock_free(m_asio_buf.lock); + BASS_ASIO_Free(); + return 0; + } + } + + m_asio_latency = (UINT32) info.bufpref; + + osd_printf_verbose("ASIO: Driver %s initialized with latency %u,\n" + " sample rate %.2f, compensated sample rate %.6f,\n", + info.name, m_asio_latency, m_asio_rate, (m_asio_rate != m_asio_rate_compensated) ? + m_asio_rate_compensated : 0.f); + + if (m_machine->options().asio_log()) + osd_printf_verbose(" driver version: %lu, bufmin: %lu, bufmax: %lu,\n" + " bufpref: %lu, bufgran: %d\n", + info.version, info.bufmin, info.bufmax, info.bufpref, info.bufgran); + + osd_printf_verbose(" audio latency is %d\n", m_audio_latency); + + osd_printf_verbose("ASIO: Setting initial playback rate to %.3f Hz\n", m_new_rate); + + m_asio_running = true; + } + } + + return 0; +} + +void sound_asio::exit() +{ + if (m_asio_running) { + m_asio_running = false; + BASS_ASIO_ChannelPause(0, 0); + + if (m_asio_log) { + m_logfile.open("asio.log"); + if (m_logfile.is_open()) { + m_logfile << m_log.str(); + m_logfile.close(); + } else { + osd_printf_verbose("ASIO: Could not write log.\n"); + } + } + + osd_printf_verbose("ASIO: Average callback timeslice usage: %f\n", m_asio_avg_cpu); + osd_printf_verbose("ASIO: Overrun/underrun: %u/%u\n", m_rup, m_rdn); + + BASS_ASIO_Stop(); + osd_lock_acquire(m_asio_buf.lock); + global_free_array(m_asio_buf.buf); + osd_lock_release(m_asio_buf.lock); + osd_lock_free(m_asio_buf.lock); + BASS_ASIO_Free(); + } +} + +/* + This is needed because the sound card driver does not usually request + exactly 48000 samples each second (or whatever the sample rate is set to). + A linear fit is performed to calculate the actual rate. + + For this to work, the driver needs to request the samples it's supposed to + want continuously. If it fails to do so, the calibration will be invalid. +*/ +double rate_est = 0; +void sound_asio::calc_asio_freq(bool reset_calibration) +{ + const double samples_requested = m_asio_buf.log.samples_requested; + + static double accum = 0; + static double prev_requested = samples_requested; + + static double time_start = m_asio_buf.log.time_last_fetch; + const double time = m_asio_buf.log.time_last_fetch - time_start; + + double curr = 0; + static double n = 0; + + curr = samples_requested - prev_requested; + curr /= m_new_rate; + curr *= m_sample_rate; + accum += curr; + + n++; + + /* Fit */ + static double m_x = 0, m_y = 0, m_dx2 = 0, m_dxdy = 0; + { + m_x += (time - m_x) / n; + m_y += (accum / 2.f - m_y) / n; + + const double dx = time - m_x; + const double dy = accum / 2.f - m_y; + + m_dx2 += (dx * dx - m_dx2) / n; + m_dxdy += (dx * dy - m_dxdy) / n; + + rate_est = m_dxdy / m_dx2; + + if (!isnan(rate_est) && fabs(rate_est - m_asio_rate) < 0.01 * m_asio_rate && !reset_calibration) + m_asio_rate_compensated = rate_est; + } + + if (reset_calibration) { + m_x = m_y = m_dx2 = m_dxdy = accum = n = 0; + m_asio_rate_compensated = m_asio_rate; + } + + prev_requested = samples_requested; +} + +void sound_asio::log(void) +{ + static const double tps = (double)osd_ticks_per_second(); + static const double time_start = (double)osd_ticks() / tps; + double time_now = (double)osd_ticks() / tps - time_start; + if (m_log.good()) { + m_log << m_machine->video().speed_percent() << + ",\t\t" << ASIO_BUF_CT(&m_asio_buf) << + ",\t\t" << m_asio_buf.log.samples_received << + ",\t\t" << m_asio_buf.log.samples_requested << + ",\t\t" << m_audio_updates << + ",\t\t" << m_new_rate << + ",\t\t" << std::fixed << std::setprecision(5) << m_asio_rate_compensated << + ",\t\t" << std::fixed << std::setprecision(5) << time_now << + ",\t\t" << std::fixed << std::setprecision(5) << rate_est << +// ",\t\t" << m_machine->time().as_double() << + std::endl; + } +} + +void sound_asio::copy_sample_data(asio_buf_t *chan, const INT16 *buffer, int samples_this_frame, bool reset) +{ + if (reset) { // empty, fastforward + memcpy(chan->buf, buffer, sizeof(INT16) * samples_this_frame); + chan->head = 0; + chan->tail = samples_this_frame; + } else if ((chan->tail + samples_this_frame) >= chan->buf_size) { // wrap + memcpy(chan->buf + chan->tail, buffer, sizeof(INT16) * (chan->buf_size - chan->tail)); + memcpy(chan->buf, buffer + (chan->buf_size - chan->tail), sizeof(INT16) * (samples_this_frame - (chan->buf_size - chan->tail))); + chan->tail = samples_this_frame - (chan->buf_size - chan->tail); + } else { + memcpy(chan->buf + chan->tail, buffer, sizeof(INT16) * samples_this_frame); + chan->tail += samples_this_frame; + } +} + +void sound_asio::update_audio_stream(bool is_throttled, const INT16 *buffer, int samples_this_frame) +{ + bool reset = false, rdn = false, rup = false; + static bool reset_calibration = false; + + if (!m_asio_running) + return; + + m_audio_updates++; + + if (m_machine->options().asio_log()) + log(); + + if (!m_machine->options().asio_calibration_freq()) + calc_asio_freq(reset_calibration); + + reset_calibration = false; + + if (m_machine->video().fastforward()) + reset = true; + else + m_asio_buf.log.samples_received += samples_this_frame; + + osd_lock_acquire(m_asio_buf.lock); + + copy_sample_data(&m_asio_buf, buffer, samples_this_frame * 2, reset); + + if (m_asio_buf.log.underrun && !reset) { + int adjust = 0; + + if ((ASIO_BUF_CT(&m_asio_buf) / 2 - samples_this_frame) <= m_audio_latency * m_asio_latency) { + // We rewind a bit to get more samples into the buffer. + adjust = m_audio_latency * m_asio_latency * 2 - (ASIO_BUF_CT(&m_asio_buf) - samples_this_frame * 2); + + if (m_asio_buf.head - adjust < 0) + m_asio_buf.head = m_asio_buf.buf_size + (m_asio_buf.head - adjust); + else + m_asio_buf.head -= adjust; + } + + osd_lock_release(m_asio_buf.lock); + + rdn = true; + m_asio_buf.log.underrun = 0; + + if (m_machine->options().asio_log() && m_machine->video().throttled()) + osd_printf_verbose("ASIO: Reverting head %d counts at update %d, just got %d samples, speed is %f\n", + adjust / 2, m_audio_updates, samples_this_frame, m_machine->video().speed_percent()); + } else { + int count = 0; + + if ((ASIO_BUF_CT(&m_asio_buf) / 2 - samples_this_frame) > (m_audio_latency + 3) * m_asio_latency && !reset) { + // We're currently having more samples in the buffer than we need. + // We advance the head to get fewer samples into it. + int adjust = (m_audio_latency + 2) * m_asio_latency * 2; + + if ((ASIO_BUF_CT(&m_asio_buf) - samples_this_frame * 2) - adjust > 0) { + count = (ASIO_BUF_CT(&m_asio_buf) - samples_this_frame * 2) - adjust; + m_asio_buf.head += count; + m_asio_buf.head %= m_asio_buf.buf_size; + rup = true; + } + } + + osd_lock_release(m_asio_buf.lock); + + if (m_machine->options().asio_log() && count != 0 && m_machine->video().throttled()) + osd_printf_verbose("ASIO: Advancing head %d counts at update %d, speed is %f\n", + count / 2, m_audio_updates, m_machine->video().speed_percent()); + } + + if (rup || rdn) + reset_calibration = true; + + // Collect over-/underrun statistic + if (m_machine->video().overall_emutime().seconds() >= 2 + && !m_machine->video().fastforward() && (rup || rdn)) { + if (rup) + m_rup++; + else + m_rdn++; + } + + // Set playback rate + if (!m_machine->video().fastforward()) { + m_new_rate = ((double) m_sample_rate + m_asio_rate - m_asio_rate_compensated) * (double) m_machine->video().target_speed(); + + BASS_ASIO_ChannelSetRate(0, 0, m_new_rate); + } + + m_asio_avg_cpu = BASS_ASIO_GetCPU() / (m_asio_avg_cpu ? 2.f : 1.f) + m_asio_avg_cpu / 2.f; + + // this needs work/fixing, start playback when enough samples have been accumulated + if (ASIO_BUF_CT(&m_asio_buf) >= (m_audio_latency * m_asio_latency * 2) && m_audio_updates > 1 && + BASS_ASIO_ChannelIsActive(0, 0) == BASS_ASIO_ACTIVE_PAUSED && + !m_machine->video().fastforward()) + { + BASS_ASIO_ChannelReset(0, 0, BASS_ASIO_RESET_PAUSE); + } +} + +void sound_asio::set_mastervolume(int attenuation) +{ + if (!m_asio_running) + return; + + for (int i = 0; i < 2; i++) + BASS_ASIO_ChannelSetVolume(0, i, (32.f + (float) attenuation) / 32.f); +} + +MODULE_DEFINITION(SOUND_ASIO, sound_asio) diff -Naur -x *.p* -x *.orig -x *.rej -x *.bak -x neogeo_noslot.c -x arcade.lst -x z80*.c -x hk68*.c --ignore-all-space mame170/src/osd/modules/sound/asio.h mame170-asio/src/osd/modules/sound/asio.h --- mame170/src/osd/modules/sound/asio.h Thu Jan 1 01:00:00 1970 +++ mame170-asio/src/osd/modules/sound/asio.h Wed Feb 3 18:55:51 2016 @@ -0,0 +1,84 @@ +// license:BSD-3-Clause +/*************************************************************************** + + asio.h + + Preliminary ASIO implementation using BASSASIO. + +*******************************************************************c********/ + +#pragma once + +#ifndef __SOUND_ASIO_H__ +#define __SOUND_ASIO_H__ + +#include "osdepend.h" +#include "sound_module.h" + +#include + +#include +#include +#include + +struct asio_log_t { + volatile UINT32 samples_received, + samples_requested, + overrun, + underrun; + + volatile double time_last_fetch; +}; + +struct asio_buf_t { + INT16 *buf; + + int head, + tail, + buf_size; + + osd_lock *lock; + + asio_log_t log; +}; + +class sound_asio : public osd_module, public sound_module +{ +public: + // construction/destruction + sound_asio() + : osd_module(OSD_SOUND_PROVIDER, "asio"), sound_module() + { + } + virtual ~sound_asio(void) { }; + + virtual int init(osd_options const &options); + virtual void exit(); + + virtual void update_audio_stream(bool is_throttled, const INT16 *buffer, int samples_this_frame); + virtual void set_mastervolume(int attenuation); + + virtual void set_machine(running_machine& machine) { m_machine = &machine; } +private: + void init_asio(void); + void calc_asio_freq(bool reset_calibration); + void log(void); + void copy_sample_data(asio_buf_t *asio_buf, const INT16 *buffer, int samples_this_frame, bool reset); + + asio_buf_t m_asio_buf; + running_machine* m_machine; + int m_audio_updates; + UINT32 m_rup; + UINT32 m_rdn; + int m_asio_latency; + float m_asio_avg_cpu; + double m_new_rate; + double m_asio_rate; // the rate the asio driver claims to use + double m_asio_rate_compensated; // the rate from the frequency calibration tool + bool m_asio_running; + bool m_asio_log; + std::ofstream m_logfile; + std::stringstream m_log; +}; + +#endif /* __SOUND_ASIO_H__ */ diff -Naur -x *.p* -x *.orig -x *.rej -x *.bak -x neogeo_noslot.c -x arcade.lst -x z80*.c -x hk68*.c --ignore-all-space mame170/src/osd/modules/sound/direct_sound.cpp mame170-asio/src/osd/modules/sound/direct_sound.cpp --- mame170/src/osd/modules/sound/direct_sound.cpp Wed Jan 27 09:15:10 2016 +++ mame170-asio/src/osd/modules/sound/direct_sound.cpp Wed Feb 3 18:42:41 2016 @@ -72,6 +72,7 @@ // sound_module virtual void update_audio_stream(bool is_throttled, INT16 const *buffer, int samples_this_frame) override; virtual void set_mastervolume(int attenuation) override; + virtual void set_machine(running_machine& machine) { } private: class buffer diff -Naur -x *.p* -x *.orig -x *.rej -x *.bak -x neogeo_noslot.c -x arcade.lst -x z80*.c -x hk68*.c --ignore-all-space mame170/src/osd/modules/sound/none.cpp mame170-asio/src/osd/modules/sound/none.cpp --- mame170/src/osd/modules/sound/none.cpp Wed Jan 27 09:15:10 2016 +++ mame170-asio/src/osd/modules/sound/none.cpp Wed Feb 3 18:42:41 2016 @@ -27,6 +27,7 @@ virtual void update_audio_stream(bool is_throttled, const INT16 *buffer, int samples_this_frame) override { } virtual void set_mastervolume(int attenuation) override { } + virtual void set_machine(running_machine& machine) { } }; diff -Naur -x *.p* -x *.orig -x *.rej -x *.bak -x neogeo_noslot.c -x arcade.lst -x z80*.c -x hk68*.c --ignore-all-space mame170/src/osd/modules/sound/sdl_sound.cpp mame170-asio/src/osd/modules/sound/sdl_sound.cpp --- mame170/src/osd/modules/sound/sdl_sound.cpp Wed Jan 27 09:15:10 2016 +++ mame170-asio/src/osd/modules/sound/sdl_sound.cpp Wed Feb 3 18:42:41 2016 @@ -64,6 +64,7 @@ virtual void update_audio_stream(bool is_throttled, const INT16 *buffer, int samples_this_frame) override; virtual void set_mastervolume(int attenuation) override; + virtual void set_machine(running_machine& machine) { } private: int lock_buffer(bool is_throttled, long offset, long size, void **buffer1, long *length1, void **buffer2, long *length2); diff -Naur -x *.p* -x *.orig -x *.rej -x *.bak -x neogeo_noslot.c -x arcade.lst -x z80*.c -x hk68*.c --ignore-all-space mame170/src/osd/modules/sound/sound_module.h mame170-asio/src/osd/modules/sound/sound_module.h --- mame170/src/osd/modules/sound/sound_module.h Wed Jan 27 09:15:10 2016 +++ mame170-asio/src/osd/modules/sound/sound_module.h Wed Feb 3 18:42:41 2016 @@ -26,6 +26,7 @@ virtual void update_audio_stream(bool is_throttled, const INT16 *buffer, int samples_this_frame) = 0; virtual void set_mastervolume(int attenuation) = 0; + virtual void set_machine(running_machine& machine) = 0; int sample_rate() { return m_sample_rate; } diff -Naur -x *.p* -x *.orig -x *.rej -x *.bak -x neogeo_noslot.c -x arcade.lst --ignore-all-space mame170/scripts/genie.lua mame170-asio/scripts/genie.lua --- mame170/scripts/genie.lua Wed Jan 27 09:14:58 2016 +++ mame170-asio/scripts/genie.lua Wed Feb 3 18:42:41 2016 @@ -1074,12 +1074,21 @@ "-static", } links { + "bassasio", "user32", "winmm", "advapi32", "shlwapi", "wsock32", } +configuration { "x32", "mingw*" } + libdirs { + MAME_DIR .. "bassasio/c", + } +configuration { "x64", "mingw*" } + libdirs { + MAME_DIR .. "bassasio/c/x64", + } configuration { "mingw-clang" } linkoptions { "-pthread", @@ -1095,6 +1104,7 @@ "_CRT_SECURE_NO_DEPRECATE", } links { + "bassasio", "user32", "winmm", "advapi32", diff -Naur -x *.p* -x *.orig -x *.rej -x *.bak -x neogeo_noslot.c -x arcade.lst --ignore-all-space mame170/scripts/src/osd/modules.lua mame170-asio/scripts/src/osd/modules.lua --- mame170/scripts/src/osd/modules.lua Wed Jan 27 09:14:58 2016 +++ mame170-asio/scripts/src/osd/modules.lua Wed Feb 3 18:42:41 2016 @@ -65,6 +65,7 @@ MAME_DIR .. "src/osd/modules/midi/none.cpp", MAME_DIR .. "src/osd/modules/sound/js_sound.cpp", MAME_DIR .. "src/osd/modules/sound/direct_sound.cpp", + MAME_DIR .. "src/osd/modules/sound/asio.cpp", MAME_DIR .. "src/osd/modules/sound/coreaudio_sound.cpp", MAME_DIR .. "src/osd/modules/sound/sdl_sound.cpp", MAME_DIR .. "src/osd/modules/sound/xaudio2_sound.cpp", @@ -74,6 +75,7 @@ if _OPTIONS["targetos"]=="windows" then includedirs { MAME_DIR .. "3rdparty/winpcap/Include", + MAME_DIR .. "bassasio/c", } end diff -Naur --ignore-all-space mame170/batool/batool.c mame170-asio/batool/batool.c --- mame170/batool/batool.c Thu Jan 1 01:00:00 1970 +++ mame170-asio/batool/batool.c Wed Feb 3 18:42:41 2016 @@ -0,0 +1,230 @@ +//license: GPL due to gsl_fit_linear +#include +#include +#include "bassasio.h" +#include +#include + +#define MAX_SAMPLES 500000 + +LARGE_INTEGER StartingTime, Frequency; + +double *x, *y; +volatile int idx = 0; + +volatile int n = 0; + +// ASIO function +DWORD CALLBACK AsioProc(BOOL input, DWORD channel, void *buffer, DWORD length, void *user) +{ + if (!StartingTime.QuadPart) + QueryPerformanceCounter(&StartingTime); + + LARGE_INTEGER EndingTime; + + QueryPerformanceCounter(&EndingTime); + + LARGE_INTEGER ElapsedMicroseconds; + ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart; + ElapsedMicroseconds.QuadPart *= 1000000; + ElapsedMicroseconds.QuadPart /= Frequency.QuadPart; + + n += length / 2 / 2; // two channels and length is in bytes + + if (idx < MAX_SAMPLES) { + y[idx] = (double) n; + x[idx] = (double) ElapsedMicroseconds.QuadPart; + } + + idx++; + + return 0; +} + +void CtrlHandler(DWORD fdwCtrlType) +{ + switch(fdwCtrlType) { + case CTRL_C_EVENT: + BASS_ASIO_Stop(); + BASS_ASIO_Free(); + exit(0); + default: + break; + } +} + +/* stripped gsl_fit_linear from GSL */ +int +fit_linear (const double *x, const double *y, + const size_t n, double *c1) +{ + double m_x = 0, m_y = 0, m_dx2 = 0, m_dxdy = 0; + + size_t i; + + for (i = 0; i < n; i++) { + m_x += (x[i] - m_x) / (i + 1.0); + m_y += (y[i] - m_y) / (i + 1.0); + } + + for (i = 0; i < n; i++) { + const double dx = x[i] - m_x; + const double dy = y[i] - m_y; + + m_dx2 += (dx * dx - m_dx2) / (i + 1.0); + m_dxdy += (dx * dy - m_dxdy) / (i + 1.0); + } + + *c1 = m_dxdy / m_dx2; + + return 0; +} + +// display error messages +void Error(const char *text) +{ + printf("Error(%d): %s\n", (int) BASS_ASIO_ErrorGetCode(), text); + BASS_ASIO_Free(); + exit(0); +} + +// taken from list.c +void list(unsigned char cp) +{ + BASS_ASIO_DEVICEINFO di; + int a; + for (a = 0; BASS_ASIO_GetDeviceInfo(a, &di); a++) { + printf("dev %d: %s\ndriver: %s\n", a, di.name, di.driver); + if (!BASS_ASIO_Init(a, BASS_ASIO_THREAD)) continue; + { + BASS_ASIO_CHANNELINFO i; + int b; + for (b = 0; BASS_ASIO_ChannelGetInfo(0, b, &i); b++) + printf("\tout %d: %s (group %d, format %d)\n", b, i.name, (int) i.group, (int) i.format); + if (cp) + BASS_ASIO_ControlPanel(); + } + BASS_ASIO_Free(); + } +} + +int args[4] = { 0, 0, 0, 0 }; + +int main(int argc, char **argv) +{ + int i; + + x = (double*) malloc(sizeof(double) * MAX_SAMPLES); + y = (double*) malloc(sizeof(double) * MAX_SAMPLES); + + StartingTime.QuadPart = 0; + Frequency.QuadPart = 0; + + SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE); + + if (argc == 1) { + usage: + list(0); + printf("\nusage: %s [device] [sample rate] [# decimals] | [--cp]\n", argv[0]); + exit(0); + } else { + if (!strcmp(argv[1], "--cp")) { + list(1); + exit(0); + } else if (argc >= 2) { + for (i = 0; i < argc - 1; i++) { + if (sscanf(argv[i + 1], "%d", &args[i]) != 1) { + goto usage; + } + } + if (!args[1]) + args[1] = 48000; + if (!args[2]) + args[2] = 2; + } else { + goto usage; + } + + list(0); + } + + if (!BASS_ASIO_Init(args[0], BASS_ASIO_THREAD | BASS_ASIO_JOINORDER)) + Error("Can't initialize ASIO device"); + + BASS_ASIO_ChannelEnable(0, 0, &AsioProc, NULL); // enable output channels + BASS_ASIO_ChannelJoin(FALSE, 1, 0); + BASS_ASIO_ChannelSetFormat(0, 0, BASS_ASIO_FORMAT_16BIT); // set the source format (16-bit) + + QueryPerformanceFrequency(&Frequency); + printf("\nQPC frequency is %I64d\n", Frequency.QuadPart); + + if (BASS_ASIO_CheckRate((double) args[1]) == BASS_ERROR_NOTAVAIL) + printf("requested sample rate %d is not supported by the driver\n", args[1]); + + BASS_ASIO_SetRate((double) args[1]); + + BASS_ASIO_INFO info; + BASS_ASIO_GetInfo(&info); + + if (!BASS_ASIO_Start(info.bufpref, 0)) + Error("Can't start ASIO device"); + + int bufsize = (UINT32) BASS_ASIO_GetLatency(0); + + printf("measuring device %s with latency %d and sample rate %.2f\n", info.name, bufsize, BASS_ASIO_GetRate()); + + int mult = 1; + + for (i = 0; i < args[2]; i++) + mult *= 10; + + char format[128]; + sprintf(format, "\rrate is currently determined to be %s.%df Hz", "%", args[2]); + + while (1) { + double c1, rate; + static double prev_rate; + static int it_count = 0; + static int c_count = 0; + + fit_linear(x, y, idx, &c1); + + rate = (c1 * 1000 * 1000 * mult); + rate = ceil(rate); + rate /= (float) mult; + + printf(format, rate); + + if (rate == prev_rate) + c_count++; + else + c_count = 0; + + if (c_count == 200) { + printf("\nrate has converged in %.1f seconds.\n", (double) it_count / 10.f); + break; + } else if (idx > MAX_SAMPLES) { + printf("\nrate did not converge after %.1f seconds\n", (double) it_count / 10.f); + break; + } else { + c_count++; + } + + prev_rate = rate; + + Sleep(100); + + it_count++; + } + + printf("press any key to continue\n"); + getch(); + + BASS_ASIO_Stop(); + BASS_ASIO_Free(); + + free((void*) x); + free((void*) y); + + return 0; +} diff -Naur --ignore-all-space mame170/batool/build.bat mame170-asio/batool/build.bat --- mame170/batool/build.bat Thu Jan 1 01:00:00 1970 +++ mame170-asio/batool/build.bat Wed Feb 3 18:42:41 2016 @@ -0,0 +1 @@ +gcc -O2 -I..\bassasio\c -L..\bassasio\c -s batool.c -lbassasio -o ..\batool.exe diff -Naur --ignore-all-space mame170/batool/build32msvc.bat mame170-asio/batool/build32msvc.bat --- mame170/batool/build32msvc.bat Thu Jan 1 01:00:00 1970 +++ mame170-asio/batool/build32msvc.bat Wed Feb 3 18:42:41 2016 @@ -0,0 +1,2 @@ +cl /O2 -I..\bassasio\c batool.c ..\bassasio\c\bassasio.lib /Fe..\batool.exe +del batool.obj diff -Naur --ignore-all-space mame170/batool/build64.bat mame170-asio/batool/build64.bat --- mame170/batool/build64.bat Thu Jan 1 01:00:00 1970 +++ mame170-asio/batool/build64.bat Wed Feb 3 18:42:41 2016 @@ -0,0 +1 @@ +gcc -Wall -O2 -I..\bassasio\c -L..\bassasio\c\x64 -s batool.c -lbassasio -o ..\batool64.exe diff -Naur --ignore-all-space mame170/batool/build64msvc.bat mame170-asio/batool/build64msvc.bat --- mame170/batool/build64msvc.bat Thu Jan 1 01:00:00 1970 +++ mame170-asio/batool/build64msvc.bat Wed Feb 3 18:42:41 2016 @@ -0,0 +1,2 @@ +cl /O2 -I..\bassasio\c batool.c ..\bassasio\c\x64\bassasio.lib /Fe..\batool64.exe +del batool.obj --- mame170/fix_bassasio_mingw.bat Mon Jun 29 23:06:21 2015 +++ mame170-asio/fix_bassasio_mingw.bat Wed Feb 3 18:42:41 2016 @@ -0,0 +1,13 @@ +rem thank you un4seen forums. +cd bassasio +cd c +gendef ..\bassasio.dll +move bassasio.lib bassasio.lib.disabled +dlltool -l bassasio.lib -d bassasio.def +del bassasio.def +cd x64 +gendef ..\..\x64\bassasio.dll +move bassasio.lib bassasio.lib.disabled +dlltool -l bassasio.lib -d bassasio.def +del bassasio.def +cd ..\..\..