twn_audio: rework interface
This commit is contained in:
@ -54,15 +54,6 @@ static int64_t get_audio_data(const char *path, unsigned char **data) {
|
||||
}
|
||||
|
||||
|
||||
void audio_play(const char *path, const char *channel) {
|
||||
const AudioChannelItem *pair = shgetp_null(ctx.audio_channels, channel);
|
||||
if (!pair)
|
||||
audio_play_ex(path, channel, audio_get_default_args());
|
||||
else
|
||||
audio_play_ex(path, channel, pair->value.args);
|
||||
}
|
||||
|
||||
|
||||
static AudioFileType infer_audio_file_type(const char *path) {
|
||||
size_t path_len = SDL_strlen(path);
|
||||
|
||||
@ -163,18 +154,25 @@ static void repeat_audio(AudioChannel *channel) {
|
||||
}
|
||||
|
||||
|
||||
void audio_play_ex(const char *path, const char *channel, PlayAudioArgs args) {
|
||||
void audio_play(const char *path,
|
||||
const char *channel,
|
||||
bool repeat,
|
||||
float volume,
|
||||
float panning)
|
||||
{
|
||||
AudioChannelItem *pair = shgetp_null(ctx.audio_channels, channel);
|
||||
|
||||
/* create a channel if it doesn't exist */
|
||||
if (!pair) {
|
||||
AudioFileType file_type = infer_audio_file_type(path);
|
||||
AudioChannel new_channel = {
|
||||
.args = args,
|
||||
.file_type = file_type,
|
||||
.context = init_audio_context(path, file_type),
|
||||
.path = path,
|
||||
.name = channel,
|
||||
.repeat = repeat,
|
||||
.volume = volume,
|
||||
.panning = panning,
|
||||
};
|
||||
shput(ctx.audio_channels, channel, new_channel);
|
||||
pair = shgetp_null(ctx.audio_channels, channel);
|
||||
@ -188,22 +186,40 @@ void audio_play_ex(const char *path, const char *channel, PlayAudioArgs args) {
|
||||
}
|
||||
|
||||
|
||||
PlayAudioArgs *audio_get_args(const char *channel) {
|
||||
TWN_API void audio_set(const char *channel, AudioParam param, float value) {
|
||||
AudioChannelItem *pair = shgetp_null(ctx.audio_channels, channel);
|
||||
if (!pair)
|
||||
return NULL;
|
||||
if (!pair) {
|
||||
log_warn("No channel by the name of %s to set a parameter for", channel);
|
||||
return;
|
||||
}
|
||||
|
||||
return &pair->value.args;
|
||||
}
|
||||
|
||||
|
||||
PlayAudioArgs audio_get_default_args(void) {
|
||||
return (PlayAudioArgs){
|
||||
.repeat = false,
|
||||
.crossfade = false,
|
||||
.volume = 1.0f,
|
||||
.panning = 0.0f,
|
||||
};
|
||||
switch (param) {
|
||||
case AUDIO_PARAM_REPEAT:
|
||||
pair->value.repeat = (bool)value;
|
||||
break;
|
||||
case AUDIO_PARAM_VOLUME:
|
||||
if (value > 1.0f) {
|
||||
log_warn("Out of range volume for channel %s set", channel);
|
||||
value = 1.0f;
|
||||
}
|
||||
if (value < 0.0f) {
|
||||
log_warn("Out of range volume for channel %s set", channel);
|
||||
value = 0.0f;
|
||||
}
|
||||
pair->value.volume = value;
|
||||
break;
|
||||
case AUDIO_PARAM_PANNING:
|
||||
if (value > 1.0f) {
|
||||
log_warn("Out of range panning for channel %s set", channel);
|
||||
value = 1.0f;
|
||||
}
|
||||
if (value < -1.0f) {
|
||||
log_warn("Out of range panning for channel %s set", channel);
|
||||
value = -1.0f;
|
||||
}
|
||||
pair->value.panning = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -216,15 +232,15 @@ static void audio_mixin_streams(const AudioChannel *channel,
|
||||
float *const sa = (float *)a;
|
||||
float *const sb = (float *)b;
|
||||
|
||||
const float left_panning = fminf(fabsf(channel->args.panning - 1.0f), 1.0f);
|
||||
const float right_panning = fminf(fabsf(channel->args.panning + 1.0f), 1.0f);
|
||||
const float left_panning = fminf(fabsf(channel->panning - 1.0f), 1.0f);
|
||||
const float right_panning = fminf(fabsf(channel->panning + 1.0f), 1.0f);
|
||||
|
||||
for (size_t s = 0; s < frames; s += 2) {
|
||||
/* left channel */
|
||||
sa[s] += (float)(sb[s] * channel->args.volume * left_panning);
|
||||
sa[s] += (float)(sb[s] * channel->volume * left_panning);
|
||||
|
||||
/* right channel */
|
||||
sa[s + 1] += (float)(sb[s + 1] * channel->args.volume * right_panning);
|
||||
sa[s + 1] += (float)(sb[s + 1] * channel->volume * right_panning);
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,7 +269,7 @@ static void audio_sample_and_mixin_channel(const AudioChannel *channel,
|
||||
|
||||
/* handle end of file */
|
||||
if (samples_per_channel == 0) {
|
||||
if (channel->args.repeat) {
|
||||
if (channel->repeat) {
|
||||
/* seek to start and try sampling some more */
|
||||
stb_vorbis_seek_start(channel->context.vorbis.handle);
|
||||
continue;
|
||||
@ -284,7 +300,7 @@ static void audio_sample_and_mixin_channel(const AudioChannel *channel,
|
||||
|
||||
/* handle end of file */
|
||||
if (samples_per_channel == 0) {
|
||||
if (channel->args.repeat) {
|
||||
if (channel->repeat) {
|
||||
/* seek to start and try sampling some more */
|
||||
xm_restart(channel->context.xm.handle);
|
||||
continue;
|
||||
@ -313,10 +329,10 @@ static void audio_sample_and_mixin_channel(const AudioChannel *channel,
|
||||
|
||||
|
||||
static void sanity_check_channel(const AudioChannel *channel) {
|
||||
if (channel->args.volume < 0.0f || channel->args.volume > 1.0f)
|
||||
if (channel->volume < 0.0f || channel->volume > 1.0f)
|
||||
log_warn("Volume argument is out of range for channel (%s)", channel->name);
|
||||
|
||||
if (channel->args.panning < -1.0f || channel->args.panning > 1.0f)
|
||||
if (channel->panning < -1.0f || channel->panning > 1.0f)
|
||||
log_warn("Panning argument is out of range for channel (%s)", channel->name);
|
||||
}
|
||||
|
||||
@ -332,3 +348,11 @@ void audio_callback(void *userdata, uint8_t *stream, int len) {
|
||||
audio_sample_and_mixin_channel(&ctx.audio_channels[i].value, stream, len);
|
||||
}
|
||||
}
|
||||
|
||||
TWN_API void audio_play_args(PlayAudioArgs args) {
|
||||
const char *channel = m_or(args, channel, NULL);
|
||||
const bool repeat = m_or(args, repeat, false);
|
||||
const float volume = m_or(args, volume, 1.0f);
|
||||
const float panning = m_or(args, panning, 0.0f);
|
||||
audio_play(args.path, channel, repeat, volume, panning);
|
||||
}
|
||||
|
@ -36,11 +36,13 @@ union AudioContext {
|
||||
|
||||
|
||||
typedef struct AudioChannel {
|
||||
PlayAudioArgs args;
|
||||
AudioFileType file_type;
|
||||
union AudioContext context; /* interpreted by `file_type` value */
|
||||
const char *path;
|
||||
const char *name;
|
||||
bool repeat;
|
||||
float volume;
|
||||
float panning;
|
||||
} AudioChannel;
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user