Skip to content

Commit

Permalink
add 'loop_mode' option to gbsplayrc
Browse files Browse the repository at this point in the history
`loop mode` can select all available loop modes and uses a convenient
string to do so.

The old option `loop` that was a boolean and could only select the
loop modes `none` and `range` is hereby deprecated but kept for
backwards compatibility of existing configurations.
  • Loading branch information
mmitch committed Feb 22, 2025
1 parent 89c977c commit 1b7d91f
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 23 deletions.
3 changes: 3 additions & 0 deletions HISTORY
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ Enhancements:
- display current loop mode
- add i18n

- configuration:
- deprecate 'loop' option in gbsplayrc in favor of new 'loop_mode'

- documentation:
- describe loop mode keybinding in gbsplay(1) manpage

Expand Down
98 changes: 80 additions & 18 deletions cfgparser.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "common.h"
#include "cfgparser.h"
#include "libgbs.h"
#include "plugout.h"
#include "test.h"

Expand Down Expand Up @@ -47,6 +48,7 @@ struct player_cfg cfg = {
/* forward declarations needed by configuration directives */
static void cfg_string(void* const ptr);
static void cfg_long(void* const ptr);
static void cfg_loop_mode(void* const ptr);
static void cfg_bool_as_int(void* const ptr);
static void cfg_endian(void* const ptr);

Expand All @@ -56,6 +58,7 @@ static const struct cfg_option options[] = {
{ "fadeout", &cfg.fadeout, cfg_long },
{ "filter_type", &cfg.filter_type, cfg_string },
{ "loop", &cfg.loop_mode, cfg_bool_as_int },
{ "loop_mode", &cfg.loop_mode, cfg_loop_mode },
{ "output_plugin", &cfg.sound_name, cfg_string },
{ "rate", &cfg.rate, cfg_long },
{ "refresh_delay", &cfg.refresh_delay, cfg_long },
Expand All @@ -67,6 +70,18 @@ static const struct cfg_option options[] = {
{ NULL, NULL, NULL }
};

struct loop_mode_map {
const char *keyword;
enum gbs_loop_mode loop_mode;
};

static const struct loop_mode_map loop_mode_map[] = {
{ "none", LOOP_OFF },
{ "range", LOOP_RANGE },
{ "single", LOOP_SINGLE },
{ NULL, -1 }
};

static long cfg_line, cfg_char;
static FILE *cfg_file;

Expand Down Expand Up @@ -139,7 +154,23 @@ static void cfg_endian(void* const ptr)
nextstate = 1;
}

static void cfg_string(void * const ptr)
static void cfg_loop_mode(void* const ptr)
{
char *s;
enum gbs_loop_mode *loop_mode = ptr;
const struct loop_mode_map *entry;

cfg_string(&s);

for (entry = loop_mode_map; entry->keyword; entry++) {
if (strncmp(s, entry->keyword, sizeof(s)-1) == 0) {
*loop_mode = entry->loop_mode;
break;
}
}
}

static void cfg_string(void* const ptr)
{
char s[200];
unsigned long n = 0;
Expand Down Expand Up @@ -324,12 +355,19 @@ test void save_initial_cfg() {
initial_cfg.filter_type = strdup(cfg.filter_type);
initial_cfg.sound_name = strdup(cfg.sound_name);
};
TEST(save_initial_cfg);

test void restore_initial_cfg() {
cfg = initial_cfg;
cfg.filter_type = strdup(initial_cfg.filter_type);
cfg.sound_name = strdup(initial_cfg.sound_name);
};

/************************* tests ************************/

test void test_parse_missing_config_file() {
// given
save_initial_cfg();
restore_initial_cfg();

// when
cfg_parse("test/gbsplayrc-this-file-does-not-exist");
Expand All @@ -341,7 +379,7 @@ TEST(test_parse_missing_config_file);

test void test_parse_empty_configuration() {
// given
save_initial_cfg();
restore_initial_cfg();

// when
cfg_parse("test/gbsplayrc-empty");
Expand All @@ -353,6 +391,7 @@ TEST(test_parse_empty_configuration);

test void test_parse_complete_configuration() {
// given
restore_initial_cfg();

// when
cfg_parse("test/gbsplayrc-full");
Expand All @@ -374,38 +413,61 @@ TEST(test_parse_complete_configuration);

/* manpage says: an integer; 0 = false = no loop mode; everything else = true = range loop mode */
test void test_loop_0() {
// given

// when
restore_initial_cfg();
cfg_parse("test/gbsplayrc-loop-0");

// then
ASSERT_EQUAL("loop_mode %d", cfg.loop_mode, LOOP_OFF);
}
TEST(test_loop_0);

test void test_loop_1() {
// given

// when
restore_initial_cfg();
cfg_parse("test/gbsplayrc-loop-1");

// then
ASSERT_EQUAL("loop_mode %d", cfg.loop_mode, LOOP_RANGE);
}
TEST(test_loop_1);

test void test_loop_2() {
// given

// when
restore_initial_cfg();
cfg_parse("test/gbsplayrc-loop-2");

// then
ASSERT_EQUAL("loop_mode %d", cfg.loop_mode, LOOP_RANGE);
}
TEST(test_loop_2);

test void test_loop_mode_none() {
restore_initial_cfg();
cfg_parse("test/gbsplayrc-loop-mode-none");
ASSERT_EQUAL("loop_mode %d", cfg.loop_mode, LOOP_OFF);
}
TEST(test_loop_mode_none);

test void test_loop_mode_range() {
restore_initial_cfg();
cfg_parse("test/gbsplayrc-loop-mode-range");
ASSERT_EQUAL("loop_mode %d", cfg.loop_mode, LOOP_RANGE);
}
TEST(test_loop_mode_range);

test void test_loop_mode_single() {
restore_initial_cfg();
cfg_parse("test/gbsplayrc-loop-mode-single");
ASSERT_EQUAL("loop_mode %d", cfg.loop_mode, LOOP_SINGLE);
}
TEST(test_loop_mode_single);

test void test_loop_mode_after_loop() {
restore_initial_cfg();
cfg_parse("test/gbsplayrc-loop-mode-after-loop");
ASSERT_EQUAL("loop_mode %d", cfg.loop_mode, LOOP_SINGLE);
}
TEST(test_loop_mode_after_loop);

test void test_loop_after_loop_mode() {
restore_initial_cfg();
cfg_parse("test/gbsplayrc-loop-after-loop-mode");
ASSERT_EQUAL("loop_mode %d", cfg.loop_mode, LOOP_OFF);
}
TEST(test_loop_after_loop_mode);

TEST_EOF;

#endif /* ENABLE_TEST */
28 changes: 23 additions & 5 deletions man/gbsplayrc.in.5
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.\" This manpage 2003-2020 (C) by Christian Garbs <mitch@cgarbs.de>
.\" This manpage 2003-2025 (C) by Christian Garbs <mitch@cgarbs.de>
.\" Licensed under GNU GPL v1 or, at your option, any later version.
.TH "GBSPLAYRC" "5" "%%%VERSION%%%" "Tobias Diedrich" "Gameboy sound player"
.SH "NAME"
Expand Down Expand Up @@ -39,6 +39,17 @@ big endian
.B Integer
An integer number in decimal.
.TP
.B Loop mode
A string to select the loop mode:
.RS
.IP \fBnone\fP
no looping
.IP \fBrange\fP
loop over selected subsongs
.IP \fBsingle\fP
loop a single subsong
.RE
.TP
.B Plugin
The name of an output plugin.
Run `\fIgbsplay\ \-o\ list\fP' to get a list of all available output plugins.
Expand All @@ -52,9 +63,16 @@ Set the fadeout time in seconds.
Instead of cutting the subsong off hard, do a soft fadeout.
.TP
.BR loop " = " \fIBoolean\fP
Enable or disable loop mode.
In loop mode the playback will restart from the beginning
after the last subsong has been played.
Set loop mode \fBrange\fP when enabled.
Set loop mode \fBnone\fP when disabled.
Deprecated in favor of the \fBloop_mode\fP option.
.TP
.BR loop_mode " = " \fILoop\ mode\fP
Set the desired loop mode. See
.I LOOP MODES
in
.BR gbsplay (1)
for details.
.TP
.BR output_plugin " = " \fIPlugin\fP
Set the sound output plugin.
Expand All @@ -76,7 +94,7 @@ the player will skip to the next subsong.
.BR subsong_gap " = " \fIInteger\fP
Set the subsong gap in seconds.
Before playing the next subsong after the subsong timeout,
\fIsubsong\-gap\fP seconds of silence will be played.
\fIsubsong_gap\fP seconds of silence will be played.
.TP
.BR subsong_timeout " = " \fIInteger\fP
Set the subsong timeout in seconds.
Expand Down
2 changes: 2 additions & 0 deletions test/gbsplayrc-loop-after-loop-mode
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
loop_mode=range
loop=0
3 changes: 3 additions & 0 deletions test/gbsplayrc-loop-mode-after-loop
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
loop=1
loop_mode=single

1 change: 1 addition & 0 deletions test/gbsplayrc-loop-mode-none
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
loop_mode=none
1 change: 1 addition & 0 deletions test/gbsplayrc-loop-mode-range
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
loop_mode=range
1 change: 1 addition & 0 deletions test/gbsplayrc-loop-mode-single
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
loop_mode=single

0 comments on commit 1b7d91f

Please # to comment.