diff --git a/.clang_format b/.clang_format new file mode 100644 index 0000000..6b05891 --- /dev/null +++ b/.clang_format @@ -0,0 +1,17 @@ +// Remove me and name file '.clang-format', put in top level source +BasedOnStyle: Google +AllowShortBlocksOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +BreakBeforeBraces: Allman +BreakBeforeTernaryOperators: false +ColumnLimit: 100 +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +IndentWidth: 4 +Standard: Cpp03 +TabWidth: 4 +UseTab: ForIndentation +DerivePointerAlignment: false +PointerAlignment: Left \ No newline at end of file diff --git a/.gitignore b/.gitignore index 259148f..a3d1123 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,6 @@ *.exe *.out *.app + +bin/ +lib/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..d48dde3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ThirdParty/rtmidi"] + path = ThirdParty/rtmidi + url = https://github.com/thestk/rtmidi diff --git a/Jamfile b/Jamfile index 6c5213f..968d41a 100644 --- a/Jamfile +++ b/Jamfile @@ -7,7 +7,15 @@ if $(WINDOWS) SUFEXE = .exe ; } -Main liveMusicMachine : src/Main.cpp ; +Library libRtMidi : #ThirdParty/rtmidi/midiprobe.cpp + ThirdParty/rtmidi/RtMidi.cpp ; + +MakeLocate libRtMidi.a : lib ; + +LinkLibraries liveMusicMachine : libRtMidi ; + +Main liveMusicMachine : src/Main.cpp + src/Midi.cpp ; MakeLocate liveMusicMachine : bin ; diff --git a/Jamrules b/Jamrules index 7be2d54..0adf0e2 100644 --- a/Jamrules +++ b/Jamrules @@ -35,17 +35,18 @@ LINK = clang++ ; # -Wno-unused-parameter = I should probably get rid of this at some point # Arguments used on all projects, regardless of any variables -C++FLAGS = -std=c++11 -Wall -Wextra -Wno-unused-parameter ; +# Define ALSA for RtMidi (http://www.music.mcgill.ca/~gary/rtmidi/) +C++FLAGS = -std=c++11 -Wall -Wextra -Wno-unused-parameter -D__LINUX_ALSA__ ; ALLLIBSC++FLAGS = -g ; # Required arguments for linux LINUXC++FLAGS = -g ; # Required arguments for Windows -#WINDOWSC++FLAGS = -g -stdlib=libc++ -fPIC ; -#WINDOWSC++FLAGS = -g -stdlib=libc++ -target x86_64-win32 ; -#WINDOWSC++FLAGS = -g -stdlib=libc++ -target x86_64-w64-mingw32 ; +#WINDOWSC++FLAGS = -g -stdlib=libc++ -fPIC -D__WINDOWS_MM__; +#WINDOWSC++FLAGS = -g -stdlib=libc++ -target x86_64-win32 -D__WINDOWS_MM__; +#WINDOWSC++FLAGS = -g -stdlib=libc++ -target x86_64-w64-mingw32 -D__WINDOWS_MM__; -LINKLIBS = -lsfml-audio -lsfml-graphics -lsfml-window -lsfml-system ; +LINKLIBS = -lsfml-audio -lsfml-graphics -lsfml-window -lsfml-system -lasound -lpthread ; KEEPOBJS = true ; # This doesn't actually fix anything, though it seems like it should NOARSCAN = true ; # This actually fixes the problem @@ -75,8 +76,8 @@ else OPTIM = -O0 ; -HDRS = libs/base2.0 ; - +#HDRS = libs/base2.0 ; +HDRS = ThirdParty/rtmidi ; # Some helpful Jam commands diff --git a/ThirdParty/rtmidi b/ThirdParty/rtmidi new file mode 160000 index 0000000..81eabf2 --- /dev/null +++ b/ThirdParty/rtmidi @@ -0,0 +1 @@ +Subproject commit 81eabf2563431160496f091937b5ead4d205376e diff --git a/bin/liveMusicMachine b/bin/liveMusicMachine index acfb25b..e840897 100755 Binary files a/bin/liveMusicMachine and b/bin/liveMusicMachine differ diff --git a/notes.txt b/notes.txt new file mode 100644 index 0000000..41cd992 --- /dev/null +++ b/notes.txt @@ -0,0 +1,2 @@ +TODO +Left off with MidiNote not printing the correct velocity/note. diff --git a/src/Main.cpp b/src/Main.cpp index 1f226c7..cf2b192 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -1,7 +1,10 @@ #include +#include "Midi.hpp" + int main() { std::cout << "Hello, world!\n"; + TestRtMidi(); return 0; } diff --git a/src/Midi.cpp b/src/Midi.cpp new file mode 100644 index 0000000..cc64cc7 --- /dev/null +++ b/src/Midi.cpp @@ -0,0 +1,205 @@ +#include "RtMidi.h" + +#include +#include +#include + +bool done; +static void finish(int ignore) +{ + done = true; +} + +// From http://www.music.mcgill.ca/~gary/rtmidi/ +void RtMidiDemoListen() +{ + try + { + RtMidiIn midiIn; + unsigned int numPorts = midiIn.getPortCount(); + if (!numPorts) + { + std::cout << "No MIDI ports available\n"; + return; + } + std::cout << numPorts << " MIDI ports available\n"; + + midiIn.openPort(1); + + // From demo + { + std::vector message; + int nBytes, i; + double stamp; + // Install an interrupt handler function. + done = false; + (void)signal(SIGINT, finish); + // Periodically check input queue. + std::cout << "Reading MIDI from port ... quit with Ctrl-C.\n"; + while (!done) + { + stamp = midiIn.getMessage(&message); + nBytes = message.size(); + for (i = 0; i < nBytes; i++) + std::cout << "Byte " << i << " = " << (int)message[i] << ", "; + if (nBytes > 0) + std::cout << "stamp = " << stamp << std::endl; + // Sleep for 10 milliseconds ... platform-dependent. + // sleep(10); + } + } + } + catch (RtMidiError& error) + { + error.printMessage(); + } + return; +} + +/* Midi Commands + From http://www.songstuff.com/recording/article/midi_message_format/ +Note Off 8n Note Number Velocity +Note On 9n Note Number Velocity +Polyphonic Aftertouch An Note Number Pressure +Control Change Bn Controller Number Data +Program Change Cn Program Number Unused +Channel Aftertouch Dn Pressure Unused +Pitch Wheel En LSB MSB +*/ +enum class MidiCommandType : unsigned char +{ + NoteOn = 8, + NoteOff = 9, + Aftertouch = 0xA, + ControlChange = 0xB, + ProgramChange = 0xC, + ChannelAftertouch = 0xD, + PitchWheel = 0xE, +}; + +struct MidiNoteOn; +struct MidiCommand +{ + unsigned char channel : 4; + MidiCommandType command : 4; + void Print(); +}; + +struct MidiNote +{ + unsigned char velocity : 8; + unsigned char note : 8; + MidiCommand status; + + void Print(); +}; + +void MidiNote::Print() +{ + std::cout << (int)note << " (" << (int)velocity << ")"; +} + +void MidiCommand::Print() +{ + std::cout << "[" << (int)channel << "] "; + switch (command) + { + case MidiCommandType::NoteOn: + { + std::cout << "NoteOn "; + MidiNote* noteOn = reinterpret_cast(this); + noteOn->Print(); + break; + } + case MidiCommandType::NoteOff: + { + std::cout << "NoteOff "; + MidiNote* noteOff = reinterpret_cast(this); + noteOff->Print(); + break; + } + case MidiCommandType::Aftertouch: + { + std::cout << "Aftertouch "; + break; + } + case MidiCommandType::ControlChange: + { + std::cout << "ControlChange "; + break; + } + case MidiCommandType::ProgramChange: + { + std::cout << "ProgramChange "; + break; + } + case MidiCommandType::ChannelAftertouch: + { + std::cout << "ChannelAftertouch "; + break; + } + case MidiCommandType::PitchWheel: + { + std::cout << "PitchWheel "; + break; + } + default: + { + std::cout << "Unknown command " << (int)command; + break; + } + } + + std::cout << "\n"; +} + +void TestRtMidi() +{ + try + { + RtMidiIn midiIn; + unsigned int numPorts = midiIn.getPortCount(); + if (!numPorts) + { + std::cout << "No MIDI ports available\n"; + return; + } + std::cout << numPorts << " MIDI ports available\n"; + + midiIn.openPort(1); + + // From demo + { + std::vector message; + int nBytes, i; + double stamp; + // Install an interrupt handler function. + done = false; + (void)signal(SIGINT, finish); + // Periodically check input queue. + std::cout << "Reading MIDI from port ... quit with Ctrl-C.\n"; + while (!done) + { + stamp = midiIn.getMessage(&message); + nBytes = message.size(); + /* for (i = 0; i < nBytes; i++) + std::cout << "Byte " << i << " = " << (int)message[i] << ", ";*/ + if (nBytes && message.size() == 3) + { + MidiCommand* testCommand = reinterpret_cast(&message[0]); + testCommand->Print(); + } + + if (nBytes > 0) + std::cout << "stamp = " << stamp << std::endl; + // Sleep for 10 milliseconds ... platform-dependent. + // sleep(10); + } + } + } + catch (RtMidiError& error) + { + error.printMessage(); + } + return; +} diff --git a/src/Midi.hpp b/src/Midi.hpp new file mode 100644 index 0000000..ace94ac --- /dev/null +++ b/src/Midi.hpp @@ -0,0 +1,3 @@ +#pragma once + +void TestRtMidi();