move positions to osd interface
  add special-casing for LFE
  add reverb (currently too subtle, need to find out why)

vgm_visualizer: stop going OOB on the bitmap
This commit is contained in:
Olivier Galibert 2025-06-17 00:55:55 +02:00
parent 292b999b03
commit f0e6df8048
41 changed files with 3271 additions and 275 deletions

View File

@ -99,6 +99,8 @@ files {
MAME_DIR .. "src/frontend/mame/ui/audio_effect_eq.h",
MAME_DIR .. "src/frontend/mame/ui/audio_effect_filter.cpp",
MAME_DIR .. "src/frontend/mame/ui/audio_effect_filter.h",
MAME_DIR .. "src/frontend/mame/ui/audio_effect_reverb.cpp",
MAME_DIR .. "src/frontend/mame/ui/audio_effect_reverb.h",
MAME_DIR .. "src/frontend/mame/ui/auditmenu.cpp",
MAME_DIR .. "src/frontend/mame/ui/auditmenu.h",
MAME_DIR .. "src/frontend/mame/ui/barcode.cpp",

View File

@ -52,6 +52,7 @@ function osdmodulesbuild()
files {
MAME_DIR .. "src/osd/watchdog.cpp",
MAME_DIR .. "src/osd/watchdog.h",
MAME_DIR .. "src/osd/interface/audio.cpp",
MAME_DIR .. "src/osd/interface/audio.h",
MAME_DIR .. "src/osd/interface/inputcode.h",
MAME_DIR .. "src/osd/interface/inputdev.h",

View File

@ -739,7 +739,7 @@ void vgmviz_device::draw_waveform(bitmap_rgb32 &bitmap)
bitmap.pix(CHANNEL_HEIGHT + 1 + CHANNEL_CENTER, x) = MED_GRAY;
const float raw_l = m_audio_buf[1 - m_audio_fill_index][0][((int)m_history_length + 1 + x) % FFT_LENGTH];
const int sample_l = (int)((raw_l - 0.5f) * (CHANNEL_HEIGHT - 1));
const int sample_l = std::clamp((int)((raw_l - 0.5f) * (CHANNEL_HEIGHT - 1)), -CHANNEL_CENTER, CHANNEL_CENTER);
const int dy_l = (sample_l == 0) ? 0 : ((sample_l < 0) ? -1 : 1);
const int endy_l = CHANNEL_CENTER;
int y = endy_l - sample_l;
@ -750,7 +750,7 @@ void vgmviz_device::draw_waveform(bitmap_rgb32 &bitmap)
} while(y != endy_l);
const float raw_r = m_audio_buf[1 - m_audio_fill_index][1][((int)m_history_length + 1 + x) % FFT_LENGTH];
const int sample_r = (int)((raw_r - 0.5f) * (CHANNEL_HEIGHT - 1));
const int sample_r = std::clamp((int)((raw_r - 0.5f) * (CHANNEL_HEIGHT - 1)), -CHANNEL_CENTER, CHANNEL_CENTER);
const int dy_r = (sample_r == 0) ? 0 : ((sample_r < 0) ? -1 : 1);
const int endy_r = CHANNEL_HEIGHT + 1 + CHANNEL_CENTER;
y = endy_r - sample_r;

View File

@ -15,13 +15,13 @@ const char *const audio_effect::effect_names[COUNT] = {
"Equalizer"
};
audio_effect *audio_effect::create(int type, u32 sample_rate, audio_effect *def)
audio_effect *audio_effect::create(int type, speaker_device *speaker, u32 sample_rate, audio_effect *def)
{
switch(type) {
case FILTER: return new audio_effect_filter (sample_rate, def);
case COMPRESSOR: return new audio_effect_compressor(sample_rate, def);
case REVERB: return new audio_effect_reverb (sample_rate, def);
case EQ: return new audio_effect_eq (sample_rate, def);
case FILTER: return new audio_effect_filter (speaker, sample_rate, def);
case COMPRESSOR: return new audio_effect_compressor(speaker, sample_rate, def);
case REVERB: return new audio_effect_reverb (speaker, sample_rate, def);
case EQ: return new audio_effect_eq (speaker, sample_rate, def);
}
return nullptr;
}
@ -31,8 +31,7 @@ void audio_effect::copy(const emu::detail::output_buffer_flat<sample_t> &src, em
{
u32 samples = src.available_samples();
dest.prepare_space(samples);
u32 channels = src.channels();
for(u32 channel = 0; channel != channels; channel++) {
for(u32 channel = 0; channel != m_channels; channel++) {
const sample_t *srcd = src.ptrs(channel, 0);
sample_t *destd = dest.ptrw(channel, 0);
std::copy(srcd, srcd + samples, destd);

View File

@ -6,6 +6,8 @@
#ifndef MAME_EMU_AUDIO_EFFECTS_AEFFECT_H
#define MAME_EMU_AUDIO_EFFECTS_AEFFECT_H
#include "speaker.h"
class audio_effect
{
public:
@ -21,9 +23,9 @@ public:
static const char *const effect_names[COUNT];
static audio_effect *create(int type, u32 sample_rate, audio_effect *def = nullptr);
static audio_effect *create(int type, speaker_device *speaker, u32 sample_rate, audio_effect *def = nullptr);
audio_effect(u32 sample_rate, audio_effect *def) : m_default(def), m_sample_rate(sample_rate) {}
audio_effect(speaker_device *speaker, u32 sample_rate, audio_effect *def) : m_default(def), m_speaker(speaker), m_channels(speaker ? speaker->channels() : 0), m_sample_rate(sample_rate) {}
virtual ~audio_effect() = default;
void copy(const emu::detail::output_buffer_flat<sample_t> &src, emu::detail::output_buffer_flat<sample_t> &dest) const;
@ -37,7 +39,8 @@ public:
protected:
audio_effect *m_default;
u32 m_sample_rate;
speaker_device *m_speaker;
u32 m_channels, m_sample_rate;
};
#endif

View File

@ -7,8 +7,15 @@
#include "compressor.h"
#include "xmlfile.h"
audio_effect_compressor::audio_effect_compressor(u32 sample_rate, audio_effect *def) : audio_effect(sample_rate, def)
audio_effect_compressor::audio_effect_compressor(speaker_device *speaker, u32 sample_rate, audio_effect *def) :
audio_effect(speaker, sample_rate, def)
{
m_slewed_signal.resize(m_channels, -200);
m_gain_reduction.resize(m_channels, 0);
m_input_samples.resize(m_channels, 0);
m_output_samples.resize(m_channels, 0);
m_inertia_velocity.resize(m_channels, 0);
reset_mode();
reset_attack();
reset_release();
@ -362,23 +369,14 @@ void audio_effect_compressor::apply(const emu::detail::output_buffer_flat<sample
}
u32 samples = src.available_samples();
u32 channels = src.channels();
dest.prepare_space(samples);
if(m_slewed_signal.empty()) {
m_slewed_signal.resize(channels, -200);
m_gain_reduction.resize(channels, 0);
m_input_samples.resize(channels, 0);
m_output_samples.resize(channels, 0);
m_inertia_velocity.resize(channels, 0);
}
double attack_coefficient = exp(-1/(m_sample_rate * m_attack / 1000));
double release_coefficient = exp(-1/(m_sample_rate * m_release / 1000));
double m_inertia_decay_coefficient = 0.99 + m_inertia_decay * 0.01;
for(u32 sample = 0; sample != samples; sample ++) {
for(u32 channel = 0; channel != channels; channel ++) {
for(u32 channel = 0; channel != m_channels; channel ++) {
double input_db = value_to_db(std::abs(*src.ptrs(channel, sample))) + m_input_gain + std::abs(m_output_samples[channel]) * m_feedback;
m_output_samples[channel] = 0;
@ -432,11 +430,11 @@ void audio_effect_compressor::apply(const emu::detail::output_buffer_flat<sample
}
double max_gain = m_gain_reduction[0];
for(u32 channel = 1; channel < channels; channel++)
for(u32 channel = 1; channel != m_channels; channel++)
if(m_gain_reduction[channel] > max_gain)
max_gain = m_gain_reduction[channel];
for(u32 channel = 0; channel != channels; channel ++) {
for(u32 channel = 0; channel != m_channels; channel ++) {
m_gain_reduction[channel] = max_gain * m_channel_link + m_gain_reduction[channel] * (1 - m_channel_link);
double output_sample = db_to_value(m_input_samples[channel] - m_gain_reduction[channel]);
if(*src.ptrs(channel, sample) < 0)

View File

@ -11,7 +11,7 @@
class audio_effect_compressor : public audio_effect
{
public:
audio_effect_compressor(u32 sample_rate, audio_effect *def);
audio_effect_compressor(speaker_device *speaker, u32 sample_rate, audio_effect *def);
virtual ~audio_effect_compressor() = default;
virtual int type() const override { return COMPRESSOR; }

View File

@ -12,8 +12,11 @@
// [Zölzer 2011] "DAFX: Digital Audio Effects", Udo Zölzer, Second Edition, Wiley publishing, 2011 (Tables 2.3 and 2.4)
// [Zölzer 2008] "Digital Audio Signal Processing", Udo Zölzer, Second Edition, Wiley publishing, 2008 (Tables 5.3, 5.4 and 5.5)
audio_effect_eq::audio_effect_eq(u32 sample_rate, audio_effect *def) : audio_effect(sample_rate, def)
audio_effect_eq::audio_effect_eq(speaker_device *speaker, u32 sample_rate, audio_effect *def) :
audio_effect(speaker, sample_rate, def)
{
m_history.resize(m_channels);
// Minimal init to avoid using uninitialized values when reset_*
// recomputes filters
@ -322,11 +325,8 @@ void audio_effect_eq::apply(const emu::detail::output_buffer_flat<sample_t> &src
u32 samples = src.available_samples();
dest.prepare_space(samples);
u32 channels = src.channels();
if(m_history.empty())
m_history.resize(channels);
for(u32 channel = 0; channel != channels; channel++) {
for(u32 channel = 0; channel != m_channels; channel++) {
const sample_t *srcd = src.ptrs(channel, 0);
sample_t *destd = dest.ptrw(channel, 0);
for(u32 sample = 0; sample != samples; sample++) {

View File

@ -13,7 +13,7 @@ class audio_effect_eq : public audio_effect
public:
enum { BANDS = 5 };
audio_effect_eq(u32 sample_rate, audio_effect *def);
audio_effect_eq(speaker_device *speaker, u32 sample_rate, audio_effect *def);
virtual ~audio_effect_eq() = default;
virtual int type() const override { return EQ; }

View File

@ -13,8 +13,11 @@
// [Zölzer 2011] "DAFX: Digital Audio Effects", Udo Zölzer, Second Edition, Wiley publishing, 2011 (Table 2.2)
audio_effect_filter::audio_effect_filter(u32 sample_rate, audio_effect *def) : audio_effect(sample_rate, def)
audio_effect_filter::audio_effect_filter(speaker_device *speaker, u32 sample_rate, audio_effect *def) :
audio_effect(speaker, sample_rate, def)
{
m_history.resize(m_channels);
// Minimal init to avoid using uninitialized values when reset_*
// recomputes filters
m_fl = m_fh = 1000;
@ -159,11 +162,8 @@ void audio_effect_filter::apply(const emu::detail::output_buffer_flat<sample_t>
u32 samples = src.available_samples();
dest.prepare_space(samples);
u32 channels = src.channels();
if(m_history.empty())
m_history.resize(channels);
for(u32 channel = 0; channel != channels; channel++) {
for(u32 channel = 0; channel != m_channels; channel++) {
const sample_t *srcd = src.ptrs(channel, 0);
sample_t *destd = dest.ptrw(channel, 0);
for(u32 sample = 0; sample != samples; sample++) {

View File

@ -11,7 +11,7 @@
class audio_effect_filter : public audio_effect
{
public:
audio_effect_filter(u32 sample_rate, audio_effect *def);
audio_effect_filter(speaker_device *speaker, u32 sample_rate, audio_effect *def);
virtual ~audio_effect_filter() = default;
virtual int type() const override { return FILTER; }

File diff suppressed because it is too large Load Diff

View File

@ -8,10 +8,12 @@
#include "aeffect.h"
#include <random>
class audio_effect_reverb : public audio_effect
{
public:
audio_effect_reverb(u32 sample_rate, audio_effect *def);
audio_effect_reverb(speaker_device *speaker, u32 sample_rate, audio_effect *def);
virtual ~audio_effect_reverb() = default;
virtual int type() const override { return REVERB; }
@ -19,6 +21,420 @@ public:
virtual void config_load(util::xml::data_node const *ef_node) override;
virtual void config_save(util::xml::data_node *ef_node) const override;
virtual void default_changed() override;
void set_mode(u32 mode);
void set_early_tap_setup(u32 index);
void set_early_damping(double cutoff);
void set_stereo_width(double width);
void set_early_room_size(double size);
void set_late_room_size(double size);
void set_late_spin(double speed);
void set_late_wander(double wander);
void set_late_diffusion(double value);
void set_late_damping(double cutoff);
void set_late_predelay(double delay);
void set_late_global_decay(float value);
void set_dry_level(double level);
void set_early_level(double level);
void set_late_level(double level);
void set_early_to_late_level(double level);
u32 mode() const { return m_mode; }
u32 early_tap_setup() const { return m_early_tap_setup; }
double early_damping() const { return m_early_damping; }
double stereo_width() const { return m_stereo_width; }
double early_room_size() const { return m_early_room_size; }
double late_room_size() const { return m_late_room_size; }
double late_spin() const { return m_late_spin; }
double late_wander() const { return m_late_wander; }
double late_diffusion() const { return m_late_diffusion; }
double late_damping() const { return m_late_damping; }
double late_predelay() const { return m_late_predelay; }
float late_global_decay() const { return m_late_global_decay; }
double dry_level() const { return m_dry_level; }
double early_level() const { return m_early_level; }
double late_level() const { return m_late_level; }
double early_to_late_level() const { return m_early_to_late_level; }
bool isset_mode() const { return m_isset_mode; }
bool isset_early_tap_setup() const { return m_isset_early_tap_setup; }
bool isset_early_damping() const { return m_isset_early_damping; }
bool isset_stereo_width() const { return m_isset_stereo_width; }
bool isset_early_room_size() const { return m_isset_early_room_size; }
bool isset_late_room_size() const { return m_isset_late_room_size; }
bool isset_late_spin() const { return m_isset_late_spin; }
bool isset_late_wander() const { return m_isset_late_wander; }
bool isset_late_diffusion() const { return m_isset_late_diffusion; }
bool isset_late_damping() const { return m_isset_late_damping; }
bool isset_late_predelay() const { return m_isset_late_predelay; }
bool isset_late_global_decay() const { return m_isset_late_global_decay; }
bool isset_dry_level() const { return m_isset_dry_level; }
bool isset_early_level() const { return m_isset_early_level; }
bool isset_late_level() const { return m_isset_late_level; }
bool isset_early_to_late_level() const { return m_isset_early_to_late_level; }
void reset_mode();
void reset_early_tap_setup();
void reset_early_damping();
void reset_stereo_width();
void reset_early_room_size();
void reset_late_room_size();
void reset_late_spin();
void reset_late_wander();
void reset_late_diffusion();
void reset_late_damping();
void reset_late_predelay();
void reset_late_global_decay();
void reset_dry_level();
void reset_early_level();
void reset_late_level();
void reset_early_to_late_level();
static u32 preset_count();
static const char *preset_name(u32 id);
static u32 early_tap_setup_count();
static const char *early_tap_setup_name(u32 id);
void load_preset(u32 id);
private:
struct preset {
const char *name;
u32 early_tap_setup;
double early_damping;
double stereo_width;
double early_room_size;
double late_room_size;
double late_spin;
double late_wander;
double late_diffusion;
double late_damping;
double late_predelay;
float late_global_decay;
double dry_level;
double early_level;
double late_level;
double early_to_late_level;
};
static const preset presets[];
enum { INPUT_DIFFUSION_ALLPASS = 10, CROSS_DIFFUSION_ALLPASS = 4 };
struct early_reverb_tap_map {
const char *name;
u32 m_count[2];
float m_delay[2][18];
float m_gain[2][18];
};
static const early_reverb_tap_map tap_maps[15];
struct delay_buffer {
enum { D_MASK = 8191 };
sample_t m_samples[D_MASK+1];
u32 m_index;
void clear();
void push(sample_t value);
sample_t get(u32 dist) const;
sample_t geti(float dist) const; // Get with interpolation
delay_buffer() { clear(); }
};
struct delay {
delay_buffer m_delay_buffer;
std::vector<u32> m_taps;
void clear();
void set_tap(u32 tap, u32 dist);
void push(sample_t value);
sample_t get(u32 tap) const;
sample_t process(sample_t value) { push(value); return get(0); }
delay() { clear(); }
};
struct iir1h {
sample_t m_y1;
void clear();
iir1h() { clear(); }
};
struct iir1 {
float m_a2, m_b1, m_b2;
sample_t process(iir1h &h, sample_t x0);
void prepare_lpf(double cutoff, u32 sample_rate);
void prepare_hpf(double cutoff, u32 sample_rate);
};
struct iir2h {
sample_t m_x1, m_x2, m_y1, m_y2;
void clear();
iir2h() { clear(); }
};
struct iir2 {
float m_a1, m_a2, m_b0, m_b1, m_b2;
sample_t process(iir2h &h, sample_t x0);
void prepare_lpf(double cutoff, double bw, u32 sample_rate);
void prepare_apf(double cutoff, double bw, u32 sample_rate);
};
struct dccuth {
float m_y1, m_y2;
void clear();
dccuth() { clear(); }
};
struct dccut {
float m_gain;
sample_t process(dccuth &h, sample_t x0);
void prepare(double cutoff, u32 sample_rate);
};
struct pink {
enum { SIZE = 1 << 15 };
std::mt19937 m_rng;
std::uniform_real_distribution<sample_t> m_dis;
sample_t m_buffer[SIZE];
u32 m_index;
void clear();
pink() : m_rng(std::random_device()()), m_dis(-1, 1) { clear(); }
sample_t process();
};
struct lfo {
float m_c, m_s, m_rc, m_rs;
u32 m_count;
void clear();
lfo() : m_rc(1), m_rs(0) { clear(); }
void prepare(double speed, u32 sample_rate);
float process();
};
struct allpass {
delay_buffer m_delay_buffer;
float m_gain;
u32 m_delay;
void clear();
sample_t process(sample_t input);
void set_gain(float base);
void set_delay(u32 base);
allpass() { clear(); }
};
struct allpass_m {
delay_buffer m_delay_buffer;
float m_base_gain;
float m_base_delay, m_mod_delay;
void clear();
sample_t process(sample_t input, float delay_mod, float gain_mod);
void set_gain(float base);
void set_delay(float base, float mod);
allpass_m() { clear(); }
};
struct allpass_md {
delay_buffer m_delay_buffer;
float m_base_gain, m_decay;
float m_base_delay, m_mod_delay;
void clear();
sample_t process(sample_t input, float delay_mod, float gain_mod);
void set_gain(float base);
void set_delay(float base, float mod);
void set_decay(float base);
allpass_md() { clear(); }
};
struct allpass2 {
delay_buffer m_delay_buffer_1, m_delay_buffer_2;
float m_gain_1, m_gain_2, m_decay_1, m_decay_2;
u32 m_delay_1, m_delay_2;
std::vector<u32> m_taps_1, m_taps_2;
void clear();
sample_t process(sample_t input);
void set_gain_1(float base);
void set_gain_2(float base);
void set_delays(u32 base_1, u32 base_2);
void set_decay_1(float base);
void set_decay_2(float base);
void set_tap_1(u32 tap, u32 dist);
void set_tap_2(u32 tap, u32 dist);
sample_t get_1(u32 tap) const;
sample_t get_2(u32 tap) const;
allpass2() { clear(); }
};
struct allpass3m {
delay_buffer m_delay_buffer_1, m_delay_buffer_2, m_delay_buffer_3;
float m_gain_1, m_gain_2, m_gain_3, m_decay_1, m_decay_2, m_decay_3;
u32 m_base_delay_1, m_mod_delay_1, m_delay_2, m_delay_3;
std::vector<u32> m_taps_1, m_taps_2, m_taps_3;
void clear();
sample_t process(sample_t input, float delay_mod);
void set_gain_1(float base);
void set_gain_2(float base);
void set_gain_3(float base);
void set_delays(u32 base_1, u32 mod_1, u32 base_2, u32 base_3);
void set_decay_1(float base);
void set_decay_2(float base);
void set_decay_3(float base);
void set_tap_1(u32 tap, u32 dist);
void set_tap_2(u32 tap, u32 dist);
void set_tap_3(u32 tap, u32 dist);
sample_t get_1(u32 tap) const;
sample_t get_2(u32 tap) const;
sample_t get_3(u32 tap) const;
allpass3m() { clear(); }
};
struct comb {
delay_buffer m_delay_buffer;
sample_t m_filter_history;
u32 m_size;
void clear();
sample_t process(sample_t input, float feedback);
void set_size(u32 size);
comb() { clear(); }
};
enum ch_type_t { T_MONO, T_LEFT, T_RIGHT };
u32 m_mode;
u32 m_early_tap_setup;
double m_early_damping;
double m_stereo_width;
double m_early_room_size;
double m_late_room_size;
double m_late_spin;
double m_late_wander;
double m_late_diffusion;
double m_late_damping;
double m_late_predelay;
float m_late_global_decay;
double m_dry_level;
double m_early_level;
double m_late_level;
double m_early_to_late_level;
bool m_isset_mode;
bool m_isset_early_tap_setup;
bool m_isset_early_damping;
bool m_isset_stereo_width;
bool m_isset_early_room_size;
bool m_isset_late_room_size;
bool m_isset_late_spin;
bool m_isset_late_wander;
bool m_isset_late_diffusion;
bool m_isset_late_damping;
bool m_isset_late_predelay;
bool m_isset_late_global_decay;
bool m_isset_dry_level;
bool m_isset_early_level;
bool m_isset_late_level;
bool m_isset_early_to_late_level;
std::vector<ch_type_t> m_ch_type;
std::vector<int> m_ch_pair;
iir1 m_early_lpf, m_early_hpf;
iir2 m_early_diffusion_allpass, m_early_cross_allpass;
dccut m_late_dccut;
pink m_late_noise;
lfo m_late_lfo1, m_late_lfo2;
iir1 m_late_lfo1_lpf, m_late_lfo2_lpf, m_late_input_damping, m_late_damping_1;
iir2 m_late_bass, m_late_damping_2, m_late_output_lpf;
std::vector<iir1h> m_early_lpf_h, m_early_hpf_h;
std::vector<iir2h> m_early_diffusion_allpass_h, m_early_cross_allpass_h;
std::vector<dccuth> m_late_dccut_h;
iir1h m_late_lfo1_lpf_h, m_late_lfo2_lpf_h;
std::vector<delay_buffer> m_early_delays;
std::vector<delay_buffer> m_early_xdelays;
std::vector<std::vector<allpass_m>> m_late_input_diffusion;
std::vector<std::vector<allpass>> m_late_cross_diffusion;
std::vector<iir1h> m_late_input_damping_h, m_late_damping_1_h;
std::vector<iir2h> m_late_bass_h, m_late_damping_2_h, m_late_output_lpf_h;
std::vector<allpass_md> m_late_step_1, m_late_step_3;
std::vector<allpass2> m_late_step_5;
std::vector<allpass3m> m_late_step_7;
std::vector<delay> m_late_step_2, m_late_step_4, m_late_step_6, m_late_step_8;
std::vector<comb> m_late_comb;
std::vector<delay> m_late_final_delay;
std::vector<sample_t> m_early_in, m_early_wet, m_early_out;
std::vector<sample_t> m_late_in, m_late_diff, m_late_cross, m_late_cross2, m_late_pre_out, m_late_out;
float m_wet1, m_wet2;
float m_early_room_size_ratio;
float m_late_room_size_ratio;
float m_late_wander_actual;
float m_late_modulation_noise_1, m_late_modulation_noise_2;
float m_late_crossfeed;
float m_late_decay_0, m_late_decay_1, m_late_decay_2, m_late_decay_3, m_late_decay_f;
float m_late_loop_decay, m_late_bass_boost;
float m_actual_dry_level, m_actual_early_level, m_actual_late_level, m_actual_early_to_late_level;
u32 m_early_tap_dists[2][18];
u32 m_early_xdelays_dist;
const preset *m_default_preset;
void commit_early_tap_setup();
void commit_early_damping();
void commit_stereo_width();
void commit_early_room_size();
void commit_late_room_size();
void commit_late_decay();
void commit_late_spin();
void commit_late_wander();
void commit_late_diffusion();
void commit_late_damping();
void commit_late_predelay();
void commit_dry_level();
void commit_early_level();
void commit_late_level();
void commit_early_to_late_level();
void set_early_hpf(double cutoff);
void set_early_diffusion_ap(double cutoff, double bw);
void set_early_cross_ap(double cutoff, double bw);
void set_early_multichannel_delay(double delay);
void set_late_dccut(double cutoff);
void set_late_spin_limit_1(double cutoff);
void set_late_spin_limit_2(double cutoff);
void set_late_modulation_noise_1(double mod);
void set_late_modulation_noise_2(double mod);
void set_late_diffusion_1(double value);
void set_late_diffusion_2(double value);
void set_late_diffusion_3(double value);
void set_late_diffusion_4(double value);
void set_late_input_damping(double cutoff);
void set_late_damping_2(double cutoff, double bw);
void set_late_decay_0(float value);
void set_late_decay_1(float value);
void set_late_decay_2(float value);
void set_late_decay_3(float value);
void set_late_decay_f(float value);
void set_late_bass_allpass(double cutoff, double bw);
void set_late_spin_to_wander(double value);
static const preset *find_preset(std::string name);
static bool is_prime(u32 value);
static u32 find_prime(u32 v);
};
#endif

View File

@ -308,7 +308,8 @@ sound_stream::sound_stream(device_t &device, u32 inputs, u32 outputs, u32 sample
m_sync_timer(nullptr),
m_callback(std::move(callback))
{
sound_assert(outputs > 0 || inputs > 0);
if(inputs == 0 && outputs == 0)
fatalerror("Device %s requiring to create a stream without inputs or outputs\n", device.tag());
// create a name
m_name = m_device.name();
@ -854,7 +855,7 @@ void sound_manager::after_devices_init()
// Create the default effect chain
for(u32 effect = 0; effect != audio_effect::COUNT; effect++)
m_default_effects.emplace_back(audio_effect::create(effect, machine().sample_rate(), nullptr));
m_default_effects.emplace_back(audio_effect::create(effect, nullptr, machine().sample_rate(), nullptr));
// Inventory speakers and microphones
m_outputs_count = 0;
@ -862,7 +863,7 @@ void sound_manager::after_devices_init()
dev.set_id(m_speakers.size());
m_speakers.emplace_back(speaker_info(dev, machine().sample_rate(), m_outputs_count));
for(u32 effect = 0; effect != audio_effect::COUNT; effect++)
m_speakers.back().m_effects[effect].m_effect.reset(audio_effect::create(effect, machine().sample_rate(), m_default_effects[effect].get()));
m_speakers.back().m_effects[effect].m_effect.reset(audio_effect::create(effect, &dev, machine().sample_rate(), m_default_effects[effect].get()));
m_outputs_count += dev.inputs();
}
@ -1980,17 +1981,24 @@ void sound_manager::generate_mapping()
// Find where to map a sound_io channel into a node's channels depending on their positions
std::vector<u32> sound_manager::find_channel_mapping(const std::array<double, 3> &position, const osd::audio_info::node_info *node)
std::vector<u32> sound_manager::find_channel_mapping(const osd::channel_position &pos, const osd::audio_info::node_info *node)
{
std::vector<u32> result;
if(position[0] == 0 && position[1] == 0 && position[2] == 0)
if(pos.is_lfe()) {
for(u32 port = 0; port != node->m_port_positions.size(); port++)
if(node->m_port_positions[port].is_lfe())
result.push_back(port);
return result;
}
if(pos.is_onreq())
return result;
double best_dist = -1;
for(u32 port = 0; port != node->m_port_positions.size(); port++)
if(sound_io_device::mapping_allowed(node->m_port_positions[port])) {
double dx = position[0] - node->m_port_positions[port][0];
double dy = position[1] - node->m_port_positions[port][1];
double dz = position[2] - node->m_port_positions[port][2];
if(!node->m_port_positions[port].is_onreq() && !node->m_port_positions[port].is_lfe()) {
double dx = pos.m_x - node->m_port_positions[port].m_z;
double dy = pos.m_y - node->m_port_positions[port].m_y;
double dz = pos.m_z - node->m_port_positions[port].m_z;
double dist = dx*dx + dy*dy + dz*dz;
if(best_dist == -1 || dist < best_dist) {
best_dist = dist;
@ -2496,12 +2504,10 @@ void sound_manager::mapping_update()
if(port_count < node.m_sources)
port_count = node.m_sources;
for(uint32_t port = 0; port != port_count; port++)
LOG_OUTPUT_FUNC(" %s %s [%g %g %g]\n",
(port < node.m_sinks) ? ((port < node.m_sources) ? "<>" : ">") : "<",
node.m_port_names[port],
node.m_port_positions[port][0],
node.m_port_positions[port][1],
node.m_port_positions[port][2]);
LOG_OUTPUT_FUNC(" %s %s [%s]\n",
port < node.m_sinks ? port < node.m_sources ? "<>" : ">" : "<",
node.m_port_names[port].c_str(),
node.m_port_positions[port].name());
}
LOG_OUTPUT_FUNC("- streams:\n");
for(const auto &stream : m_osd_info.m_streams) {

View File

@ -50,8 +50,8 @@
By default, the inputs will have been resampled to match the output
sample rate, unless otherwise specified.
SOUND_DISABLE_THREADING if to be defined when your environment does
not support threads (e.g. emscripten). The effects suddendly become
SOUND_DISABLE_THREADING is to be defined when your environment does
not support threads (e.g. emscripten). The effects suddenly become
costly then though.
***************************************************************************/
@ -84,23 +84,6 @@ constexpr u32 SAMPLE_RATE_INPUT_ADAPTIVE = 0xffffffff;
constexpr u32 SAMPLE_RATE_OUTPUT_ADAPTIVE = 0xfffffffe;
constexpr u32 SAMPLE_RATE_ADAPTIVE = 0xfffffffd;
//**************************************************************************
// DEBUGGING
//**************************************************************************
// turn this on to enable aggressive assertions and other checks
#ifdef MAME_DEBUG
#define SOUND_DEBUG (1)
#else
#define SOUND_DEBUG (1)
#endif
// if SOUND_DEBUG is on, make assertions fire regardless of MAME_DEBUG
#if (SOUND_DEBUG)
#define sound_assert(x) do { if (!(x)) { osd_printf_error("sound_assert: " #x "\n"); osd_break_into_debugger("sound_assert: " #x "\n"); } } while (0)
#else
#define sound_assert assert
#endif
using stream_update_delegate = delegate<void (sound_stream &stream)>;
class audio_effect;
@ -599,7 +582,7 @@ private:
void update(s32);
// handle mixing mapping update if needed
static std::vector<u32> find_channel_mapping(const std::array<double, 3> &position, const osd::audio_info::node_info *node);
static std::vector<u32> find_channel_mapping(const osd::channel_position &pos, const osd::audio_info::node_info *node);
void startup_cleanups();
void streams_update();
template<bool is_output, typename S> void apply_osd_changes(std::vector<S> &streams);

View File

@ -18,37 +18,21 @@
DEFINE_DEVICE_TYPE(SPEAKER, speaker_device, "speaker", "Speaker")
DEFINE_DEVICE_TYPE(MICROPHONE, microphone_device, "microphone", "Microphone")
const sound_io_device::position_name_mapping sound_io_device::position_name_mappings[] = {
{ 0.0, 0.0, 1.0, "Front center" },
{ -0.2, 0.0, 1.0, "Front left" },
{ 0.0, -0.5, 1.0, "Front floor" },
{ 0.2, 0.0, 1.0, "Front right" },
{ 0.0, 0.0, -0.5, "Rear center" },
{ -0.2, 0.0, -0.5, "Rear left" },
{ 0.2, 0.0, -0.5, "Read right" },
{ 0.0, 0.0, -0.1, "Headrest center" },
{ -0.1, 0.0, -0.1, "Headrest left" },
{ 0.1, 0.0, -0.1, "Headrest right" },
{ 0.0, -0.5, 0.0, "Seat" },
{ 0.0, -0.2, 0.1, "Backrest" },
{ }
};
std::string sound_io_device::get_position_name(u32 channel) const
{
for(unsigned int i = 0; position_name_mappings[i].m_name; i++)
if(m_positions[channel][0] == position_name_mappings[i].m_x && m_positions[channel][1] == position_name_mappings[i].m_y && m_positions[channel][2] == position_name_mappings[i].m_z)
return position_name_mappings[i].m_name;
return util::string_format("#%d", channel);
}
sound_io_device &sound_io_device::set_position(u32 channel, double x, double y, double z)
{
if(channel >= m_positions.size())
fatalerror("%s: Requested channel %d on %d channel device\n", tag(), channel, m_positions.size());
m_positions[channel][0] = x;
m_positions[channel][1] = y;
m_positions[channel][2] = z;
m_positions[channel].m_x = x;
m_positions[channel].m_y = y;
m_positions[channel].m_z = z;
return *this;
}
sound_io_device &sound_io_device::set_position(u32 channel, const osd::channel_position &pos)
{
if(channel >= m_positions.size())
fatalerror("%s: Requested channel %d on %d channel device\n", tag(), channel, m_positions.size());
m_positions[channel] = pos;
return *this;
}

View File

@ -41,30 +41,32 @@ DECLARE_DEVICE_TYPE(MICROPHONE, microphone_device)
class sound_io_device : public device_t, public device_sound_interface
{
public:
virtual ~sound_io_device();
// configuration helpers
sound_io_device &set_position(u32 channel, double x, double y, double z);
sound_io_device &front_center(u32 channel = 0) { return set_position(channel, 0.0, 0.0, 1.0); }
sound_io_device &front_left(u32 channel = 0) { return set_position(channel, -0.2, 0.0, 1.0); }
sound_io_device &front_floor(u32 channel = 0) { return set_position(channel, 0.0, -0.5, 1.0); }
sound_io_device &front_right(u32 channel = 0) { return set_position(channel, 0.2, 0.0, 1.0); }
sound_io_device &rear_center(u32 channel = 0) { return set_position(channel, 0.0, 0.0, -0.5); }
sound_io_device &rear_left(u32 channel = 0) { return set_position(channel, -0.2, 0.0, -0.5); }
sound_io_device &rear_right(u32 channel = 0) { return set_position(channel, 0.2, 0.0, -0.5); }
sound_io_device &headrest_center(u32 channel = 0) { return set_position(channel, 0.0, 0.0, -0.1); }
sound_io_device &headrest_left(u32 channel = 0) { return set_position(channel, -0.1, 0.0, -0.1); }
sound_io_device &headrest_right(u32 channel = 0) { return set_position(channel, 0.1, 0.0, -0.1); }
sound_io_device &seat(u32 channel = 0) { return set_position(channel, 0.0, -0.5, 0.0); }
sound_io_device &backrest(u32 channel = 0) { return set_position(channel, 0.0, -0.2, 0.1); }
sound_io_device &unknown(u32 channel = 0) { return set_position(channel, 0.0, 0.0, 0.0); }
sound_io_device &map_on_request_only(u32 channel = 0) { return set_position(channel, 0.0, 0.0, 10.0); }
sound_io_device &set_position(u32 channel, const osd::channel_position &pos);
sound_io_device &front_center(u32 channel = 0) { return set_position(channel, osd::channel_position::FC); }
sound_io_device &front_left(u32 channel = 0) { return set_position(channel, osd::channel_position::FL); }
sound_io_device &front_right(u32 channel = 0) { return set_position(channel, osd::channel_position::FR); }
sound_io_device &rear_center(u32 channel = 0) { return set_position(channel, osd::channel_position::RC); }
sound_io_device &rear_left(u32 channel = 0) { return set_position(channel, osd::channel_position::RL); }
sound_io_device &rear_right(u32 channel = 0) { return set_position(channel, osd::channel_position::RR); }
sound_io_device &headrest_center(u32 channel = 0) { return set_position(channel, osd::channel_position::HC); }
sound_io_device &headrest_left(u32 channel = 0) { return set_position(channel, osd::channel_position::HL); }
sound_io_device &headrest_right(u32 channel = 0) { return set_position(channel, osd::channel_position::RC); }
sound_io_device &backrest(u32 channel = 0) { return set_position(channel, osd::channel_position::BACKREST); }
sound_io_device &unknown(u32 channel = 0) { return set_position(channel, osd::channel_position::UNKNOWN); }
sound_io_device &map_on_request_only(u32 channel = 0) { return set_position(channel, osd::channel_position::ONREQ); }
sound_io_device &lfe(u32 channel = 0) { return set_position(channel, osd::channel_position::LFE); }
sound_io_device &front() { return front_left(0).front_right(1); }
sound_io_device &rear() { return rear_left(0).rear_right(1); }
sound_io_device &corners() { return front_left(0).front_right(1).rear_left(2).rear_right(3); }
int channels() const { return m_positions.size(); }
std::array<double, 3> get_position(u32 channel) const { return m_positions[channel]; }
std::string get_position_name(u32 channel) const;
const osd::channel_position &get_position(u32 channel) const { return m_positions[channel]; }
virtual bool is_output() const = 0;
void set_id(int id) { m_id = id; }
@ -72,20 +74,9 @@ public:
sound_stream *stream() const { return m_stream; }
static bool mapping_allowed(const std::array<double, 3> &position) {
return position[0] != 0 || position[1] != 0 || position[2] != 10.0;
}
protected:
struct position_name_mapping {
double m_x, m_y, m_z;
const char *m_name;
};
static const position_name_mapping position_name_mappings[];
// configuration state
std::vector<std::array<double, 3>> m_positions;
std::vector<osd::channel_position> m_positions;
sound_stream *m_stream;
int m_id;

View File

@ -1696,9 +1696,9 @@ void lua_engine::initialize()
{
auto pos = iodev->get_position(channel);
auto table = sol().create_table();
table[1] = pos[0];
table[2] = pos[1];
table[3] = pos[2];
table[1] = pos.m_x;
table[2] = pos.m_y;
table[3] = pos.m_z;
pos_table[channel+1] = table;
}
return pos_table;
@ -1710,7 +1710,7 @@ void lua_engine::initialize()
auto *iodev = dynamic_cast<sound_io_device *>(&dev.device());
if (iodev)
for(int channel=0; channel != iodev->channels(); channel++)
pos_table[channel+1] = iodev->get_position_name(channel);
pos_table[channel+1] = iodev->get_position(channel).name();
return pos_table;
});

View File

@ -0,0 +1,655 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert
/*********************************************************************
ui/audio_effect_reverb.cpp
Reverb configuration
*********************************************************************/
#include "emu.h"
#include "ui/audio_effect_reverb.h"
#include "audio_effects/aeffect.h"
#include "audio_effects/reverb.h"
#include "ui/ui.h"
namespace ui {
menu_audio_effect_reverb::menu_audio_effect_reverb(mame_ui_manager &mui, render_container &container, u16 chain, u16 entry, audio_effect *effect)
: menu(mui, container)
{
m_chain = chain;
m_entry = entry;
m_preset = 0;
m_effect = static_cast<audio_effect_reverb *>(effect);
set_heading(util::string_format("%s #%u", chain == 0xffff ? _("Default") : machine().sound().effect_chain_tag(chain), entry+1));
set_process_flags(PROCESS_LR_REPEAT | PROCESS_LR_ALWAYS);
}
menu_audio_effect_reverb::~menu_audio_effect_reverb()
{
}
bool menu_audio_effect_reverb::handle(event const *ev)
{
if(!ev)
return false;
bool alt_pressed = machine().input().code_pressed(KEYCODE_LALT) || machine().input().code_pressed(KEYCODE_RALT);
bool ctrl_pressed = machine().input().code_pressed(KEYCODE_LCONTROL) || machine().input().code_pressed(KEYCODE_RCONTROL);
bool shift_pressed = machine().input().code_pressed(KEYCODE_LSHIFT) || machine().input().code_pressed(KEYCODE_RSHIFT);
switch(ev->iptkey) {
case IPT_UI_SELECT:
if(uintptr_t(ev->itemref) == PRESET) {
m_effect->load_preset(m_preset);
reset(reset_options::REMEMBER_POSITION);
return true;
}
break;
case IPT_UI_LEFT: {
switch(uintptr_t(ev->itemref)) {
case MODE:
m_effect->set_mode(0);
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case PRESET:
if(m_preset != 0)
m_preset --;
reset(reset_options::REMEMBER_POSITION);
return true;
case DRYL:
m_effect->set_dry_level(change_percent(m_effect->dry_level(), false, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case EL:
m_effect->set_early_level(change_percent(m_effect->early_level(), false, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LL:
m_effect->set_late_level(change_percent(m_effect->late_level(), false, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case E2LL:
m_effect->set_early_to_late_level(change_percent(m_effect->early_to_late_level(), false, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case ERS:
m_effect->set_early_room_size(change_percent(m_effect->early_room_size(), false, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LRS:
m_effect->set_late_room_size(change_percent(m_effect->late_room_size(), false, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case SW:
m_effect->set_stereo_width(change_percent(m_effect->stereo_width(), false, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LDIFF:
m_effect->set_late_diffusion(change_percent(m_effect->late_diffusion(), false, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LWANDER:
m_effect->set_late_wander(change_percent(m_effect->late_wander(), false, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case EDAMP:
m_effect->set_early_damping(change_freq(m_effect->early_damping(), false, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LDAMP:
m_effect->set_late_damping(change_freq(m_effect->late_damping(), false, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LPDELAY:
m_effect->set_late_predelay(change_ms(m_effect->late_predelay(), false, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LDECAY:
m_effect->set_late_global_decay(change_decay(m_effect->late_global_decay(), false, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LSPIN:
m_effect->set_late_spin(change_spin(m_effect->late_spin(), false, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case ETAP:
if(m_effect->early_tap_setup() != 0) {
m_effect->set_early_tap_setup(m_effect->early_tap_setup() - 1);
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
}
return true;
}
break;
}
case IPT_UI_RIGHT: {
switch(uintptr_t(ev->itemref)) {
case MODE:
m_effect->set_mode(1);
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case PRESET:
if(m_preset != audio_effect_reverb::preset_count() - 1)
m_preset ++;
reset(reset_options::REMEMBER_POSITION);
return true;
case DRYL:
m_effect->set_dry_level(change_percent(m_effect->dry_level(), true, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case EL:
m_effect->set_early_level(change_percent(m_effect->early_level(), true, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LL:
m_effect->set_late_level(change_percent(m_effect->late_level(), true, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case E2LL:
m_effect->set_early_to_late_level(change_percent(m_effect->early_to_late_level(), true, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case ERS:
m_effect->set_early_room_size(change_percent(m_effect->early_room_size(), true, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LRS:
m_effect->set_late_room_size(change_percent(m_effect->late_room_size(), true, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case SW:
m_effect->set_stereo_width(change_percent(m_effect->stereo_width(), true, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LDIFF:
m_effect->set_late_diffusion(change_percent(m_effect->late_diffusion(), true, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LWANDER:
m_effect->set_late_wander(change_percent(m_effect->late_wander(), true, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case EDAMP:
m_effect->set_early_damping(change_freq(m_effect->early_damping(), true, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LDAMP:
m_effect->set_late_damping(change_freq(m_effect->late_damping(), true, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LPDELAY:
m_effect->set_late_predelay(change_ms(m_effect->late_predelay(), true, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LDECAY:
m_effect->set_late_global_decay(change_decay(m_effect->late_global_decay(), true, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LSPIN:
m_effect->set_late_spin(change_spin(m_effect->late_spin(), true, shift_pressed, ctrl_pressed, alt_pressed));
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case ETAP:
if(m_effect->early_tap_setup() != audio_effect_reverb::early_tap_setup_count() - 1) {
m_effect->set_early_tap_setup(m_effect->early_tap_setup() + 1);
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
}
return true;
}
break;
}
case IPT_UI_CLEAR: {
switch(uintptr_t(ev->itemref)) {
case MODE:
m_effect->reset_mode();
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case DRYL:
m_effect->reset_dry_level();
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case EL:
m_effect->reset_early_level();
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LL:
m_effect->reset_late_level();
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case E2LL:
m_effect->reset_early_to_late_level();
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case ERS:
m_effect->reset_early_room_size();
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LRS:
m_effect->reset_late_room_size();
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case SW:
m_effect->reset_stereo_width();
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LDIFF:
m_effect->reset_late_diffusion();
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LWANDER:
m_effect->reset_late_wander();
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case EDAMP:
m_effect->reset_early_damping();
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LDAMP:
m_effect->reset_late_damping();
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LPDELAY:
m_effect->reset_late_predelay();
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LDECAY:
m_effect->reset_late_global_decay();
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case LSPIN:
m_effect->reset_late_spin();
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
case ETAP:
m_effect->reset_early_tap_setup();
if(m_chain == 0xffff)
machine().sound().default_effect_changed(m_entry);
reset(reset_options::REMEMBER_POSITION);
return true;
}
break;
}
}
return false;
}
std::string menu_audio_effect_reverb::format_percent(double val)
{
return util::string_format("%d%", u32(val));
}
std::string menu_audio_effect_reverb::format_freq(double val)
{
return util::string_format("%dHz", u32(val+0.5));
}
std::string menu_audio_effect_reverb::format_ms(double val)
{
return util::string_format("%5.1fms", val);
}
std::string menu_audio_effect_reverb::format_decay(double val)
{
return util::string_format("%5.2fs", val);
}
std::string menu_audio_effect_reverb::format_spin(double val)
{
return util::string_format("%3.2fHz", val);
}
u32 menu_audio_effect_reverb::flag_percent(double val, bool isset)
{
u32 flag = 0;
if(!isset)
flag |= FLAG_INVERT;
if(val > 0)
flag |= FLAG_LEFT_ARROW;
if(val < 100)
flag |= FLAG_RIGHT_ARROW;
return flag;
}
u32 menu_audio_effect_reverb::flag_freq(double val, bool isset)
{
u32 flag = 0;
if(!isset)
flag |= FLAG_INVERT;
if(val > 100)
flag |= FLAG_LEFT_ARROW;
if(val < 16000)
flag |= FLAG_RIGHT_ARROW;
return flag;
}
u32 menu_audio_effect_reverb::flag_ms(double val, bool isset)
{
u32 flag = 0;
if(!isset)
flag |= FLAG_INVERT;
if(val > 0)
flag |= FLAG_LEFT_ARROW;
if(val < 200)
flag |= FLAG_RIGHT_ARROW;
return flag;
}
u32 menu_audio_effect_reverb::flag_decay(double val, bool isset)
{
u32 flag = 0;
if(!isset)
flag |= FLAG_INVERT;
if(val > 0.1)
flag |= FLAG_LEFT_ARROW;
if(val < 30)
flag |= FLAG_RIGHT_ARROW;
return flag;
}
u32 menu_audio_effect_reverb::flag_spin(double val, bool isset)
{
u32 flag = 0;
if(!isset)
flag |= FLAG_INVERT;
if(val > 0)
flag |= FLAG_LEFT_ARROW;
if(val < 5)
flag |= FLAG_RIGHT_ARROW;
return flag;
}
double menu_audio_effect_reverb::change_percent(double val, bool inc, bool shift, bool ctrl, bool alt)
{
double step = alt ? 100 : ctrl ? 20 : shift ? 1 : 5;
if(inc)
val = std::min(100.0, val + step);
else
val = std::max(0.0, val - step);
return val;
}
double menu_audio_effect_reverb::change_freq(double val, bool inc, bool shift, bool ctrl, bool alt)
{
double step = alt ? 16000 : ctrl ? 20 : shift ? 1 : 5;
if(val >= 10000)
step *= 100;
else if(val >= 500)
step *= 50;
else if(val >= 250)
step *= 20;
else if(val >= 1000)
step *= 10;
else if(val >= 500)
step *= 5;
else if(val >= 250)
step *= 2;
if(inc)
val = std::min(16000.0, val + step);
else
val = std::max(100.0, val - step);
return val;
}
double menu_audio_effect_reverb::change_ms(double val, bool inc, bool shift, bool ctrl, bool alt)
{
double step = alt ? 200 : ctrl ? 10 : shift ? 0.1 : 1;
if(inc)
val = std::min(200.0, val + step);
else
val = std::max(0.0, val - step);
val = u32(val * 10 + 0.5) / 10.0;
return val;
}
double menu_audio_effect_reverb::change_decay(double val, bool inc, bool shift, bool ctrl, bool alt)
{
double step = alt ? 30 : ctrl ? 1 : shift ? 0.01 : 0.1;
if(inc)
val = std::min(30.0, val + step);
else
val = std::max(0.1, val - step);
val = u32(val * 100 + 0.5) / 100.0;
return val;
}
double menu_audio_effect_reverb::change_spin(double val, bool inc, bool shift, bool ctrl, bool alt)
{
double step = alt ? 5 : ctrl ? 1 : shift ? 0.01 : 0.1;
if(inc)
val = std::min(5.0, val + step);
else
val = std::max(0.0, val - step);
val = u32(val * 100 + 0.5) / 100.0;
return val;
}
void menu_audio_effect_reverb::populate()
{
item_append(_(audio_effect::effect_names[audio_effect::REVERB]), FLAG_UI_HEADING | FLAG_DISABLE, nullptr);
item_append(_("Mode"), m_effect->mode() ? _("Active") : _("Bypass"), flag_mode(), (void *)MODE);
item_append(_("Load preset"), audio_effect_reverb::preset_name(m_preset), flag_preset(), (void *)PRESET);
item_append(_("Dry level"), format_percent(m_effect->dry_level()), flag_percent(m_effect->dry_level(), m_effect->isset_dry_level()), (void *)DRYL);
item_append(_("Stereo width"), format_percent(m_effect->stereo_width()), flag_percent(m_effect->stereo_width(), m_effect->isset_stereo_width()), (void *)SW);
item_append(_("Early Reflections"), FLAG_UI_HEADING | FLAG_DISABLE, nullptr);
item_append(_("Room size"), format_percent(m_effect->early_room_size()), flag_percent(m_effect->early_room_size(), m_effect->isset_early_room_size()), (void *)ERS);
item_append(_("Tap setup"), audio_effect_reverb::early_tap_setup_name(m_effect->early_tap_setup()), flag_tap_setup(), (void *)ETAP);
item_append(_("Damping"), format_freq(m_effect->early_damping()), flag_percent(m_effect->early_damping(), m_effect->isset_early_damping()), (void *)EDAMP);
item_append(_("Level"), format_percent(m_effect->early_level()), flag_percent(m_effect->early_level(), m_effect->isset_early_level()), (void *)EL);
item_append(_("Send to Late"), format_percent(m_effect->early_to_late_level()), flag_percent(m_effect->early_to_late_level(), m_effect->isset_early_to_late_level()), (void *)E2LL);
item_append(_("Late Reflections"), FLAG_UI_HEADING | FLAG_DISABLE, nullptr);
item_append(_("Room size"), format_percent(m_effect->late_room_size()), flag_percent(m_effect->late_room_size(), m_effect->isset_late_room_size()), (void *)LRS);
item_append(_("Damping"), format_freq(m_effect->late_damping()), flag_percent(m_effect->late_damping(), m_effect->isset_late_damping()), (void *)LDAMP);
item_append(_("Pre-delay"), format_ms(m_effect->late_predelay()), flag_percent(m_effect->late_predelay(), m_effect->isset_late_predelay()), (void *)LPDELAY);
item_append(_("Diffusion"), format_percent(m_effect->late_diffusion()), flag_percent(m_effect->late_diffusion(), m_effect->isset_late_diffusion()), (void *)LDIFF);
item_append(_("Wander"), format_percent(m_effect->late_wander()), flag_percent(m_effect->late_wander(), m_effect->isset_late_wander()), (void *)LWANDER);
item_append(_("Decay"), format_decay(m_effect->late_global_decay()), flag_decay(m_effect->late_global_decay(), m_effect->isset_late_global_decay()), (void *)LDECAY);
item_append(_("Spin"), format_spin(m_effect->late_spin()), flag_spin(m_effect->late_spin(), m_effect->isset_late_spin()), (void *)LSPIN);
item_append(_("Level"), format_percent(m_effect->late_level()), flag_percent(m_effect->late_level(), m_effect->isset_late_level()), (void *)LL);
item_append(menu_item_type::SEPARATOR);
}
void menu_audio_effect_reverb::recompute_metrics(uint32_t width, uint32_t height, float aspect)
{
menu::recompute_metrics(width, height, aspect);
}
void menu_audio_effect_reverb::custom_render(uint32_t flags, void *selectedref, float top, float bottom, float x1, float y1, float x2, float y2)
{
}
void menu_audio_effect_reverb::menu_activated()
{
// scripts or the other form of the menu could have changed something in the mean time
reset(reset_options::REMEMBER_POSITION);
}
void menu_audio_effect_reverb::menu_deactivated()
{
}
u32 menu_audio_effect_reverb::flag_mode() const
{
u32 flag = 0;
if(!m_effect->isset_mode())
flag |= FLAG_INVERT;
if(m_effect->mode())
flag |= FLAG_LEFT_ARROW;
else
flag |= FLAG_RIGHT_ARROW;
return flag;
}
u32 menu_audio_effect_reverb::flag_tap_setup() const
{
u32 flag = 0;
if(!m_effect->isset_early_tap_setup())
flag |= FLAG_INVERT;
if(m_effect->early_tap_setup() != 0)
flag |= FLAG_LEFT_ARROW;
if(m_effect->early_tap_setup() != audio_effect_reverb::early_tap_setup_count() - 1)
flag |= FLAG_RIGHT_ARROW;
return flag;
}
u32 menu_audio_effect_reverb::flag_preset() const
{
u32 flag = 0;
if(m_preset != 0)
flag |= FLAG_LEFT_ARROW;
if(m_preset != audio_effect_reverb::preset_count() - 1)
flag |= FLAG_RIGHT_ARROW;
return flag;
}
}

View File

@ -0,0 +1,88 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert
/***************************************************************************
ui/audio_effect_reverb.h
Reverb configuration
***************************************************************************/
#ifndef MAME_FRONTEND_UI_AUDIO_EFFECT_REVERB_H
#define MAME_FRONTEND_UI_AUDIO_EFFECT_REVERB_H
#pragma once
#include "ui/menu.h"
class audio_effect_reverb;
namespace ui {
class menu_audio_effect_reverb : public menu
{
public:
menu_audio_effect_reverb(mame_ui_manager &mui, render_container &container, u16 chain, u16 entry, audio_effect *effect);
virtual ~menu_audio_effect_reverb() override;
protected:
virtual void recompute_metrics(uint32_t width, uint32_t height, float aspect) override;
virtual void custom_render(uint32_t flags, void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
virtual void menu_activated() override;
virtual void menu_deactivated() override;
private:
enum {
MODE,
PRESET,
DRYL,
EL,
LL,
E2LL,
SW,
EDAMP,
ERS,
ETAP,
LDAMP,
LDIFF,
LPDELAY,
LRS,
LDECAY,
LSPIN,
LWANDER
};
u16 m_chain, m_entry;
u32 m_preset;
audio_effect_reverb *m_effect;
virtual void populate() override;
virtual bool handle(event const *ev) override;
static std::string format_percent(double val);
static std::string format_freq(double val);
static std::string format_ms(double val);
static std::string format_decay(double val);
static std::string format_spin(double val);
u32 flag_mode() const;
u32 flag_tap_setup() const;
u32 flag_preset() const;
static u32 flag_percent(double val, bool isset);
static u32 flag_freq(double val, bool isset);
static u32 flag_ms(double val, bool isset);
static u32 flag_decay(double val, bool isset);
static u32 flag_spin(double val, bool isset);
static double change_percent(double val, bool inc, bool shift, bool ctrl, bool alt);
static double change_freq(double val, bool inc, bool shift, bool ctrl, bool alt);
static double change_ms(double val, bool inc, bool shift, bool ctrl, bool alt);
static double change_decay(double val, bool inc, bool shift, bool ctrl, bool alt);
static double change_spin(double val, bool inc, bool shift, bool ctrl, bool alt);
};
} // namespace ui
#endif // MAME_FRONTEND_UI_AUDIO_EFFECT_REVERB_H

View File

@ -15,6 +15,7 @@
#include "audio_effect_compressor.h"
#include "audio_effect_eq.h"
#include "audio_effect_filter.h"
#include "audio_effect_reverb.h"
#include "ui/ui.h"
@ -106,6 +107,10 @@ bool menu_audio_effects::handle(event const *ev)
case audio_effect::FILTER:
menu::stack_push<menu_audio_effect_filter>(ui(), container(), chain, entry, eff);
break;
case audio_effect::REVERB:
menu::stack_push<menu_audio_effect_reverb>(ui(), container(), chain, entry, eff);
break;
}
return true;
}

View File

@ -599,7 +599,7 @@ void menu_audio_mixer::populate()
}
for(const auto &cmap : omap.m_channel_mappings) {
const auto &node = find_node(cmap.m_node);
std::string guest_channel = omap.m_dev->get_position_name(cmap.m_guest_channel);
std::string guest_channel = omap.m_dev->get_position(cmap.m_guest_channel).name();
if(curline == cursel_line && m_current_group == GRP_GUEST_CHANNEL)
guest_channel = u8"\u25c4" + guest_channel + u8"\u25ba";

View File

@ -903,7 +903,7 @@ void atarigt_state::atarigt_stereo(machine_config &config)
// based on dedicated cabinet configuration;
// 'universal' kit supports mono and stereo, with/without subwoofer.
SPEAKER(config, "speaker", 2).front();
SPEAKER(config, "subwoofer").front_floor(); // Next to the coin door at dedicated cabinet, just silence for now (not implemented)
SPEAKER(config, "subwoofer").lfe(); // Next to the coin door at dedicated cabinet, just silence for now (not implemented)
// TODO: correct? sound board has only 1 DAC populated.
m_cage->add_route(0, "speaker", 1.0, 1);
@ -925,7 +925,7 @@ void atarigt_state::tmek(machine_config &config)
// 5 Channel output (4 Channel input connected to Quad Amp PCB)
SPEAKER(config, "speaker", 4).front().headrest_left(2).headrest_right(3);
//SPEAKER(config, "subwoofer").seat(); Not implemented, Quad Amp PCB output;
//SPEAKER(config, "subwoofer").lfe(); Not implemented, Quad Amp PCB output;
m_cage->set_speedup(0x4fad);
m_cage->add_route(0, "speaker", 1.0, 1); // Foward Right

View File

@ -761,7 +761,7 @@ void metalmx_state::metalmx(machine_config &config)
// TODO: copied from atarigt.cpp; Same configurations as T-Mek?
// 5 Channel output (4 Channel input connected to Quad Amp PCB)
SPEAKER(config, "speaker", 4).front().headrest_left(2).headrest_right(3);
//SPEAKER(config, "subwoofer").seat(); Not implemented, Quad Amp PCB output;
//SPEAKER(config, "subwoofer").lfe(); Not implemented, Quad Amp PCB output;
ATARI_CAGE(config, m_cage, 0);
m_cage->set_speedup(0); // TODO: speedup address

View File

@ -2171,7 +2171,7 @@ void seattle_state::sfrush(machine_config &config)
// 5 Channel output (4 Channel input connected to Quad Amp PCB)
SPEAKER(config, "speaker", 4).corners();
//SPEAKER(config, "subwoofer").seat(); Not implemented, Quad Amp PCB output;
//SPEAKER(config, "subwoofer").lfe(); Not implemented, Quad Amp PCB output;
ATARI_CAGE_SEATTLE(config, m_cage, 0);
m_cage->set_speedup(0x5236);
@ -2201,7 +2201,7 @@ void seattle_state::sfrushrk(machine_config &config)
// 5 Channel output (4 Channel input connected to Quad Amp PCB)
SPEAKER(config, "speaker", 4).corners();
//SPEAKER(config, "subwoofer").seat(); Not implemented, Quad Amp PCB output;
//SPEAKER(config, "subwoofer").lfe(); Not implemented, Quad Amp PCB output;
ATARI_CAGE_SEATTLE(config, m_cage, 0);
m_cage->set_speedup(0x5329);

View File

@ -3846,7 +3846,7 @@ void namcos22s_state::airco22b(machine_config &config)
{
namcos22s(config);
SPEAKER(config, "bodysonic").backrest();
SPEAKER(config, "bodysonic").lfe();
m_c352->add_route(2, "bodysonic", 0.50); // to subwoofer behind back
}
@ -3892,7 +3892,7 @@ void namcos22s_state::tokyowar(machine_config &config)
{
namcos22s(config);
SPEAKER(config, "vibration").seat();
SPEAKER(config, "vibration").lfe();
SPEAKER(config, "seat").headrest_center();
m_c352->add_route(2, "vibration", 0.5); // to "bass shaker"

View File

@ -394,7 +394,7 @@ void s11b_state::s11b_jokerz(machine_config &config)
m_cvsd_filter2->add_route(ALL_OUTPUTS, m_ps88, (0.25*4.0), 1);
m_pia34->ca2_handler().set(m_ps88, FUNC(pinsnd88_device::resetq_w));
m_ps88->syncq_cb().set(m_pia34, FUNC(pia6821_device::ca1_w)); // the sync connection comes from sound connector pin 16 to MCA1, not the usual pin 12 to MCB1
SPEAKER(config, "cabinet").front_floor(); // the cabinet speaker is aimed down underneath the pinball table itself
SPEAKER(config, "cabinet").set_position(0, 0.0, -0.5, 1.0); // the cabinet speaker is aimed down underneath the pinball table itself
SPEAKER(config, "backbox").front_center(); // the backbox speakers are roughly level with the user, but farther in front of them than the cabinet
m_ps88->add_route(0, "cabinet", 1.0);
m_ps88->add_route(1, "backbox", 1.0);

View File

@ -974,7 +974,7 @@ void ninjaw_state::ninjaw(machine_config &config)
/* sound hardware */
SPEAKER(config, "speaker", 2).front();
SPEAKER(config, "subwoofer").seat();
SPEAKER(config, "subwoofer").lfe();
ym2610_device &ymsnd(YM2610(config, "ymsnd", 16000000/2));
ymsnd.irq_handler().set_inputline("audiocpu", 0);
@ -1079,7 +1079,7 @@ void ninjaw_state::darius2(machine_config &config)
/* sound hardware */
SPEAKER(config, "speaker", 2).front();
SPEAKER(config, "subwoofer").seat();
SPEAKER(config, "subwoofer").lfe();
ym2610_device &ymsnd(YM2610(config, "ymsnd", 16000000/2));
ymsnd.irq_handler().set_inputline("audiocpu", 0);

View File

@ -3221,7 +3221,7 @@ void contcirc_state::contcirc(machine_config &config) //OSC: 26.686, 24.000, 16.
/* sound hardware */
SPEAKER(config, "front").front_center();
SPEAKER(config, "rear").rear_center();
SPEAKER(config, "subwoofer").set_position(0, 0.0, 0.0, 0.0); // FIXME: where is this speaker located?
SPEAKER(config, "subwoofer").lfe();
ym2610_device &ymsnd(YM2610(config, "ymsnd", XTAL(16'000'000)/2)); // 8 MHz
ymsnd.irq_handler().set_inputline(m_audiocpu, 0);
@ -3280,7 +3280,7 @@ void chasehq_state::chasehq(machine_config &config) //OSC: 26.686, 24.000, 16.00
/* sound hardware */
SPEAKER(config, "front").front_center();
SPEAKER(config, "rear").rear_center();
SPEAKER(config, "subwoofer").set_position(0, 0.0, 0.0, 0.0); // FIXME: where is this speaker located?
SPEAKER(config, "subwoofer").lfe();
ym2610_device &ymsnd(YM2610(config, "ymsnd", XTAL(16'000'000)/2)); // 8 MHz
ymsnd.irq_handler().set_inputline(m_audiocpu, 0);
@ -3539,7 +3539,7 @@ void nightstr_state::nightstr(machine_config &config) //OSC: 26.686, 24.000, 16.
/* sound hardware */
SPEAKER(config, "front").front_center();
SPEAKER(config, "rear").rear_center();
SPEAKER(config, "subwoofer").set_position(0, 0.0, 0.0, 0.0); // FIXME: where is this located in the cabinet?
SPEAKER(config, "subwoofer").lfe();
ym2610_device &ymsnd(YM2610(config, "ymsnd", XTAL(16'000'000)/2)); // 8 MHz
ymsnd.irq_handler().set_inputline(m_audiocpu, 0);

View File

@ -1155,7 +1155,7 @@ void dendego_state::dendego(machine_config &config)
m_screen->set_screen_update(FUNC(dendego_state::screen_update_dendego));
/* sound hardware */
SPEAKER(config, "vibration").seat();
SPEAKER(config, "vibration").lfe();
/* clock frequency & pin 7 not verified */
OKIM6295(config, "oki", 1056000, okim6295_device::PIN7_HIGH).add_route(ALL_OUTPUTS, "vibration", 0.20);

View File

@ -630,7 +630,7 @@ void warriorb_state::darius2d(machine_config &config)
// sound hardware
SPEAKER(config, "speaker", 2).front();
SPEAKER(config, "subwoofer").seat();
SPEAKER(config, "subwoofer").lfe();
ym2610_device &ymsnd(YM2610(config, "ymsnd", 16_MHz_XTAL / 2));
ymsnd.irq_handler().set_inputline("audiocpu", 0);

View File

@ -0,0 +1,49 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert
#include "emu.h"
#include "audio.h"
const osd::channel_position osd::channel_position::UNKNOWN(0.0, 0.0, 0.0);
const osd::channel_position osd::channel_position::ONREQ (0.0, 0.0, 10.0);
const osd::channel_position osd::channel_position::LFE (0.0, 0.0, 11.0);
bool osd::channel_position::is_lfe() const { return *this == LFE; }
bool osd::channel_position::is_onreq() const { return *this == ONREQ; }
bool osd::channel_position::is_unknown() const { return *this == UNKNOWN; }
const osd::channel_position osd::channel_position::FC ( 0.0, 0.0, 1.0);
const osd::channel_position osd::channel_position::FL (-0.2, 0.0, 1.0);
const osd::channel_position osd::channel_position::FR ( 0.2, 0.0, 1.0);
const osd::channel_position osd::channel_position::RC ( 0.0, 0.0, -0.5);
const osd::channel_position osd::channel_position::RL (-0.2, 0.0, -0.5);
const osd::channel_position osd::channel_position::RR ( 0.2, 0.0, -0.5);
const osd::channel_position osd::channel_position::HC ( 0.0, 0.0, -0.1);
const osd::channel_position osd::channel_position::HL (-0.1, 0.0, -0.1);
const osd::channel_position osd::channel_position::HR ( 0.1, 0.0, -0.1);
const osd::channel_position osd::channel_position::BACKREST( 0.0, -0.2, 0.1);
const osd::detail::position_name_mapping osd::detail::position_name_mappings[] = {
{ channel_position::FC, "Front center" },
{ channel_position::FL, "Front left" },
{ channel_position::FR, "Front right" },
{ channel_position::RC, "Rear center" },
{ channel_position::RL, "Rear left" },
{ channel_position::RR, "Rear right" },
{ channel_position::HC, "Headrest center" },
{ channel_position::HL, "Headrest left" },
{ channel_position::HR, "Headrest right" },
{ channel_position::BACKREST, "Backrest" },
{ channel_position::LFE, "Subwoofer" },
{ channel_position::ONREQ, "Auxiliary" },
{ channel_position::UNKNOWN, "Unknown" }
};
std::string osd::channel_position::name() const
{
for(unsigned int i=0; i != sizeof(detail::position_name_mappings)/sizeof(detail::position_name_mappings[0]); i++)
if(*this == detail::position_name_mappings[i].m_pos)
return detail::position_name_mappings[i].m_name;
return util::string_format("[%f %f %f]", m_x, m_y, m_z);
}

View File

@ -16,6 +16,57 @@
namespace osd {
struct channel_position {
// Special positions
// Position is unknown, placed in the middle
static const struct channel_position UNKNOWN;
// This channel should only be mapped explicitely through a channel mapping (on request)
static const struct channel_position ONREQ;
// This channel is a LFE
static const struct channel_position LFE;
// Standard positions
static const struct channel_position FC;
static const struct channel_position FL;
static const struct channel_position FR;
static const struct channel_position RC;
static const struct channel_position RL;
static const struct channel_position RR;
static const struct channel_position HC;
static const struct channel_position HL;
static const struct channel_position HR;
static const struct channel_position BACKREST;
double m_x, m_y, m_z;
bool is_lfe() const;
bool is_onreq() const;
bool is_unknown() const;
channel_position() : channel_position(UNKNOWN) {}
channel_position(double x, double y, double z) : m_x(x), m_y(y), m_z(z) {}
channel_position(const channel_position &pos) : m_x(pos.m_x), m_y(pos.m_y), m_z(pos.m_z) {}
bool operator == (const channel_position &pos) const {
return pos.m_x == m_x && pos.m_y == m_y && pos.m_z == m_z;
}
std::string name() const;
};
namespace detail {
struct position_name_mapping {
struct channel_position m_pos;
const char *m_name;
};
extern const position_name_mapping position_name_mappings[];
};
struct audio_rate_range {
uint32_t m_default_rate;
uint32_t m_min_rate;
@ -41,7 +92,7 @@ struct audio_info {
uint32_t m_id;
audio_rate_range m_rate;
std::vector<std::string> m_port_names;
std::vector<std::array<double, 3> > m_port_positions;
std::vector<channel_position> m_port_positions;
uint32_t m_sinks;
uint32_t m_sources;

View File

@ -102,62 +102,62 @@ static const char *sMacChannelLabels[sMacChannelCount] =
// "Surround" channels are at X = -0.4 (left) and 0.4 (right).
static const std::array<double,3> sChannelPositions[sMacChannelCount] =
{
{ 0.0, 0.0, 0.0 }, // unused
{ -0.2, 0.0, 1.0 }, // Front Left
{ 0.2, 0.0, 1.0 }, // Front Right
{ 0.0, 0.0, 1.0 }, // Front Center
{ 0.0, -0.5, 0.0 }, // Low Frequency Effects
{ -0.2, 0.0, -0.5 }, // Rear Left
{ 0.2, 0.0, -0.5 }, // Rear Right
{ -0.1, 0.0, 1.0 }, // Front Left of Center
{ 0.1, 0.0, 1.0 }, // Front Right of Center
{ 0.0, 0.0, -1.0 }, // Rear Center
{ -0.2, 0.0, 0.5 }, // Side Left
{ 0.2, 0.0, 0.5 }, // Side Right
{ 0.0, 0.5, -0.1 }, // Top Center
{ -0.2, 0.5, 1.0 }, // Top Front Left
{ 0.0, 0.5, 1.0 }, // Top Front Center
{ 0.2, 0.5, 1.0 }, // Top Front Right
{ -0.2, 0.5, -0.5 }, // Top Rear Left
{ 0.2, 0.5, -0.5 }, // Top Rear Center
{ 0.2, 0.5, -0.5 }, // Top Rear Right
{ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 },
{ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 },
{ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 },
{ -0.4, 0.0, -0.5 }, // Rear Surround Left
{ 0.4, 0.0, -0.5 }, // Rear Surround Right
{ -0.4, 0.0, 1.0 }, // Left Wide
{ 0.4, 0.0, 1.0 }, // Right Wide
{ 0.0, -0.5, 0.0 }, // Low Frequency Effects 2
{ -0.1, 0.0, -0.1 }, // Left Total
{ 0.1, 0.0, -0.1 }, // Right Total
{ 0.0, 0.0, 1.0 }, // Hearing Impaired
{ 0.0, 0.0, 1.0 }, // Narration
{ 0.0, 0.0, 1.0 }, // Mono
{ 0.0, 0.0, 1.0 }, // Dialog Centric Mix
{ 0.0, 0.0, -0.1 }, // Center Surround Direct
{ 0.0, 0.0, 0.0 }, // Haptic
{ 0.0, 0.0, 0.0 }, // unused
{ 0.0, 0.0, 0.0 }, // unused
{ 0.0, 0.0, 0.0 }, // unused
{ -0.2, 0.5, 0.0 }, // Left Top Middle
{ 0.0, 0.0, 0.0 }, // unused
{ 0.2, 0.5, 0.0 }, // Right Top Middle
{ -0.2, 0.5, -0.5 }, // Left Top Rear
{ 0.0, 0.5, -0.5 }, // Center Top Rear
{ 0.2, 0.5, -0.5 }, // Right Top Rear
{ -0.4, 0.0, -0.1 }, // Left Side Surround
{ 0.4, 0.0, -0.1 }, // Right Side Surround
{ -0.2, -0.5, 0.0 }, // Left Bottom
{ 0.2, -0.5, 0.0 }, // Right Bottom
{ 0.0, -0.5, 0.0 }, // Center Bottom
{ -0.4, 0.5, -0.1 }, // Left Top Surround
{ 0.4, 0.5, -0.1 }, // Right Top Surround
{ 0.0, 0.0, 0.0 }, // Low Frequency Effects 3
{ -0.4, 0.0, -0.5 }, // Left Rear Surround
{ 0.4, 0.0, -0.5 }, // Right Rear Surround
{ -0.1, 0.0, 1.0 }, // Left Edge of Screen
{ 0.1, 0.0, 1.0 } // Right Edge of Screen
osd::channel_position::UNKNOWN, // unused
osd::channel_position::FL, // Front Left
osd::channel_position::FR, // Front Right
osd::channel_position::FC, // Front Center
osd::channel_position::LFE, // Low Frequency Effects
osd::channel_position::RL, // Rear Left
osd::channel_position::RR, // Rear Right
osd::channel_position( -0.1, 0.0, 1.0 ), // Front Left of Center
osd::channel_position( 0.1, 0.0, 1.0 ), // Front Right of Center
osd::channel_position::RC, // Rear Center
osd::channel_position( -0.2, 0.0, 0.5 ), // Side Left
osd::channel_position( 0.2, 0.0, 0.5 ), // Side Right
osd::channel_position( 0.0, 0.5, -0.1 ), // Top Center
osd::channel_position( -0.2, 0.5, 1.0 ), // Top Front Left
osd::channel_position( 0.0, 0.5, 1.0 ), // Top Front Center
osd::channel_position( 0.2, 0.5, 1.0 ), // Top Front Right
osd::channel_position( -0.2, 0.5, -0.5 ), // Top Rear Left
osd::channel_position( 0.2, 0.5, -0.5 ), // Top Rear Center
osd::channel_position( 0.2, 0.5, -0.5 ), // Top Rear Right
osd::channel_position::UNKNOWN, osd::channel_position::UNKNOWN,
osd::channel_position::UNKNOWN, osd::channel_position::UNKNOWN, osd::channel_position::UNKNOWN, osd::channel_position::UNKNOWN, osd::channel_position::UNKNOWN, osd::channel_position::UNKNOWN, osd::channel_position::UNKNOWN, osd::channel_position::UNKNOWN, osd::channel_position::UNKNOWN, osd::channel_position::UNKNOWN,
osd::channel_position::UNKNOWN, osd::channel_position::UNKNOWN,
osd::channel_position( -0.4, 0.0, -0.5 ), // Rear Surround Left
osd::channel_position( 0.4, 0.0, -0.5 ), // Rear Surround Right
osd::channel_position( -0.4, 0.0, 1.0 ), // Left Wide
osd::channel_position( 0.4, 0.0, 1.0 ), // Right Wide
osd::channel_position::LFE, // Low Frequency Effects 2
osd::channel_position::HL, // Left Total
osd::channel_position::HR, // Right Total
osd::channel_position::FC, // Hearing Impaired
osd::channel_position::FC, // Narration
osd::channel_position::FC, // Mono
osd::channel_position::FC, // Dialog Centric Mix
osd::channel_position::HC, // Center Surround Direct
osd::channel_position::UNKNOWN, // Haptic
osd::channel_position::UNKNOWN, // unused
osd::channel_position::UNKNOWN, // unused
osd::channel_position::UNKNOWN, // unused
osd::channel_position( -0.2, 0.5, 0.0 ), // Left Top Middle
osd::channel_position::UNKNOWN, // unused
osd::channel_position( 0.2, 0.5, 0.0 ), // Right Top Middle
osd::channel_position( -0.2, 0.5, -0.5 ), // Left Top Rear
osd::channel_position( 0.0, 0.5, -0.5 ), // Center Top Rear
osd::channel_position( 0.2, 0.5, -0.5 ), // Right Top Rear
osd::channel_position( -0.4, 0.0, -0.1 ), // Left Side Surround
osd::channel_position( 0.4, 0.0, -0.1 ), // Right Side Surround
osd::channel_position( -0.2, -0.5, 0.0 ), // Left Bottom
osd::channel_position( 0.2, -0.5, 0.0 ), // Right Bottom
osd::channel_position( 0.0, -0.5, 0.0 ), // Center Bottom
osd::channel_position( -0.4, 0.5, -0.1 ), // Left Top Surround
osd::channel_position( 0.4, 0.5, -0.1 ), // Right Top Surround
osd::channel_position::UNKNOWN, // Low Frequency Effects 3
osd::channel_position( -0.4, 0.0, -0.5 ), // Left Rear Surround
osd::channel_position( 0.4, 0.0, -0.5 ), // Right Rear Surround
osd::channel_position( -0.1, 0.0, 1.0 ), // Left Edge of Screen
osd::channel_position( 0.1, 0.0, 1.0 ) // Right Edge of Screen
};
struct coreaudio_device
@ -1064,7 +1064,7 @@ void sound_coreaudio::build_device_list()
{
std::string chLabel = "Channel " + std::to_string(desc + 1);
node.m_port_names.push_back(chLabel);
node.m_port_positions.emplace_back(std::array<double, 3>({0.0, 0.0, 1.0}));
node.m_port_positions.emplace_back(osd::channel_position::FC);
}
else
{

View File

@ -48,25 +48,25 @@ char const *const f_speaker_names[] ={
"TBC", // SPEAKER_TOP_BACK_CENTER
"TBR" }; // SPEAKER_TOP_BACK_RIGHT
std::array<double, 3> const f_speaker_positions[] = {
{ -0.2, 0.0, 1.0 }, // SPEAKER_FRONT_LEFT
{ 0.2, 0.0, 1.0 }, // SPEAKER_FRONT_RIGHT
{ 0.0, 0.0, 1.0 }, // SPEAKER_FRONT_CENTER
{ 0.0, -0.5, 1.0 }, // SPEAKER_LOW_FREQUENCY
{ -0.2, 0.0, -0.5 }, // SPEAKER_BACK_LEFT
{ 0.2, 0.0, -0.5 }, // SPEAKER_BACK_RIGHT
{ -0.1, 0.0, 1.0 }, // SPEAKER_FRONT_LEFT_OF_CENTER
{ 0.1, 0.0, 1.0 }, // SPEAKER_FRONT_RIGHT_OF_CENTER
{ 0.0, 0.0, -0.5 }, // SPEAKER_BACK_CENTER
{ -0.2, 0.0, 0.0 }, // SPEAKER_SIDE_LEFT
{ 0.2, 0.0, 0.0 }, // SPEAKER_SIDE_RIGHT
{ 0.0, 0.5, 0.0 }, // SPEAKER_TOP_CENTER
{ -0.2, 0.5, 1.0 }, // SPEAKER_TOP_FRONT_LEFT
{ 0.0, 0.5, 1.0 }, // SPEAKER_TOP_FRONT_CENTER
{ 0.2, 0.5, 1.0 }, // SPEAKER_TOP_FRONT_RIGHT
{ -0.2, 0.5, -0.5 }, // SPEAKER_TOP_BACK_LEFT
{ 0.0, 0.5, -0.5 }, // SPEAKER_TOP_BACK_CENTER
{ 0.2, 0.5, -0.5 } }; // SPEAKER_TOP_BACK_RIGHT
osd::channel_position const f_speaker_positions[] = {
osd::channel_position::FL, // SPEAKER_FRONT_LEFT
osd::channel_position::FR, // SPEAKER_FRONT_RIGHT
osd::channel_position::FC, // SPEAKER_FRONT_CENTER
osd::channel_position::LFE, // SPEAKER_LOW_FREQUENCY
osd::channel_position::RL, // SPEAKER_BACK_LEFT
osd::channel_position::RR, // SPEAKER_BACK_RIGHT
osd::channel_position( -0.1, 0.0, 1.0 ), // SPEAKER_FRONT_LEFT_OF_CENTER
osd::channel_position( 0.1, 0.0, 1.0 ), // SPEAKER_FRONT_RIGHT_OF_CENTER
osd::channel_position::RC, // SPEAKER_BACK_CENTER
osd::channel_position( -0.2, 0.0, 0.0 ), // SPEAKER_SIDE_LEFT
osd::channel_position( 0.2, 0.0, 0.0 ), // SPEAKER_SIDE_RIGHT
osd::channel_position( 0.0, 0.5, 0.0 ), // SPEAKER_TOP_CENTER
osd::channel_position( -0.2, 0.5, 1.0 ), // SPEAKER_TOP_FRONT_LEFT
osd::channel_position( 0.0, 0.5, 1.0 ), // SPEAKER_TOP_FRONT_CENTER
osd::channel_position( 0.2, 0.5, 1.0 ), // SPEAKER_TOP_FRONT_RIGHT
osd::channel_position( -0.2, 0.5, -0.5 ), // SPEAKER_TOP_BACK_LEFT
osd::channel_position( 0.0, 0.5, -0.5 ), // SPEAKER_TOP_BACK_CENTER
osd::channel_position( 0.2, 0.5, -0.5 ) }; // SPEAKER_TOP_BACK_RIGHT
} // anonymous namespace

View File

@ -101,17 +101,17 @@ int sound_pa::init(osd_interface &osd, osd_options const &options)
enum { FL, FR, FC, LFE, BL, BR, BC, SL, SR, AUX };
static const char *const posname[10] = { "FL", "FR", "FC", "LFE", "BL", "BR", "BC", "SL", "SR", "AUX" };
static const std::array<double, 3> pos3d[10] = {
{ -0.2, 0.0, 1.0 },
{ 0.2, 0.0, 1.0 },
{ 0.0, 0.0, 1.0 },
{ 0.0, -0.5, 1.0 },
{ -0.2, 0.0, -0.5 },
{ 0.2, 0.0, -0.5 },
{ 0.0, 0.0, -0.5 },
{ -0.2, 0.0, 0.0 },
{ 0.2, 0.0, 0.0 },
{ 0.0, 0.0, 10.0 },
static const osd::channel_position pos3d[10] = {
osd::channel_position::FL,
osd::channel_position::FR,
osd::channel_position::FC,
osd::channel_position::LFE,
osd::channel_position::RL,
osd::channel_position::RR,
osd::channel_position::RC,
osd::channel_position(-0.2, 0.0, 0.0),
osd::channel_position( 0.2, 0.0, 0.0),
osd::channel_position::ONREQ
};
static const uint32_t positions[9][9] = {

View File

@ -53,7 +53,7 @@ public:
private:
struct position_info {
uint32_t m_position;
std::array<double, 3> m_coords;
osd::channel_position m_coords;
};
static const position_info position_infos[];
@ -73,7 +73,7 @@ private:
uint32_t m_sinks, m_sources;
std::vector<uint32_t> m_position_codes;
std::vector<std::string> m_port_names;
std::vector<std::array<double, 3>> m_positions;
std::vector<osd::channel_position> m_positions;
osd::audio_rate_range m_rate;
bool m_has_s16;
@ -165,16 +165,16 @@ private:
// Try to more or less map to speaker.h positions
const sound_pipewire::position_info sound_pipewire::position_infos[] = {
{ SPA_AUDIO_CHANNEL_MONO, { 0.0, 0.0, 1.0 } },
{ SPA_AUDIO_CHANNEL_FL, { -0.2, 0.0, 1.0 } },
{ SPA_AUDIO_CHANNEL_FR, { 0.2, 0.0, 1.0 } },
{ SPA_AUDIO_CHANNEL_FC, { 0.0, 0.0, 1.0 } },
{ SPA_AUDIO_CHANNEL_LFE, { 0.0, -0.5, 1.0 } },
{ SPA_AUDIO_CHANNEL_RL, { -0.2, 0.0, -0.5 } },
{ SPA_AUDIO_CHANNEL_RR, { 0.2, 0.0, -0.5 } },
{ SPA_AUDIO_CHANNEL_RC, { 0.0, 0.0, -0.5 } },
{ SPA_AUDIO_CHANNEL_AUX0, { 0.0, 0.0, 10.0 } },
{ SPA_AUDIO_CHANNEL_UNKNOWN, { 0.0, 0.0, 0.0 } }
{ SPA_AUDIO_CHANNEL_MONO, osd::channel_position::FC },
{ SPA_AUDIO_CHANNEL_FL, osd::channel_position::FL },
{ SPA_AUDIO_CHANNEL_FR, osd::channel_position::FR },
{ SPA_AUDIO_CHANNEL_FC, osd::channel_position::FC },
{ SPA_AUDIO_CHANNEL_LFE, osd::channel_position::LFE },
{ SPA_AUDIO_CHANNEL_RL, osd::channel_position::RL },
{ SPA_AUDIO_CHANNEL_RR, osd::channel_position::RR },
{ SPA_AUDIO_CHANNEL_RC, osd::channel_position::RC },
{ SPA_AUDIO_CHANNEL_AUX0, osd::channel_position::ONREQ },
{ SPA_AUDIO_CHANNEL_UNKNOWN, osd::channel_position::UNKNOWN }
};

View File

@ -45,7 +45,7 @@ public:
private:
struct position_info {
pa_channel_position_t m_position;
std::array<double, 3> m_coords;
osd::channel_position m_coords;
};
static const position_info position_infos[];
@ -61,7 +61,7 @@ private:
// Audio node info
std::vector<pa_channel_position_t> m_position_codes;
std::vector<std::string> m_position_names;
std::vector<std::array<double, 3>> m_positions;
std::vector<osd::channel_position> m_positions;
uint32_t m_sink_port_count, m_source_port_count;
osd::audio_rate_range m_rate;
@ -122,15 +122,15 @@ private:
// Try to more or less map to speaker.h positions
const sound_pulse::position_info sound_pulse::position_infos[] = {
{ PA_CHANNEL_POSITION_MONO, { 0.0, 0.0, 1.0 } },
{ PA_CHANNEL_POSITION_FRONT_LEFT, { -0.2, 0.0, 1.0 } },
{ PA_CHANNEL_POSITION_FRONT_RIGHT, { 0.2, 0.0, 1.0 } },
{ PA_CHANNEL_POSITION_FRONT_CENTER, { 0.0, 0.0, 1.0 } },
{ PA_CHANNEL_POSITION_LFE, { 0.0, -0.5, 1.0 } },
{ PA_CHANNEL_POSITION_REAR_LEFT, { -0.2, 0.0, -0.5 } },
{ PA_CHANNEL_POSITION_REAR_RIGHT, { 0.2, 0.0, -0.5 } },
{ PA_CHANNEL_POSITION_REAR_CENTER, { 0.0, 0.0, -0.5 } },
{ PA_CHANNEL_POSITION_MAX, { 0.0, 0.0, 10.0 } }
{ PA_CHANNEL_POSITION_MONO, osd::channel_position::FC },
{ PA_CHANNEL_POSITION_FRONT_LEFT, osd::channel_position::FL },
{ PA_CHANNEL_POSITION_FRONT_RIGHT, osd::channel_position::FR },
{ PA_CHANNEL_POSITION_FRONT_CENTER, osd::channel_position::FC },
{ PA_CHANNEL_POSITION_LFE, osd::channel_position::LFE },
{ PA_CHANNEL_POSITION_REAR_LEFT, osd::channel_position::RL },
{ PA_CHANNEL_POSITION_REAR_RIGHT, osd::channel_position::RR },
{ PA_CHANNEL_POSITION_REAR_CENTER, osd::channel_position::RC },
{ PA_CHANNEL_POSITION_MAX, osd::channel_position::ONREQ },
};

View File

@ -148,17 +148,17 @@ osd::audio_info sound_sdl::get_information()
enum { FL, FR, FC, LFE, BL, BR, BC, SL, SR, AUX };
static const char *const posname[10] = { "FL", "FR", "FC", "LFE", "BL", "BR", "BC", "SL", "SR", "AUX" };
static std::array<double, 3> pos3d[10] = {
{ -0.2, 0.0, 1.0 },
{ 0.2, 0.0, 1.0 },
{ 0.0, 0.0, 1.0 },
{ 0.0, -0.5, 1.0 },
{ -0.2, 0.0, -0.5 },
{ 0.2, 0.0, -0.5 },
{ 0.0, 0.0, -0.5 },
{ -0.2, 0.0, 0.0 },
{ 0.2, 0.0, 0.0 },
{ 0.0, 0.0, 10.0 },
static const osd::channel_position pos3d[10] = {
osd::channel_position::FL,
osd::channel_position::FR,
osd::channel_position::FC,
osd::channel_position::LFE,
osd::channel_position::RL,
osd::channel_position::RR,
osd::channel_position::RC,
osd::channel_position(-0.2, 0.0, 0.0),
osd::channel_position( 0.2, 0.0, 0.0),
osd::channel_position::ONREQ
};
static const uint32_t positions[8][9] = {

View File

@ -30,8 +30,8 @@ osd::audio_info sound_module::get_information()
result.m_nodes[0].m_sources = 0;
result.m_nodes[0].m_port_names.emplace_back("L");
result.m_nodes[0].m_port_names.emplace_back("R");
result.m_nodes[0].m_port_positions.emplace_back(std::array<double, 3>({ -0.2, 0.0, 1.0 }));
result.m_nodes[0].m_port_positions.emplace_back(std::array<double, 3>({ 0.2, 0.0, 1.0 }));
result.m_nodes[0].m_port_positions.emplace_back(osd::channel_position::FL);
result.m_nodes[0].m_port_positions.emplace_back(osd::channel_position::FR);
result.m_streams.resize(1);
result.m_streams[0].m_id = 1;
result.m_streams[0].m_node = 1;
@ -40,13 +40,18 @@ osd::audio_info sound_module::get_information()
sound_module::abuffer::abuffer(uint32_t channels) noexcept : m_channels(channels), m_used_buffers(0), m_last_sample(channels, 0)
{
m_delta = 0;
m_delta2 = 0;
}
void sound_module::abuffer::get(int16_t *data, uint32_t samples) noexcept
{
m_delta -= samples;
m_delta2 -= samples;
uint32_t pos = 0;
while(pos != samples) {
if(!m_used_buffers) {
m_delta2 += samples - pos;
while(pos != samples) {
std::copy_n(m_last_sample.data(), m_channels, data);
data += m_channels;
@ -74,10 +79,13 @@ void sound_module::abuffer::get(int16_t *data, uint32_t samples) noexcept
pos += avail;
data += avail * m_channels;
}
// printf("# %d %d\n", m_delta, m_delta2);
}
void sound_module::abuffer::push(const int16_t *data, uint32_t samples)
{
m_delta += samples;
m_delta2 += samples;
auto &buf = push_buffer();
buf.m_cpos = 0;
buf.m_data.resize(samples * m_channels);
@ -85,6 +93,8 @@ void sound_module::abuffer::push(const int16_t *data, uint32_t samples)
std::copy_n(data + ((samples - 1) * m_channels), m_channels, m_last_sample.data());
if(m_used_buffers > 10) {
for(uint32_t i=0; i != m_used_buffers-10; i++)
m_delta2 -= (m_buffers[i].m_data.size()/m_channels - m_buffers[i].m_cpos);
// If there are way too many buffers, drop some so only 10 are left (roughly 0.2s)
for(unsigned i = 0; 10 > i; ++i) {
using std::swap;
@ -95,8 +105,10 @@ void sound_module::abuffer::push(const int16_t *data, uint32_t samples)
// If there are too many buffers, remove five samples per buffer
// to slowly resync to reduce latency (4 seconds to
// compensate one buffer, roughly)
m_delta2 -= std::max<uint32_t>(samples / 200, 1);
buf.m_cpos = std::max<uint32_t>(samples / 200, 1);
}
// printf("# %d %d\n", m_delta, m_delta2);
}
uint32_t sound_module::abuffer::available() const noexcept

View File

@ -63,6 +63,7 @@ protected:
void pop_buffer() noexcept;
buffer &push_buffer();
int32_t m_delta, m_delta2;
uint32_t m_channels;
uint32_t m_used_buffers;
std::vector<int16_t> m_last_sample;