mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 08:20:54 +01:00
Update mixing code
This commit is contained in:
parent
dd1bafb201
commit
151de6a39c
@ -21,7 +21,7 @@
|
|||||||
#define VERSION "(unknown version)"
|
#define VERSION "(unknown version)"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BUFFER_SAMPLES 0x8000
|
#define SAMPLE_BUFFER_SIZE 0x8000
|
||||||
|
|
||||||
/* getopt globals (the horror...) */
|
/* getopt globals (the horror...) */
|
||||||
extern char * optarg;
|
extern char * optarg;
|
||||||
@ -384,9 +384,17 @@ int main(int argc, char ** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* modify the VGMSTREAM if needed */
|
/* modify the VGMSTREAM if needed (before printing file info) */
|
||||||
apply_config(vgmstream, &cfg);
|
apply_config(vgmstream, &cfg);
|
||||||
|
|
||||||
|
channels = vgmstream->channels;
|
||||||
|
input_channels = vgmstream->channels;
|
||||||
|
|
||||||
|
#ifdef VGMSTREAM_MIXING
|
||||||
|
/* enable after config but before outbuf */
|
||||||
|
vgmstream_mixing_enable(vgmstream, SAMPLE_BUFFER_SIZE, &input_channels, &channels);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (cfg.play_forever && (!vgmstream->loop_flag || vgmstream->loop_target > 0)) {
|
if (cfg.play_forever && (!vgmstream->loop_flag || vgmstream->loop_target > 0)) {
|
||||||
fprintf(stderr,"I could play a nonlooped track forever, but it wouldn't end well.");
|
fprintf(stderr,"I could play a nonlooped track forever, but it wouldn't end well.");
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -462,15 +470,7 @@ int main(int argc, char ** argv) {
|
|||||||
|
|
||||||
|
|
||||||
/* last init */
|
/* last init */
|
||||||
channels = vgmstream->channels;
|
buf = malloc(SAMPLE_BUFFER_SIZE * sizeof(sample_t) * input_channels);
|
||||||
input_channels = vgmstream->channels;
|
|
||||||
|
|
||||||
#ifdef VGMSTREAM_MIXING
|
|
||||||
/* enable after all config but before outbuf */
|
|
||||||
vgmstream_mixing_enable(vgmstream, BUFFER_SAMPLES, &input_channels, &channels);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
buf = malloc(BUFFER_SAMPLES * sizeof(sample_t) * input_channels);
|
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
fprintf(stderr,"failed allocating output buffer\n");
|
fprintf(stderr,"failed allocating output buffer\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -492,7 +492,7 @@ int main(int argc, char ** argv) {
|
|||||||
|
|
||||||
/* decode forever */
|
/* decode forever */
|
||||||
while (cfg.play_forever) {
|
while (cfg.play_forever) {
|
||||||
int to_get = BUFFER_SAMPLES;
|
int to_get = SAMPLE_BUFFER_SIZE;
|
||||||
|
|
||||||
render_vgmstream(buf, to_get, vgmstream);
|
render_vgmstream(buf, to_get, vgmstream);
|
||||||
|
|
||||||
@ -508,9 +508,9 @@ int main(int argc, char ** argv) {
|
|||||||
|
|
||||||
|
|
||||||
/* decode */
|
/* decode */
|
||||||
for (i = 0; i < len_samples; i += BUFFER_SAMPLES) {
|
for (i = 0; i < len_samples; i += SAMPLE_BUFFER_SIZE) {
|
||||||
int to_get = BUFFER_SAMPLES;
|
int to_get = SAMPLE_BUFFER_SIZE;
|
||||||
if (i + BUFFER_SAMPLES > len_samples)
|
if (i + SAMPLE_BUFFER_SIZE > len_samples)
|
||||||
to_get = len_samples - i;
|
to_get = len_samples - i;
|
||||||
|
|
||||||
render_vgmstream(buf, to_get, vgmstream);
|
render_vgmstream(buf, to_get, vgmstream);
|
||||||
@ -563,9 +563,9 @@ int main(int argc, char ** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* decode */
|
/* decode */
|
||||||
for (i = 0; i < len_samples; i += BUFFER_SAMPLES) {
|
for (i = 0; i < len_samples; i += SAMPLE_BUFFER_SIZE) {
|
||||||
int to_get = BUFFER_SAMPLES;
|
int to_get = SAMPLE_BUFFER_SIZE;
|
||||||
if (i + BUFFER_SAMPLES > len_samples)
|
if (i + SAMPLE_BUFFER_SIZE > len_samples)
|
||||||
to_get = len_samples - i;
|
to_get = len_samples - i;
|
||||||
|
|
||||||
render_vgmstream(buf, to_get, vgmstream);
|
render_vgmstream(buf, to_get, vgmstream);
|
||||||
|
76
src/mixing.c
76
src/mixing.c
@ -658,17 +658,17 @@ void mixing_push_fade(VGMSTREAM* vgmstream, int ch_dst, double vol_start, double
|
|||||||
|
|
||||||
void mixing_macro_volume(VGMSTREAM* vgmstream, double volume, uint32_t mask) {
|
void mixing_macro_volume(VGMSTREAM* vgmstream, double volume, uint32_t mask) {
|
||||||
mixing_data *data = vgmstream->mixing_data;
|
mixing_data *data = vgmstream->mixing_data;
|
||||||
int ch, output_channels;
|
int ch;
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
return;
|
||||||
|
|
||||||
if (mask == 0) {
|
if (mask == 0) {
|
||||||
mixing_push_volume(vgmstream, -1, volume);
|
mixing_push_volume(vgmstream, -1, volume);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
output_channels = data ? data->output_channels : vgmstream->channels;
|
for (ch = 0; ch < data->output_channels; ch++) {
|
||||||
|
|
||||||
for (ch = 0; ch < output_channels; ch++) {
|
|
||||||
if (!((mask >> ch) & 1))
|
if (!((mask >> ch) & 1))
|
||||||
continue;
|
continue;
|
||||||
mixing_push_volume(vgmstream, ch, volume);
|
mixing_push_volume(vgmstream, ch, volume);
|
||||||
@ -677,16 +677,17 @@ void mixing_macro_volume(VGMSTREAM* vgmstream, double volume, uint32_t mask) {
|
|||||||
|
|
||||||
void mixing_macro_track(VGMSTREAM* vgmstream, uint32_t mask) {
|
void mixing_macro_track(VGMSTREAM* vgmstream, uint32_t mask) {
|
||||||
mixing_data *data = vgmstream->mixing_data;
|
mixing_data *data = vgmstream->mixing_data;
|
||||||
int ch, output_channels;
|
int ch;
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
return;
|
||||||
|
|
||||||
if (mask == 0) {
|
if (mask == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
output_channels = data ? data->output_channels : vgmstream->channels;
|
|
||||||
|
|
||||||
/* reverse remove all channels (easier this way as when removing channels numbers change) */
|
/* reverse remove all channels (easier this way as when removing channels numbers change) */
|
||||||
for (ch = output_channels - 1; ch >= 0; ch--) {
|
for (ch = data->output_channels - 1; ch >= 0; ch--) {
|
||||||
if ((mask >> ch) & 1)
|
if ((mask >> ch) & 1)
|
||||||
continue;
|
continue;
|
||||||
mixing_push_downmix(vgmstream, ch);
|
mixing_push_downmix(vgmstream, ch);
|
||||||
@ -695,18 +696,21 @@ void mixing_macro_track(VGMSTREAM* vgmstream, uint32_t mask) {
|
|||||||
|
|
||||||
void mixing_macro_layer(VGMSTREAM* vgmstream, int max, uint32_t mask, int overlap) {
|
void mixing_macro_layer(VGMSTREAM* vgmstream, int max, uint32_t mask, int overlap) {
|
||||||
mixing_data *data = vgmstream->mixing_data;
|
mixing_data *data = vgmstream->mixing_data;
|
||||||
int current, ch, output_channels, selected_channels;
|
int current, ch, selected_channels;
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
return;
|
||||||
|
if (max <= 0 || data->output_channels <= max)
|
||||||
|
return;
|
||||||
|
|
||||||
/* set all channels (non-existant channels will be ignored) */
|
/* set all channels (non-existant channels will be ignored) */
|
||||||
if (mask == 0) {
|
if (mask == 0) {
|
||||||
mask = ~mask;
|
mask = ~mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
output_channels = data ? data->output_channels : vgmstream->channels;
|
|
||||||
|
|
||||||
/* count possibly set channels */
|
/* count possibly set channels */
|
||||||
selected_channels = 0;
|
selected_channels = 0;
|
||||||
for (ch = 0; ch < output_channels; ch++) {
|
for (ch = 0; ch < data->output_channels; ch++) {
|
||||||
selected_channels += (mask >> ch) & 1;
|
selected_channels += (mask >> ch) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -717,7 +721,7 @@ void mixing_macro_layer(VGMSTREAM* vgmstream, int max, uint32_t mask, int overla
|
|||||||
|
|
||||||
/* add all layers in this order: ch0: 0, 0+N, 0+N*2 ... / ch1: 1, 1+N ... */
|
/* add all layers in this order: ch0: 0, 0+N, 0+N*2 ... / ch1: 1, 1+N ... */
|
||||||
current = 0;
|
current = 0;
|
||||||
for (ch = 0; ch < output_channels; ch++) {
|
for (ch = 0; ch < data->output_channels; ch++) {
|
||||||
double volume = 1.0;
|
double volume = 1.0;
|
||||||
|
|
||||||
if (!((mask >> ch) & 1))
|
if (!((mask >> ch) & 1))
|
||||||
@ -728,6 +732,8 @@ void mixing_macro_layer(VGMSTREAM* vgmstream, int max, uint32_t mask, int overla
|
|||||||
/* find how many will be mixed in current channel (earlier channels receive more
|
/* find how many will be mixed in current channel (earlier channels receive more
|
||||||
* mixes than later ones, ex: selected 8ch + max 3ch: ch0=0+3+6, ch1=1+4+7, ch2=2+5) */
|
* mixes than later ones, ex: selected 8ch + max 3ch: ch0=0+3+6, ch1=1+4+7, ch2=2+5) */
|
||||||
int channel_mixes = selected_channels / max;
|
int channel_mixes = selected_channels / max;
|
||||||
|
if (channel_mixes <= 0) /* ??? */
|
||||||
|
channel_mixes = 1;
|
||||||
if (current < selected_channels % (channel_mixes * max)) /* may be simplified? */
|
if (current < selected_channels % (channel_mixes * max)) /* may be simplified? */
|
||||||
channel_mixes += 1;
|
channel_mixes += 1;
|
||||||
|
|
||||||
@ -749,12 +755,15 @@ void mixing_macro_crosstrack(VGMSTREAM* vgmstream, int max) {
|
|||||||
int current, ch, track, track_ch, track_num, output_channels;
|
int current, ch, track, track_ch, track_num, output_channels;
|
||||||
int32_t change_pos, change_next, change_time;
|
int32_t change_pos, change_next, change_time;
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
return;
|
||||||
|
if (max <= 0 || data->output_channels <= max)
|
||||||
|
return;
|
||||||
if (!vgmstream->loop_flag) /* maybe force loop? */
|
if (!vgmstream->loop_flag) /* maybe force loop? */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* this probably only makes sense for even channels so upmix before if needed) */
|
/* this probably only makes sense for even channels so upmix before if needed) */
|
||||||
output_channels = data ? data->output_channels : vgmstream->channels;
|
output_channels = data->output_channels;
|
||||||
if (output_channels % 2) {
|
if (output_channels % 2) {
|
||||||
mixing_push_upmix(vgmstream, output_channels);
|
mixing_push_upmix(vgmstream, output_channels);
|
||||||
output_channels += 1;
|
output_channels += 1;
|
||||||
@ -807,12 +816,15 @@ void mixing_macro_crosslayer(VGMSTREAM* vgmstream, int max) {
|
|||||||
int current, ch, layer, layer_ch, layer_num, loop, output_channels;
|
int current, ch, layer, layer_ch, layer_num, loop, output_channels;
|
||||||
int32_t change_pos, change_time;
|
int32_t change_pos, change_time;
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
return;
|
||||||
|
if (max <= 0 || data->output_channels <= max)
|
||||||
|
return;
|
||||||
if (!vgmstream->loop_flag) /* maybe force loop? */
|
if (!vgmstream->loop_flag) /* maybe force loop? */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* this probably only makes sense for even channels so upmix before if needed) */
|
/* this probably only makes sense for even channels so upmix before if needed) */
|
||||||
output_channels = data ? data->output_channels : vgmstream->channels;
|
output_channels = data->output_channels;
|
||||||
if (output_channels % 2) {
|
if (output_channels % 2) {
|
||||||
mixing_push_upmix(vgmstream, output_channels);
|
mixing_push_upmix(vgmstream, output_channels);
|
||||||
output_channels += 1;
|
output_channels += 1;
|
||||||
@ -889,9 +901,9 @@ void mixing_setup(VGMSTREAM * vgmstream, int32_t max_sample_count) {
|
|||||||
data->mixing_on = 1;
|
data->mixing_on = 1;
|
||||||
|
|
||||||
/* a bit wonky but eh... */
|
/* a bit wonky but eh... */
|
||||||
if (vgmstream->channel_layout && vgmstream->channels != vgmstream->output_channels) {
|
if (vgmstream->channel_layout && vgmstream->channels != data->output_channels) {
|
||||||
vgmstream->channel_layout = 0;
|
vgmstream->channel_layout = 0;
|
||||||
vgmstream->start_vgmstream->channel_layout = 0;
|
((VGMSTREAM*)vgmstream->start_vgmstream)->channel_layout = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* since data exists on its own memory and pointer is already set
|
/* since data exists on its own memory and pointer is already set
|
||||||
@ -904,23 +916,22 @@ fail:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mixing_info(VGMSTREAM * vgmstream, int *input_channels, int *output_channels) {
|
void mixing_info(VGMSTREAM * vgmstream, int *out_input_channels, int *out_output_channels) {
|
||||||
mixing_data *data = vgmstream->mixing_data;
|
mixing_data *data = vgmstream->mixing_data;
|
||||||
|
int input_channels, output_channels;
|
||||||
|
|
||||||
if (!data) goto fail;
|
if (!data) goto fail;
|
||||||
|
|
||||||
if (output_channels) {
|
output_channels = data->output_channels;
|
||||||
*output_channels = data->output_channels;
|
if (data->output_channels > vgmstream->channels)
|
||||||
}
|
input_channels = data->output_channels;
|
||||||
|
else
|
||||||
|
input_channels = vgmstream->channels;
|
||||||
|
|
||||||
if (input_channels) {
|
if (out_input_channels) *out_input_channels = input_channels;
|
||||||
if (data->output_channels > vgmstream->channels)
|
if (out_output_channels) *out_output_channels = output_channels;
|
||||||
*input_channels = data->output_channels;
|
|
||||||
else
|
|
||||||
*input_channels = vgmstream->channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
//;VGM_LOG("MIX: channels in=%i, out=%i, mix=%i\n", *input_channels, *output_channels, data->mixing_channels);
|
//;VGM_LOG("MIX: channels %i, in=%i, out=%i, mix=%i\n", vgmstream->channels, input_channels, output_channels, data->mixing_channels);
|
||||||
return;
|
return;
|
||||||
fail:
|
fail:
|
||||||
return;
|
return;
|
||||||
@ -933,11 +944,14 @@ void vgmstream_mixing_enable(VGMSTREAM* vgmstream, int32_t max_sample_count, int
|
|||||||
|
|
||||||
/* ********************************************************* */
|
/* ********************************************************* */
|
||||||
|
|
||||||
void vgmstream_mixing_downmix(VGMSTREAM *vgmstream, int max_channels) {
|
void vgmstream_mixing_autodownmix(VGMSTREAM *vgmstream, int max_channels) {
|
||||||
mixing_data *data = vgmstream->mixing_data;
|
mixing_data *data = vgmstream->mixing_data;
|
||||||
|
|
||||||
if (!data) goto fail;
|
if (!data) goto fail;
|
||||||
|
|
||||||
|
if (max_channels <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
/* guess mixing the best we can */
|
/* guess mixing the best we can */
|
||||||
|
|
||||||
//todo: could use standard downmixing for known max_channels <> vgmstream->channels combos:
|
//todo: could use standard downmixing for known max_channels <> vgmstream->channels combos:
|
||||||
|
@ -87,7 +87,7 @@ void vgmstream_tags_close(VGMSTREAM_TAGS* tags);
|
|||||||
void vgmstream_mixing_enable(VGMSTREAM* vgmstream, int32_t max_sample_count, int *input_channels, int *output_channels);
|
void vgmstream_mixing_enable(VGMSTREAM* vgmstream, int32_t max_sample_count, int *input_channels, int *output_channels);
|
||||||
|
|
||||||
/* sets automatic downmixing if vgmstream's channels are higher than max_channels */
|
/* sets automatic downmixing if vgmstream's channels are higher than max_channels */
|
||||||
void vgmstream_mixing_downmix(VGMSTREAM *vgmstream, int max_channels);
|
void vgmstream_mixing_autodownmix(VGMSTREAM *vgmstream, int max_channels);
|
||||||
|
|
||||||
/* sets a fadeout */
|
/* sets a fadeout */
|
||||||
//void vgmstream_mixing_fadeout(VGMSTREAM *vgmstream, float start_second, float duration_seconds);
|
//void vgmstream_mixing_fadeout(VGMSTREAM *vgmstream, float start_second, float duration_seconds);
|
||||||
|
@ -2315,6 +2315,18 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
|||||||
snprintf(temp,TEMPSIZE, "channels: %d\n", vgmstream->channels);
|
snprintf(temp,TEMPSIZE, "channels: %d\n", vgmstream->channels);
|
||||||
concatn(length,desc,temp);
|
concatn(length,desc,temp);
|
||||||
|
|
||||||
|
#ifdef VGMSTREAM_MIXING
|
||||||
|
{
|
||||||
|
int output_channels = 0;
|
||||||
|
mixing_info(vgmstream, NULL, &output_channels);
|
||||||
|
|
||||||
|
if (output_channels != vgmstream->channels) {
|
||||||
|
snprintf(temp,TEMPSIZE, "output channels: %d\n", output_channels);
|
||||||
|
concatn(length,desc,temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (vgmstream->channel_layout) {
|
if (vgmstream->channel_layout) {
|
||||||
int cl = vgmstream->channel_layout;
|
int cl = vgmstream->channel_layout;
|
||||||
|
|
||||||
@ -2903,7 +2915,6 @@ int vgmstream_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t s
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
VGM_LOG("fail\n");
|
|
||||||
/* open streams will be closed in close_vgmstream(), hopefully called by the meta */
|
/* open streams will be closed in close_vgmstream(), hopefully called by the meta */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user