Skip to content

Commit

Permalink
Merge pull request #13 from SubhadeepJasu/midi-player
Browse files Browse the repository at this point in the history
Song Player
  • Loading branch information
SubhadeepJasu authored Jul 22, 2021
2 parents fbf7f56 + 04e4082 commit 9b94013
Show file tree
Hide file tree
Showing 12 changed files with 833 additions and 26 deletions.
5 changes: 5 additions & 0 deletions com.github.subhadeepjasu.ensembles.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ finish-args:
- '--socket=pulseaudio'
- '--device=all'
- '--filesystem=home'
# Required for system wide dark style preference
- '--system-talk-name=org.freedesktop.Accounts'
# Required for media keys and MPRIS access
- '--own-name=org.mpris.MediaPlayer2.com.github.subhadeepjasu.ensembles'
- '--talk-name=org.gnome.SettingsDaemon.MediaKeys'
modules:
- name: granite
buildsystem: meson
Expand Down
9 changes: 5 additions & 4 deletions data/com.github.subhadeepjasu.ensembles.desktop.in
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
[Desktop Entry]
Name=Ensembles
GenericName=Ensembles Arranger Workstation
GenericName=Arranger Workstation
Comment=Play and arrange music live as a one-person band
Categories=Audio;AudioVideo;Music;Midi;Education;GTK;
Exec=com.github.subhadeepjasu.ensembles
MimeType=audio/midi
Exec=com.github.subhadeepjasu.ensembles %U
Icon=com.github.subhadeepjasu.ensembles
Terminal=false
Type=Application
Keywords=midi;virtual;music;arranger;piano;keyboard;workstation;daw;
X-GNOME-Gettext-Domain=com.github.subhadeepjasu.ensembles
Keywords=midi;virtual;music;arranger;piano;keyboard;workstation;
X-GNOME-Gettext-Domain=com.github.subhadeepjasu.ensembles
103 changes: 103 additions & 0 deletions src/Core/SongPlayer.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
namespace Ensembles.Core {
public class SongPlayer : Object {
public enum PlayerStatus {
READY,
PLAYING,
STOPPING,
DONE
}
public int current_file_tempo = 30;
public signal void player_status_changed (float fraction, int tempo_bpm, PlayerStatus status);
bool monitoring_player = false;
string sf_loc;

public SongPlayer (string sf_loc, string midi_file_path) {
this.sf_loc = sf_loc;
music_player_init (sf_loc);
current_file_tempo = music_player_load_file (midi_file_path);
player_status_changed (0.0f, current_file_tempo, get_status ());
start_monitoring ();
}

public void start_monitoring () {
monitoring_player = true;
debug ("Starting monitor");
new Thread<int> ("monitor_player", monitor_player);
}
public void songplayer_destroy () {
monitoring_player = false;
music_player_destruct ();
}

public void play () {
music_player_play ();
}

public void pause () {
music_player_pause ();
}

public void seek (float seek_fraction) {
music_player_seek ((int) (seek_fraction * total_ticks));
}

public void seek_lock (bool lock) {
if (lock) {
monitoring_player = false;
} else {
start_monitoring ();
}
}

public void rewind () {
pause ();
seek (0.0f);
play ();
}

public void set_repeat (bool enable) {
player_repeat = enable ? 1 : 0;
}

public PlayerStatus get_status () {
switch (music_player_get_status ()) {
case 0:
return PlayerStatus.READY;
case 1:
return PlayerStatus.PLAYING;
case 2:
return PlayerStatus.STOPPING;
}
return PlayerStatus.DONE;
}

private int monitor_player () {
while (monitoring_player) {
Idle.add (() => {
if (total_ticks > 0 && monitoring_player) {
player_status_changed ((float) current_ticks / (float) total_ticks, current_file_tempo, get_status ());
} else {
player_status_changed (0.0f, current_file_tempo, get_status ());
}
return false;
});
Thread.yield ();
Thread.usleep (10000);
}
return 0;
}
}
}

extern void music_player_init (string sf_loc);
extern void music_player_destruct ();
extern int music_player_load_file (string path);
extern void music_player_play ();
extern void music_player_pause ();
extern void music_player_seek (int seek_point);
extern int music_player_get_status ();

extern int note_watch_channel;
extern int total_ticks;
extern int current_ticks;
extern int player_repeat;
5 changes: 5 additions & 0 deletions src/Core/StylePlayer.vala
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ namespace Ensembles.Core {
public void change_chords (int chord_main, int chord_type) {
style_player_change_chord (chord_main, chord_type);
}

public void change_tempo (int tempo) {
style_player_set_tempo (tempo);
}
}
}

Expand All @@ -103,5 +107,6 @@ extern void style_player_queue_ending (int start, int end);
extern void style_player_break ();
extern void style_player_sync_start ();
extern void style_player_sync_stop ();
extern void style_player_set_tempo (int tempo_bpm);

extern void style_player_change_chord (int cd_main, int cd_type);
133 changes: 133 additions & 0 deletions src/Core/music_player.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*-
* Copyright (c) 2021-2022 Subhadeep Jasu <subhajasu@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Authored by: Subhadeep Jasu <subhajasu@gmail.com>
*/

#include <fluidsynth.h>
#include <gtk/gtk.h>
#include <glib.h>
#include <string.h>

// These are actually used to render audio
fluid_settings_t* mp_settings;
fluid_synth_t* mp_synth;
fluid_audio_driver_t* mp_adriver;
fluid_player_t* mp_player;

int note_watch_channel = 0;
int total_ticks = 0;
int current_ticks = 0;


gchar* midi_file_path;

int player_repeat;

int
mp_parse_midi_events (void *data, fluid_midi_event_t *event) {
return fluid_synth_handle_midi_event (mp_synth, event);
}

int
mp_parse_ticks (void* data, int ticks) {
current_ticks = ticks;
if (total_ticks < 10) {
total_ticks = fluid_player_get_total_ticks (mp_player);

printf ("total_ticks = %d\n", total_ticks);
}
if (total_ticks > 10 && current_ticks + 10 > total_ticks) {
if (player_repeat > 0) {
current_ticks = 0;
return fluid_player_seek (mp_player, 1);
} else {
fluid_player_stop (mp_player);
current_ticks = 0;
return fluid_player_seek (mp_player, 1);
}
}
return FLUID_OK;
}

void
music_player_init (const gchar* sf_loc) {
mp_settings = new_fluid_settings();
fluid_settings_setstr(mp_settings, "audio.driver", "pulseaudio");
fluid_settings_setint(mp_settings, "audio.periods", 16);
fluid_settings_setint(mp_settings, "audio.period-size", 4096);
fluid_settings_setint(mp_settings, "audio.realtime-prio", 40);
fluid_settings_setnum(mp_settings, "synth.gain", 1.0);
mp_synth = new_fluid_synth(mp_settings);
mp_adriver = new_fluid_audio_driver(mp_settings, mp_synth);

if (fluid_is_soundfont(sf_loc)) {
fluid_synth_sfload(mp_synth, sf_loc, 1);
}
mp_player = new_fluid_player(mp_synth);
fluid_player_set_playback_callback(mp_player, mp_parse_midi_events, mp_synth);
fluid_player_set_tick_callback (mp_player, mp_parse_ticks, mp_synth);
}

int
music_player_load_file (gchar* path) {
midi_file_path = (char *)malloc(sizeof (char) * strlen (path));
strcpy (midi_file_path, path);
if (fluid_is_midifile (midi_file_path)) {
fluid_player_add (mp_player, midi_file_path);
total_ticks = fluid_player_get_total_ticks (mp_player);
return fluid_player_get_bpm (mp_player);
}
return -1;
}

void
music_player_play () {
fluid_player_play (mp_player);
}

void
music_player_pause () {
fluid_player_stop (mp_player);
fluid_synth_all_notes_off (mp_synth, -1);
fluid_synth_all_sounds_off (mp_synth, -1);
}

void
music_player_seek (int seek_point) {
fluid_player_seek (mp_player, seek_point);
}

int
music_player_get_status () {
if (mp_player) {
return fluid_player_get_status (mp_player);
}
return 0;
}

void
music_player_destruct () {
if (mp_player) {
fluid_player_stop (mp_player);
fluid_player_join (mp_player);
delete_fluid_player(mp_player);
mp_player = NULL;
}
delete_fluid_synth(mp_synth);
delete_fluid_settings(mp_settings);
delete_fluid_audio_driver(mp_adriver);
}
8 changes: 7 additions & 1 deletion src/Core/style_player.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,12 @@ style_player_add_style_file (const gchar* mid_file, int reload) {
}
}

void
style_player_set_tempo (int tempo_bpm) {
fluid_player_set_tempo (player, FLUID_PLAYER_TEMPO_EXTERNAL_BPM, (double)tempo_bpm);
set_central_loaded_tempo (tempo_bpm);
}

void
style_player_reload_style () {
style_player_add_style_file (style_player_style_path, 1);
Expand All @@ -420,7 +426,6 @@ style_player_reload_style () {
void
style_player_destruct () {
/* cleanup */
delete_fluid_audio_driver(adriver);
if (player) {
/* wait for playback termination */
fluid_player_stop (player);
Expand All @@ -430,6 +435,7 @@ style_player_destruct () {
}
delete_fluid_synth(synth);
delete_fluid_settings(settings);
delete_fluid_audio_driver(adriver);
}

void
Expand Down
Loading

0 comments on commit 9b94013

Please sign in to comment.