Skip to content

Commit

Permalink
add new 'Extend Mono sound to Stereo' option, to help multi channel (…
Browse files Browse the repository at this point in the history
…e.g. 5.1 or 7.1 speaker setup) sound system users

address parts of #155 and fix vpinball/vpinball#564
  • Loading branch information
toxieainc committed Oct 3, 2023
1 parent 0e7137f commit 42fb04b
Show file tree
Hide file tree
Showing 13 changed files with 75 additions and 33 deletions.
2 changes: 2 additions & 0 deletions release/whatsnewVPM.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Version 3.6 (XX XXth, 2023) - "Sounds good III"
------------------------------------------------------------------------------
- Add 'ModOutputType' to COM-API for new PWM support (see whatsnew.txt and https://github.com/vpinball/pinmame/pull/89 for details and usage)

- Add new 'Extend Mono sound to Stereo' option, to help multi channel (e.g. 5.1 or 7.1 speaker setup) sound system users

- Remove the SyncLevel option from the options, nowadays this should be counter-productive

Version 3.5 (October 23rd, 2022) - "Trick or Treat"
Expand Down
9 changes: 5 additions & 4 deletions src/driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,12 @@ typedef struct {
int sound_mode; // 0 = pinmame, 1 = altsound, 2 = pinsound, 3 = pinsound + recordings
#endif
#ifdef PROC_SUPPORT
char *p_roc; /* YAML Machine description file */
int alpha_on_dmd; /* Virtual alphanumeric displays on P-ROC DMD */
int virtual_dmd; /* If we have no screen, then we can suppress the DMD */
char *p_roc; /* YAML Machine description file */
int alpha_on_dmd; /* Virtual alphanumeric displays on P-ROC DMD */
int virtual_dmd; /* If we have no screen, then we can suppress the DMD */
#endif /* PROC_SUPPORT */
int vgmwrite;
int vgmwrite; // bool
int force_mono_to_stereo; // bool
} tPMoptions;
extern tPMoptions pmoptions;
struct pinMachine {
Expand Down
4 changes: 2 additions & 2 deletions src/ios/sound.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,11 @@ int osd_start_audio_stream(int stereo)

if (Machine->sample_rate != 0) {
memset(&aqc, 0, sizeof(AQCallbackStruct));

aqc.dataFormat.mSampleRate = (Float64) Machine->sample_rate;
aqc.dataFormat.mFormatID = kAudioFormatLinearPCM;
aqc.dataFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
aqc.dataFormat.mChannelsPerFrame = (Machine->drv->sound_attributes & SOUND_SUPPORTS_STEREO) ? 2 : 1;
aqc.dataFormat.mChannelsPerFrame = stereo ? 2 : 1;
aqc.dataFormat.mFramesPerPacket = 1;
aqc.dataFormat.mBitsPerChannel = 16;
aqc.dataFormat.mBytesPerPacket = 2 * aqc.dataFormat.mChannelsPerFrame;
Expand Down
2 changes: 0 additions & 2 deletions src/sound/mixer.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@
#define mixerlogerror(a) do { } while (0)
#endif

/* accumulators have ACCUMULATOR_SAMPLES samples (must be a power of 2) */
#define ACCUMULATOR_SAMPLES 8192
#define ACCUMULATOR_MASK (ACCUMULATOR_SAMPLES - 1)

/* fractional numbers have FRACTION_BITS bits of resolution */
Expand Down
3 changes: 3 additions & 0 deletions src/sound/mixer.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

#define MIXER_MAX_CHANNELS 25

/* accumulators have ACCUMULATOR_SAMPLES samples (must be a power of 2) */
#define ACCUMULATOR_SAMPLES 8192

/*
When you allocate a channel, you pass a default mixing level setting.
The mixing level is in the range 0-100, and is passed down to the OS dependant
Expand Down
2 changes: 2 additions & 0 deletions src/ui/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ static REG_OPTION regGameOpts[] =
{ "sound_mode", RO_INT, &gOpts.sound_mode, 0, 0},
#endif
{ "vgmwrite", RO_BOOL, &gOpts.vgmwrite, 0, 0},
{ "force_stereo", RO_BOOL, &gOpts.force_mono_to_stereo, 0, 0},
#endif /* PINMAME */

};
Expand Down Expand Up @@ -816,6 +817,7 @@ BOOL OptionsInit()
global.sound_mode = 0;
#endif
global.vgmwrite = FALSE;
global.force_mono_to_stereo = FALSE;
#endif /* PINMAME */

// game_options[x] is valid if game_variables[i].options_loaded == true
Expand Down
3 changes: 2 additions & 1 deletion src/ui/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,8 @@ typedef struct
#if defined(VPINMAME_ALTSOUND) || defined(VPINMAME_PINSOUND)
int sound_mode;
#endif
int vgmwrite;
int vgmwrite; // bool
int force_mono_to_stereo; // bool
#endif /* PINMAME */

} options_type;
Expand Down
6 changes: 6 additions & 0 deletions src/win32com/ControllerGameSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ class CGameSettingsDlg : public CDialogImpl<CGameSettingsDlg> {
SetDlgItemInt(IDC_ANTIALIAS, vValue.lVal, FALSE);
VariantClear(&vValue);

pGameSettings->get_Value(CComBSTR("force_stereo"), &vValue);
CheckDlgButton(IDC_MONOTOSTEREO, (vValue.boolVal == VARIANT_TRUE) ? BST_CHECKED : BST_UNCHECKED);
VariantClear(&vValue);

pGameSettings->get_Value(CComBSTR("showpindmd"), &vValue);
CheckDlgButton(IDC_PINDMD, (vValue.boolVal==VARIANT_TRUE)?BST_CHECKED:BST_UNCHECKED);
VariantClear(&vValue);
Expand Down Expand Up @@ -200,6 +204,8 @@ class CGameSettingsDlg : public CDialogImpl<CGameSettingsDlg> {
pGameSettings->put_Value(CComBSTR("samplerate"), CComVariant((int) GetDlgItemInt(IDC_SAMPLERATE,NULL,TRUE)));
pGameSettings->put_Value(CComBSTR("dmd_antialias"), CComVariant((int) GetDlgItemInt(IDC_ANTIALIAS,NULL,TRUE)));

pGameSettings->put_Value(CComBSTR("force_stereo"), CComVariant((BOOL)IsDlgButtonChecked(IDC_MONOTOSTEREO)));

pGameSettings->put_Value(CComBSTR("showpindmd"), CComVariant((BOOL) IsDlgButtonChecked(IDC_PINDMD)));
pGameSettings->put_Value(CComBSTR("showwindmd"), CComVariant((BOOL) IsDlgButtonChecked(IDC_WINDMD)));

Expand Down
5 changes: 3 additions & 2 deletions src/win32com/VPinMAME.rc
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,9 @@ BEGIN
EDITTEXT IDC_RESAMPLEQ,178,26,49,12,ES_AUTOHSCROLL
RTEXT "Alt. Sound Mode (0-3):",IDC_STATIC,103,42,72,8
EDITTEXT IDC_SOUNDMODE,178,40,49,12,ES_AUTOHSCROLL
RTEXT "Emulation Fast Frames:",IDC_STATIC,101,56,74,8
EDITTEXT IDC_FASTFRAMES,178,54,49,12,ES_AUTOHSCROLL
CONTROL "Extend Mono sound to Stereo",IDC_MONOTOSTEREO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,115,55,110,10
RTEXT "Emulation Fast Frames:",IDC_STATIC,101,70,74,8
EDITTEXT IDC_FASTFRAMES,178,68,49,12,ES_AUTOHSCROLL
RTEXT "Display &Antialias %:",IDC_STATIC,113,84,62,8
EDITTEXT IDC_ANTIALIAS,178,82,49,12,ES_AUTOHSCROLL
RTEXT "Display Opacity %:",IDC_STATIC,111,98,64,8
Expand Down
3 changes: 3 additions & 0 deletions src/win32com/VPinMAMEConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ int resampling_quality = 0;
int sound_mode = 0;
#endif
int g_vgmwrite = 0;
int g_force_mono_to_stereo = 0;

int threadpriority = 1;
static int deprecated_synclevel = 0;
Expand Down Expand Up @@ -102,6 +103,7 @@ static struct rc_option vpinmame_opts[] = {
{ "low_latency_throttle", NULL, rc_bool, &g_low_latency_throttle, "1", 0, 0, NULL, "Distribute CPU execution across one emulated frame to minimize flipper latency" },

{ "vgmwrite", NULL, rc_bool, &g_vgmwrite, "0", 0, 0, NULL, "Enable to write a VGM of the current session (name is based on romname)" },
{ "force_stereo", NULL, rc_bool, &g_force_mono_to_stereo, "0", 0, 0, NULL, "Always force stereo output (e.g. to better support multi channel sound systems)" },
{ NULL, NULL, rc_end, NULL, NULL, 0, 0, NULL, NULL }
};

Expand Down Expand Up @@ -220,6 +222,7 @@ const static char* RunningGameSettings[] = {
"low_latency_throttle",

"vgmwrite",
"force_stereo",

// video_opts
"screen",
Expand Down
1 change: 1 addition & 0 deletions src/win32com/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#define IDC_CABINETMODE 106
#define IDC_SAMPLERATE 110
#define IDC_ANTIALIAS 111
#define IDC_MONOTOSTEREO 112
#define IDC_FASTFRAMES 113
#define IDC_PINDMD 114
#define IDC_WINDMD 115
Expand Down
1 change: 1 addition & 0 deletions src/windows/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ struct rc_option pinmame_opts[] = {
{ "virtual_dmd", NULL, rc_bool, &pmoptions.virtual_dmd, "1", 0, 0, NULL, "Enable DMD emulation" },
#endif /* PROC_SUPPORT */
{ "vgmwrite", NULL, rc_bool, &pmoptions.vgmwrite, "0", 0, 0, NULL, "Enable to write a VGM of the current session (name is based on romname)" },
{ "force_stereo", NULL, rc_bool, &pmoptions.force_mono_to_stereo, "0", 0, 0, NULL, "Always force stereo output (e.g. to better support multi channel sound systems)" },
{ NULL, NULL, rc_end, NULL, NULL, 0, 0, NULL, NULL }
};
#endif /* PINMAME */
Expand Down
67 changes: 45 additions & 22 deletions src/windows/sound.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,17 +106,28 @@ static int upper_thresh;
// enabled state
static int is_enabled = 1;

static int is_stereo;
static int force_mono_to_stereo;

static int consecutive_lows = 0;
static int consecutive_mids = 0;
static int consecutive_highs = 0;

// for mono -> stereo conversion
static INT16 mix_buffer[ACCUMULATOR_SAMPLES * 2]; /* *2 for stereo */

// debugging
#if LOG_SOUND
static FILE * sound_log;
#endif

// sound options (none at this time)
// sound options
struct rc_option sound_opts[] =
{
// name, shortname, type, dest, deflt, min, max, func, help
{ "Windows sound options", NULL, rc_seperator, NULL, NULL, 0, 0, NULL, NULL },
{ "audio_latency", NULL, rc_int, &audio_latency, "1", 1, 4, NULL, "set audio latency (increase to reduce glitches)" },
{ "force_stereo", NULL, rc_bool, &force_mono_to_stereo, "0", 0, 0, NULL, "always force stereo output (e.g. to better support multi channel sound systems)" },
{ NULL, NULL, rc_end, NULL, NULL, 0, 0, NULL, NULL }
};

Expand All @@ -140,9 +151,7 @@ static void dsound_destroy_buffers(void);
INLINE int bytes_in_stream_buffer(void)
{
DWORD play_position, write_position;
HRESULT result;

result = IDirectSoundBuffer_GetCurrentPosition(stream_buffer, &play_position, &write_position);
HRESULT result = IDirectSoundBuffer_GetCurrentPosition(stream_buffer, &play_position, &write_position);
if (stream_buffer_in > play_position)
return stream_buffer_in - play_position;
else
Expand All @@ -161,6 +170,14 @@ int osd_start_audio_stream(int stereo)
sound_log = fopen("sound.log", "w");
#endif

consecutive_lows = 0;
consecutive_mids = 0;
consecutive_highs = 0;

is_stereo = stereo;

force_mono_to_stereo = pmoptions.force_mono_to_stereo; //!! how to use/set the sound_opts in here?

// skip if sound disabled
if (Machine->sample_rate != 0)
{
Expand Down Expand Up @@ -202,7 +219,7 @@ void osd_stop_audio_stream(void)

// print out over/underflow stats
if (verbose && (buffer_overflows || buffer_underflows))
fprintf(stderr, "Sound buffer: overflows=%d underflows=%d\n", buffer_overflows, buffer_underflows);
fprintf(stderr, "Sound: buffer overflows=%d underflows=%d\n", buffer_overflows, buffer_underflows);

#if LOG_SOUND
if (sound_log)
Expand All @@ -219,10 +236,6 @@ void osd_stop_audio_stream(void)

static void update_sample_adjustment(int buffered)
{
static int consecutive_lows = 0;
static int consecutive_mids = 0;
static int consecutive_highs = 0;

// if we're not throttled don't bother
if (!throttle)
{
Expand Down Expand Up @@ -299,11 +312,10 @@ static void copy_sample_data(INT16 *data, int bytes_to_copy) // adopted from MAM
{
void *buffer1, *buffer2;
DWORD length1, length2;
HRESULT result;
int cur_bytes;

// attempt to lock the stream buffer
result = IDirectSoundBuffer_Lock(stream_buffer, stream_buffer_in, bytes_to_copy, &buffer1, &length1, &buffer2, &length2, 0);
HRESULT result = IDirectSoundBuffer_Lock(stream_buffer, stream_buffer_in, bytes_to_copy, &buffer1, &length1, &buffer2, &length2, 0);

// if we failed, assume it was an underflow (i.e.,
if (result != DS_OK)
Expand All @@ -323,8 +335,8 @@ static void copy_sample_data(INT16 *data, int bytes_to_copy) // adopted from MAM
bytes_to_copy -= cur_bytes;
data = (INT16 *)((UINT8 *)data + cur_bytes); // adopted from MAME 0.105

// copy the second chunk
if (bytes_to_copy != 0)
// copy the second chunk (2 pointers due to circular dsound buffer)
if (bytes_to_copy != 0 && buffer2)
{
cur_bytes = (bytes_to_copy > length2) ? length2 : bytes_to_copy;
memcpy(buffer2, data, cur_bytes);
Expand All @@ -345,13 +357,22 @@ int osd_update_audio_stream(INT16 *buffer)
// if nothing to do, don't do it
if (Machine->sample_rate != 0 && stream_buffer)
{
int original_bytes = bytes_in_stream_buffer();
int input_bytes = samples_this_frame * stream_format.nBlockAlign;
const int original_bytes = bytes_in_stream_buffer();
const int input_bytes = samples_this_frame * stream_format.nBlockAlign;
int final_bytes;

// update the sample adjustment
update_sample_adjustment(original_bytes);

// copy mono to stereo buffer if requested
if(!is_stereo && force_mono_to_stereo)
{
int i;
for (i = 0; i < input_bytes/2; ++i)
mix_buffer[i*2] = mix_buffer[i*2+1] = buffer[i];
buffer = mix_buffer;
}

// copy data into the sound buffer
copy_sample_data(buffer, input_bytes);

Expand Down Expand Up @@ -411,7 +432,7 @@ void osd_set_mastervolume(int _attenuation)

// set the master volume
if (stream_buffer && is_enabled)
IDirectSoundBuffer_SetVolume(stream_buffer, attenuation * 100);
IDirectSoundBuffer_SetVolume(stream_buffer, (attenuation == -32) ? DSBVOLUME_MIN : attenuation * 100);
}


Expand Down Expand Up @@ -455,7 +476,7 @@ typedef struct
// maximum number of handled devices
#define MAX_HANDLED_DEVICES 10

// AudioDevices informations
// AudioDevices information
AudioDevice audio_devices[MAX_HANDLED_DEVICES];

// Number of enumerated audio devices
Expand Down Expand Up @@ -554,7 +575,7 @@ static int dsound_init(void)
LPGUID guid = NULL; // Default audio device

osd_enum_audio_devices(); // (Re-)Enumerate devices

// Get the guid to the user selected audio device (NULL if no selected)
if(current_audio_device>= 0 && current_audio_device<audio_devices_number)
guid = audio_devices[current_audio_device].guid;
Expand Down Expand Up @@ -587,7 +608,7 @@ static int dsound_init(void)
// make a format description for what we want
stream_format.wBitsPerSample = 16;
stream_format.wFormatTag = WAVE_FORMAT_PCM;
stream_format.nChannels = (Machine->drv->sound_attributes & SOUND_SUPPORTS_STEREO) ? 2 : 1;
stream_format.nChannels = (is_stereo || force_mono_to_stereo) ? 2 : 1;
stream_format.nSamplesPerSec = (int)(Machine->sample_rate+0.5);
stream_format.nBlockAlign = stream_format.wBitsPerSample * stream_format.nChannels / 8;
stream_format.nAvgBytesPerSec = stream_format.nSamplesPerSec * stream_format.nBlockAlign;
Expand All @@ -597,6 +618,8 @@ static int dsound_init(void)
stream_buffer_size = (stream_buffer_size * stream_format.nBlockAlign) / 4;
stream_buffer_size = (UINT32)((stream_buffer_size * 30) / Machine->drv->frames_per_second + 0.5);
stream_buffer_size = (stream_buffer_size / 1024) * 1024;
if (stream_buffer_size < 1024)
stream_buffer_size = 1024;

// compute the upper/lower thresholds
lower_thresh = audio_latency * stream_buffer_size / 5;
Expand Down Expand Up @@ -687,11 +710,11 @@ static int dsound_create_buffers(void)
result = IDirectSoundBuffer_GetFormat(primary_buffer, &primary_format, sizeof(primary_format), NULL);
if (result != DS_OK)
{
fprintf(stderr, "Error getting primary format: %08x\n", (UINT32)result);
fprintf(stderr, "Error getting primary DirectSound buffer format: %08x\n", (UINT32)result);
goto cant_get_primary_format;
}
if (verbose)
fprintf(stderr, "Primary buffer: %d Hz, %d bits, %d channels\n",
fprintf(stderr, "DirectSound: Primary buffer: %d Hz, %d bits, %d channels\n",
(int)primary_format.nSamplesPerSec, (int)primary_format.wBitsPerSample, (int)primary_format.nChannels);

// create a buffer desc for the stream buffer
Expand Down Expand Up @@ -749,7 +772,7 @@ static void dsound_destroy_buffers(void)
if (stream_buffer)
IDirectSoundBuffer_Stop(stream_buffer);

// release the buffer
// release the stream buffer
if (stream_buffer)
IDirectSoundBuffer_Release(stream_buffer);
stream_buffer = NULL;
Expand Down

0 comments on commit 42fb04b

Please sign in to comment.