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

play MIDI on Linux #80

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
115 changes: 114 additions & 1 deletion PixelGameEngine/SmallerProjects/OneLoneCoder_PGE_MIDI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,53 @@

Author
~~~~~~
David Barr, aka javidx9, �OneLoneCoder 2018, 2019, 2020
David Barr, aka javidx9, �OneLoneCoder 2018, 2019, 2020
*/

/*
On Linux need to install fluidsynth, compile with -lfluidsynth,
and add a midi font file `midi_font.sf2`.
https://github.com/FluidSynth/fluidsynth

Install fluidsynth (default location is /usr/local)
```
wget https://github.com/FluidSynth/fluidsynth/archive/refs/tags/v2.3.2.zip
unzip v2.3.2.zip
cd fluidsynth-2.3.2
mkdir -p build
cd build
cmake ..
cmake --build .
cmake --install .
```

Compile with `-lfluidsynth`
```
g++ -o midi OneLoneCoder_PGE_MIDI.cpp -lfluidsynth -I../BiggerProjects/CarCrimeCity/Part2 -lGL -lpng -lX11 -lpthread -lstdc++fs -std=c++17
```

Download a MIDI Font (there are many online), or install `vlc-plugin-fluidsynth`, it adds a default.sf2 at `/usr/share/sounds/sf2/default-GM.sf2`
```
sudo apt install vlc-plugin-fluidsynth
```

Once you have `ff7_battle.mid` and `midi_font.sf2`, just run
```
./midi
```
*/

#define OLC_PGE_APPLICATION
#include "olcPixelGameEngine.h"

#include <fstream>
#include <array>

#ifdef WIN32
//#pragma comment(lib, "winmm.lib")
#else
#include <fluidsynth.h>
#endif


struct MidiEvent
Expand Down Expand Up @@ -498,7 +534,16 @@ class olcMIDIViewer : public olc::PixelGameEngine

MidiFile midi;

#ifdef WIN32
//HMIDIOUT hInstrument;
#else
fluid_settings_t *settings = NULL;
fluid_synth_t *synth = NULL;
fluid_audio_driver_t *adriver = NULL;
int sfont_id;
int i, key;
const char *sMidiFontFile = "midi_font.sf2";
#endif
size_t nCurrentNote[16]{ 0 };

double dSongTime = 0.0;
Expand All @@ -512,6 +557,7 @@ class olcMIDIViewer : public olc::PixelGameEngine

midi.ParseFile("ff7_battle.mid");

#ifdef WIN32
/*
int nMidiDevices = midiOutGetNumDevs();
if (nMidiDevices > 0)
Expand All @@ -522,7 +568,45 @@ class olcMIDIViewer : public olc::PixelGameEngine
}
}
*/
#else
/* Create the settings. */
settings = new_fluid_settings();
if (settings == NULL)
{
puts("Failed to create the settings!");
return false;
}

/* Change the settings if necessary*/

/* Create the synthesizer. */
synth = new_fluid_synth(settings);
if (synth == NULL)
{
puts("Failed to create the synth!");
return false;
}

/* Load a SoundFont and reset presets (so that new instruments
* get used from the SoundFont)
* Depending on the size of the SoundFont, this will take some time to complete...
*/
sfont_id = fluid_synth_sfload(synth, sMidiFontFile, 1);
if (sfont_id == FLUID_FAILED)
{
puts("Loading the SoundFont failed!");
return false;
}

/* Create the audio driver. The synthesizer starts playing as soon
as the driver is created. */
adriver = new_fluid_audio_driver(settings, synth);
if (adriver == NULL)
{
puts("Failed to create the audio driver!");
return false;
}
#endif

return true;
}
Expand Down Expand Up @@ -584,12 +668,19 @@ class olcMIDIViewer : public olc::PixelGameEngine
uint32_t nNote = midi.vecTracks[nTrack].vecEvents[nCurrentNote[nTrack]].nKey;
uint32_t nVelocity = midi.vecTracks[nTrack].vecEvents[nCurrentNote[nTrack]].nVelocity;

#ifdef WIN32
if (midi.vecTracks[nTrack].vecEvents[nCurrentNote[nTrack]].event == MidiEvent::Type::NoteOn)
nStatus = 0x90;
else
nStatus = 0x80;

midiOutShortMsg(hInstrument, (nVelocity << 16) | (nNote << 8) | nStatus);
#else
if (midi.vecTracks[nTrack].vecEvents[nCurrentNote[nTrack]].event == MidiEvent::Type::NoteOn)
fluid_synth_noteon(synth, nTrack, nNote, nVelocity);
else
fluid_synth_noteoff(synth, nTrack, nNote);
#endif
nCurrentNote[nTrack]++;
}
else
Expand All @@ -598,6 +689,7 @@ class olcMIDIViewer : public olc::PixelGameEngine
}
}

#ifdef WIN32
if (GetKey(olc::Key::SPACE).bPressed)
{
midiOutShortMsg(hInstrument, 0x00403C90);
Expand All @@ -607,12 +699,33 @@ class olcMIDIViewer : public olc::PixelGameEngine
{
midiOutShortMsg(hInstrument, 0x00003C80);
}
#else
if (GetKey(olc::Key::SPACE).bPressed)
{
fluid_synth_noteon(synth, 0, 0x3C, 0x40);
}
if (GetKey(olc::Key::SPACE).bReleased)
{
fluid_synth_noteoff(synth, 0, 0x3C);
}
#endif
*/


return true;
}

#ifndef WIN32
bool OnUserDestroy() override
{
/* Clean up */
delete_fluid_audio_driver(adriver);
delete_fluid_synth(synth);
delete_fluid_settings(settings);

return true;
}
#endif

};

Expand Down