Commit d85c48e8 authored by Jeffrey Lee's avatar Jeffrey Lee
Browse files

Allow configuration of default audio controller device

Detail:
  If SndSetup detects that a version of SoundDMA is in use which supports controller enumeration & selection, the plugin display will have an extra string set gadget which can be used to select which device should be used
  When switching between devices the list of mixer controllers will update accordingly
  The controller selection will be saved to the SndSetup choices file, along with the mixer settings - with mixer settings being saved for all mxiers that are present, not just the selected one.
  File changes:
  - Resources/UK/Res,fae, h/defines - Updated to add the new string set and tweak the layout a bit
  - h/sound, c/sound - Added linked list of controller devices. Mixer channel detail arrays are now allocated on demand and stored as part of the controller details. Channel details now also tracks the currently selected mute & gain settings, since we can no longer rely on the UI to store those values for us if we're recreating gadgets ...
parent b96e4f6c
No preview for this file type
/* (2.07)
/* (2.08)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1.
*
*/
#define Module_MajorVersion_CMHG 2.07
#define Module_MajorVersion_CMHG 2.08
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 20 Jul 2013
#define Module_Date_CMHG 08 Jun 2016
#define Module_MajorVersion "2.07"
#define Module_Version 207
#define Module_MajorVersion "2.08"
#define Module_Version 208
#define Module_MinorVersion ""
#define Module_Date "20 Jul 2013"
#define Module_Date "08 Jun 2016"
#define Module_ApplicationDate "20-Jul-13"
#define Module_ApplicationDate "08-Jun-16"
#define Module_ComponentName "SndSetup"
#define Module_ComponentPath "castle/RiscOS/Sources/SystemRes/Configure2/PlugIns/SndSetup"
#define Module_FullVersion "2.07"
#define Module_HelpVersion "2.07 (20 Jul 2013)"
#define Module_LibraryVersionInfo "2:7"
#define Module_FullVersion "2.08"
#define Module_HelpVersion "2.08 (08 Jun 2016)"
#define Module_LibraryVersionInfo "2:8"
......@@ -38,6 +38,8 @@ static MessagesFD messages_desc;
static IdBlock idb;
static char messages_string[255];
static ObjectId config_window_id;
static unsigned int stretch_width;
static int adjustment = 0;
/*---------------------------------------------------------------------------*
......@@ -118,7 +120,7 @@ static int action_selected(int event_code, ToolboxEvent *event_block, IdBlock *i
{
case SetButton:
sound_read_write_cmos_settings(WriteCMOSSettings, config_window_id);
sound_save_choices(config_window_id);
sound_save_choices();
if ((block->hdr.flags & 1) == 0) program_exit(); /* Return or left button pressed */
sound_reset_to_configured(config_window_id);
break;
......@@ -179,191 +181,268 @@ static int message_reopen(WimpMessage *event, void *handler)
/*----------------------------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*
* open_configure_window *
* setup_sliders *
* *
* Called to open the configure window on screen and register handlers. *
* Recreate sliders so that their state matches selected_controller *
*---------------------------------------------------------------------------*/
static void open_configure_window(int at_x, int at_y)
void setup_sliders(void)
{
BBox bbox;
int adjustment = 0;
int screenx;
int screeny;
WindowShowObjectBlock buffer;
const ComponentId stretch_gadgets[] = { BeepGroup, VoicesStringSet };
const ComponentId move_gadgets[] = { DefaultButton, VoicesLabel, QuietRadio, LoudRadio, BeepingErrorsOption };
/* Create window */
error_trap(toolbox_create_object(0, "Window", &config_window_id), 1);
/* Delete current sliders */
for (int i = 0; i < maxchannels*4; i++)
{
window_remove_gadget(0, config_window_id, i);
}
/* Register handlers for the configure window */
error_trap(event_register_toolbox_handler(config_window_id, ActionButton_Selected, action_selected, NULL), 0);
error_trap(event_register_toolbox_handler(config_window_id, OptionButton_StateChanged, sound_reflect_gadget_state, NULL), 0);
error_trap(event_register_toolbox_handler(config_window_id, RadioButton_StateChanged, sound_reflect_gadget_state, NULL), 0);
error_trap(event_register_toolbox_handler(config_window_id, Slider_ValueChanged, sound_reflect_gadget_state, NULL), 0);
error_trap(event_register_toolbox_handler(config_window_id, StringSet_ValueChanged, sound_reflect_gadget_state, NULL), 0);
error_trap(event_register_wimp_handler(-1, Wimp_EKeyPressed, default_key_handler, NULL), 0);
if (!selected_controller)
{
return;
}
/* Do dynamic gadget creation and resizing */
error_trap(window_remove_gadget(0, config_window_id, TemplateLabel), 0);
error_trap(window_remove_gadget(0, config_window_id, TemplateButton), 0);
error_trap(window_remove_gadget(0, config_window_id, TemplateSlider), 0);
error_trap(window_remove_gadget(0, config_window_id, TemplateOption), 0);
ObjectTemplateHeader *object_template;
error_trap(toolbox_template_lookup(0, "Window", (void **)&object_template), 0);
const char *gadget_template[4];
size_t gadget_template_size[4];
error_trap(window_extract_gadget_info(0, object_template, TemplateLabel, (void **)&gadget_template[0], (int *)&gadget_template_size[0]), 0);
error_trap(window_extract_gadget_info(0, object_template, TemplateButton, (void **)&gadget_template[1], (int *)&gadget_template_size[1]), 0);
error_trap(window_extract_gadget_info(0, object_template, TemplateSlider, (void **)&gadget_template[2], (int *)&gadget_template_size[2]), 0);
error_trap(window_extract_gadget_info(0, object_template, TemplateOption, (void **)&gadget_template[3], (int *)&gadget_template_size[3]), 0);
/* Work out memory footprint of largest gadget which we need to dynamically create */
size_t max_template_size = (gadget_template_size[0] > gadget_template_size[1]) ? gadget_template_size[0] : gadget_template_size[1];
if (gadget_template_size[2] > max_template_size) max_template_size = gadget_template_size[2];
if (gadget_template_size[3] > max_template_size) max_template_size = gadget_template_size[3];
char gadget[max_template_size];
int my_adjustment = maxchannels * SLIDER_HEIGHT;
if (!vidcmix)
{
/* Adjust for the 2 gadget height equivalent of OversamplingOption & SixteenBitOption */
for (int i = 0; i < 4; i++)
{
((Gadget *)gadget_template[i])->hdr.box.ymax -= 2 * SLIDER_HEIGHT;
((Gadget *)gadget_template[i])->hdr.box.ymin -= 2 * SLIDER_HEIGHT;
}
adjustment = 2;
/* And get rid of them */
error_trap(window_remove_gadget(0, config_window_id, OversamplingOption), 0);
error_trap(window_remove_gadget(0, config_window_id, SixteenBitOption), 0);
my_adjustment -= 2 * SLIDER_HEIGHT;
}
/* 1) Name field */
memcpy(gadget, gadget_template[0], gadget_template_size[0]);
((Gadget *)gadget)->hdr.box.ymax += nchannels * SLIDER_HEIGHT;
((Gadget *)gadget)->hdr.box.ymin += nchannels * SLIDER_HEIGHT;
unsigned int widest_label = 0;
for (int i = 0; i < nchannels; i++)
((Gadget *)gadget)->hdr.box.ymax += my_adjustment;
((Gadget *)gadget)->hdr.box.ymin += my_adjustment;
for (int i = 0; i < selected_controller->nchannels; i++)
{
char token[11] = "Name";
strcat(token, channel[i].token_suffix);
strcat(token, selected_controller->channels[i].token_suffix);
char param[4];
if (channel[i].token_suffix[4] == '1')
if (selected_controller->channels[i].token_suffix[4] == '1')
{
param[0] = '\0';
}
else
{
sprintf(param, " %d", channel[i].index + 1);
sprintf(param, " %d", selected_controller->channels[i].index + 1);
}
const char *name = messages_lookup_withparam(token, param);
char label[strlen(name) + 1];
strcpy(label, name);
unsigned int this_width = 0;
_swix(Wimp_TextOp, _INR(0,2)|_OUT(0),
1,
label,
0,
&this_width);
if (this_width > widest_label) widest_label = this_width;
((Gadget *)gadget)->hdr.box.xmin -= stretch_width;
((Gadget *)gadget)->hdr.box.ymax -= SLIDER_HEIGHT;
((Gadget *)gadget)->hdr.box.ymin -= SLIDER_HEIGHT;
((Gadget *)gadget)->hdr.component_id = i * 4;
sprintf(token, "HelpL%s", channel[i].token_suffix);
((Gadget *)gadget)->hdr.help_message = (char *)messages_lookup_withparam(token, channel[i].name);
sprintf(token, "HelpL%s", selected_controller->channels[i].token_suffix);
((Gadget *)gadget)->hdr.help_message = (char *)messages_lookup_withparam(token, selected_controller->channels[i].name);
((Gadget *)gadget)->data.label.label = label;
error_trap(window_add_gadget(0, config_window_id, (Gadget *)gadget, NULL), 0);
}
/* 2) Mono/stereo tote */
memcpy(gadget, gadget_template[1], gadget_template_size[1]);
((Gadget *)gadget)->hdr.box.ymax += nchannels * SLIDER_HEIGHT;
((Gadget *)gadget)->hdr.box.ymin += nchannels * SLIDER_HEIGHT;
for (int i = 0; i < nchannels; i++)
((Gadget *)gadget)->hdr.box.ymax += my_adjustment;
((Gadget *)gadget)->hdr.box.ymin += my_adjustment;
for (int i = 0; i < selected_controller->nchannels; i++)
{
((Gadget *)gadget)->hdr.box.ymax -= SLIDER_HEIGHT;
((Gadget *)gadget)->hdr.box.ymin -= SLIDER_HEIGHT;
((Gadget *)gadget)->hdr.component_id = 1 + i * 4;
char token[11] = "HelpB";
strcat(token, channel[i].token_suffix);
((Gadget *)gadget)->hdr.help_message = (char *)messages_lookup_withparam(token, channel[i].name);
((Gadget *)gadget)->data.button.validation = channel[i].mono ? "R2;Smono" : "R2;Sstereo";
strcat(token, selected_controller->channels[i].token_suffix);
((Gadget *)gadget)->hdr.help_message = (char *)messages_lookup_withparam(token, selected_controller->channels[i].name);
((Gadget *)gadget)->data.button.validation = selected_controller->channels[i].mono ? "R2;Smono" : "R2;Sstereo";
error_trap(window_add_gadget(0, config_window_id, (Gadget *)gadget, NULL), 0);
}
/* 3) Slider */
memcpy(gadget, gadget_template[2], gadget_template_size[2]);
((Gadget *)gadget)->hdr.box.ymax += nchannels * SLIDER_HEIGHT;
((Gadget *)gadget)->hdr.box.ymin += nchannels * SLIDER_HEIGHT;
for (int i = 0; i < nchannels; i++)
((Gadget *)gadget)->hdr.box.ymax += my_adjustment;
((Gadget *)gadget)->hdr.box.ymin += my_adjustment;
for (int i = 0; i < selected_controller->nchannels; i++)
{
((Gadget *)gadget)->hdr.box.ymax -= SLIDER_HEIGHT;
((Gadget *)gadget)->hdr.box.ymin -= SLIDER_HEIGHT;
((Gadget *)gadget)->hdr.component_id = 2 + i * 4;
char token[12] = "HelpS";
if (channel[i].fixed) strcpy(token, "HelpSF");
strcat(token, channel[i].token_suffix);
((Gadget *)gadget)->hdr.help_message = (char *)messages_lookup_withparam(token, channel[i].name);
if (selected_controller->channels[i].fixed) strcpy(token, "HelpSF");
strcat(token, selected_controller->channels[i].token_suffix);
((Gadget *)gadget)->hdr.help_message = (char *)messages_lookup_withparam(token, selected_controller->channels[i].name);
((Gadget *)gadget)->hdr.flags &= ~(Gadget_Faded | Slider_BarColour);
((Gadget *)gadget)->hdr.flags |= (channel[i].category >= 0 ? 10 : 11) << Slider_BarColourShift;
if (channel[i].fixed) ((Gadget *)gadget)->hdr.flags |= Gadget_Faded;
((Gadget *)gadget)->hdr.flags |= (selected_controller->channels[i].category >= 0 ? 10 : 11) << Slider_BarColourShift;
if (selected_controller->channels[i].fixed) ((Gadget *)gadget)->hdr.flags |= Gadget_Faded;
error_trap(window_add_gadget(0, config_window_id, (Gadget *)gadget, NULL), 0);
error_trap(slider_set_bounds(7, config_window_id, 2+i*4, channel[i].mingain, channel[i].maxgain, channel[i].step), 0);
error_trap(slider_set_bounds(7, config_window_id, 2+i*4, selected_controller->channels[i].mingain, selected_controller->channels[i].maxgain, selected_controller->channels[i].step), 0);
error_trap(slider_set_value(0, config_window_id, 2 + i * 4, selected_controller->channels[i].selected_gain), 0);
}
/* 4) Mute option */
memcpy(gadget, gadget_template[3], gadget_template_size[3]);
((Gadget *)gadget)->hdr.box.ymax += nchannels * SLIDER_HEIGHT;
((Gadget *)gadget)->hdr.box.ymin += nchannels * SLIDER_HEIGHT;
for (int i = 0; i < nchannels; i++)
((Gadget *)gadget)->hdr.box.ymax += my_adjustment;
((Gadget *)gadget)->hdr.box.ymin += my_adjustment;
for (int i = 0; i < selected_controller->nchannels; i++)
{
((Gadget *)gadget)->hdr.box.ymax -= SLIDER_HEIGHT;
((Gadget *)gadget)->hdr.box.ymin -= SLIDER_HEIGHT;
((Gadget *)gadget)->hdr.component_id = 3 + i * 4;
char token[12] = "HelpO";
if (channel[i].fixed) strcpy(token, "HelpOF");
strcat(token, channel[i].token_suffix);
((Gadget *)gadget)->hdr.help_message = (char *)messages_lookup_withparam(token, channel[i].name);
if (selected_controller->channels[i].fixed) strcpy(token, "HelpOF");
strcat(token, selected_controller->channels[i].token_suffix);
((Gadget *)gadget)->hdr.help_message = (char *)messages_lookup_withparam(token, selected_controller->channels[i].name);
((Gadget *)gadget)->hdr.flags &= ~Gadget_Faded;
if (vidcmix) ((Gadget *)gadget)->hdr.flags |= Gadget_Faded; /* Unmutable */
if (channel[i].fixed) ((Gadget *)gadget)->hdr.flags |= Gadget_Faded;
if (selected_controller->channels[i].fixed) ((Gadget *)gadget)->hdr.flags |= Gadget_Faded;
error_trap(window_add_gadget(0, config_window_id, (Gadget *)gadget, NULL), 0);
error_trap(optionbutton_set_state(0, config_window_id, 3 + i * 4, selected_controller->channels[i].selected_mute), 0);
}
}
/*---------------------------------------------------------------------------*
* open_configure_window *
* *
* Called to open the configure window on screen and register handlers. *
*---------------------------------------------------------------------------*/
static void open_configure_window(int at_x, int at_y)
{
BBox bbox;
int screenx;
int screeny;
WindowShowObjectBlock buffer;
const ComponentId stretch_gadgets[] = { BeepGroup, VoicesStringSet };
const ComponentId move_gadgets[] = { DefaultButton, VoicesLabel, QuietRadio, LoudRadio, BeepingErrorsOption };
/* Create window */
error_trap(toolbox_create_object(0, "Window", &config_window_id), 1);
/* Register handlers for the configure window */
error_trap(event_register_toolbox_handler(config_window_id, ActionButton_Selected, action_selected, NULL), 0);
error_trap(event_register_toolbox_handler(config_window_id, OptionButton_StateChanged, sound_reflect_gadget_state, NULL), 0);
error_trap(event_register_toolbox_handler(config_window_id, RadioButton_StateChanged, sound_reflect_gadget_state, NULL), 0);
error_trap(event_register_toolbox_handler(config_window_id, Slider_ValueChanged, sound_reflect_gadget_state, NULL), 0);
error_trap(event_register_toolbox_handler(config_window_id, StringSet_ValueChanged, sound_reflect_gadget_state, NULL), 0);
error_trap(event_register_wimp_handler(-1, Wimp_EKeyPressed, default_key_handler, NULL), 0);
error_trap(gadget_get_bbox(0, config_window_id, TemplateLabel, &bbox), 0);
stretch_width = bbox.xmax - bbox.xmin;
/* Do dynamic gadget creation and resizing */
error_trap(window_remove_gadget(0, config_window_id, TemplateLabel), 0);
error_trap(window_remove_gadget(0, config_window_id, TemplateButton), 0);
error_trap(window_remove_gadget(0, config_window_id, TemplateSlider), 0);
error_trap(window_remove_gadget(0, config_window_id, TemplateOption), 0);
if (!vidcmix)
{
/* Adjust for the 2 gadget height equivalent of OversamplingOption & SixteenBitOption */
adjustment = 2 * SLIDER_HEIGHT;
/* And get rid of them */
error_trap(window_remove_gadget(0, config_window_id, OversamplingOption), 0);
error_trap(window_remove_gadget(0, config_window_id, SixteenBitOption), 0);
}
if (!multidevice)
{
/* Adjust for the height equivalent of DeviceStringSet */
adjustment += STRINGSET_HEIGHT;
/* And get rid of them */
error_trap(window_remove_gadget(0, config_window_id, DeviceLabel), 0);
error_trap(window_remove_gadget(0, config_window_id, DeviceStringSet), 0);
}
/* Calculate width of widest name */
unsigned int widest_label = 0;
for (controller_list_entry_t *controller = controllers; controller; controller = controller->next)
{
for (int i = 0; i < controller->nchannels; i++)
{
char token[11] = "Name";
strcat(token, controller->channels[i].token_suffix);
char param[4];
if (controller->channels[i].token_suffix[4] == '1')
{
param[0] = '\0';
}
else
{
sprintf(param, " %d", controller->channels[i].index + 1);
}
const char *name = messages_lookup_withparam(token, param);
char label[strlen(name) + 1];
strcpy(label, name);
unsigned int this_width = 0;
_swix(Wimp_TextOp, _INR(0,2)|_OUT(0),
1,
label,
0,
&this_width);
if (this_width > widest_label) widest_label = this_width;
}
}
unsigned int stretch_width = ((Gadget *)gadget_template[0])->hdr.box.xmax - ((Gadget *)gadget_template[0])->hdr.box.xmin;
stretch_width = widest_label + /* fudge factor */ 16 - stretch_width;
adjustment -= (maxchannels - 1) * SLIDER_HEIGHT;
error_trap(window_get_extent(0, config_window_id, &bbox), 0);
bbox.xmin -= stretch_width;
bbox.ymax += (nchannels - 1 - adjustment) * SLIDER_HEIGHT;
bbox.ymax -= adjustment;
error_trap(window_set_extent(0, config_window_id, &bbox), 0);
for (ComponentId g = 0; g < 4 * nchannels; g+= 4)
{
BBox bbox;
error_trap(gadget_get_bbox(0, config_window_id, g, &bbox), 0);
bbox.xmin -= stretch_width;
error_trap(gadget_move_gadget(0, config_window_id, g, &bbox), 0);
}
error_trap(gadget_get_bbox(0, config_window_id, HardwareBox, &bbox), 0);
bbox.xmin -= stretch_width;
bbox.ymax -= adjustment;
error_trap(gadget_move_gadget(0, config_window_id, HardwareBox, &bbox), 0);
for (int i = 0; i < (sizeof stretch_gadgets / sizeof *stretch_gadgets); i++)
{
BBox bbox;
error_trap(gadget_get_bbox(0, config_window_id, stretch_gadgets[i], &bbox), 0);
bbox.xmin -= stretch_width;
error_trap(gadget_move_gadget(0, config_window_id, stretch_gadgets[i], &bbox), 0);
}
for (int i = 0; i < (sizeof move_gadgets / sizeof *move_gadgets); i++)
{
BBox bbox;
error_trap(gadget_get_bbox(0, config_window_id, move_gadgets[i], &bbox), 0);
bbox.xmin -= stretch_width;
bbox.xmax -= stretch_width;
error_trap(gadget_move_gadget(0, config_window_id, move_gadgets[i], &bbox), 0);
}
if (multidevice)
{
error_trap(gadget_get_bbox(0, config_window_id, DeviceLabel, &bbox), 0);
bbox.xmin -= stretch_width;
bbox.xmax -= stretch_width;
bbox.ymin -= adjustment;
bbox.ymax -= adjustment;
error_trap(gadget_move_gadget(0, config_window_id, DeviceLabel, &bbox), 0);
error_trap(gadget_get_bbox(0, config_window_id, DeviceStringSet, &bbox), 0);
bbox.xmin -= stretch_width;
bbox.ymin -= adjustment;
bbox.ymax -= adjustment;
error_trap(gadget_move_gadget(0, config_window_id, DeviceStringSet, &bbox), 0);
}
error_trap(window_get_extent(0, config_window_id, &bbox), 0);
/* Work out positioning (unless it was supplied in the command line) */
if ((at_x==-1) && (at_y==-1))
{
error_trap(common_read_screensize(&screenx, &screeny), 0);
error_trap(window_get_extent(0, config_window_id, &bbox), 0);
at_y = (screeny + bbox.ymax - bbox.ymin) / 2;
at_x = (screenx - bbox.xmax + bbox.xmin) / 2;
}
......@@ -442,9 +521,10 @@ int main(int argc, char *argv[])
/* Do main initialisation */
if (!main_initialise()) return 0;
sound_detect_mix_mode();
sound_read_channel_info();
sound_enumerate_devices();
open_configure_window(openat_x, openat_y);
sound_make_voices_menu(config_window_id);
sound_make_devices_menu(config_window_id);
sound_reset_to_configured(config_window_id);
/* Poll loop */
......
This diff is collapsed.
......@@ -30,5 +30,6 @@ void ungrey_gadget(int objectid, int gadgetid);
int strncmpa(char* str1, char* str2, int size);
int read_cmos_value(int location);
void write_cmos_value(int location, int value);
void setup_sliders(void);
extern char TaskName[];
......@@ -33,10 +33,15 @@
#define BeepingErrorsOption ((ComponentId) 0x206)
#define OversamplingOption ((ComponentId) 0x207)
#define SixteenBitOption ((ComponentId) 0x208)
#define HardwareBox ((ComponentId) 0x209)
#define DeviceLabel ((ComponentId) 0x20a)
#define DeviceStringSet ((ComponentId) 0x20b)
/* Height offset between volume sliders (OS units) */
#define SLIDER_HEIGHT (56)
#define STRINGSET_HEIGHT (60)
/* Other stuff */
#define ChoicesWrite "<Choices$Write>.Boot.PreDesk.SndSetup"
#define ChoicesRead "Choices:Boot.PreDesk.SndSetup"
......
......@@ -23,7 +23,7 @@
#define MAX_CHANNELS 64 /* currently dictated by component IDs */
extern struct channel
typedef struct
{
char token_suffix[6];
char *name;
......@@ -33,29 +33,48 @@ extern struct channel
bool original_mute;
int configured_gain; /* what to show if the user ADJUST-clicks Cancel */
bool configured_mute;
int selected_gain;
bool selected_mute;
bool fixed;
bool mono;
bool muted_by_default;
int mingain;
int maxgain;
int step;
} channel[MAX_CHANNELS];
} channel_t;
#define VIDC_CHANNEL "O2s01", NULL, mixer_CATEGORY_HEADPHONES, 0, \
0, FALSE, \
0, FALSE, \
0, FALSE, \
FALSE, FALSE, FALSE, \
-21*16, 0*16, 3*16
extern unsigned int nchannels;
typedef struct controller_list_entry
{
struct controller_list_entry *next;
int index; /* Index in string set */
channel_t *channels;
unsigned int nchannels;
const char *mixer_id; /* ID to use with SoundCtrl; will be NULL if !multidevice */
char config_id[1]; /* ID to use with config files; will be '0' if !multidevice */
} controller_list_entry_t;
extern controller_list_entry_t *original_controller;
extern controller_list_entry_t *configured_controller;
extern controller_list_entry_t *selected_controller;
extern controller_list_entry_t *controllers;
extern BOOL vidcmix;
extern BOOL multidevice;
extern unsigned int maxchannels;
void sound_detect_mix_mode(void);
void sound_read_channel_info(void);
void sound_enumerate_devices(void);
void sound_make_voices_menu(int window_id);
void sound_make_devices_menu(int window_id);
void sound_read_write_cmos_settings(int condition_code, int window_id);
void sound_read_choices(int window_id);
void sound_save_choices(int window_id);
void sound_read_choices(void);
void sound_save_choices(void);
int sound_reflect_gadget_state(int event_code, ToolboxEvent *event_block, IdBlock *id_block, void *handle);
void sound_reset_to_configured(int window_id);
void sound_reset_to_defaults(int window_id);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment