Update mixing code

This commit is contained in:
bnnm 2019-02-25 00:38:35 +01:00
parent 05119fdceb
commit c99034cff8
3 changed files with 69 additions and 16 deletions

View File

@ -340,7 +340,7 @@ int main(int argc, char ** argv) {
char outfilename_temp[PATH_LIMIT]; char outfilename_temp[PATH_LIMIT];
sample_t * buf = NULL; sample_t * buf = NULL;
int channels; int channels, input_channels;
int32_t len_samples; int32_t len_samples;
int32_t fade_samples; int32_t fade_samples;
int i, j; int i, j;
@ -458,8 +458,19 @@ int main(int argc, char ** argv) {
/* last init */ /* last init */
channels = vgmstream->channels; channels = vgmstream->channels;
input_channels = vgmstream->channels;
buf = malloc(BUFFER_SAMPLES * sizeof(sample_t) * channels); #ifdef VGMSTREAM_MIXING
/* enable after all config but before outbuf */
{
vgmstream_enable_mixing(vgmstream, BUFFER_SAMPLES);
channels = vgmstream->output_channels;
input_channels = vgmstream->input_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;

View File

@ -569,6 +569,16 @@ static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile) {
} }
void setup_vgmstream(VGMSTREAM * vgmstream) { void setup_vgmstream(VGMSTREAM * vgmstream) {
#ifdef VGMSTREAM_MIXING
/* fill default config to simplify external code (mixing off will always happen
* initially, and if they contain values it means mixing must be enabled) */
if (!vgmstream->mixing_on || vgmstream->input_channels <= 0)
vgmstream->input_channels = vgmstream->channels;
if (!vgmstream->mixing_on || vgmstream->output_channels <= 0)
vgmstream->output_channels = vgmstream->channels;
#endif
/* save start things so we can restart when seeking */ /* save start things so we can restart when seeking */
memcpy(vgmstream->start_ch, vgmstream->ch, sizeof(VGMSTREAMCHANNEL)*vgmstream->channels); memcpy(vgmstream->start_ch, vgmstream->ch, sizeof(VGMSTREAMCHANNEL)*vgmstream->channels);
memcpy(vgmstream->start_vgmstream, vgmstream, sizeof(VGMSTREAM)); memcpy(vgmstream->start_vgmstream, vgmstream, sizeof(VGMSTREAM));
@ -747,9 +757,9 @@ VGMSTREAM * allocate_vgmstream(int channel_count, int loop_flag) {
#ifdef VGMSTREAM_MIXING #ifdef VGMSTREAM_MIXING
/* fixed arrays, for now */ /* fixed arrays, for now */
vgmstream->mixing_size = 64; vgmstream->mixing_size = VGMSTREAM_MAX_MIXING;
vgmstream->stream_name_size = STREAM_NAME_SIZE;
#endif #endif
//vgmstream->stream_name_size = STREAM_NAME_SIZE;
return vgmstream; return vgmstream;
fail: fail:
if (vgmstream) { if (vgmstream) {
@ -980,6 +990,9 @@ void vgmstream_set_loop_target(VGMSTREAM* vgmstream, int loop_target) {
vgmstream_set_loop_target(data->layers[i], loop_target); vgmstream_set_loop_target(data->layers[i], loop_target);
} }
} }
/* notify of new initial state */
setup_vgmstream(vgmstream);
} }
@ -1042,7 +1055,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
break; break;
} }
#ifndef VGMSTREAM_MIXING
/* swap channels if set, to create custom channel mappings */ /* swap channels if set, to create custom channel mappings */
if (vgmstream->channel_mappings_on) { if (vgmstream->channel_mappings_on) {
int ch_from,ch_to,s; int ch_from,ch_to,s;
@ -1075,6 +1088,11 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
} }
} }
} }
#endif
#ifdef VGMSTREAM_MIXING
mix_vgmstream(buffer, sample_count, vgmstream);
#endif
} }
/* Get the number of samples of a single frame (smallest self-contained sample group, 1/N channels) */ /* Get the number of samples of a single frame (smallest self-contained sample group, 1/N channels) */
@ -2529,7 +2547,7 @@ static void try_dual_file_stereo(VGMSTREAM * opened_vgmstream, STREAMFILE *strea
} }
/* check these even if there is no loop, because they should then be zero in both /* check these even if there is no loop, because they should then be zero in both
* Homura PS2 right channel doesn't have loop points so it's ignored */ * (Homura PS2 right channel doesn't have loop points so this check is ignored) */
if (new_vgmstream->meta_type != meta_PS2_SMPL && if (new_vgmstream->meta_type != meta_PS2_SMPL &&
!(new_vgmstream->loop_flag == opened_vgmstream->loop_flag && !(new_vgmstream->loop_flag == opened_vgmstream->loop_flag &&
new_vgmstream->loop_start_sample== opened_vgmstream->loop_start_sample && new_vgmstream->loop_start_sample== opened_vgmstream->loop_start_sample &&

View File

@ -9,6 +9,9 @@
enum { PATH_LIMIT = 32768 }; enum { PATH_LIMIT = 32768 };
enum { STREAM_NAME_SIZE = 255 }; enum { STREAM_NAME_SIZE = 255 };
enum { VGMSTREAM_MAX_CHANNELS = 64 }; enum { VGMSTREAM_MAX_CHANNELS = 64 };
#ifdef VGMSTREAM_MIXING
enum { VGMSTREAM_MAX_MIXING = 64 };
#endif
#include "streamfile.h" #include "streamfile.h"
@ -731,20 +734,28 @@ typedef enum {
MIX_ADD, MIX_ADD,
MIX_ADD_VOLUME, MIX_ADD_VOLUME,
MIX_VOLUME, MIX_VOLUME,
MIX_CROSSFADE, MIX_LIMIT,
MIX_DOWNMIX, MIX_DOWNMIX,
MIX_DOWNMIX_REST, MIX_DOWNMIX_REST,
MIX_UPMIX MIX_UPMIX,
MIX_FADE
} mix_command_t; } mix_command_t;
typedef struct { typedef struct {
mix_command_t command; mix_command_t command;
int ch_a; /* common */
int ch_b; int ch_dst;
float vol_a; int ch_src;
float vol_b; float vol;
float pos_a;
float pos_b; /* fade envelope */
float vol_start; /* volume from pre to start */
float vol_end; /* volume from end to post */
char shape; /* curve type */
float time_pre; /* position before curve where vol_str applies (-1 = beginning) */
float time_start; /* curve start position where vol changes from src to dst */
float time_end; /* curve end position where vol changes from src to dst */
float time_post; /* position after curve where vol_dst applies (-1 = end) */
} mix_config_data; } mix_config_data;
#endif #endif
@ -823,15 +834,19 @@ typedef struct {
/* other config */ /* other config */
int allow_dual_stereo; /* search for dual stereo (file_L.ext + file_R.ext = single stereo file) */ int allow_dual_stereo; /* search for dual stereo (file_L.ext + file_R.ext = single stereo file) */
#ifndef VGMSTREAM_MIXING
uint32_t channel_mask; /* to silence crossfading subsongs/layers */ uint32_t channel_mask; /* to silence crossfading subsongs/layers */
int channel_mappings_on; /* channel mappings are active */ int channel_mappings_on; /* channel mappings are active */
int channel_mappings[32]; /* swap channel "i" with "[i]" */ int channel_mappings[32]; /* swap channel "i" with "[i]" */
#endif
#ifdef VGMSTREAM_MIXING #ifdef VGMSTREAM_MIXING
int output_channels; /* resulting channels after mixing (may be ignored if plugin doesn't support it) */ /* may be ignored if plugin doesn't support it, but fields will be always set to simplify plugin's code */
int input_channels; /* starting channels before mixing (outbuf must be this big) */
int output_channels; /* resulting channels after mixing */
int mixing_on; /* mixing allowed */ int mixing_on; /* mixing allowed */
int mixing_count; /* mixing number */ int mixing_count; /* mixing number */
mix_config_data mixing[64]; /* applies transformation to output samples (could be alloc'ed but to simplify...) */
size_t mixing_size; /* mixing max */ size_t mixing_size; /* mixing max */
mix_config_data mixing_chain[VGMSTREAM_MAX_MIXING]; /* effects to apply (could be alloc'ed but to simplify...) */
#endif #endif
/* config requests, players must read and honor these values */ /* config requests, players must read and honor these values */
/* (ideally internally would work as a player, but for now player must do it manually) */ /* (ideally internally would work as a player, but for now player must do it manually) */
@ -1317,6 +1332,15 @@ VGMSTREAM * allocate_vgmstream(int channel_count, int looped);
/* Prepare the VGMSTREAM's initial state once parsed and ready, but before playing. */ /* Prepare the VGMSTREAM's initial state once parsed and ready, but before playing. */
void setup_vgmstream(VGMSTREAM * vgmstream); void setup_vgmstream(VGMSTREAM * vgmstream);
#ifdef VGMSTREAM_MIXING
/* Applies mixing commands to the vgmstream to the sample buffer.
* Mixing must be enabled and outbuf must be big enough for output_channels*samples_to_do big. */
void mix_vgmstream(sample_t *outbuf, int32_t sample_count, VGMSTREAM* vgmstream);
/* Add a new internal mix. Always use this as it validates mixes. */
void vgmstream_add_mixing(VGMSTREAM* vgmstream, mix_config_data mix);
#endif
/* Get the number of samples of a single frame (smallest self-contained sample group, 1/N channels) */ /* Get the number of samples of a single frame (smallest self-contained sample group, 1/N channels) */
int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream); int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream);
/* Get the number of bytes of a single frame (smallest self-contained byte group, 1/N channels) */ /* Get the number of bytes of a single frame (smallest self-contained byte group, 1/N channels) */