mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-01 03:18:09 +03:00
Implement System40.ini/AliceStart.ini mixers
Implement "VolumeValancer" mixer channels from the .ini file. Mixers are now recursive, with the master and voice channels being parent nodes (this seems to be hardcoded in system 4, or at least I haven't found where the hierarchy is specified). Also implement .wai file support (needed for mixer channel info on sound files).
This commit is contained in:
@@ -28,10 +28,25 @@ struct bgi {
|
||||
int volume;
|
||||
};
|
||||
|
||||
struct wai {
|
||||
//int uk1;
|
||||
//int uk2;
|
||||
int channel;
|
||||
//int uk3; // version 4+
|
||||
};
|
||||
|
||||
void bgi_read(const char *path);
|
||||
struct bgi *bgi_get(int no);
|
||||
void wai_load(const char *path);
|
||||
struct wai *wai_get(int no);
|
||||
|
||||
void mixer_init(void);
|
||||
int mixer_get_numof(void);
|
||||
const char *mixer_get_name(int n);
|
||||
int mixer_get_volume(int n, int *volume);
|
||||
int mixer_set_volume(int n, int volume);
|
||||
int mixer_get_mute(int n, int *mute);
|
||||
int mixer_set_mute(int n, int mute);
|
||||
|
||||
struct channel;
|
||||
enum asset_type;
|
||||
|
||||
+3
-2
@@ -341,8 +341,9 @@ void sts_mixer_mix_audio(sts_mixer_t* mixer, void* output, unsigned int samples)
|
||||
}
|
||||
|
||||
// write to buffer
|
||||
left = sts_mixer__clamp_sample(left);
|
||||
right = sts_mixer__clamp_sample(right);
|
||||
// NOTE: xsystem4 change: use mixer gain (not sure why this isn't implemented upstream...)
|
||||
left = sts_mixer__clamp_sample(left * mixer->gain);
|
||||
right = sts_mixer__clamp_sample(right * mixer->gain);
|
||||
switch (mixer->audio_format) {
|
||||
case STS_MIXER_SAMPLE_FORMAT_8:
|
||||
*out_8++ = (char)(left * 127.0f);
|
||||
|
||||
@@ -30,6 +30,8 @@ struct config {
|
||||
int view_height;
|
||||
size_t mixer_nr_channels;
|
||||
char **mixer_channels;
|
||||
int *mixer_volumes;
|
||||
int default_volume;
|
||||
|
||||
char *bgi_path;
|
||||
char *wai_path;
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "system4.h"
|
||||
#include "system4/file.h"
|
||||
#include "mixer.h"
|
||||
#include "little_endian.h"
|
||||
|
||||
#define BGI_MAX 100
|
||||
|
||||
@@ -91,3 +94,59 @@ struct bgi *bgi_get(int no)
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct wai *wai_data = NULL;
|
||||
static int nr_wai = 0;
|
||||
|
||||
void wai_load(const char *path)
|
||||
{
|
||||
size_t len;
|
||||
uint8_t *file = file_read(path, &len);
|
||||
|
||||
if (len < 48 || file[0] != 'X' || file[1] != 'I' || file[2] != '2' || file[3] != '\0') {
|
||||
WARNING("Not a .wai file: %s", path);
|
||||
goto end;
|
||||
}
|
||||
int count = LittleEndian_getDW(file, 8) - 1;
|
||||
if (count < 0) {
|
||||
WARNING("Invalid .wai count: %d", count);
|
||||
goto end;
|
||||
}
|
||||
int version = LittleEndian_getDW(file, 12);
|
||||
if (version < 3 || version > 4) {
|
||||
WARNING("Unsupported .wai version: %d", version);
|
||||
goto end;
|
||||
}
|
||||
|
||||
uint8_t *data;
|
||||
int record_size;
|
||||
if (version == 4) {
|
||||
data = file + 40;
|
||||
record_size = 4*4;
|
||||
} else {
|
||||
data = file + 36;
|
||||
record_size = 3*4;
|
||||
}
|
||||
|
||||
if (len - (version == 4 ? 40 : 36) < (size_t)count*record_size) {
|
||||
WARNING(".wai file truncated");
|
||||
goto end;
|
||||
}
|
||||
|
||||
wai_data = xcalloc(count, sizeof(struct wai));
|
||||
for (int i = 0; i < count; i++) {
|
||||
wai_data[i].channel = LittleEndian_getDW(data, i*record_size + 8);
|
||||
}
|
||||
nr_wai = count;
|
||||
|
||||
end:
|
||||
free(file);
|
||||
}
|
||||
|
||||
struct wai *wai_get(int no)
|
||||
{
|
||||
no--;
|
||||
if (no < 0 || no >= nr_wai)
|
||||
return NULL;
|
||||
return &wai_data[no];
|
||||
}
|
||||
|
||||
+180
-20
@@ -28,6 +28,8 @@
|
||||
#include "mixer.h"
|
||||
#include "xsystem4.h"
|
||||
|
||||
#define clamp(min_value, max_value, value) min(max_value, max(min_value, value))
|
||||
|
||||
/*
|
||||
* The actual mixer implementation is contained in this header.
|
||||
* The rest of this file implements a high level interface for managing mixer
|
||||
@@ -51,6 +53,7 @@ struct channel {
|
||||
// archive data
|
||||
struct archive_data *dfile;
|
||||
int no;
|
||||
int mixer_no;
|
||||
|
||||
// audio file data
|
||||
SNDFILE *file;
|
||||
@@ -73,15 +76,34 @@ struct channel {
|
||||
struct fade fade;
|
||||
};
|
||||
|
||||
struct mixer {
|
||||
sts_mixer_t mixer;
|
||||
sts_mixer_stream_t stream;
|
||||
int voice;
|
||||
atomic_bool muted;
|
||||
float data[CHUNK_SIZE * 2];
|
||||
char *name;
|
||||
|
||||
struct mixer *parent;
|
||||
struct mixer **children;
|
||||
int nr_children;
|
||||
};
|
||||
|
||||
static struct mixer *master = NULL;
|
||||
static struct mixer *mixers = NULL;
|
||||
static int nr_mixers = 0;
|
||||
|
||||
static SDL_AudioDeviceID audio_device = 0;
|
||||
static sts_mixer_t mixer;
|
||||
|
||||
/*
|
||||
* The SDL2 audio callback.
|
||||
*/
|
||||
static void audio_callback(possibly_unused void *data, Uint8 *stream, int len)
|
||||
{
|
||||
sts_mixer_mix_audio(&mixer, stream, len / (sizeof(float) * 2));
|
||||
sts_mixer_mix_audio(&master->mixer, stream, len / (sizeof(float) * 2));
|
||||
if (master->muted) {
|
||||
memset(stream, 0, len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -122,7 +144,6 @@ static bool cb_loop(struct channel *ch)
|
||||
* Callback to refill the stream's audio data.
|
||||
* Called from sys_mixer_mix_audio.
|
||||
*/
|
||||
//static int refill_stream(sts_mixer_sample_t *sample, void *data)
|
||||
static int cb_read_frames(struct channel *ch, float *out, sf_count_t frame_count)
|
||||
{
|
||||
sf_count_t num_read = 0;
|
||||
@@ -210,7 +231,7 @@ static int refill_stream(sts_mixer_sample_t *sample, void *data)
|
||||
// set gain for fade
|
||||
if (ch->fade.fading) {
|
||||
float gain = cb_calc_fade(&ch->fade, ch->frame);
|
||||
mixer.voices[ch->voice].gain = gain;
|
||||
mixers[ch->mixer_no].mixer.voices[ch->voice].gain = gain;
|
||||
ch->volume = gain * 100.0;
|
||||
|
||||
if (ch->frame >= ch->fade.end_pos) {
|
||||
@@ -224,6 +245,17 @@ static int refill_stream(sts_mixer_sample_t *sample, void *data)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int refill_mixer(sts_mixer_sample_t *sample, void *data)
|
||||
{
|
||||
struct mixer *mixer = data;
|
||||
sts_mixer_mix_audio(&mixer->mixer, &mixer->data, CHUNK_SIZE);
|
||||
if (mixer->muted) {
|
||||
memset(mixer->data, 0, sizeof(float) * sample->length);
|
||||
}
|
||||
|
||||
return STS_STREAM_CONTINUE;
|
||||
}
|
||||
|
||||
int channel_play(struct channel *ch)
|
||||
{
|
||||
SDL_LockAudioDevice(audio_device);
|
||||
@@ -231,7 +263,7 @@ int channel_play(struct channel *ch)
|
||||
SDL_UnlockAudioDevice(audio_device);
|
||||
return 0;
|
||||
}
|
||||
ch->voice = sts_mixer_play_stream(&mixer, &ch->stream, 1.0f);
|
||||
ch->voice = sts_mixer_play_stream(&mixers[ch->mixer_no].mixer, &ch->stream, 1.0f);
|
||||
SDL_UnlockAudioDevice(audio_device);
|
||||
return 1;
|
||||
}
|
||||
@@ -243,7 +275,7 @@ int channel_stop(struct channel *ch)
|
||||
SDL_UnlockAudioDevice(audio_device);
|
||||
return 0;
|
||||
}
|
||||
sts_mixer_stop_voice(&mixer, ch->voice);
|
||||
sts_mixer_stop_voice(&mixers[ch->mixer_no].mixer, ch->voice);
|
||||
ch->voice = -1;
|
||||
SDL_UnlockAudioDevice(audio_device);
|
||||
return 1;
|
||||
@@ -291,7 +323,7 @@ int channel_fade(struct channel *ch, int time, int volume, bool stop)
|
||||
ch->fade.start_pos = ch->frame;
|
||||
ch->fade.start_volume = (float)ch->volume / 100.0;
|
||||
ch->fade.end_pos = ch->fade.start_pos + ((time * ch->info.samplerate) / 1000);
|
||||
ch->fade.end_volume = min(1.0, max(0.0, (float)volume / 100.0));
|
||||
ch->fade.end_volume = clamp(0.0f, 1.0f, (float)volume / 100.0f);
|
||||
SDL_UnlockAudioDevice(audio_device);
|
||||
return 1;
|
||||
}
|
||||
@@ -395,7 +427,7 @@ static sf_count_t channel_vio_seek(sf_count_t offset, int whence, void *data)
|
||||
ch->offset = ch->dfile->size + offset;
|
||||
break;
|
||||
}
|
||||
ch->offset = min((sf_count_t)ch->dfile->size, max(0, ch->offset));
|
||||
ch->offset = clamp(0, (sf_count_t)ch->dfile->size, ch->offset);
|
||||
return ch->offset;
|
||||
}
|
||||
|
||||
@@ -459,17 +491,28 @@ struct channel *channel_open(enum asset_type type, int no)
|
||||
ch->stream.sample.data = ch->data;
|
||||
ch->voice = -1;
|
||||
|
||||
struct bgi *bgi = bgi_get(no);
|
||||
if (bgi) {
|
||||
ch->volume = min(100, max(0, bgi->volume));
|
||||
ch->loop_start = min(ch->info.frames, max(0, bgi->loop_start));
|
||||
ch->loop_end = min(ch->info.frames, max(0, bgi->loop_end));
|
||||
ch->loop_count = max(0, bgi->loop_count);
|
||||
} else {
|
||||
if (type == ASSET_SOUND) {
|
||||
struct wai *wai = wai_get(no);
|
||||
ch->volume = 100;
|
||||
ch->loop_start = 0;
|
||||
ch->loop_end = ch->info.frames;
|
||||
ch->loop_count = type == ASSET_SOUND ? 1 : 0;
|
||||
ch->loop_count = 1;
|
||||
ch->mixer_no = wai ? wai->channel : 1;
|
||||
} else {
|
||||
struct bgi *bgi = bgi_get(no);
|
||||
if (bgi) {
|
||||
ch->volume = clamp(0, 100, bgi->volume);
|
||||
ch->loop_start = clamp(0, ch->info.frames, bgi->loop_start);
|
||||
ch->loop_end = clamp(0, ch->info.frames, bgi->loop_end);
|
||||
ch->loop_count = max(0, bgi->loop_count);
|
||||
ch->mixer_no = clamp(0, nr_mixers, bgi->channel);
|
||||
} else {
|
||||
ch->volume = 100;
|
||||
ch->loop_start = 0;
|
||||
ch->loop_end = ch->info.frames;
|
||||
ch->loop_count = 0;
|
||||
ch->mixer_no = 0;
|
||||
}
|
||||
}
|
||||
ch->no = no;
|
||||
|
||||
@@ -490,8 +533,81 @@ void channel_close(struct channel *ch)
|
||||
free(ch);
|
||||
}
|
||||
|
||||
#define SJIS_MASTER "\x83\x7d\x83\x58\x83\x5e\x81\x5b"
|
||||
#define SJIS_VOICE "\x89\xb9\x90\xba"
|
||||
|
||||
void mixer_init(void)
|
||||
{
|
||||
// initialize mixer naming
|
||||
if (!config.mixer_nr_channels) {
|
||||
nr_mixers = 3;
|
||||
mixers = xcalloc(nr_mixers, sizeof(struct mixer));
|
||||
mixers[0].name = "Music";
|
||||
mixers[1].name = "Sound";
|
||||
mixers[2].name = "Master";
|
||||
} else {
|
||||
// NOTE: Older games don't have an explicit master channel.
|
||||
// We add an extra mixer in this case for consistency.
|
||||
int need_master = 1;
|
||||
if (!strcmp(config.mixer_channels[0], "Master") || !strcmp(config.mixer_channels[0], SJIS_MASTER)) {
|
||||
need_master = 0;
|
||||
}
|
||||
nr_mixers = config.mixer_nr_channels + need_master;
|
||||
mixers = xcalloc(nr_mixers, sizeof(struct mixer));
|
||||
for (unsigned i = 0; i < config.mixer_nr_channels; i++) {
|
||||
mixers[i].name = config.mixer_channels[i];
|
||||
}
|
||||
if (need_master) {
|
||||
mixers[nr_mixers-1].name = "Master";
|
||||
master = &mixers[nr_mixers-1];
|
||||
} else {
|
||||
master = &mixers[0];
|
||||
}
|
||||
}
|
||||
|
||||
// initialize mixer hierarchy
|
||||
// NOTE: "Master" and "Voice" are special nodes; all channels following
|
||||
// them in the list become their children. This appears to be
|
||||
// hardcoded behavior in system 4.
|
||||
struct mixer *parent = master;
|
||||
for (int i = 0; i < nr_mixers; i++) {
|
||||
if (&mixers[i] == master)
|
||||
continue;
|
||||
mixers[i].parent = parent;
|
||||
parent->children = xrealloc_array(parent->children, parent->nr_children, parent->nr_children+1, sizeof(struct mixer*));
|
||||
parent->children[parent->nr_children++] = &mixers[i];
|
||||
if (!strcmp(mixers[i].name, "Voice") || !strcmp(mixers[i].name, SJIS_VOICE)) {
|
||||
parent = &mixers[i];
|
||||
}
|
||||
}
|
||||
|
||||
// initialize mixers
|
||||
for (int i = 0; i < nr_mixers; i++) {
|
||||
sts_mixer_init(&mixers[i].mixer, 44100, STS_MIXER_SAMPLE_FORMAT_FLOAT);
|
||||
int volume = i < (int)config.mixer_nr_channels ? config.mixer_volumes[i] : config.default_volume;
|
||||
mixers[i].mixer.gain = clamp(0.0f, 1.0f, (float)volume / 100.0f);
|
||||
}
|
||||
|
||||
// initialize mixer streams
|
||||
for (int i = 0; i < nr_mixers; i++) {
|
||||
if (&mixers[i] == master)
|
||||
continue;
|
||||
mixers[i].stream.userdata = &mixers[i];
|
||||
mixers[i].stream.callback = refill_mixer;
|
||||
mixers[i].stream.sample.frequency = 44100;
|
||||
mixers[i].stream.sample.audio_format = STS_MIXER_SAMPLE_FORMAT_FLOAT;
|
||||
mixers[i].stream.sample.length = CHUNK_SIZE * 2;
|
||||
mixers[i].stream.sample.data = mixers[i].data;
|
||||
mixers[i].voice = sts_mixer_play_stream(&mixers[i].parent->mixer, &mixers[i].stream, 1.0f);
|
||||
}
|
||||
|
||||
// read audio metadata
|
||||
if (config.bgi_path)
|
||||
bgi_read(config.bgi_path);
|
||||
if (config.wai_path)
|
||||
wai_load(config.wai_path);
|
||||
|
||||
// initialize SDL audio
|
||||
SDL_AudioSpec have;
|
||||
SDL_AudioSpec want = {
|
||||
.format = AUDIO_F32,
|
||||
@@ -501,9 +617,53 @@ void mixer_init(void)
|
||||
.callback = audio_callback,
|
||||
};
|
||||
audio_device = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
|
||||
sts_mixer_init(&mixer, 44100, STS_MIXER_SAMPLE_FORMAT_FLOAT);
|
||||
if (config.bgi_path)
|
||||
bgi_read(config.bgi_path);
|
||||
|
||||
SDL_PauseAudioDevice(audio_device, 0);
|
||||
}
|
||||
|
||||
int mixer_get_numof(void)
|
||||
{
|
||||
return nr_mixers;
|
||||
}
|
||||
|
||||
const char *mixer_get_name(int n)
|
||||
{
|
||||
if (n < 0 || n >= nr_mixers)
|
||||
return NULL;
|
||||
return mixers[n].name;
|
||||
}
|
||||
|
||||
int mixer_get_volume(int n, int *volume)
|
||||
{
|
||||
if (n < 0 || n >= nr_mixers) {
|
||||
return 0;
|
||||
}
|
||||
SDL_LockAudioDevice(audio_device);
|
||||
*volume = clamp(0, 100, (int)(mixers[n].mixer.gain * 100));
|
||||
SDL_UnlockAudioDevice(audio_device);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mixer_set_volume(int n, int volume)
|
||||
{
|
||||
if (n < 0 || n >= nr_mixers)
|
||||
return 0;
|
||||
SDL_LockAudioDevice(audio_device);
|
||||
mixers[n].mixer.gain = clamp(0.0f, 1.0f, (float)volume / 100.0f);
|
||||
SDL_UnlockAudioDevice(audio_device);
|
||||
return 1;
|
||||
}
|
||||
int mixer_get_mute(int n, int *mute)
|
||||
{
|
||||
if (n < 0 || n >= nr_mixers)
|
||||
return 0;
|
||||
*mute = mixers[n].muted;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mixer_set_mute(int n, int mute)
|
||||
{
|
||||
if (n < 0 || n >= nr_mixers)
|
||||
return 0;
|
||||
mixers[n].muted = !!mute;
|
||||
return 1;
|
||||
}
|
||||
|
||||
+9
-44
@@ -18,56 +18,21 @@
|
||||
|
||||
#include "system4/string.h"
|
||||
|
||||
#include "mixer.h"
|
||||
#include "xsystem4.h"
|
||||
#include "hll.h"
|
||||
|
||||
static int SystemService_GetMixerNumof(void)
|
||||
{
|
||||
return config.mixer_nr_channels;
|
||||
}
|
||||
|
||||
static int SystemService_GetMixerName(int n, struct string **name)
|
||||
{
|
||||
if (n < 0 || (size_t)n >= config.mixer_nr_channels)
|
||||
const char *r = mixer_get_name(n);
|
||||
if (!r)
|
||||
return 0;
|
||||
*name = make_string(config.mixer_channels[n], strlen(config.mixer_channels[n]));
|
||||
*name = make_string(r, strlen(r));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int SystemService_GetMixerVolume(int n, int *volume)
|
||||
{
|
||||
if (n < 0 || (size_t)n >= config.mixer_nr_channels)
|
||||
return 0;
|
||||
*volume = 100;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int SystemService_GetMixerMute(int n, int *mute)
|
||||
{
|
||||
if (n < 0 || (size_t)n >= config.mixer_nr_channels)
|
||||
return 0;
|
||||
*mute = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
//bool SystemService_SetMixerName(int nNum, string szName);
|
||||
|
||||
static int SystemService_SetMixerVolume(int n, possibly_unused int volume)
|
||||
{
|
||||
if (n < 0 || (size_t)n >= config.mixer_nr_channels)
|
||||
return 0;
|
||||
// TODO
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int SystemService_SetMixerMute(int n, possibly_unused int mute)
|
||||
{
|
||||
if (n < 0 || (size_t)n >= config.mixer_nr_channels)
|
||||
return 0;
|
||||
// TODO
|
||||
return 1;
|
||||
}
|
||||
|
||||
//int SystemService_GetGameVersion(void);
|
||||
static void SystemService_GetGameName(struct string **game_name)
|
||||
{
|
||||
@@ -163,13 +128,13 @@ static bool SystemService_GetMouseCursorConfig(int type, int *value)
|
||||
static void SystemService_RestrainScreensaver(void) { }
|
||||
|
||||
HLL_LIBRARY(SystemService,
|
||||
HLL_EXPORT(GetMixerNumof, SystemService_GetMixerNumof),
|
||||
HLL_EXPORT(GetMixerNumof, mixer_get_numof),
|
||||
HLL_EXPORT(GetMixerName, SystemService_GetMixerName),
|
||||
HLL_EXPORT(GetMixerVolume, SystemService_GetMixerVolume),
|
||||
HLL_EXPORT(GetMixerMute, SystemService_GetMixerMute),
|
||||
HLL_EXPORT(GetMixerVolume, mixer_get_volume),
|
||||
HLL_EXPORT(GetMixerMute, mixer_get_mute),
|
||||
HLL_TODO_EXPORT(SetMixerName, SystemService_SetMixerName),
|
||||
HLL_EXPORT(SetMixerVolume, SystemService_SetMixerVolume),
|
||||
HLL_EXPORT(SetMixerMute, SystemService_SetMixerMute),
|
||||
HLL_EXPORT(SetMixerVolume, mixer_set_volume),
|
||||
HLL_EXPORT(SetMixerMute, mixer_set_mute),
|
||||
HLL_TODO_EXPORT(GetGameVersion, SystemService_GetGameVersion),
|
||||
HLL_EXPORT(GetGameName, SystemService_GetGameName),
|
||||
HLL_TODO_EXPORT(AddURLMenu, SystemService_AddURLMenu),
|
||||
|
||||
@@ -51,6 +51,7 @@ struct config config = {
|
||||
.view_height = 600,
|
||||
.mixer_nr_channels = 0,
|
||||
.mixer_channels = NULL,
|
||||
.default_volume = 100,
|
||||
.joypad = false,
|
||||
};
|
||||
|
||||
@@ -120,6 +121,7 @@ static void read_mixer_channels(struct ini_entry *entry)
|
||||
|
||||
config.mixer_nr_channels = entry->value.list_size;
|
||||
config.mixer_channels = xcalloc(entry->value.list_size, sizeof(char*));
|
||||
config.mixer_volumes = xcalloc(entry->value.list_size, sizeof(int));
|
||||
for (size_t i = 0; i < entry->value.list_size; i++) {
|
||||
if (entry->value.list[i].type == INI_NULL) {
|
||||
WARNING("No name given for VolumeValancer[%d]", i);
|
||||
@@ -127,6 +129,8 @@ static void read_mixer_channels(struct ini_entry *entry)
|
||||
}
|
||||
if (entry->value.list[i].type == INI_STRING) {
|
||||
config.mixer_channels[i] = strdup(entry->value.list[i].s->text);
|
||||
// XXX: assumes default_volume was already initialized
|
||||
config.mixer_volumes[i] = config.default_volume;
|
||||
} else if (entry->value.list[i].type == INI_LIST) {
|
||||
if (entry->value.list[i].list_size != 2)
|
||||
ERROR("ini value for 'VolumeValancer' is list of wrong size");
|
||||
@@ -135,6 +139,7 @@ static void read_mixer_channels(struct ini_entry *entry)
|
||||
if (entry->value.list[i].list[1].type != INI_INTEGER)
|
||||
ERROR("ini value for 'VolumeValancer' level is not an integer");
|
||||
config.mixer_channels[i] = strdup(entry->value.list[i].list[0].s->text);
|
||||
config.mixer_volumes[i] = entry->value.list[i].list[1].i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,6 +164,8 @@ static void read_config(const char *path)
|
||||
config.view_height = ini_integer(&ini[i]);
|
||||
} else if (!strcmp(ini[i].name->text, "VolumeValancer")) {
|
||||
read_mixer_channels(&ini[i]);
|
||||
} else if (!strcmp(ini[i].name->text, "DefaultVolumeRate")) {
|
||||
config.default_volume = ini_integer(&ini[i]);
|
||||
}
|
||||
ini_free_entry(&ini[i]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user