Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rocket: implement GNU Rocket integration #353

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "gnurocket"]
path = rocket
url = https://github.com/rocket/rocket
21 changes: 19 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,22 @@ cflags_flac=-DUSE_FLAC
libs_flac=-lFLAC
endif

if USE_ROCKET
# TODO: it's fragile to be intimately grabbing rocket/lib/*.[ch] stuff here,
# and if we continue doing that we need to DTRT regarding os-specific defines
# like USE_NODELAY
files_rocket = \
include/rocket.h \
schism/rocket.c \
rocket/lib/base.h \
rocket/lib/device.c \
rocket/lib/device.h \
rocket/lib/sync.h \
rocket/lib/track.c \
rocket/lib/track.h
cflags_rocket=-DUSE_ROCKET
endif

if USE_NETWORK
cflags_network=-DUSE_NETWORK
endif
Expand Down Expand Up @@ -362,7 +378,8 @@ schismtracker_SOURCES = \
$(files_mmap) \
$(files_wii) \
$(files_windres) \
$(files_flac)
$(files_flac) \
$(files_rocket)

# have version.o rely on all files
schism/version.$(OBJEXT): $(filter-out schism/version.$(OBJEXT),$(schismtracker_OBJECTS)) $(HEADERS)
Expand All @@ -373,7 +390,7 @@ AM_CPPFLAGS = -D_USE_AUTOCONF -D_GNU_SOURCE -I$(srcdir)/include -I.
AM_CFLAGS = $(SDL_CFLAGS) $(cflags_alsa) $(cflags_oss) \
$(cflags_network) $(cflags_x11) $(cflags_fmopl) \
$(cflags_version) $(cflags_win32) $(cflags_wii) \
$(cflags_macosx) $(cflags_flac)
$(cflags_macosx) $(cflags_flac) $(cflags_rocket)
AM_OBJCFLAGS = $(AM_CFLAGS)

schismtracker_DEPENDENCIES = $(files_windres)
Expand Down
10 changes: 10 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,11 @@ AC_ARG_WITH([flac],
[],
[with_flac=yes])

AC_ARG_WITH([rocket],
[AS_HELP_STRING([--with-rocket],[Build with GNU Rocket support @<:@default=no@:>@])],
[with_rocket=yes],
[])

dnl fortify needs -O; do this early so ADD_OPT can override with higher -O level
if test x$ADD_FORTIFY \!= xno; then
CFLAGS="$CFLAGS -O -D_FORTIFY_SOURCE=2"
Expand Down Expand Up @@ -334,6 +339,11 @@ if test "x$with_flac" = "xyes"; then
fi
fi

AM_CONDITIONAL([USE_ROCKET], false)
if test "x$with_rocket" = "xyes"; then
AM_CONDITIONAL([USE_ROCKET], true)
fi

dnl ... but put the warnings first, to make it possible to quiet certain
dnl warnings if necessary, while still providing most of the benefit
if test x$ADD_WARN \!= xno; then
Expand Down
7 changes: 7 additions & 0 deletions include/rocket.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef _SCHISM_ROCKET_H
#define _SCHISM_ROCKET_H

int schism_rocket_connect(const char *host, const char *port, const char *bpm, const char *rpb);
void schism_rocket_update(void);

#endif
5 changes: 3 additions & 2 deletions include/sndfile.h
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ typedef struct song {
// chaseback
int stop_at_order;
int stop_at_row;
unsigned int stop_at_time;
unsigned int stop_at_time_ms;

// multi-write stuff -- NULL if no multi-write is in progress, else array of one struct per channel
struct multi_write *multi_write;
Expand Down Expand Up @@ -663,7 +663,8 @@ int csf_process_tick(song_t *csf);
int csf_read_note(song_t *csf);

// snd_fx
unsigned int csf_get_length(song_t *csf); // (in seconds)
unsigned int csf_get_length_ms(song_t *csf);
unsigned int csf_get_length_secs(song_t *csf);
void csf_instrument_change(song_t *csf, song_voice_t *chn, uint32_t instr, int porta, int instr_column);
void csf_note_change(song_t *csf, uint32_t chan, int note, int porta, int retrig, int have_inst);
uint32_t csf_get_nna_channel(song_t *csf, uint32_t chan);
Expand Down
7 changes: 4 additions & 3 deletions include/song.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,9 @@ const char *song_get_tracker_id(void);
char *song_get_title(void); // editable
char *song_get_message(void); // editable

// returned value = seconds
unsigned int song_get_length_to(int order, int row);
void song_get_at_time(unsigned int seconds, int *order, int *row);
// returned value = milliseconds
unsigned int song_get_length_to_ms(int order, int row);
void song_get_at_time(unsigned int ms, int *order, int *row);

// gee. can't just use malloc/free... no, that would be too simple.
signed char *song_sample_allocate(int bytes);
Expand Down Expand Up @@ -254,6 +254,7 @@ const char *song_audio_driver(void);
void song_toggle_multichannel_mode(void);
int song_is_multichannel_mode(void);
void song_change_current_play_channel(int relative, int wraparound);
void main_song_mode_changed_cb(void);
int song_get_current_play_channel(void);

/* These return the channel that was used for the note.
Expand Down
12 changes: 8 additions & 4 deletions player/effects.c
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,7 @@ void csf_process_midi_macro(song_t *csf, uint32_t nchan, const char * macro, uin
# error csf_get_length assumes 64 channels
#endif

unsigned int csf_get_length(song_t *csf)
unsigned int csf_get_length_ms(song_t *csf)
{
uint32_t elapsed = 0, row = 0, next_row = 0, cur_order = 0, next_order = 0, pat = csf->orderlist[0],
speed = csf->initial_speed, tempo = csf->initial_tempo, psize, n;
Expand Down Expand Up @@ -1047,9 +1047,9 @@ unsigned int csf_get_length(song_t *csf)
if (csf->stop_at_order > -1 && csf->stop_at_row > -1) {
if (csf->stop_at_order <= (signed) cur_order && csf->stop_at_row <= (signed) row)
break;
if (csf->stop_at_time > 0) {
if (csf->stop_at_time_ms > 0) {
/* stupid api decision */
if (((elapsed + 500) / 1000) >= csf->stop_at_time) {
if (elapsed >= csf->stop_at_time_ms) {
csf->stop_at_order = cur_order;
csf->stop_at_row = row;
break;
Expand Down Expand Up @@ -1130,9 +1130,13 @@ unsigned int csf_get_length(song_t *csf)
elapsed += (speed + speed_count) * 2500 / tempo;
}

return (elapsed + 500) / 1000;
return elapsed;
}

unsigned int csf_get_length_secs(song_t *csf)
{
return (csf_get_length_ms(csf) + 500) / 1000;
}

//////////////////////////////////////////////////////////////////////////////////////////////////
// Effects
Expand Down
1 change: 1 addition & 0 deletions rocket
Submodule rocket added at b7594c
18 changes: 17 additions & 1 deletion schism/audio_playback.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ static void audio_callback(UNUSED void *qq, uint8_t * stream, int len)

/* this should be in page.c; the audio handling code doesn't need to know what
a page is, much less be talking to them */
static void main_song_mode_changed_cb(void)
void main_song_mode_changed_cb(void)
{
int n;
for (n = 0; n < PAGE_MAX; n++) {
Expand Down Expand Up @@ -630,6 +630,12 @@ void song_loop_pattern(int pattern, int row)

song_reset_play_state();

/* Since this plays an arbitrary pattern irrespective of current order,
* which may not even be part of an order list at all - there isn't an
* clear "play time" to bootstrap from (we don't have an order to give
* song_get_length_to_ms()).
*/

max_channels_used = 0;
csf_loop_pattern(current_song, pattern, row);

Expand All @@ -646,6 +652,16 @@ void song_start_at_order(int order, int row)
song_lock_audio();

song_reset_play_state();
/* Try approximate how many samples would have been played
* up to this [order,row], so Time: can reflect in-song time
* had it been played from the start to this [order,row].
*
* This is particularly relevant for Rocket integration where during
* playback the current Rocket row is derived from samples_played, and
* it's useful for 'F7' plays from arbitrary rows to keep Rocket in
* sync.
*/
samples_played = ((double)song_get_length_to_ms(order, row) * .001) * current_song->mix_frequency;

csf_set_current_order(current_song, order);
current_song->break_row = row;
Expand Down
2 changes: 1 addition & 1 deletion schism/disko.c
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ int disko_export_song(const char *filename, const struct save_format *format)
export_format = format;
status.flags |= DISKWRITER_ACTIVE; /* tell main to care about us */

disko_dialog_setup((csf_get_length(&export_dwsong) * export_dwsong.mix_frequency) ?: 1);
disko_dialog_setup((csf_get_length_secs(&export_dwsong) * export_dwsong.mix_frequency) ?: 1);

return DW_OK;
}
Expand Down
78 changes: 78 additions & 0 deletions schism/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@

#include "osdefs.h"

#ifdef USE_ROCKET
#include "rocket.h"
#endif

#include <errno.h>

#include "sdlmain.h"
Expand Down Expand Up @@ -80,6 +84,14 @@ static const char *audio_driver = NULL;
static int did_fullscreen = 0;
static int did_classic = 0;

#ifdef USE_ROCKET
static int use_rocket;
static const char *rocket_host;
static const char *rocket_port;
static const char *rocket_bpm; /* Rocket beats per minute, should match with Editor */
static const char *rocket_rpb; /* Rocket rows per beat, also should match with Editor */
#endif

/* --------------------------------------------------------------------- */

static void display_print_info(void)
Expand Down Expand Up @@ -269,6 +281,13 @@ enum {
#endif
O_DISKWRITE,
O_DEBUG,
#if USE_ROCKET
O_ROCKET,
O_ROCKET_HOST,
O_ROCKET_PORT,
O_ROCKET_BPM,
O_ROCKET_RPB,
#endif
O_VERSION,
};

Expand Down Expand Up @@ -322,6 +341,13 @@ static void parse_options(int argc, char **argv)
{"no-hooks", 0, NULL, O_NO_HOOKS},
#endif
{"debug", 1, NULL, O_DEBUG},
#ifdef USE_ROCKET
{"rocket", 0, NULL, O_ROCKET},
{"rocket-host", 1, NULL, O_ROCKET_HOST},
{"rocket-port", 1, NULL, O_ROCKET_PORT},
{"rocket-bpm", 1, NULL, O_ROCKET_BPM},
{"rocket-rpb", 1, NULL, O_ROCKET_RPB},
#endif
{"version", 0, NULL, O_VERSION},
{"help", 0, NULL, O_HELP},
{NULL, 0, NULL, 0},
Expand Down Expand Up @@ -389,6 +415,29 @@ static void parse_options(int argc, char **argv)
put_env_var("DISPLAY", optarg);
break;
#endif

#ifdef USE_ROCKET
case O_ROCKET:
use_rocket = 1;
break;
case O_ROCKET_HOST:
use_rocket = 1;
rocket_host = optarg;
break;
case O_ROCKET_PORT:
use_rocket = 1;
rocket_port = optarg;
break;
case O_ROCKET_BPM:
use_rocket = 1;
rocket_bpm = optarg;
break;
case O_ROCKET_RPB:
use_rocket = 1;
rocket_rpb = optarg;
break;
#endif

case O_FULLSCREEN:
video_fullscreen(1);
did_fullscreen = 1;
Expand Down Expand Up @@ -455,6 +504,13 @@ static void parse_options(int argc, char **argv)
" --hooks (--no-hooks)\n"
#endif
//" --debug=OPS\n"
#if USE_ROCKET
" --rocket\n"
" --rocket-host=HOST_OVERRIDE (implies --rocket)\n"
" --rocket-port=PORT_OVERRIDE (implies --rocket)\n"
" --rocket-bpm=BPM_OVERRIDE (beats per minute, default: 125 (implies --rocket))\n"
" --rocket-rpb=RPB_OVERRIDE (rows per beat, default: 8 (implies --rocket))\n"
#endif
" --version\n"
" -h, --help\n"
);
Expand Down Expand Up @@ -981,6 +1037,10 @@ static void event_loop(void)
status.flags &= ~(CLIPPY_PASTE_BUFFER|CLIPPY_PASTE_SELECTION);
}

#ifdef USE_ROCKET
if (use_rocket)
schism_rocket_update();
#endif
check_update();

switch (song_get_mode()) {
Expand Down Expand Up @@ -1095,6 +1155,24 @@ int main(int argc, char **argv)
alsa_dlinit();
#endif

#if USE_ROCKET
/* For now we just try to connect to rocket once at startup, so a
* rocket editor must be running, and we'll fail hard if we can't reach
* it.
*
* TODO: make more robust/do reconnects, have something in the GUI for
* seeing the connection status and disconnect/(re)connecting, changing
* host/port etc.
*
* This is good enough for basic demo development and proving/iterating
* the concept though.
*/
if (use_rocket && schism_rocket_connect(rocket_host, rocket_port, rocket_bpm, rocket_rpb) < 0) {
SDL_Log("Unable to connect GNU Rocket, aborting");
return 1;
}
#endif

cfg_init_dir();

#if ENABLE_HOOKS
Expand Down
15 changes: 8 additions & 7 deletions schism/mplink.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,33 +40,34 @@ song_t *current_song = NULL;
// ------------------------------------------------------------------------
// song information

unsigned int song_get_length_to(int order, int row)
unsigned int song_get_length_to_ms(int order, int row)
{
unsigned int t;

song_lock_audio();
current_song->stop_at_order = order;
current_song->stop_at_row = row;
t = csf_get_length(current_song);
t = csf_get_length_ms(current_song);
current_song->stop_at_order = current_song->stop_at_row = -1;
song_unlock_audio();
return t;
}
void song_get_at_time(unsigned int seconds, int *order, int *row)

void song_get_at_time(unsigned int ms, int *order, int *row)
{
if (!seconds) {
if (!ms) {
if (order) *order = 0;
if (row) *row = 0;
} else {
song_lock_audio();
current_song->stop_at_order = MAX_ORDERS;
current_song->stop_at_row = 255; /* unpossible */
current_song->stop_at_time = seconds;
csf_get_length(current_song);
current_song->stop_at_time_ms = ms;
(void) csf_get_length_ms(current_song);
if (order) *order = current_song->stop_at_order;
if (row) *row = current_song->stop_at_row;
current_song->stop_at_order = current_song->stop_at_row = -1;
current_song->stop_at_time = 0;
current_song->stop_at_time_ms = 0;
song_unlock_audio();
}
}
Expand Down
Loading