diff --git a/apps/scenery/scenes/ingame.c b/apps/scenery/scenes/ingame.c index 572ffcc..b7e6d1f 100644 --- a/apps/scenery/scenes/ingame.c +++ b/apps/scenery/scenes/ingame.c @@ -106,10 +106,9 @@ Scene *ingame_scene(State *state) { new_scene->cam = (Camera){ .pos = { 32, 0, 1 }, .up = { 0, 1, 0 }, .fov = (float)M_PI_2 }; - audio_play_ex("music/mod65.xm", "soundtrack", (PlayAudioArgs){ - .repeat = true, - .volume = 1.0f - }); + m_audio(m_set("music/mod65.xm"), + m_opt(channel, "soundtrack"), + m_opt(repeat, true)); input_set_mouse_captured(&ctx.input, true); diff --git a/common-data/scripts/game.lua b/common-data/scripts/game.lua deleted file mode 100644 index f571881..0000000 --- a/common-data/scripts/game.lua +++ /dev/null @@ -1,31 +0,0 @@ -ORIGIN = { x = 320, y = 180 } -RADIUS = 48 -offset = { x = 0, y = 0 } -angle = 0 - -function game_tick() - rectangle { - rect = { x = 0, y = 0, w = 640, h = 360 }, - color = { r = 127, g = 0, b = 127, a = 255 }, - } - - sprite { - path = "/assets/title.png", - rect = { - x = 320 - (320 / 2), - y = 180 - (128 / 2), - w = 320, - h = 128, - }, - } - - text { - string = "IT KEEPS HAPPENING", - position = offset, - font = "/fonts/kenney-pixel.ttf", - } - - offset.x = ORIGIN.x + (math.cos(angle) * RADIUS) - offset.y = ORIGIN.y + (math.sin(angle) * RADIUS) - angle = angle + 0.1 -end diff --git a/include/twn_audio.h b/include/twn_audio.h index 8823d1d..70a4b6c 100644 --- a/include/twn_audio.h +++ b/include/twn_audio.h @@ -2,37 +2,45 @@ #define TWN_AUDIO_H #include "twn_engine_api.h" +#include "twn_option.h" #include +/* plays audio file at specified channel or at scratch channel if NULL is passed, without ability to refer to it later */ +/* path path must contain valid file extension to infer which file format it is */ +/* supported formats: .ogg, .xm */ +TWN_API void audio_play(const char *path, + const char *channel, /* optional */ + bool repeat, /* default: false */ + float volume, /* default: 1.0f, range: 0.0f to 1.0f */ + float panning); /* default: 0.0f, range: -1.0 to 1.0f */ + +typedef enum { + AUDIO_PARAM_REPEAT, + AUDIO_PARAM_VOLUME, + AUDIO_PARAM_PANNING, +} AudioParam; + +TWN_API void audio_set(const char *channel, AudioParam param, float value); + +/* TODO */ +// TWN_API bool audio_ended(const char *channel); + +#ifndef TWN_NOT_C typedef struct PlayAudioArgs { - /* default: false */ - bool repeat; - /* crossfade between already playing audio on a given channel, if any */ - /* default: false */ - bool crossfade; - /* range: 0.0f to 1.0f */ - /* default: 1.0f */ - float volume; - /* range: -1.0 to 1.0f */ - /* default: 0.0f */ - float panning; + char *path; + + m_option_list( + char *, channel, + bool, repeat, + float, volume, + float, panning ) } PlayAudioArgs; - -/* plays audio file at specified channel or anywhere if NULL is passed */ -/* path must contain valid file extension to infer which file format it is */ -/* supported formats: .ogg, .xm */ -/* preserves args that are already specified on the channel */ -TWN_API void audio_play(const char *path, const char *channel); - -TWN_API void audio_play_ex(const char *path, const char *channel, PlayAudioArgs args); - -/* could be used for modifying args */ -/* warn: is only valid if no other calls to audio are made */ -TWN_API PlayAudioArgs *audio_get_args(const char *channel); - -TWN_API PlayAudioArgs audio_get_default_args(void); +TWN_API void audio_play_args(PlayAudioArgs args); +#define m_audio(...) (audio_play_args((PlayAudioArgs){__VA_ARGS__})) + +#endif #endif diff --git a/src/twn_audio.c b/src/twn_audio.c index 630a959..ffd08a9 100644 --- a/src/twn_audio.c +++ b/src/twn_audio.c @@ -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); +} diff --git a/src/twn_audio_c.h b/src/twn_audio_c.h index acd2434..1f3fb9b 100644 --- a/src/twn_audio_c.h +++ b/src/twn_audio_c.h @@ -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;