Skip to content

add Mix_SetMusicBeat and Mix_GetMusicBeat #481

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

Draft
wants to merge 1 commit into
base: main
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
23 changes: 23 additions & 0 deletions include/SDL_mixer.h
Original file line number Diff line number Diff line change
Expand Up @@ -2471,6 +2471,29 @@ extern DECLSPEC double SDLCALL Mix_GetMusicPosition(Mix_Music *music);
*/
extern DECLSPEC double SDLCALL Mix_MusicDuration(Mix_Music *music);

/**
* Set the current position in the music stream, in beats.
*
* This function is only implemented for MIDI via Timidity at the moment.
*
* \param beat the new position, in beats (as a int).
* \returns 0 if successful, or -1 if it failed or not implemented.
*
* \since This function is available since SDL_mixer 2.7.0.
*/
extern DECLSPEC int SDLCALL Mix_SetMusicBeat(int beat);

/**
* Get the current position in the music stream, in beats.
*
* This function is only implemented for MIDI via Timidity at the moment.
*
* \returns current beat position if successful, or -1 if it failed or not implemented.
*
* \since This function is available since SDL_mixer 2.7.0.
*/
extern DECLSPEC int SDLCALL Mix_GetMusicBeat();

/**
* Get the loop start time position of music stream, in seconds.
*
Expand Down
18 changes: 16 additions & 2 deletions playmus.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,11 @@ int main(int argc, char *argv[])
int audio_channels;
int audio_buffers;
int audio_volume = MIX_MAX_VOLUME;
int beat = 0;
int looping = 0;
int interactive = 0;
int rwops = 0;
int supports_beats;
int i;
const char *typ;
const char *tag_title = NULL;
Expand Down Expand Up @@ -162,6 +164,10 @@ int main(int argc, char *argv[])
if (strcmp(argv[i], "-l") == 0) {
looping = -1;
} else
if (strcmp(argv[i], "-n") == 0 && argv[i+1]) {
++i;
beat = atoi(argv[i]);
} else
if (strcmp(argv[i], "-i") == 0) {
interactive = 1;
} else
Expand Down Expand Up @@ -295,14 +301,22 @@ int main(int argc, char *argv[])
if (loop_start > 0.0 && loop_end > 0.0 && loop_length > 0.0) {
SDL_Log("Loop points: start %g s, end %g s, length %g s\n", loop_start, loop_end, loop_length);
}
Mix_FadeInMusic(music,looping,2000);
Mix_PlayMusic(music, looping);

supports_beats = Mix_GetMusicBeat(music) != -1;
if (supports_beats)
Mix_SetMusicBeat(beat);

while (!next_track && (Mix_PlayingMusic() || Mix_PausedMusic())) {
if(interactive)
Menu();
else {
current_position = Mix_GetMusicPosition(music);
if (current_position >= 0.0) {
printf("Position: %g seconds \r", current_position);
if (supports_beats)
printf("Position: %0.2f seconds Beat: %d\r", current_position, Mix_GetMusicBeat(music));
else
printf("Position: %0.2f seconds \r", current_position);
fflush(stdout);
}
SDL_Delay(100);
Expand Down
17 changes: 16 additions & 1 deletion src/codecs/music_timidity.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,12 +225,25 @@ static int TIMIDITY_Seek(void *context, double position)
return 0;
}

static int TIMIDITY_SeekBeat(void *context, int index)
{
TIMIDITY_Music *music = (TIMIDITY_Music *)context;
Timidity_SeekBeat(music->song, (Uint32)index);
return 0;
}

static double TIMIDITY_Tell(void *context)
{
TIMIDITY_Music *music = (TIMIDITY_Music *)context;
return Timidity_GetSongTime(music->song) / 1000.0;
}

static int TIMIDITY_TellBeat(void *context)
{
TIMIDITY_Music *music = (TIMIDITY_Music *)context;
return Timidity_GetSongBeat(music->song);
}

static double TIMIDITY_Duration(void *context)
{
TIMIDITY_Music *music = (TIMIDITY_Music *)context;
Expand Down Expand Up @@ -291,7 +304,9 @@ Mix_MusicInterface Mix_MusicInterface_TIMIDITY =
TIMIDITY_Stop,
TIMIDITY_Delete,
TIMIDITY_Close,
NULL /* Unload */
NULL, /* Unload */
TIMIDITY_SeekBeat,
TIMIDITY_TellBeat
};

#endif /* MUSIC_MID_TIMIDITY */
Expand Down
85 changes: 85 additions & 0 deletions src/codecs/timidity/playmidi.c
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,75 @@ static void seek_forward(MidiSong *song, Sint32 until_time)
song->current_sample=until_time;
}

static void seek_forward_beat(MidiSong *song, Uint32 beat)
{
reset_voices(song);
while (song->current_event->beat < beat)
{
switch(song->current_event->type)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exact same contents in this switch statement as the other seek_foward function. I could split out to a help function.

{
/* All notes stay off. Just handle the parameter changes. */

case ME_PITCH_SENS:
song->channel[song->current_event->channel].pitchsens =
song->current_event->a;
song->channel[song->current_event->channel].pitchfactor = 0;
break;

case ME_PITCHWHEEL:
song->channel[song->current_event->channel].pitchbend =
song->current_event->a + song->current_event->b * 128;
song->channel[song->current_event->channel].pitchfactor = 0;
break;

case ME_MAINVOLUME:
song->channel[song->current_event->channel].volume =
song->current_event->a;
break;

case ME_PAN:
song->channel[song->current_event->channel].panning =
song->current_event->a;
break;

case ME_EXPRESSION:
song->channel[song->current_event->channel].expression =
song->current_event->a;
break;

case ME_PROGRAM:
if (ISDRUMCHANNEL(song, song->current_event->channel))
/* Change drum set */
song->channel[song->current_event->channel].bank =
song->current_event->a;
else
song->channel[song->current_event->channel].program =
song->current_event->a;
break;

case ME_SUSTAIN:
song->channel[song->current_event->channel].sustain =
song->current_event->a;
break;

case ME_RESET_CONTROLLERS:
reset_controllers(song, song->current_event->channel);
break;

case ME_TONE_BANK:
song->channel[song->current_event->channel].bank =
song->current_event->a;
break;

case ME_EOT:
song->current_sample = song->current_event->time;
return;
}
song->current_event++;
}
song->current_sample=song->current_event->time;
}

static void skip_to(MidiSong *song, Sint32 until_time)
{
if (song->current_sample > until_time)
Expand Down Expand Up @@ -645,6 +714,17 @@ void Timidity_Seek(MidiSong *song, Uint32 ms)
skip_to(song, (ms * (song->rate / 100)) / 10);
}

void Timidity_SeekBeat(MidiSong *song, Uint32 beat)
{
reset_midi(song);
song->buffered_count = 0;
song->buffer_pointer = song->common_buffer;
song->current_event = song->events;

if (beat)
seek_forward_beat(song, beat);
}

Uint32 Timidity_GetSongLength(MidiSong *song)
{
MidiEvent *last_event = &song->events[song->groomed_event_count - 1];
Expand All @@ -661,6 +741,11 @@ Uint32 Timidity_GetSongTime(MidiSong *song)
return retvalue;
}

Uint32 Timidity_GetSongBeat(MidiSong *song)
{
return song->current_event->beat;
}

int Timidity_PlaySome(MidiSong *song, void *stream, Sint32 len)
{
Sint32 start_sample, end_sample, samples;
Expand Down
2 changes: 2 additions & 0 deletions src/codecs/timidity/readmidi.c
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,7 @@ static MidiEvent *groom_list(MidiSong *song, Sint32 divisions,Sint32 *eventsp,
/* Add the event to the list */
*lp=meep->event;
lp->time=st;
lp->beat = meep->event.time / divisions;
lp++;
our_event_count++;
}
Expand All @@ -510,6 +511,7 @@ static MidiEvent *groom_list(MidiSong *song, Sint32 divisions,Sint32 *eventsp,
}
/* Add an End-of-Track event */
lp->time=st;
lp->beat=UINT8_MAX;
lp->type=ME_EOT;
our_event_count++;
free_midi_list(song);
Expand Down
3 changes: 3 additions & 0 deletions src/codecs/timidity/timidity.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ typedef struct {
typedef struct {
Sint32 time;
Uint8 channel, type, a, b;
Uint32 beat;
} MidiEvent;

typedef struct _MidiEventList {
Expand Down Expand Up @@ -154,7 +155,9 @@ extern int Timidity_PlaySome(MidiSong *song, void *stream, Sint32 len);
extern MidiSong *Timidity_LoadSong(SDL_RWops *rw, SDL_AudioSpec *audio);
extern void Timidity_Start(MidiSong *song);
extern void Timidity_Seek(MidiSong *song, Uint32 ms);
extern void Timidity_SeekBeat(MidiSong *song, Uint32 beat);
extern Uint32 Timidity_GetSongLength(MidiSong *song); /* returns millseconds */
extern Uint32 Timidity_GetSongBeat(MidiSong *song); /* returns current beat (aka quarter note) */
extern Uint32 Timidity_GetSongTime(MidiSong *song); /* returns millseconds */
extern void Timidity_Stop(MidiSong *song);
extern int Timidity_IsActive(MidiSong *song);
Expand Down
46 changes: 46 additions & 0 deletions src/music.c
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,52 @@ int Mix_SetMusicPosition(double position)
return(retval);
}

int Mix_SetMusicBeat(int beat)
{
int retval;

Mix_LockAudio();
if (music_playing) {
if (music_playing->interface->SeekBeat) {
retval = music_playing->interface->SeekBeat(music_playing->context, beat);
} else {
retval = -1;
}
if (retval < 0) {
Mix_SetError("Seek beat not implemented for music type");
}
} else {
Mix_SetError("Music isn't playing");
retval = -1;
}
Mix_UnlockAudio();

return(retval);
}

int Mix_GetMusicBeat()
{
int retval;

Mix_LockAudio();
if (music_playing) {
if (music_playing->interface->TellBeat) {
retval = music_playing->interface->TellBeat(music_playing->context);
} else {
retval = -1;
}
if (retval < 0) {
Mix_SetError("Get beat not implemented for music type");
}
} else {
Mix_SetError("Music isn't playing");
retval = -1;
}
Mix_UnlockAudio();

return(retval);
}

/* Set the playing music position */
static double music_internal_position_get(Mix_Music *music)
{
Expand Down
6 changes: 6 additions & 0 deletions src/music.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ typedef struct

/* Unload the library */
void (*Unload)(void);

/* Seek to a play position (in beats) */
int (*SeekBeat)(void *music, int beats);

/* Tell current beat */
int (*TellBeat)(void *music);
} Mix_MusicInterface;


Expand Down