Added ostd/Midi.hpp file + added midifile library as included dependency
This commit is contained in:
parent
f343c10018
commit
53e578a0a6
19 changed files with 11560 additions and 8 deletions
|
|
@ -30,8 +30,18 @@ list(APPEND INCLUDE_DIRS
|
|||
${CMAKE_CURRENT_LIST_DIR}/src/ostd
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ogfx
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/vendor
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/vendor/midifile
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/vendor/nlohmann
|
||||
)
|
||||
list(APPEND OSTD_SOURCE_FILES
|
||||
# MidiFile
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/vendor/midifile/Binasc.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/vendor/midifile/MidiEvent.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/vendor/midifile/MidiEventList.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/vendor/midifile/MidiFile.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/vendor/midifile/MidiMessage.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/vendor/midifile/Options.cpp
|
||||
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/BaseObject.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/Color.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/Console.cpp
|
||||
|
|
@ -44,6 +54,7 @@ list(APPEND OSTD_SOURCE_FILES
|
|||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/Logger.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/Logic.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/md5.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/Midi.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/OutputHandlers.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/PathFinder.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/QuadTree.cpp
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
1928
|
||||
1937
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
[0.2.1936]
|
||||
Added JsonFile class to handle Json files
|
||||
Added MidiParser class to parse Midi files
|
||||
|
||||
[0.2.1923]
|
||||
Added MacOS support
|
||||
|
||||
|
|
|
|||
|
|
@ -36,9 +36,13 @@ elif [[ "$(uname -s)" == MINGW64_NT* ]]; then
|
|||
fi
|
||||
|
||||
mkdir -p $RELEASE_DIR/include/ostd/vendor
|
||||
mkdir -p $RELEASE_DIR/include/ostd/vendor/midifile
|
||||
mkdir -p $RELEASE_DIR/include/ostd/vendor/nlohmann
|
||||
mkdir -p $RELEASE_DIR/include/ogfx/
|
||||
find ../src/ostd -maxdepth 1 -name "*.hpp" -exec cp {} $RELEASE_DIR/include/ostd \;
|
||||
find ../src/ogfx -maxdepth 1 -name "*.hpp" -exec cp {} $RELEASE_DIR/include/ogfx \;
|
||||
find ../src/ostd/vendor -maxdepth 1 -name "*.hpp" -exec cp {} $RELEASE_DIR/include/ostd/vendor \;
|
||||
find ../src/ostd -maxdepth 1 -name "*.h*" -exec cp {} $RELEASE_DIR/include/ostd \;
|
||||
find ../src/ogfx -maxdepth 1 -name "*.h*" -exec cp {} $RELEASE_DIR/include/ogfx \;
|
||||
find ../src/ostd/vendor -maxdepth 1 -name "*.h*" -exec cp {} $RELEASE_DIR/include/ostd/vendor \;
|
||||
find ../src/ostd/vendor/midifile -maxdepth 1 -name "*.h*" -exec cp {} $RELEASE_DIR/include/ostd/vendor/midifile \;
|
||||
find ../src/ostd/vendor/nlohmann -maxdepth 1 -name "*.h*" -exec cp {} $RELEASE_DIR/include/ostd/vendor/nlohmann \;
|
||||
cp -r ../licences $RELEASE_DIR
|
||||
cp ../LICENSE $RELEASE_DIR/licences/OmniaFramework-LICENCE.txt
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include <ostd/Geometry.hpp>
|
||||
#include <ostd/String.hpp>
|
||||
#include <ostd/Color.hpp>
|
||||
#include "vendor/nlohmann/json.hpp" // IWYU pragma: keep
|
||||
#include <ostd/vendor/nlohmann/json.hpp> // IWYU pragma: keep
|
||||
|
||||
namespace ostd
|
||||
{
|
||||
|
|
|
|||
98
src/ostd/Midi.cpp
Normal file
98
src/ostd/Midi.cpp
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
#include "Midi.hpp"
|
||||
#include <ostd/vendor/midifile/MidiFile.h>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <array>
|
||||
|
||||
|
||||
|
||||
namespace ostd
|
||||
{
|
||||
//TODO: Errors
|
||||
std::vector<MidiParser::NoteEvent> MidiParser::parseFile(const ostd::String& filePath)
|
||||
{
|
||||
smf::MidiFile midi;
|
||||
|
||||
if (!midi.read(filePath))
|
||||
throw std::runtime_error("Failed to read MIDI file: " + filePath.cpp_str());
|
||||
|
||||
// Check track count
|
||||
if (midi.getTrackCount() != 1)
|
||||
throw std::runtime_error("Expected exactly 1 track, but found " + std::to_string(midi.getTrackCount()));
|
||||
|
||||
// Prepare time analysis and note pairing
|
||||
midi.doTimeAnalysis();
|
||||
midi.linkNotePairs();
|
||||
|
||||
std::vector<NoteEvent> notes;
|
||||
notes.reserve(256);
|
||||
|
||||
for (int e = 0; e < midi[0].size(); ++e)
|
||||
{
|
||||
auto& ev = midi[0][e];
|
||||
if (ev.isNoteOn())
|
||||
{
|
||||
NoteEvent note;
|
||||
note.pitch = ev.getKeyNumber();
|
||||
note.startTime = ev.seconds;
|
||||
note.duration = ev.getDurationInSeconds();
|
||||
note.endTime = note.startTime + note.duration;
|
||||
note.velocity = ev.getVelocity();
|
||||
note.channel = ev.getChannel();
|
||||
note.rightHand = false;
|
||||
note.last = false;
|
||||
note.first = false;
|
||||
notes.push_back(note);
|
||||
}
|
||||
}
|
||||
|
||||
NoteEvent* notePtr = nullptr;
|
||||
double noteTime = 0.0;
|
||||
for (auto& note : notes)
|
||||
{
|
||||
if (note.endTime > noteTime)
|
||||
{
|
||||
notePtr = ¬e;
|
||||
noteTime = note.endTime;
|
||||
}
|
||||
}
|
||||
if (notePtr != nullptr)
|
||||
notePtr->last = true;
|
||||
|
||||
notePtr = nullptr;
|
||||
noteTime = 999999.0;
|
||||
for (auto& note : notes)
|
||||
{
|
||||
if (note.startTime < noteTime)
|
||||
{
|
||||
notePtr = ¬e;
|
||||
noteTime = note.startTime;
|
||||
}
|
||||
}
|
||||
if (notePtr != nullptr)
|
||||
notePtr->first = true;
|
||||
|
||||
return notes;
|
||||
}
|
||||
|
||||
MidiParser::NoteInfo MidiParser::getNoteInfo(int midiPitch)
|
||||
{
|
||||
static const std::array<std::string, 12> noteNames = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};
|
||||
|
||||
NoteInfo info;
|
||||
|
||||
// Calculate name and octave
|
||||
info.noteInOctave = midiPitch % 12;
|
||||
info.name = noteNames[info.noteInOctave];
|
||||
info.octave = (midiPitch / 12) - 1; // MIDI 0 = C-1
|
||||
|
||||
// Calculate 88-key index (A0 = MIDI 21, C8 = MIDI 108)
|
||||
if (midiPitch >= 21 && midiPitch <= 108)
|
||||
info.keyIndex = midiPitch - 21;
|
||||
else
|
||||
info.keyIndex = -1; // Outside standard piano range
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
84
src/ostd/Midi.hpp
Normal file
84
src/ostd/Midi.hpp
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
#pragma once
|
||||
|
||||
#include <ostd/String.hpp>
|
||||
#include <ostd/Defines.hpp>
|
||||
|
||||
namespace ostd
|
||||
{
|
||||
class MidiParser
|
||||
{
|
||||
public: class NoteEvent
|
||||
{
|
||||
public:
|
||||
int32_t pitch { 0 }; // MIDI note number (0-127)
|
||||
double startTime { 0.0 }; // Start time in seconds
|
||||
double endTime { 0.0 }; // Start time in seconds
|
||||
double duration { 0.0 }; // Duration in seconds
|
||||
int32_t velocity { 0 }; // Attack velocity (1-127)
|
||||
int32_t channel { 0 }; // MIDI channel (0-15)
|
||||
|
||||
bool hit { false };
|
||||
bool rightHand { false };
|
||||
bool last { false };
|
||||
bool first { false };
|
||||
|
||||
public:
|
||||
inline bool operator<(const NoteEvent& other) const
|
||||
{
|
||||
return startTime < other.startTime;
|
||||
}
|
||||
inline ostd::String toString(void) const
|
||||
{
|
||||
ostd::String str = "Pitch: ";
|
||||
str.add(pitch);
|
||||
str.add("\nstartTime: ").add(startTime);
|
||||
str.add("\nendTime: ").add(endTime);
|
||||
str.add("\nduration: ").add(duration);
|
||||
str.add("\nvelocity: ").add(velocity);
|
||||
str.add("\nchannel: ").add(channel);
|
||||
str.add("\nhit: ").add(STR_BOOL(hit));
|
||||
return str;
|
||||
}
|
||||
};
|
||||
public: class NoteInfo
|
||||
{
|
||||
public:
|
||||
ostd::String name { "" }; // e.g., "A", "C#", "F"
|
||||
int octave { 0 }; // e.g., 4 for C4
|
||||
int noteInOctave { 0 }; // 0-11
|
||||
int keyIndex { 0 }; // 0-based index for 88-key piano (A0=0), -1 if out of range
|
||||
|
||||
public:
|
||||
inline bool isWhiteKey(void) const
|
||||
{
|
||||
return noteInOctave == 0 || noteInOctave == 2 || noteInOctave == 4 ||
|
||||
noteInOctave == 5 || noteInOctave == 7 || noteInOctave == 9 ||
|
||||
noteInOctave == 11;
|
||||
}
|
||||
inline bool isBlackKey(void) const { return !isWhiteKey(); }
|
||||
inline ostd::String toString(void) const
|
||||
{
|
||||
ostd::String str = "NOTE INFO: ";
|
||||
str.add(name).add(octave);
|
||||
str.add(" - noteInOctave: ").add(noteInOctave);
|
||||
str.add(" - keyIndex: ").add(keyIndex);
|
||||
str.add("\n");
|
||||
return str;
|
||||
}
|
||||
|
||||
static inline bool isWhiteKey(int32_t noteInOctave)
|
||||
{
|
||||
return noteInOctave == 0 || noteInOctave == 2 || noteInOctave == 4 ||
|
||||
noteInOctave == 5 || noteInOctave == 7 || noteInOctave == 9 ||
|
||||
noteInOctave == 11;
|
||||
}
|
||||
static inline bool isBlackKey(int32_t noteInOctave) { return !NoteInfo::isWhiteKey(noteInOctave); }
|
||||
};
|
||||
|
||||
public:
|
||||
// Parses a single-track MIDI file and returns a vector of NoteEvents
|
||||
static std::vector<NoteEvent> parseFile(const ostd::String& filePath);
|
||||
// Convert MIDI pitch to NoteInfo
|
||||
static NoteInfo getNoteInfo(int midiPitch);
|
||||
};
|
||||
}
|
||||
2012
src/ostd/vendor/midifile/Binasc.cpp
vendored
Normal file
2012
src/ostd/vendor/midifile/Binasc.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
161
src/ostd/vendor/midifile/Binasc.h
vendored
Normal file
161
src/ostd/vendor/midifile/Binasc.h
vendored
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
//
|
||||
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
|
||||
// Creation Date: Mon Feb 16 12:26:32 PST 2015 Adapted from binasc program.
|
||||
// Last Modified: Sat Apr 21 10:52:19 PDT 2018 Removed using namespace std;
|
||||
// Filename: midifile/include/Binasc.h
|
||||
// Website: http://midifile.sapp.org
|
||||
// Syntax: C++11
|
||||
// vim: ts=3 noexpandtab
|
||||
//
|
||||
// description: Interface to convert bytes between binary and ASCII forms.
|
||||
//
|
||||
|
||||
#ifndef _BINASC_H_INCLUDED
|
||||
#define _BINASC_H_INCLUDED
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace smf {
|
||||
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
class Binasc {
|
||||
|
||||
public:
|
||||
Binasc (void);
|
||||
|
||||
~Binasc ();
|
||||
|
||||
// functions for setting options:
|
||||
int setLineLength (int length);
|
||||
int getLineLength (void);
|
||||
int setLineBytes (int length);
|
||||
int getLineBytes (void);
|
||||
void setComments (int state);
|
||||
void setCommentsOn (void);
|
||||
void setCommentsOff (void);
|
||||
int getComments (void);
|
||||
void setBytes (int state);
|
||||
void setBytesOn (void);
|
||||
void setBytesOff (void);
|
||||
int getBytes (void);
|
||||
void setMidi (int state);
|
||||
void setMidiOn (void);
|
||||
void setMidiOff (void);
|
||||
int getMidi (void);
|
||||
|
||||
// functions for converting into a binary file:
|
||||
int writeToBinary (const std::string& outfile,
|
||||
const std::string& infile);
|
||||
int writeToBinary (const std::string& outfile,
|
||||
std::istream& input);
|
||||
int writeToBinary (std::ostream& out,
|
||||
const std::string& infile);
|
||||
int writeToBinary (std::ostream& out,
|
||||
std::istream& input);
|
||||
|
||||
// functions for converting into an ASCII file with hex bytes:
|
||||
int readFromBinary (const std::string&
|
||||
outfile,
|
||||
const std::string& infile);
|
||||
int readFromBinary (const std::string& outfile,
|
||||
std::istream& input);
|
||||
int readFromBinary (std::ostream& out,
|
||||
const std::string& infile);
|
||||
int readFromBinary (std::ostream& out,
|
||||
std::istream& input);
|
||||
|
||||
// static functions for writing ordered bytes:
|
||||
static std::ostream& writeLittleEndianUShort (std::ostream& out,
|
||||
ushort value);
|
||||
static std::ostream& writeBigEndianUShort (std::ostream& out,
|
||||
ushort value);
|
||||
static std::ostream& writeLittleEndianShort (std::ostream& out,
|
||||
short value);
|
||||
static std::ostream& writeBigEndianShort (std::ostream& out,
|
||||
short value);
|
||||
static std::ostream& writeLittleEndianULong (std::ostream& out,
|
||||
ulong value);
|
||||
static std::ostream& writeBigEndianULong (std::ostream& out,
|
||||
ulong value);
|
||||
static std::ostream& writeLittleEndianLong (std::ostream& out,
|
||||
long value);
|
||||
static std::ostream& writeBigEndianLong (std::ostream& out,
|
||||
long value);
|
||||
static std::ostream& writeLittleEndianFloat (std::ostream& out,
|
||||
float value);
|
||||
static std::ostream& writeBigEndianFloat (std::ostream& out,
|
||||
float value);
|
||||
static std::ostream& writeLittleEndianDouble (std::ostream& out,
|
||||
double value);
|
||||
static std::ostream& writeBigEndianDouble (std::ostream& out,
|
||||
double value);
|
||||
|
||||
static std::string keyToPitchName (int key);
|
||||
|
||||
protected:
|
||||
int m_bytesQ; // option for printing hex bytes in ASCII output.
|
||||
int m_commentsQ; // option for printing comments in ASCII output.
|
||||
int m_midiQ; // output ASCII data as parsed MIDI file.
|
||||
int m_maxLineLength;// number of character in ASCII output on a line.
|
||||
int m_maxLineBytes; // number of hex bytes in ASCII output on a line.
|
||||
|
||||
private:
|
||||
// helper functions for reading ASCII content to conver to binary:
|
||||
int processLine (std::ostream& out,
|
||||
const std::string& input,
|
||||
int lineNum);
|
||||
int processAsciiWord (std::ostream& out,
|
||||
const std::string& input,
|
||||
int lineNum);
|
||||
int processStringWord (std::ostream& out,
|
||||
const std::string& input,
|
||||
int lineNum);
|
||||
int processBinaryWord (std::ostream& out,
|
||||
const std::string& input,
|
||||
int lineNum);
|
||||
int processDecimalWord (std::ostream& out,
|
||||
const std::string& input,
|
||||
int lineNum);
|
||||
int processHexWord (std::ostream& out,
|
||||
const std::string& input,
|
||||
int lineNum);
|
||||
int processVlvWord (std::ostream& out,
|
||||
const std::string& input,
|
||||
int lineNum);
|
||||
int processMidiPitchBendWord(std::ostream& out,
|
||||
const std::string& input,
|
||||
int lineNum);
|
||||
int processMidiTempoWord (std::ostream& out,
|
||||
const std::string& input,
|
||||
int lineNum);
|
||||
|
||||
// helper functions for reading binary content to convert to ASCII:
|
||||
int outputStyleAscii (std::ostream& out, std::istream& input);
|
||||
int outputStyleBinary (std::ostream& out, std::istream& input);
|
||||
int outputStyleBoth (std::ostream& out, std::istream& input);
|
||||
int outputStyleMidi (std::ostream& out, std::istream& input);
|
||||
|
||||
// MIDI parsing helper functions:
|
||||
int readMidiEvent (std::ostream& out, std::istream& infile,
|
||||
int& trackbytes, int& command);
|
||||
int getVLV (std::istream& infile, int& trackbytes);
|
||||
int getWord (std::string& word, const std::string& input,
|
||||
const std::string& terminators, int index);
|
||||
|
||||
static const char *GMinstrument[128];
|
||||
|
||||
};
|
||||
|
||||
} // end of namespace smf
|
||||
|
||||
#endif /* _BINASC_H_INCLUDED */
|
||||
|
||||
|
||||
|
||||
305
src/ostd/vendor/midifile/MidiEvent.cpp
vendored
Normal file
305
src/ostd/vendor/midifile/MidiEvent.cpp
vendored
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
//
|
||||
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
|
||||
// Creation Date: Sat Feb 14 21:40:14 PST 2015
|
||||
// Last Modified: Sat Apr 21 10:52:19 PDT 2018 Removed using namespace std;
|
||||
// Filename: midifile/src/MidiEvent.cpp
|
||||
// Website: http://midifile.sapp.org
|
||||
// Syntax: C++11
|
||||
// vim: ts=3 noexpandtab
|
||||
//
|
||||
// Description: A class which stores a MidiMessage and a timestamp
|
||||
// for the MidiFile class.
|
||||
//
|
||||
|
||||
#include "MidiEvent.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <initializer_list>
|
||||
|
||||
|
||||
namespace smf {
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEvent::MidiEvent -- Constructor classes
|
||||
//
|
||||
|
||||
MidiEvent::MidiEvent(void) : MidiMessage() {
|
||||
clearVariables();
|
||||
}
|
||||
|
||||
|
||||
MidiEvent::MidiEvent(int command) : MidiMessage(command) {
|
||||
clearVariables();
|
||||
}
|
||||
|
||||
|
||||
MidiEvent::MidiEvent(int command, int p1) : MidiMessage(command, p1) {
|
||||
clearVariables();
|
||||
}
|
||||
|
||||
|
||||
MidiEvent::MidiEvent(int command, int p1, int p2)
|
||||
: MidiMessage(command, p1, p2) {
|
||||
clearVariables();
|
||||
}
|
||||
|
||||
|
||||
MidiEvent::MidiEvent(int aTime, int aTrack, vector<uchar>& message)
|
||||
: MidiMessage(message) {
|
||||
track = aTrack;
|
||||
tick = aTime;
|
||||
seconds = 0.0;
|
||||
seq = 0;
|
||||
m_eventlink = NULL;
|
||||
}
|
||||
|
||||
|
||||
MidiEvent::MidiEvent(const MidiEvent& mfevent) : MidiMessage() {
|
||||
track = mfevent.track;
|
||||
tick = mfevent.tick;
|
||||
seconds = mfevent.seconds;
|
||||
seq = mfevent.seq;
|
||||
m_eventlink = NULL;
|
||||
|
||||
this->resize(mfevent.size());
|
||||
for (int i=0; i<(int)this->size(); i++) {
|
||||
(*this)[i] = mfevent[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEvent::~MidiEvent -- MidiFile Event destructor
|
||||
//
|
||||
|
||||
MidiEvent::~MidiEvent() {
|
||||
track = -1;
|
||||
tick = -1;
|
||||
seconds = -1.0;
|
||||
seq = -1;
|
||||
this->resize(0);
|
||||
m_eventlink = NULL;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEvent::clearVariables -- Clear everything except MidiMessage data.
|
||||
//
|
||||
|
||||
void MidiEvent::clearVariables(void) {
|
||||
track = 0;
|
||||
tick = 0;
|
||||
seconds = 0.0;
|
||||
seq = 0;
|
||||
m_eventlink = NULL;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEvent::operator= -- Copy the contents of another MidiEvent.
|
||||
//
|
||||
|
||||
MidiEvent& MidiEvent::operator=(const MidiEvent& mfevent) {
|
||||
if (this == &mfevent) {
|
||||
return *this;
|
||||
}
|
||||
tick = mfevent.tick;
|
||||
track = mfevent.track;
|
||||
seconds = mfevent.seconds;
|
||||
seq = mfevent.seq;
|
||||
m_eventlink = NULL;
|
||||
this->resize(mfevent.size());
|
||||
for (int i=0; i<(int)this->size(); i++) {
|
||||
(*this)[i] = mfevent[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
MidiEvent& MidiEvent::operator=(const MidiMessage& message) {
|
||||
if (this == &message) {
|
||||
return *this;
|
||||
}
|
||||
clearVariables();
|
||||
this->resize(message.size());
|
||||
for (int i=0; i<(int)this->size(); i++) {
|
||||
(*this)[i] = message[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
MidiEvent& MidiEvent::operator=(const vector<uchar>& bytes) {
|
||||
clearVariables();
|
||||
this->resize(bytes.size());
|
||||
for (int i=0; i<(int)this->size(); i++) {
|
||||
(*this)[i] = bytes[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
MidiEvent& MidiEvent::operator=(const vector<char>& bytes) {
|
||||
clearVariables();
|
||||
setMessage(bytes);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
MidiEvent& MidiEvent::operator=(const vector<int>& bytes) {
|
||||
clearVariables();
|
||||
setMessage(bytes);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
MidiEvent& MidiEvent::operator=(const std::initializer_list<int>& list) {
|
||||
MidiMessage::operator=(list);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEvent::unlinkEvent -- Disassociate this event with another.
|
||||
// Also tell the other event to disassociate from this event.
|
||||
//
|
||||
|
||||
void MidiEvent::unlinkEvent(void) {
|
||||
if (m_eventlink == NULL) {
|
||||
return;
|
||||
}
|
||||
MidiEvent* mev = m_eventlink;
|
||||
m_eventlink = NULL;
|
||||
mev->unlinkEvent();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEvent::linkEvent -- Make a link between two messages.
|
||||
// Unlinking
|
||||
//
|
||||
|
||||
void MidiEvent::linkEvent(MidiEvent* mev) {
|
||||
if (mev->m_eventlink != NULL) {
|
||||
// unlink other event if it is linked to something else;
|
||||
mev->unlinkEvent();
|
||||
}
|
||||
// if this is already linked to something else, then unlink:
|
||||
if (m_eventlink != NULL) {
|
||||
m_eventlink->unlinkEvent();
|
||||
}
|
||||
unlinkEvent();
|
||||
|
||||
mev->m_eventlink = this;
|
||||
m_eventlink = mev;
|
||||
}
|
||||
|
||||
|
||||
void MidiEvent::linkEvent(MidiEvent& mev) {
|
||||
linkEvent(&mev);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEvent::getLinkedEvent -- Returns a linked event. Usually
|
||||
// this is the note-off message for a note-on message and vice-versa.
|
||||
// Returns null if there are no links.
|
||||
//
|
||||
|
||||
MidiEvent* MidiEvent::getLinkedEvent(void) {
|
||||
return m_eventlink;
|
||||
}
|
||||
|
||||
|
||||
const MidiEvent* MidiEvent::getLinkedEvent(void) const {
|
||||
return m_eventlink;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEvent::isLinked -- Returns true if there is an event which is not
|
||||
// NULL. This function is similar to getLinkedEvent().
|
||||
//
|
||||
|
||||
int MidiEvent::isLinked(void) const {
|
||||
return m_eventlink == NULL ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEvent::getTickDuration -- For linked events (note-ons and note-offs),
|
||||
// return the absolute tick time difference between the two events.
|
||||
// The tick values are presumed to be in absolute tick mode rather than
|
||||
// delta tick mode. Returns 0 if not linked.
|
||||
//
|
||||
|
||||
int MidiEvent::getTickDuration(void) const {
|
||||
const MidiEvent* mev = getLinkedEvent();
|
||||
if (mev == NULL) {
|
||||
return 0;
|
||||
}
|
||||
int tick2 = mev->tick;
|
||||
if (tick2 > tick) {
|
||||
return tick2 - tick;
|
||||
} else {
|
||||
return tick - tick2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEvent::getDurationInSeconds -- For linked events (note-ons and
|
||||
// note-offs), return the duration of the note in seconds. The
|
||||
// seconds analysis must be done first; otherwise the duration will be
|
||||
// reported as zero.
|
||||
//
|
||||
|
||||
double MidiEvent::getDurationInSeconds(void) const {
|
||||
const MidiEvent* mev = getLinkedEvent();
|
||||
if (mev == NULL) {
|
||||
return 0;
|
||||
}
|
||||
double seconds2 = mev->seconds;
|
||||
if (seconds2 > seconds) {
|
||||
return seconds2 - seconds;
|
||||
} else {
|
||||
return seconds - seconds2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// operator<<(MidiMessage) -- Print tick value followed by MIDI bytes for event.
|
||||
// The tick value will be either relative or absolute depending on the state
|
||||
// of the MidiFile object containing it.
|
||||
//
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, MidiEvent& event) {
|
||||
out << event.tick << '(' << static_cast<MidiMessage&>(event) << ')';
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace smf
|
||||
|
||||
|
||||
|
||||
80
src/ostd/vendor/midifile/MidiEvent.h
vendored
Normal file
80
src/ostd/vendor/midifile/MidiEvent.h
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
//
|
||||
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
|
||||
// Creation Date: Sat Feb 14 21:47:39 PST 2015
|
||||
// Last Modified: Sat Apr 21 10:52:19 PDT 2018 Removed using namespace std;
|
||||
// Filename: midifile/include/MidiEvent.h
|
||||
// Website: http://midifile.sapp.org
|
||||
// Syntax: C++11
|
||||
// vim: ts=3 noexpandtab
|
||||
//
|
||||
// Description: A class which stores a MidiMessage and a timestamp
|
||||
// for the MidiFile class.
|
||||
//
|
||||
|
||||
#ifndef _MIDIEVENT_H_INCLUDED
|
||||
#define _MIDIEVENT_H_INCLUDED
|
||||
|
||||
#include "MidiMessage.h"
|
||||
|
||||
#include <ostream>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace smf {
|
||||
|
||||
class MidiEvent : public MidiMessage {
|
||||
public:
|
||||
MidiEvent (void);
|
||||
MidiEvent (int command);
|
||||
MidiEvent (int command, int param1);
|
||||
MidiEvent (int command, int param1, int param2);
|
||||
MidiEvent (const MidiMessage& message);
|
||||
MidiEvent (const MidiEvent& mfevent);
|
||||
MidiEvent (int aTime, int aTrack,
|
||||
std::vector<uchar>& message);
|
||||
|
||||
~MidiEvent ();
|
||||
|
||||
MidiEvent& operator= (const MidiEvent& mfevent);
|
||||
MidiEvent& operator= (const MidiMessage& message);
|
||||
MidiEvent& operator= (const std::vector<uchar>& bytes);
|
||||
MidiEvent& operator= (const std::vector<char>& bytes);
|
||||
MidiEvent& operator= (const std::vector<int>& bytes);
|
||||
MidiEvent& operator= (const std::initializer_list<int>& list);
|
||||
|
||||
void clearVariables (void);
|
||||
|
||||
// functions related to event linking (note-ons to note-offs).
|
||||
void unlinkEvent (void);
|
||||
void unlinkEvents (void);
|
||||
void linkEvent (MidiEvent* mev);
|
||||
void linkEvents (MidiEvent* mev);
|
||||
void linkEvent (MidiEvent& mev);
|
||||
void linkEvents (MidiEvent& mev);
|
||||
int isLinked (void) const;
|
||||
int hasLink (void) const { return isLinked(); }
|
||||
MidiEvent* getLinkedEvent (void);
|
||||
const MidiEvent* getLinkedEvent (void) const;
|
||||
int getTickDuration (void) const;
|
||||
double getDurationInSeconds (void) const;
|
||||
|
||||
int tick; // delta or absolute MIDI ticks
|
||||
int track; // [original] track number of event in MIDI file
|
||||
double seconds; // calculated time in sec. (after doTimeAnalysis())
|
||||
int seq; // sorting sequence number of event
|
||||
|
||||
private:
|
||||
MidiEvent* m_eventlink; // used to match note-ons and note-offs
|
||||
|
||||
};
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, MidiEvent& event);
|
||||
|
||||
|
||||
} // end of namespace smf
|
||||
|
||||
#endif /* _MIDIEVENT_H_INCLUDED */
|
||||
|
||||
|
||||
|
||||
868
src/ostd/vendor/midifile/MidiEventList.cpp
vendored
Normal file
868
src/ostd/vendor/midifile/MidiEventList.cpp
vendored
Normal file
|
|
@ -0,0 +1,868 @@
|
|||
//
|
||||
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
|
||||
// Creation Date: Sat Feb 14 21:55:38 PST 2015
|
||||
// Last Modified: Sat Apr 21 10:52:19 PDT 2018 Removed using namespace std;
|
||||
// Filename: midifile/src/MidiEventList.cpp
|
||||
// Website: http://midifile.sapp.org
|
||||
// Syntax: C++11
|
||||
// vim: ts=3 noexpandtab
|
||||
//
|
||||
// Description: A class which stores a MidiEvents for a MidiFile track.
|
||||
//
|
||||
|
||||
#include "MidiEventList.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
namespace smf {
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::MidiEventList -- Constructor.
|
||||
//
|
||||
|
||||
MidiEventList::MidiEventList(void) {
|
||||
reserve(1000);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::MidiEventList(MidiEventList&) -- Copy constructor.
|
||||
//
|
||||
|
||||
MidiEventList::MidiEventList(const MidiEventList& other) {
|
||||
list.reserve(other.list.size());
|
||||
auto it = other.list.begin();
|
||||
std::generate_n(std::back_inserter(list), other.list.size(), [&]() -> MidiEvent* {
|
||||
return new MidiEvent(**it++);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::MidiEventList(MidiEventList&&) -- Move constructor.
|
||||
//
|
||||
|
||||
MidiEventList::MidiEventList(MidiEventList&& other) {
|
||||
list = std::move(other.list);
|
||||
other.list.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::~MidiEventList -- Deconstructor. Deallocate all stored
|
||||
// data.
|
||||
//
|
||||
|
||||
MidiEventList::~MidiEventList() {
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::operator[] --
|
||||
//
|
||||
|
||||
MidiEvent& MidiEventList::operator[](int index) {
|
||||
return *list[index];
|
||||
}
|
||||
|
||||
|
||||
const MidiEvent& MidiEventList::operator[](int index) const {
|
||||
return *list[index];
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::at -- Similar to vector::at, checking validity of index.
|
||||
//
|
||||
|
||||
MidiEvent& MidiEventList::at(int index) {
|
||||
if (index < 0 || static_cast<size_t>(index) >= list.size()) {
|
||||
throw std::out_of_range("Index out of bounds: " + std::to_string(index));
|
||||
}
|
||||
return *list[index];
|
||||
}
|
||||
|
||||
|
||||
const MidiEvent& MidiEventList::at(int index) const {
|
||||
if (index < 0 || static_cast<size_t>(index) >= list.size()) {
|
||||
throw std::out_of_range("Index out of bounds: " + std::to_string(index));
|
||||
}
|
||||
return *list[index];
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::back -- Return the last element in the list.
|
||||
//
|
||||
|
||||
MidiEvent& MidiEventList::back(void) {
|
||||
return *list.back();
|
||||
}
|
||||
|
||||
|
||||
const MidiEvent& MidiEventList::back(void) const {
|
||||
return *list.back();
|
||||
}
|
||||
|
||||
//
|
||||
// MidiEventList::last -- Alias for MidiEventList::back().
|
||||
//
|
||||
|
||||
MidiEvent& MidiEventList::last(void) {
|
||||
return back();
|
||||
}
|
||||
|
||||
|
||||
const MidiEvent& MidiEventList::last(void) const {
|
||||
return back();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::getEvent -- The same thing as operator[], for
|
||||
// internal use when operator[] would look more messy.
|
||||
//
|
||||
|
||||
MidiEvent& MidiEventList::getEvent(int index) {
|
||||
return *list[index];
|
||||
}
|
||||
|
||||
|
||||
const MidiEvent& MidiEventList::getEvent(int index) const {
|
||||
return *list[index];
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::clear -- De-allocate any MidiEvents present in the list
|
||||
// and set the size of the list to 0.
|
||||
//
|
||||
|
||||
void MidiEventList::clear(void) {
|
||||
for (auto& item : list) {
|
||||
if (item != NULL) {
|
||||
delete item;
|
||||
item = NULL;
|
||||
}
|
||||
}
|
||||
list.resize(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::data -- Return the low-level array of MidiMessage
|
||||
// pointers. This is useful for applying your own sorting
|
||||
// function to the list.
|
||||
//
|
||||
|
||||
MidiEvent** MidiEventList::data(void) {
|
||||
return list.data();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::reserve -- Pre-allocate space in the list for storing
|
||||
// elements.
|
||||
//
|
||||
|
||||
void MidiEventList::reserve(int rsize) {
|
||||
if (rsize > (int)list.size()) {
|
||||
list.reserve(rsize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::getSize -- Return the number of MidiEvents stored
|
||||
// in the list.
|
||||
//
|
||||
|
||||
int MidiEventList::getSize(void) const {
|
||||
return (int)list.size();
|
||||
}
|
||||
|
||||
//
|
||||
// MidiEventList::size -- Alias for MidiEventList::getSize().
|
||||
//
|
||||
|
||||
int MidiEventList::size(void) const {
|
||||
return getSize();
|
||||
}
|
||||
|
||||
//
|
||||
// MidiEventList::getEventCount -- Alias for MidiEventList::getSize().
|
||||
//
|
||||
|
||||
int MidiEventList::getEventCount(void) const {
|
||||
return getSize();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::append -- add a MidiEvent at the end of the list. Returns
|
||||
// the index of the appended event.
|
||||
//
|
||||
|
||||
int MidiEventList::append(MidiEvent& event) {
|
||||
MidiEvent* ptr = new MidiEvent(event);
|
||||
list.push_back(ptr);
|
||||
return (int)list.size()-1;
|
||||
}
|
||||
|
||||
//
|
||||
// MidiEventList::push -- Alias for MidiEventList::append().
|
||||
//
|
||||
|
||||
int MidiEventList::push(MidiEvent& event) {
|
||||
return append(event);
|
||||
}
|
||||
|
||||
//
|
||||
// MidiEventList::push_back -- Alias for MidiEventList::append().
|
||||
//
|
||||
|
||||
int MidiEventList::push_back(MidiEvent& event) {
|
||||
return append(event);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::removeEmpties -- Remove any MIDI message which contain no
|
||||
// bytes. This function first deallocates any empty MIDI events, and then
|
||||
// removes them from the list of events.
|
||||
//
|
||||
|
||||
void MidiEventList::removeEmpties(void) {
|
||||
int count = 0;
|
||||
for (auto& item : list) {
|
||||
if (item->empty()) {
|
||||
delete item;
|
||||
item = NULL;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
std::vector<MidiEvent*> newlist;
|
||||
newlist.reserve(list.size() - count);
|
||||
for (auto& item : list) {
|
||||
if (item) {
|
||||
newlist.push_back(item);
|
||||
}
|
||||
}
|
||||
list.swap(newlist);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::linkNotePairs -- Match note-ones and note-offs together
|
||||
// There are two models that can be done if two notes are overlapping
|
||||
// on the same pitch: the first note-off affects the last note-on,
|
||||
// or the first note-off affects the first note-on. Currently the
|
||||
// first note-off affects the last note-on, but both methods could
|
||||
// be implemented with user selectability. The current state of the
|
||||
// track is assumed to be in time-sorted order. Returns the number
|
||||
// of linked notes (note-on/note-off pairs).
|
||||
//
|
||||
|
||||
int MidiEventList::linkEventPairs(void) {
|
||||
return linkNotePairsFIFO();
|
||||
}
|
||||
|
||||
|
||||
int MidiEventList::linkNotePairsFIFO(void) {
|
||||
// Note-on states:
|
||||
// dimension 1: MIDI channel (0-15)
|
||||
// dimension 2: MIDI key (0-127) (but 0 not used for note-ons)
|
||||
// dimension 3: List of active note-ons or note-offs (FIFO behavior).
|
||||
std::vector<std::vector<std::list<MidiEvent*>>> noteons;
|
||||
noteons.resize(16);
|
||||
for (auto& noteon : noteons) {
|
||||
noteon.resize(128);
|
||||
}
|
||||
|
||||
// Controller linking: The following General MIDI controller numbers are
|
||||
// also monitored for linking within the track (but not between tracks).
|
||||
// hex dec name range
|
||||
// 40 64 Hold pedal (Sustain) on/off 0..63=off 64..127=on
|
||||
// 41 65 Portamento on/off 0..63=off 64..127=on
|
||||
// 42 66 Sustenuto Pedal on/off 0..63=off 64..127=on
|
||||
// 43 67 Soft Pedal on/off 0..63=off 64..127=on
|
||||
// 44 68 Legato Pedal on/off 0..63=off 64..127=on
|
||||
// 45 69 Hold Pedal 2 on/off 0..63=off 64..127=on
|
||||
// 50 80 General Purpose Button 0..63=off 64..127=on
|
||||
// 51 81 General Purpose Button 0..63=off 64..127=on
|
||||
// 52 82 General Purpose Button 0..63=off 64..127=on
|
||||
// 53 83 General Purpose Button 0..63=off 64..127=on
|
||||
// 54 84 Undefined on/off 0..63=off 64..127=on
|
||||
// 55 85 Undefined on/off 0..63=off 64..127=on
|
||||
// 56 86 Undefined on/off 0..63=off 64..127=on
|
||||
// 57 87 Undefined on/off 0..63=off 64..127=on
|
||||
// 58 88 Undefined on/off 0..63=off 64..127=on
|
||||
// 59 89 Undefined on/off 0..63=off 64..127=on
|
||||
// 5A 90 Undefined on/off 0..63=off 64..127=on
|
||||
// 7A 122 Local Keyboard On/Off 0..63=off 64..127=on
|
||||
|
||||
// first keep track of whether the controller is an on/off switch:
|
||||
std::vector<std::pair<int, int>> contmap(128, {0, 0});
|
||||
contmap[64] = {1, 0}; contmap[65] = {1, 1}; contmap[66] = {1, 2};
|
||||
contmap[67] = {1, 3}; contmap[68] = {1, 4}; contmap[69] = {1, 5};
|
||||
contmap[80] = {1, 6}; contmap[81] = {1, 7}; contmap[82] = {1, 8};
|
||||
contmap[83] = {1, 9}; contmap[84] = {1, 10}; contmap[85] = {1, 11};
|
||||
contmap[86] = {1, 12}; contmap[87] = {1, 13}; contmap[88] = {1, 14};
|
||||
contmap[89] = {1, 15}; contmap[90] = {1, 16}; contmap[122] = {1, 17};
|
||||
|
||||
std::vector<std::vector<MidiEvent*>> contevents(18, std::vector<MidiEvent*>(16, nullptr));
|
||||
std::vector<std::vector<int>> oldstates(18, std::vector<int>(16, -1));
|
||||
|
||||
int counter = 0;
|
||||
for (int i = 0; i < getSize(); i++) {
|
||||
MidiEvent* mev = &getEvent(i);
|
||||
mev->unlinkEvent();
|
||||
|
||||
if (mev->isNoteOn()) {
|
||||
int key = mev->getKeyNumber();
|
||||
int channel = mev->getChannel();
|
||||
noteons[channel][key].push_back(mev); // Enqueue (FIFO)
|
||||
} else if (mev->isNoteOff()) {
|
||||
int key = mev->getKeyNumber();
|
||||
int channel = mev->getChannel();
|
||||
if (!noteons[channel][key].empty()) { // **Check before accessing**
|
||||
MidiEvent* noteon = noteons[channel][key].front(); // Safely access first event
|
||||
noteons[channel][key].pop_front(); // Remove first event (FIFO)
|
||||
noteon->linkEvent(mev);
|
||||
counter++;
|
||||
}
|
||||
} else if (mev->isController()) {
|
||||
int contnum = mev->getP1();
|
||||
if (contmap[contnum].first) {
|
||||
int conti = contmap[contnum].second;
|
||||
int channel = mev->getChannel();
|
||||
int contval = mev->getP2();
|
||||
int contstate = contval < 64 ? 0 : 1;
|
||||
|
||||
if ((oldstates[conti][channel] == -1) && contstate) {
|
||||
contevents[conti][channel] = mev;
|
||||
oldstates[conti][channel] = contstate;
|
||||
} else if (oldstates[conti][channel] == contstate) {
|
||||
// Redundant controller state, ignore.
|
||||
} else if ((oldstates[conti][channel] == 0) && contstate) {
|
||||
contevents[conti][channel] = mev;
|
||||
oldstates[conti][channel] = contstate;
|
||||
} else if ((oldstates[conti][channel] == 1) && (contstate == 0)) {
|
||||
contevents[conti][channel]->linkEvent(mev);
|
||||
oldstates[conti][channel] = contstate;
|
||||
contevents[conti][channel] = mev;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int MidiEventList::linkNotePairsLIFO(void) {
|
||||
|
||||
// Note-on states:
|
||||
// dimension 1: MIDI channel (0-15)
|
||||
// dimension 2: MIDI key (0-127) (but 0 not used for note-ons)
|
||||
// dimension 3: List of active note-ons or note-offs.
|
||||
std::vector<std::vector<std::vector<MidiEvent*>>> noteons;
|
||||
noteons.resize(16);
|
||||
for (auto& noteon : noteons) {
|
||||
noteon.resize(128);
|
||||
}
|
||||
|
||||
// Controller linking: The following General MIDI controller numbers are
|
||||
// also monitored for linking within the track (but not between tracks).
|
||||
// hex dec name range
|
||||
// 40 64 Hold pedal (Sustain) on/off 0..63=off 64..127=on
|
||||
// 41 65 Portamento on/off 0..63=off 64..127=on
|
||||
// 42 66 Sustenuto Pedal on/off 0..63=off 64..127=on
|
||||
// 43 67 Soft Pedal on/off 0..63=off 64..127=on
|
||||
// 44 68 Legato Pedal on/off 0..63=off 64..127=on
|
||||
// 45 69 Hold Pedal 2 on/off 0..63=off 64..127=on
|
||||
// 50 80 General Purpose Button 0..63=off 64..127=on
|
||||
// 51 81 General Purpose Button 0..63=off 64..127=on
|
||||
// 52 82 General Purpose Button 0..63=off 64..127=on
|
||||
// 53 83 General Purpose Button 0..63=off 64..127=on
|
||||
// 54 84 Undefined on/off 0..63=off 64..127=on
|
||||
// 55 85 Undefined on/off 0..63=off 64..127=on
|
||||
// 56 86 Undefined on/off 0..63=off 64..127=on
|
||||
// 57 87 Undefined on/off 0..63=off 64..127=on
|
||||
// 58 88 Undefined on/off 0..63=off 64..127=on
|
||||
// 59 89 Undefined on/off 0..63=off 64..127=on
|
||||
// 5A 90 Undefined on/off 0..63=off 64..127=on
|
||||
// 7A 122 Local Keyboard On/Off 0..63=off 64..127=on
|
||||
|
||||
// first keep track of whether the controller is an on/off switch:
|
||||
std::vector<std::pair<int, int>> contmap;
|
||||
contmap.resize(128);
|
||||
std::pair<int, int> zero(0, 0);
|
||||
std::fill(contmap.begin(), contmap.end(), zero);
|
||||
contmap[64].first = 1; contmap[64].second = 0;
|
||||
contmap[65].first = 1; contmap[65].second = 1;
|
||||
contmap[66].first = 1; contmap[66].second = 2;
|
||||
contmap[67].first = 1; contmap[67].second = 3;
|
||||
contmap[68].first = 1; contmap[68].second = 4;
|
||||
contmap[69].first = 1; contmap[69].second = 5;
|
||||
contmap[80].first = 1; contmap[80].second = 6;
|
||||
contmap[81].first = 1; contmap[81].second = 7;
|
||||
contmap[82].first = 1; contmap[82].second = 8;
|
||||
contmap[83].first = 1; contmap[83].second = 9;
|
||||
contmap[84].first = 1; contmap[84].second = 10;
|
||||
contmap[85].first = 1; contmap[85].second = 11;
|
||||
contmap[86].first = 1; contmap[86].second = 12;
|
||||
contmap[87].first = 1; contmap[87].second = 13;
|
||||
contmap[88].first = 1; contmap[88].second = 14;
|
||||
contmap[89].first = 1; contmap[89].second = 15;
|
||||
contmap[90].first = 1; contmap[90].second = 16;
|
||||
contmap[122].first = 1; contmap[122].second = 17;
|
||||
|
||||
// dimensions:
|
||||
// 1: mapped controller (0 to 17)
|
||||
// 2: channel (0 to 15)
|
||||
std::vector<std::vector<MidiEvent*>> contevents;
|
||||
contevents.resize(18);
|
||||
std::vector<std::vector<int>> oldstates;
|
||||
oldstates.resize(18);
|
||||
for (int i=0; i<18; i++) {
|
||||
contevents[i].resize(16);
|
||||
std::fill(contevents[i].begin(), contevents[i].end(), nullptr);
|
||||
oldstates[i].resize(16);
|
||||
std::fill(oldstates[i].begin(), oldstates[i].end(), -1);
|
||||
}
|
||||
|
||||
// Now iterate through the MidiEventList keeping track of note and
|
||||
// select controller states and linking notes/controllers as needed.
|
||||
int channel;
|
||||
int key;
|
||||
int contnum;
|
||||
int contval;
|
||||
int conti;
|
||||
int contstate;
|
||||
int counter = 0;
|
||||
MidiEvent* mev;
|
||||
MidiEvent* noteon;
|
||||
for (int i=0; i<getSize(); i++) {
|
||||
mev = &getEvent(i);
|
||||
mev->unlinkEvent();
|
||||
if (mev->isNoteOn()) {
|
||||
// store the note-on to pair later with a note-off message.
|
||||
key = mev->getKeyNumber();
|
||||
channel = mev->getChannel();
|
||||
noteons[channel][key].push_back(mev);
|
||||
} else if (mev->isNoteOff()) {
|
||||
key = mev->getKeyNumber();
|
||||
channel = mev->getChannel();
|
||||
if (noteons[channel][key].size() > 0) {
|
||||
noteon = noteons[channel][key].back();
|
||||
noteons[channel][key].pop_back();
|
||||
noteon->linkEvent(mev);
|
||||
counter++;
|
||||
}
|
||||
} else if (mev->isController()) {
|
||||
contnum = mev->getP1();
|
||||
if (contmap[contnum].first) {
|
||||
conti = contmap[contnum].second;
|
||||
channel = mev->getChannel();
|
||||
contval = mev->getP2();
|
||||
contstate = contval < 64 ? 0 : 1;
|
||||
if ((oldstates[conti][channel] == -1) && contstate) {
|
||||
// a newly initialized onstate was detected, so store for
|
||||
// later linking to an off state.
|
||||
contevents[conti][channel] = mev;
|
||||
oldstates[conti][channel] = contstate;
|
||||
} else if (oldstates[conti][channel] == contstate) {
|
||||
// the controller state is redundant and will be ignored.
|
||||
} else if ((oldstates[conti][channel] == 0) && contstate) {
|
||||
// controller is currently off, so store on-state for next link
|
||||
contevents[conti][channel] = mev;
|
||||
oldstates[conti][channel] = contstate;
|
||||
} else if ((oldstates[conti][channel] == 1) && (contstate == 0)) {
|
||||
// controller has just been turned off, so link to
|
||||
// stored on-message.
|
||||
contevents[conti][channel]->linkEvent(mev);
|
||||
oldstates[conti][channel] = contstate;
|
||||
// not necessary, but maybe use for something later:
|
||||
contevents[conti][channel] = mev;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::clearLinks -- remove all note-on/note-off links.
|
||||
//
|
||||
|
||||
void MidiEventList::clearLinks(void) {
|
||||
for (int i=0; i<(int)getSize(); i++) {
|
||||
getEvent(i).unlinkEvent();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::clearSequence -- Remove any sequence serial numbers from
|
||||
// MidiEvents in the list. This will cause the default ordering by
|
||||
// sortTracks() to be used, in which case the ordering of MidiEvents
|
||||
// occurring at the same tick may switch their ordering.
|
||||
//
|
||||
|
||||
void MidiEventList::clearSequence(void) {
|
||||
for (int i=0; i<getEventCount(); i++) {
|
||||
getEvent(i).seq = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::markSequence -- Assign a sequence serial number to
|
||||
// every MidiEvent in the event list. This is useful if you want
|
||||
// to preseve the order of MIDI messages in a track when they occur
|
||||
// at the same tick time. Particularly for use with joinTracks()
|
||||
// or sortTracks(). markSequence will be done automatically when
|
||||
// a MIDI file is read, in case the ordering of events occurring at
|
||||
// the same time is important. Use clearSequence() to use the
|
||||
// default sorting behavior of sortTracks() when events occur at the
|
||||
// same time. Returns the next serial number that has not yet been
|
||||
// used.
|
||||
// default value: sequence = 1.
|
||||
//
|
||||
|
||||
int MidiEventList::markSequence(int sequence) {
|
||||
for (int i=0; i<getEventCount(); i++) {
|
||||
getEvent(i).seq = sequence++;
|
||||
}
|
||||
return sequence;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// protected functions --
|
||||
//
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::detach -- De-allocate any MidiEvents present in the list
|
||||
// and set the size of the list to 0.
|
||||
//
|
||||
|
||||
|
||||
void MidiEventList::detach(void) {
|
||||
list.resize(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::push_back_no_copy -- add a MidiEvent at the end of
|
||||
// the list. The event is not copied, but memory from the
|
||||
// remote location is used. Returns the index of the appended event.
|
||||
//
|
||||
|
||||
int MidiEventList::push_back_no_copy(MidiEvent* event) {
|
||||
list.push_back(event);
|
||||
return (int)list.size()-1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::operator=(MidiEventList) -- Assignment.
|
||||
//
|
||||
|
||||
MidiEventList& MidiEventList::operator=(MidiEventList& other) {
|
||||
list.swap(other.list);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// private functions
|
||||
//
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::sort -- Private because the MidiFile class keeps
|
||||
// track of delta versus absolute tick states of the MidiEventList,
|
||||
// and sorting is only allowed in absolute tick state (The MidiEventList
|
||||
// does not know about delta/absolute tick states of its contents).
|
||||
//
|
||||
|
||||
void MidiEventList::sortNoteOnsBeforeOffs(void) {
|
||||
qsort(data(), getEventCount(), sizeof(MidiEvent*), MidiEventList::eventCompareNoteOnsBeforeOffs);
|
||||
}
|
||||
|
||||
void MidiEventList::sortNoteOffsBeforeOns(void) {
|
||||
qsort(data(), getEventCount(), sizeof(MidiEvent*), MidiEventList::eventCompareNoteOnsBeforeOffs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// external functions
|
||||
//
|
||||
|
||||
//////////////////////////////
|
||||
//
|
||||
// MidiEventList::eventCompare -- Event comparison function for sorting tracks.
|
||||
//
|
||||
// Sorting rules:
|
||||
// (1) sort by (absolute) tick value; otherwise, if tick values are the same:
|
||||
// (2) end-of-track meta message is always last.
|
||||
// (3) other meta-messages come before regular MIDI messages.
|
||||
// (4) note-offs come after all other regular MIDI messages except note-ons.
|
||||
// (5) note-ons come after all other regular MIDI messages.
|
||||
//
|
||||
// Note: If you load a MIDI file from a file, MidiMessage.seq numbers
|
||||
// will automatically be added, and sorting will follow the sequence
|
||||
// numbers. Use MidiFile::clearSequence() if you want to sort the
|
||||
// MIDI events (occuring at the same time) using the rest of the sorting
|
||||
// algorithm (such as to place note-offs before note-ons when they
|
||||
// occur at the same time).
|
||||
//
|
||||
|
||||
int MidiEventList::eventCompareNoteOnsBeforeOffs(const void* a, const void* b) {
|
||||
MidiEvent& aevent = **((MidiEvent**)a);
|
||||
MidiEvent& bevent = **((MidiEvent**)b);
|
||||
|
||||
if (aevent.tick < bevent.tick) {
|
||||
// aevent occurs before bevent
|
||||
return -1;
|
||||
} else if (aevent.tick > bevent.tick) {
|
||||
// aevent occurs after bevent
|
||||
return +1;
|
||||
} else if ((aevent.seq != 0) && (bevent.seq != 0) && (aevent.seq < bevent.seq)) {
|
||||
// aevent sequencing state occurs before bevent
|
||||
// see MidiEventList::markSequence()
|
||||
return -1;
|
||||
} else if ((aevent.seq != 0) && (bevent.seq != 0) && (aevent.seq > bevent.seq)) {
|
||||
// aevent sequencing state occurs after bevent
|
||||
// see MidiEventList::markSequence()
|
||||
return +1;
|
||||
} else if ((aevent.getP0() == 0xff) && (aevent.getP1() == 0x2f)) {
|
||||
// end-of-track meta-message should always be last (but this won't really
|
||||
// matter since the writing function ignores all end-of-track messages
|
||||
// and writes its own.
|
||||
return +1;
|
||||
} else if ((bevent.getP0() == 0xff) && (bevent.getP1() == 0x2f)) {
|
||||
// end-of-track meta-message should always be last (but won't really
|
||||
// matter since the writing function ignores all end-of-track messages
|
||||
// and writes its own.
|
||||
return -1;
|
||||
} else if (aevent.getP0() == 0xff && bevent.getP0() != 0xff) {
|
||||
// other meta-messages are placed before real MIDI messages
|
||||
return -1;
|
||||
} else if ((aevent.getP0() != 0xff) && (bevent.getP0() == 0xff)) {
|
||||
// other meta-messages are placed before real MIDI messages
|
||||
return +1;
|
||||
} else if ((aevent.getP0() == 0xff) && (bevent.getP0() == 0xff)) {
|
||||
// could sort by meta-message number here
|
||||
return 0;
|
||||
} else if (aevent.isNote() && !bevent.isNote()) {
|
||||
// notes come after all other message types
|
||||
return +1;
|
||||
} else if (!aevent.isNote() && bevent.isNote()) {
|
||||
// notes come after all other message types
|
||||
return -1;
|
||||
} else if (aevent.isNoteOff() && bevent.isNoteOn()) {
|
||||
// note-offs come after note-ons
|
||||
return +1;
|
||||
} else if (aevent.isNoteOn() && bevent.isNoteOff()) {
|
||||
// note-ons come before all other types of MIDI messages
|
||||
return -1;
|
||||
} else if (aevent.isNoteOn() && bevent.isNoteOn()) {
|
||||
// sorted further by key number
|
||||
if (aevent.getP1() < bevent.getP1()) {
|
||||
return -1;
|
||||
} else if (aevent.getP1() > bevent.getP1()) {
|
||||
return +1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
} else if (aevent.isNoteOff() && bevent.isNoteOff()) {
|
||||
// sorted further by key number
|
||||
if (aevent.getP1() < bevent.getP1()) {
|
||||
return -1;
|
||||
} else if (aevent.getP1() > bevent.getP1()) {
|
||||
return +1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
// could be sorted further by key number.
|
||||
return 0;
|
||||
} else if (((aevent.getP0() & 0xf0) == 0xb0) && ((bevent.getP0() & 0xf0) == 0xb0)) {
|
||||
// both events are continuous controllers. Sort them by controller number and value if equal
|
||||
if (aevent.getP1() > bevent.getP1()) {
|
||||
return +1;
|
||||
} if (aevent.getP1() < bevent.getP1()) {
|
||||
return -1;
|
||||
} else {
|
||||
// same controller number, so sort by data value
|
||||
// useful for sustain pedalling, for example.
|
||||
if (aevent.getP2() > bevent.getP2()) {
|
||||
return +1;
|
||||
} if (aevent.getP2() < bevent.getP2()) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int MidiEventList::eventCompareNoteOffsBeforeOns(const void* a, const void* b) {
|
||||
MidiEvent& aevent = **((MidiEvent**)a);
|
||||
MidiEvent& bevent = **((MidiEvent**)b);
|
||||
|
||||
if (aevent.tick < bevent.tick) {
|
||||
// aevent occurs before bevent
|
||||
return -1;
|
||||
} else if (aevent.tick > bevent.tick) {
|
||||
// aevent occurs after bevent
|
||||
return +1;
|
||||
} else if ((aevent.seq != 0) && (bevent.seq != 0) && (aevent.seq < bevent.seq)) {
|
||||
// aevent sequencing state occurs before bevent
|
||||
// see MidiEventList::markSequence()
|
||||
return -1;
|
||||
} else if ((aevent.seq != 0) && (bevent.seq != 0) && (aevent.seq > bevent.seq)) {
|
||||
// aevent sequencing state occurs after bevent
|
||||
// see MidiEventList::markSequence()
|
||||
return +1;
|
||||
} else if ((aevent.getP0() == 0xff) && (aevent.getP1() == 0x2f)) {
|
||||
// end-of-track meta-message should always be last (but this won't really
|
||||
// matter since the writing function ignores all end-of-track messages
|
||||
// and writes its own.
|
||||
return +1;
|
||||
} else if ((bevent.getP0() == 0xff) && (bevent.getP1() == 0x2f)) {
|
||||
// end-of-track meta-message should always be last (but won't really
|
||||
// matter since the writing function ignores all end-of-track messages
|
||||
// and writes its own.
|
||||
return -1;
|
||||
} else if (aevent.getP0() == 0xff && bevent.getP0() != 0xff) {
|
||||
// other meta-messages are placed before real MIDI messages
|
||||
return -1;
|
||||
} else if ((aevent.getP0() != 0xff) && (bevent.getP0() == 0xff)) {
|
||||
// other meta-messages are placed before real MIDI messages
|
||||
return +1;
|
||||
} else if ((aevent.getP0() == 0xff) && (bevent.getP0() == 0xff)) {
|
||||
// could sort by meta-message number here
|
||||
return 0;
|
||||
} else if (aevent.isNote() && !bevent.isNote()) {
|
||||
// notes come after all other message types
|
||||
return +1;
|
||||
} else if (!aevent.isNote() && bevent.isNote()) {
|
||||
// notes come after all other message types
|
||||
return -1;
|
||||
} else if (aevent.isNoteOff() && bevent.isNoteOn()) {
|
||||
// note-offs come before note-ons
|
||||
return -1;
|
||||
} else if (aevent.isNoteOn() && bevent.isNoteOff()) {
|
||||
// note-ons come after all other types of MIDI messages
|
||||
return +1;
|
||||
} else if (aevent.isNoteOn() && bevent.isNoteOn()) {
|
||||
// sorted further by key number
|
||||
if (aevent.getP1() < bevent.getP1()) {
|
||||
return -1;
|
||||
} else if (aevent.getP1() > bevent.getP1()) {
|
||||
return +1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
} else if (aevent.isNoteOff() && bevent.isNoteOff()) {
|
||||
// sorted further by key number
|
||||
if (aevent.getP1() < bevent.getP1()) {
|
||||
return -1;
|
||||
} else if (aevent.getP1() > bevent.getP1()) {
|
||||
return +1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
// could be sorted further by key number.
|
||||
return 0;
|
||||
} else if (((aevent.getP0() & 0xf0) == 0xb0) && ((bevent.getP0() & 0xf0) == 0xb0)) {
|
||||
// both events are continuous controllers. Sort them by controller number and value if equal
|
||||
if (aevent.getP1() > bevent.getP1()) {
|
||||
return +1;
|
||||
} if (aevent.getP1() < bevent.getP1()) {
|
||||
return -1;
|
||||
} else {
|
||||
// same controller number, so sort by data value
|
||||
// useful for sustain pedalling, for example.
|
||||
if (aevent.getP2() > bevent.getP2()) {
|
||||
return +1;
|
||||
} if (aevent.getP2() < bevent.getP2()) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // end namespace smf
|
||||
|
||||
|
||||
|
||||
90
src/ostd/vendor/midifile/MidiEventList.h
vendored
Normal file
90
src/ostd/vendor/midifile/MidiEventList.h
vendored
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
//
|
||||
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
|
||||
// Creation Date: Sat Feb 14 21:55:38 PST 2015
|
||||
// Last Modified: Sat Apr 21 10:52:19 PDT 2018 Removed using namespace std;
|
||||
// Filename: midifile/include/MidiEventList.h
|
||||
// Website: http://midifile.sapp.org
|
||||
// Syntax: C++11
|
||||
// vim: ts=3 noexpandtab
|
||||
//
|
||||
// Description: A class that stores a MidiEvents for a MidiFile track.
|
||||
//
|
||||
|
||||
#ifndef _MIDIEVENTLIST_H_INCLUDED
|
||||
#define _MIDIEVENTLIST_H_INCLUDED
|
||||
|
||||
#include "MidiEvent.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace smf {
|
||||
|
||||
class MidiEventList {
|
||||
public:
|
||||
MidiEventList (void);
|
||||
MidiEventList (const MidiEventList& other);
|
||||
MidiEventList (MidiEventList&& other);
|
||||
|
||||
~MidiEventList ();
|
||||
|
||||
MidiEventList& operator= (MidiEventList& other);
|
||||
MidiEvent& operator[] (int index);
|
||||
const MidiEvent& operator[] (int index) const;
|
||||
MidiEvent& at (int index);
|
||||
const MidiEvent& at (int index) const;
|
||||
|
||||
MidiEvent& back (void);
|
||||
const MidiEvent& back (void) const;
|
||||
MidiEvent& last (void);
|
||||
const MidiEvent& last (void) const;
|
||||
MidiEvent& getEvent (int index);
|
||||
const MidiEvent& getEvent (int index) const;
|
||||
void clear (void);
|
||||
void reserve (int rsize);
|
||||
int getEventCount (void) const;
|
||||
int getSize (void) const;
|
||||
int size (void) const;
|
||||
void removeEmpties (void);
|
||||
int linkNotePairsFIFO (void);
|
||||
int linkNotePairsLIFO (void);
|
||||
int linkNotePairs (void) { return linkNotePairsFIFO(); }
|
||||
int linkEventPairs (void);
|
||||
void clearLinks (void);
|
||||
void clearSequence (void);
|
||||
int markSequence (int sequence = 1);
|
||||
|
||||
int push (MidiEvent& event);
|
||||
int push_back (MidiEvent& event);
|
||||
int append (MidiEvent& event);
|
||||
|
||||
// careful when using these, intended for internal use in MidiFile class:
|
||||
void detach (void);
|
||||
int push_back_no_copy (MidiEvent* event);
|
||||
|
||||
// access to the list of MidiEvents for sorting with an external function:
|
||||
MidiEvent** data (void);
|
||||
|
||||
protected:
|
||||
std::vector<MidiEvent*> list;
|
||||
|
||||
private:
|
||||
void sort (void) { return sortNoteOnsBeforeOffs(); }
|
||||
void sortNoteOnsBeforeOffs (void);
|
||||
void sortNoteOffsBeforeOns (void);
|
||||
|
||||
// MidiFile class calls sort()
|
||||
friend class MidiFile;
|
||||
|
||||
static int eventCompareNoteOffsBeforeOns(const void* a, const void* b);
|
||||
static int eventCompareNoteOnsBeforeOffs(const void* a, const void* b);
|
||||
static int eventCompare(const void* a, const void* b) { return eventCompareNoteOnsBeforeOffs(a, b); }
|
||||
};
|
||||
|
||||
|
||||
} // end of namespace smf
|
||||
|
||||
#endif /* _MIDIEVENTLIST_H_INCLUDED */
|
||||
|
||||
|
||||
|
||||
3507
src/ostd/vendor/midifile/MidiFile.cpp
vendored
Normal file
3507
src/ostd/vendor/midifile/MidiFile.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
340
src/ostd/vendor/midifile/MidiFile.h
vendored
Normal file
340
src/ostd/vendor/midifile/MidiFile.h
vendored
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
//
|
||||
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
|
||||
// Creation Date: Fri Nov 26 14:12:01 PST 1999
|
||||
// Last Modified: Mon Jan 18 20:54:04 PST 2021 Added readSmf().
|
||||
// Filename: midifile/include/MidiFile.h
|
||||
// Website: http://midifile.sapp.org
|
||||
// Syntax: C++11
|
||||
// vim: ts=3 noexpandtab
|
||||
//
|
||||
// Description: A class that can read/write Standard MIDI files.
|
||||
// MIDI data is stored by track in an array.
|
||||
//
|
||||
|
||||
#ifndef _MIDIFILE_H_INCLUDED
|
||||
#define _MIDIFILE_H_INCLUDED
|
||||
|
||||
#include "MidiEventList.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <istream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace smf {
|
||||
|
||||
enum {
|
||||
TRACK_STATE_SPLIT = 0, // Tracks are separated into separate vector postions.
|
||||
TRACK_STATE_JOINED = 1 // Tracks are merged into a single vector position,
|
||||
}; // like a Type-0 MIDI file, but reversible.
|
||||
|
||||
enum {
|
||||
TIME_STATE_DELTA = 0, // MidiMessage::ticks are in delta time format (like MIDI file).
|
||||
TIME_STATE_ABSOLUTE = 1 // MidiMessage::ticks are in absolute time format (0=start time).
|
||||
};
|
||||
|
||||
class _TickTime {
|
||||
public:
|
||||
int tick;
|
||||
double seconds;
|
||||
};
|
||||
|
||||
|
||||
class MidiFile {
|
||||
public:
|
||||
MidiFile (void);
|
||||
MidiFile (const std::string& filename);
|
||||
MidiFile (std::istream& input);
|
||||
MidiFile (const MidiFile& other);
|
||||
MidiFile (MidiFile&& other);
|
||||
|
||||
~MidiFile ();
|
||||
|
||||
MidiFile& operator= (const MidiFile& other);
|
||||
MidiFile& operator= (MidiFile&& other);
|
||||
|
||||
// Reading/writing functions:
|
||||
|
||||
// Auto-detected SMF or ASCII-encoded SMF (decoded with Binasc class):
|
||||
bool read (const std::string& filename);
|
||||
bool read (std::istream& instream);
|
||||
bool readBase64 (const std::string& base64data);
|
||||
bool readBase64 (std::istream& instream);
|
||||
|
||||
// Only allow Standard MIDI File input:
|
||||
bool readSmf (const std::string& filename);
|
||||
bool readSmf (std::istream& instream);
|
||||
|
||||
bool write (const std::string& filename);
|
||||
bool write (std::ostream& out);
|
||||
bool writeBase64 (const std::string& out, int width = 0);
|
||||
bool writeBase64 (std::ostream& out, int width = 0);
|
||||
std::string getBase64 (int width = 0);
|
||||
bool writeHex (const std::string& filename, int width = 25);
|
||||
bool writeHex (std::ostream& out, int width = 25);
|
||||
bool writeBinasc (const std::string& filename);
|
||||
bool writeBinasc (std::ostream& out);
|
||||
bool writeBinascWithComments (const std::string& filename);
|
||||
bool writeBinascWithComments (std::ostream& out);
|
||||
bool status (void) const;
|
||||
|
||||
// track-related functions:
|
||||
const MidiEventList& operator[] (int aTrack) const;
|
||||
MidiEventList& operator[] (int aTrack);
|
||||
int getTrackCount (void) const;
|
||||
int getNumTracks (void) const;
|
||||
int size (void) const;
|
||||
void removeEmpties (void);
|
||||
|
||||
// tick-related functions:
|
||||
void makeDeltaTicks (void);
|
||||
void setDeltaTicks (void) { makeDeltaTicks(); }
|
||||
void deltaTicks (void);
|
||||
void makeAbsoluteTicks (void);
|
||||
void setAbsoluteTicks (void) { makeAbsoluteTicks(); }
|
||||
void absoluteTicks (void);
|
||||
int getTickState (void) const;
|
||||
bool isDeltaTicks (void) const;
|
||||
bool isAbsoluteTicks (void) const;
|
||||
|
||||
// join/split track functionality:
|
||||
void joinTracks (void);
|
||||
void splitTracks (void);
|
||||
void splitTracksByChannel (void);
|
||||
int getTrackState (void) const;
|
||||
int hasJoinedTracks (void) const;
|
||||
int hasSplitTracks (void) const;
|
||||
int getSplitTrack (int track, int index) const;
|
||||
int getSplitTrack (int index) const;
|
||||
|
||||
// track sorting funcionality:
|
||||
void sortTrack (int track) { sortTrackNoteOnsBeforeOffs(track); }
|
||||
void sortTrackNoteOnsBeforeOffs (int track);
|
||||
void sortTrackNoteOffsBeforeOns (int track);
|
||||
void sortTracks (void) { sortTracksNoteOnsBeforeOffs(); }
|
||||
void sortTracksNoteOnsBeforeOffs(void);
|
||||
void sortTracksNoteOffsBeforeOns(void);
|
||||
void markSequence (void);
|
||||
void markSequence (int track, int sequence = 1);
|
||||
void clearSequence (void);
|
||||
void clearSequence (int track);
|
||||
|
||||
// track manipulation functionality:
|
||||
int addTrack (void);
|
||||
int addTrack (int count);
|
||||
int addTracks (int count);
|
||||
void deleteTrack (int aTrack);
|
||||
void mergeTracks (int aTrack1, int aTrack2);
|
||||
int getTrackCountAsType1 (void);
|
||||
|
||||
// ticks-per-quarter related functions:
|
||||
void setMillisecondTicks (void);
|
||||
int getTicksPerQuarterNote (void) const;
|
||||
int getTPQ (void) const;
|
||||
void setTicksPerQuarterNote (int ticks);
|
||||
void setTPQ (int ticks);
|
||||
|
||||
// physical-time analysis functions:
|
||||
void doTimeAnalysis (void);
|
||||
double getTimeInSeconds (int aTrack, int anIndex);
|
||||
double getTimeInSeconds (int tickvalue);
|
||||
double getAbsoluteTickTime (double starttime);
|
||||
int getFileDurationInTicks (void);
|
||||
double getFileDurationInQuarters (void);
|
||||
double getFileDurationInSeconds (void);
|
||||
|
||||
// note-analysis functions:
|
||||
int linkNotePairsFIFO (void);
|
||||
int linkNotePairsLIFO (void);
|
||||
int linkNotePairs (void) { return linkNotePairsFIFO(); }
|
||||
int linkEventPairs (void);
|
||||
void clearLinks (void);
|
||||
|
||||
// filename functions:
|
||||
void setFilename (const std::string& aname);
|
||||
const char* getFilename (void) const;
|
||||
|
||||
// event functionality:
|
||||
MidiEvent* addEvent (int aTrack, int aTick,
|
||||
std::vector<uchar>& midiData);
|
||||
MidiEvent* addEvent (MidiEvent& mfevent);
|
||||
MidiEvent* addEvent (int aTrack, MidiEvent& mfevent);
|
||||
MidiEvent& getEvent (int aTrack, int anIndex);
|
||||
const MidiEvent& getEvent (int aTrack, int anIndex) const;
|
||||
int getEventCount (int aTrack) const;
|
||||
int getNumEvents (int aTrack) const;
|
||||
void allocateEvents (int track, int aSize);
|
||||
void erase (void);
|
||||
void clear (void);
|
||||
void clear_no_deallocate (void);
|
||||
|
||||
// MIDI message adding convenience functions:
|
||||
MidiEvent* addNoteOn (int aTrack, int aTick,
|
||||
int aChannel, int key,
|
||||
int vel);
|
||||
MidiEvent* addNoteOff (int aTrack, int aTick,
|
||||
int aChannel, int key,
|
||||
int vel);
|
||||
MidiEvent* addNoteOff (int aTrack, int aTick,
|
||||
int aChannel, int key);
|
||||
MidiEvent* addController (int aTrack, int aTick,
|
||||
int aChannel, int num,
|
||||
int value);
|
||||
MidiEvent* addPatchChange (int aTrack, int aTick,
|
||||
int aChannel, int patchnum);
|
||||
MidiEvent* addTimbre (int aTrack, int aTick,
|
||||
int aChannel, int patchnum);
|
||||
MidiEvent* addPitchBend (int aTrack, int aTick,
|
||||
int aChannel, double amount);
|
||||
|
||||
// RPN settings:
|
||||
void setPitchBendRange (int aTrack, int aTick,
|
||||
int aChannel, double range);
|
||||
|
||||
// Controller message adding convenience functions:
|
||||
MidiEvent* addSustain (int aTrack, int aTick,
|
||||
int aChannel, int value);
|
||||
MidiEvent* addSustainPedal (int aTrack, int aTick,
|
||||
int aChannel, int value);
|
||||
MidiEvent* addSustainOn (int aTrack, int aTick,
|
||||
int aChannel);
|
||||
MidiEvent* addSustainPedalOn (int aTrack, int aTick,
|
||||
int aChannel);
|
||||
MidiEvent* addSustainOff (int aTrack, int aTick,
|
||||
int aChannel);
|
||||
MidiEvent* addSustainPedalOff (int aTrack, int aTick,
|
||||
int aChannel);
|
||||
|
||||
// Meta-event adding convenience functions:
|
||||
MidiEvent* addMetaEvent (int aTrack, int aTick,
|
||||
int aType,
|
||||
std::vector<uchar>& metaData);
|
||||
MidiEvent* addMetaEvent (int aTrack, int aTick,
|
||||
int aType,
|
||||
const std::string& metaData);
|
||||
MidiEvent* addText (int aTrack, int aTick,
|
||||
const std::string& text);
|
||||
MidiEvent* addCopyright (int aTrack, int aTick,
|
||||
const std::string& text);
|
||||
MidiEvent* addTrackName (int aTrack, int aTick,
|
||||
const std::string& name);
|
||||
MidiEvent* addInstrumentName (int aTrack, int aTick,
|
||||
const std::string& name);
|
||||
MidiEvent* addLyric (int aTrack, int aTick,
|
||||
const std::string& text);
|
||||
MidiEvent* addMarker (int aTrack, int aTick,
|
||||
const std::string& text);
|
||||
MidiEvent* addCue (int aTrack, int aTick,
|
||||
const std::string& text);
|
||||
MidiEvent* addTempo (int aTrack, int aTick,
|
||||
double aTempo);
|
||||
MidiEvent* addKeySignature (int aTrack, int aTick,
|
||||
int fifths, bool mode = 0);
|
||||
MidiEvent* addTimeSignature (int aTrack, int aTick,
|
||||
int top, int bottom,
|
||||
int clocksPerClick = 24,
|
||||
int num32dsPerQuarter = 8);
|
||||
MidiEvent* addCompoundTimeSignature(int aTrack, int aTick,
|
||||
int top, int bottom,
|
||||
int clocksPerClick = 36,
|
||||
int num32dsPerQuarter = 8);
|
||||
|
||||
uchar readByte (std::istream& input);
|
||||
|
||||
// static functions:
|
||||
static ushort readLittleEndian2Bytes (std::istream& input);
|
||||
static ulong readLittleEndian4Bytes (std::istream& input);
|
||||
static std::ostream& writeLittleEndianUShort (std::ostream& out,
|
||||
ushort value);
|
||||
static std::ostream& writeBigEndianUShort (std::ostream& out,
|
||||
ushort value);
|
||||
static std::ostream& writeLittleEndianShort (std::ostream& out,
|
||||
short value);
|
||||
static std::ostream& writeBigEndianShort (std::ostream& out,
|
||||
short value);
|
||||
static std::ostream& writeLittleEndianULong (std::ostream& out,
|
||||
ulong value);
|
||||
static std::ostream& writeBigEndianULong (std::ostream& out,
|
||||
ulong value);
|
||||
static std::ostream& writeLittleEndianLong (std::ostream& out,
|
||||
long value);
|
||||
static std::ostream& writeBigEndianLong (std::ostream& out,
|
||||
long value);
|
||||
static std::ostream& writeLittleEndianFloat (std::ostream& out,
|
||||
float value);
|
||||
static std::ostream& writeBigEndianFloat (std::ostream& out,
|
||||
float value);
|
||||
static std::ostream& writeLittleEndianDouble (std::ostream& out,
|
||||
double value);
|
||||
static std::ostream& writeBigEndianDouble (std::ostream& out,
|
||||
double value);
|
||||
static std::string getGMInstrumentName (int patchIndex);
|
||||
|
||||
protected:
|
||||
// m_events == Lists of MidiEvents for each MIDI file track.
|
||||
std::vector<MidiEventList*> m_events;
|
||||
|
||||
// m_ticksPerQuarterNote == A value for the MIDI file header
|
||||
// which represents the number of ticks in a quarter note
|
||||
// that are used as units for the delta times for MIDI events
|
||||
// in MIDI file track data.
|
||||
int m_ticksPerQuarterNote = 120;
|
||||
|
||||
// m_theTrackState == state variable for whether the tracks
|
||||
// are joined or split.
|
||||
int m_theTrackState = TRACK_STATE_SPLIT;
|
||||
|
||||
// m_theTimeState == state variable for whether the MidiEvent::tick
|
||||
// variable contain absolute ticks since the start of the file's
|
||||
// time, or delta ticks since the last MIDI event in the track.
|
||||
int m_theTimeState = TIME_STATE_ABSOLUTE;
|
||||
|
||||
// m_readFileName == the filename of the last file read into
|
||||
// the object.
|
||||
std::string m_readFileName;
|
||||
|
||||
// m_timemapvalid ==
|
||||
bool m_timemapvalid = false;
|
||||
|
||||
// m_timemap ==
|
||||
std::vector<_TickTime> m_timemap;
|
||||
|
||||
// m_rwstatus == True if last read was successful, false if a problem.
|
||||
bool m_rwstatus = true;
|
||||
|
||||
// m_linkedEventQ == True if link analysis has been done.
|
||||
bool m_linkedEventsQ = false;
|
||||
|
||||
private:
|
||||
int extractMidiData (std::istream& inputfile,
|
||||
std::vector<uchar>& array,
|
||||
uchar& runningCommand);
|
||||
ulong readVLValue (std::istream& inputfile);
|
||||
ulong unpackVLV (uchar a = 0, uchar b = 0,
|
||||
uchar c = 0, uchar d = 0,
|
||||
uchar e = 0);
|
||||
void writeVLValue (long aValue,
|
||||
std::vector<uchar>& data);
|
||||
int makeVLV (uchar *buffer, int number);
|
||||
static int ticksearch (const void* A, const void* B);
|
||||
static int secondsearch (const void* A, const void* B);
|
||||
void buildTimeMap (void);
|
||||
double linearTickInterpolationAtSecond (double seconds);
|
||||
double linearSecondInterpolationAtTick (int ticktime);
|
||||
std::string base64Encode (const std::string &input);
|
||||
std::string base64Decode (const std::string &input);
|
||||
|
||||
static const std::string encodeLookup;
|
||||
static const std::vector<int> decodeLookup;
|
||||
static const char *GMinstrument[128];
|
||||
};
|
||||
|
||||
} // end of namespace smf
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, smf::MidiFile& aMidiFile);
|
||||
|
||||
#endif /* _MIDIFILE_H_INCLUDED */
|
||||
|
||||
|
||||
|
||||
2392
src/ostd/vendor/midifile/MidiMessage.cpp
vendored
Normal file
2392
src/ostd/vendor/midifile/MidiMessage.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
220
src/ostd/vendor/midifile/MidiMessage.h
vendored
Normal file
220
src/ostd/vendor/midifile/MidiMessage.h
vendored
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
//
|
||||
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
|
||||
// Creation Date: Sat Feb 14 20:36:32 PST 2015
|
||||
// Last Modified: Sat Apr 21 10:52:19 PDT 2018 Removed using namespace std;
|
||||
// Filename: midifile/include/MidiMessage.h
|
||||
// Website: http://midifile.sapp.org
|
||||
// Syntax: C++11
|
||||
// vim: ts=3 noexpandtab
|
||||
//
|
||||
// Description: Storage for bytes of a MIDI message for use in MidiFile
|
||||
// class.
|
||||
//
|
||||
|
||||
#ifndef _MIDIMESSAGE_H_INCLUDED
|
||||
#define _MIDIMESSAGE_H_INCLUDED
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace smf {
|
||||
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
class MidiMessage : public std::vector<uchar> {
|
||||
|
||||
public:
|
||||
MidiMessage (void);
|
||||
MidiMessage (int command);
|
||||
MidiMessage (int command, int p1);
|
||||
MidiMessage (int command, int p1, int p2);
|
||||
MidiMessage (const MidiMessage& message);
|
||||
MidiMessage (const std::vector<uchar>& message);
|
||||
MidiMessage (const std::vector<char>& message);
|
||||
MidiMessage (const std::vector<int>& message);
|
||||
|
||||
~MidiMessage ();
|
||||
|
||||
MidiMessage& operator= (const MidiMessage& message);
|
||||
MidiMessage& operator= (const std::vector<uchar>& bytes);
|
||||
MidiMessage& operator= (const std::vector<char>& bytes);
|
||||
MidiMessage& operator= (const std::vector<int>& bytes);
|
||||
MidiMessage& operator= (const std::initializer_list<int>& list);
|
||||
|
||||
void sortTrack (void);
|
||||
void sortTrackWithSequence(void);
|
||||
|
||||
static std::vector<uchar> intToVlv (int value);
|
||||
static double frequencyToSemitones (double frequency, double a4frequency = 440.0);
|
||||
|
||||
// data access convenience functions (returns -1 if not present):
|
||||
int getP0 (void) const;
|
||||
int getP1 (void) const;
|
||||
int getP2 (void) const;
|
||||
int getP3 (void) const;
|
||||
void setP0 (int value);
|
||||
void setP1 (int value);
|
||||
void setP2 (int value);
|
||||
void setP3 (int value);
|
||||
|
||||
int getSize (void) const;
|
||||
void setSize (int asize);
|
||||
int setSizeToCommand (void);
|
||||
int resizeToCommand (void);
|
||||
|
||||
// note-message convenience functions:
|
||||
int getKeyNumber (void) const;
|
||||
int getVelocity (void) const;
|
||||
void setKeyNumber (int value);
|
||||
void setVelocity (int value);
|
||||
void setSpelling (int base7, int accidental);
|
||||
void getSpelling (int& base7, int& accidental);
|
||||
|
||||
// controller-message convenience functions:
|
||||
int getControllerNumber (void) const;
|
||||
int getControllerValue (void) const;
|
||||
|
||||
int getCommandNibble (void) const;
|
||||
int getCommandByte (void) const;
|
||||
int getChannelNibble (void) const;
|
||||
int getChannel (void) const;
|
||||
|
||||
void setCommandByte (int value);
|
||||
void setCommand (int value);
|
||||
void setCommand (int value, int p1);
|
||||
void setCommand (int value, int p1, int p2);
|
||||
void setCommandNibble (int value);
|
||||
void setChannelNibble (int value);
|
||||
void setChannel (int value);
|
||||
void setParameters (int p1, int p2);
|
||||
void setParameters (int p1);
|
||||
void setMessage (const std::vector<uchar>& message);
|
||||
void setMessage (const std::vector<char>& message);
|
||||
void setMessage (const std::vector<int>& message);
|
||||
|
||||
// message-type convenience functions:
|
||||
bool isMetaMessage (void) const;
|
||||
bool isMeta (void) const;
|
||||
bool isNote (void) const;
|
||||
bool isNoteOff (void) const;
|
||||
bool isNoteOn (void) const;
|
||||
bool isAftertouch (void) const;
|
||||
bool isController (void) const;
|
||||
bool isSustain (void) const; // controller 64
|
||||
bool isSustainOn (void) const;
|
||||
bool isSustainOff (void) const;
|
||||
bool isSoft (void) const; // controller 67
|
||||
bool isSoftOn (void) const;
|
||||
bool isSoftOff (void) const;
|
||||
bool isPatchChange (void) const;
|
||||
bool isTimbre (void) const;
|
||||
bool isPressure (void) const;
|
||||
bool isPitchbend (void) const;
|
||||
bool isEmpty (void) const; // see MidiFile::removeEmpties()
|
||||
|
||||
// helper functions to create various MidiMessages:
|
||||
void makeNoteOn (int channel, int key, int velocity);
|
||||
void makeNoteOff (int channel, int key, int velocity);
|
||||
void makeNoteOff (int channel, int key);
|
||||
void makeNoteOff (void);
|
||||
void makePatchChange (int channel, int patchnum);
|
||||
void makeTimbre (int channel, int patchnum);
|
||||
void makeController (int channel, int num, int value);
|
||||
void makePitchBend (int channel, int lsb, int msb);
|
||||
void makePitchBend (int channel, int value);
|
||||
void makePitchBendDouble (int channel, double value);
|
||||
void makePitchbend (int channel, int lsb, int msb) { makePitchBend(channel, lsb, msb); }
|
||||
void makePitchbend (int channel, int value) { makePitchBend(channel, value); }
|
||||
void makePitchbendDouble (int channel, double value) { makePitchBendDouble(channel, value); }
|
||||
|
||||
// helper functions to create various continuous controller messages:
|
||||
void makeSustain (int channel, int value);
|
||||
void makeSustainPedal (int channel, int value);
|
||||
void makeSustainOn (int channel);
|
||||
void makeSustainPedalOn (int channel);
|
||||
void makeSustainOff (int channel);
|
||||
void makeSustainPedalOff (int channel);
|
||||
|
||||
// meta-message creation and helper functions:
|
||||
void makeMetaMessage (int mnum, const std::string& data);
|
||||
void makeText (const std::string& name);
|
||||
void makeCopyright (const std::string& text);
|
||||
void makeTrackName (const std::string& name);
|
||||
void makeInstrumentName (const std::string& name);
|
||||
void makeLyric (const std::string& text);
|
||||
void makeMarker (const std::string& text);
|
||||
void makeCue (const std::string& text);
|
||||
void makeKeySignature (int fifths, bool mode = 0);
|
||||
void makeTimeSignature (int top, int bottom,
|
||||
int clocksPerClick = 24,
|
||||
int num32dsPerQuarter = 8);
|
||||
|
||||
void makeTempo (double tempo) { setTempo(tempo); }
|
||||
int getTempoMicro (void) const;
|
||||
int getTempoMicroseconds (void) const;
|
||||
double getTempoSeconds (void) const;
|
||||
double getTempoBPM (void) const;
|
||||
double getTempoTPS (int tpq) const;
|
||||
double getTempoSPT (int tpq) const;
|
||||
|
||||
int getMetaType (void) const;
|
||||
bool isText (void) const;
|
||||
bool isCopyright (void) const;
|
||||
bool isTrackName (void) const;
|
||||
bool isInstrumentName (void) const;
|
||||
bool isLyricText (void) const;
|
||||
bool isMarkerText (void) const;
|
||||
bool isTempo (void) const;
|
||||
bool isTimeSignature (void) const;
|
||||
bool isKeySignature (void) const;
|
||||
bool isEndOfTrack (void) const;
|
||||
|
||||
std::string getMetaContent (void) const;
|
||||
void setMetaContent (const std::string& content);
|
||||
void setTempo (double tempo);
|
||||
void setTempoMicroseconds (int microseconds);
|
||||
void setMetaTempo (double tempo);
|
||||
|
||||
|
||||
void makeSysExMessage (const std::vector<uchar>& data);
|
||||
|
||||
// helper functions to create MTS tunings by key (real-time sysex)
|
||||
|
||||
// MTS type 2: Real-time frequency assignment to a arbitrary list of MIDI key numbers.
|
||||
// See page 2 of: https://docs.google.com/viewer?url=https://www.midi.org/component/edocman/midi-tuning-updated/fdocument?Itemid=9999
|
||||
void makeMts2_KeyTuningByFrequency (int key, double frequency, int program = 0);
|
||||
void makeMts2_KeyTuningsByFrequency (int key, double frequency, int program = 0);
|
||||
void makeMts2_KeyTuningsByFrequency (std::vector<std::pair<int, double>>& mapping, int program = 0);
|
||||
void makeMts2_KeyTuningBySemitone (int key, double semitone, int program = 0);
|
||||
void makeMts2_KeyTuningsBySemitone (int key, double semitone, int program = 0);
|
||||
void makeMts2_KeyTuningsBySemitone (std::vector<std::pair<int, double>>& mapping, int program = 0);
|
||||
|
||||
// MTS type 9: Real-time octave temperaments by +/- 100 cents deviation from ET
|
||||
// See page 7 of: https://docs.google.com/viewer?url=https://www.midi.org/component/edocman/midi-tuning-updated/fdocument?Itemid=9999
|
||||
void makeMts9_TemperamentByCentsDeviationFromET (std::vector<double>& mapping, int referencePitchClass = 0, int channelMask = 0b1111111111111111);
|
||||
void makeTemperamentEqual(int referencePitchClass = 0, int channelMask = 0b1111111111111111);
|
||||
void makeTemperamentBad(double maxDeviationCents = 100.0, int referencePitchClass = 0, int channelMask = 0b1111111111111111);
|
||||
void makeTemperamentPythagorean(int referencePitchClass = 2, int channelMask = 0b1111111111111111);
|
||||
void makeTemperamentMeantone(double fraction = 0.25, int referencePitchClass = 2, int channelMask = 0b1111111111111111);
|
||||
void makeTemperamentMeantoneCommaQuarter(int referencePitchClass = 2, int channelMask = 0b1111111111111111);
|
||||
void makeTemperamentMeantoneCommaThird(int referencePitchClass = 2, int channelMask = 0b1111111111111111);
|
||||
void makeTemperamentMeantoneCommaHalf(int referencePitchClass = 2, int channelMask = 0b1111111111111111);
|
||||
|
||||
};
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, MidiMessage& event);
|
||||
|
||||
|
||||
} // end of namespace smf
|
||||
|
||||
|
||||
#endif /* _MIDIMESSAGE_H_INCLUDED */
|
||||
|
||||
|
||||
|
||||
1219
src/ostd/vendor/midifile/Options.cpp
vendored
Normal file
1219
src/ostd/vendor/midifile/Options.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
157
src/ostd/vendor/midifile/Options.h
vendored
Normal file
157
src/ostd/vendor/midifile/Options.h
vendored
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
//
|
||||
// Copyright 1998-2018 by Craig Stuart Sapp, All Rights Reserved.
|
||||
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
|
||||
// Creation Date: Sun Apr 5 13:07:18 PDT 1998
|
||||
// Last Modified: Mon Jan 18 18:25:23 PST 2021 Some cleanup
|
||||
// Filename: midifile/include/Options.h
|
||||
// Web Address: http://midifile.sapp.org
|
||||
// Syntax: C++11
|
||||
// vim: ts=3 noexpandtab
|
||||
//
|
||||
// Description: Interface for command-line options.
|
||||
//
|
||||
|
||||
#ifndef _OPTIONS_H_INCLUDED
|
||||
#define _OPTIONS_H_INCLUDED
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define OPTION_TYPE_unknown '\0'
|
||||
#define OPTION_TYPE_boolean 'b'
|
||||
#define OPTION_TYPE_char 'c'
|
||||
#define OPTION_TYPE_double 'd'
|
||||
#define OPTION_TYPE_float 'f'
|
||||
#define OPTION_TYPE_int 'i'
|
||||
#define OPTION_TYPE_string 's'
|
||||
|
||||
|
||||
namespace smf {
|
||||
|
||||
class Option_register {
|
||||
public:
|
||||
Option_register (void);
|
||||
Option_register (const std::string& aDefinition,
|
||||
char aType,
|
||||
const std::string& aDefaultOption);
|
||||
Option_register (const std::string& aDefinition,
|
||||
char aType,
|
||||
const std::string& aDefaultOption,
|
||||
const std::string& aModifiedOption);
|
||||
|
||||
~Option_register ();
|
||||
|
||||
void clearModified (void);
|
||||
const std::string& getDefinition (void);
|
||||
const std::string& getDefault (void);
|
||||
const std::string& getOption (void);
|
||||
const std::string& getModified (void);
|
||||
const std::string& getDescription (void);
|
||||
bool isModified (void);
|
||||
char getType (void);
|
||||
void reset (void);
|
||||
void setDefault (const std::string& aString);
|
||||
void setDefinition (const std::string& aString);
|
||||
void setDescription (const std::string& aString);
|
||||
void setModified (const std::string& aString);
|
||||
void setType (char aType);
|
||||
std::ostream& print (std::ostream& out);
|
||||
|
||||
protected:
|
||||
std::string m_definition;
|
||||
std::string m_description;
|
||||
std::string m_defaultOption;
|
||||
std::string m_modifiedOption;
|
||||
bool m_modifiedQ;
|
||||
char m_type;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
class Options {
|
||||
public:
|
||||
Options (void);
|
||||
Options (int argc, char** argv);
|
||||
|
||||
~Options ();
|
||||
|
||||
int argc (void) const;
|
||||
const std::vector<std::string>& argv (void) const;
|
||||
int define (const std::string& aDefinition);
|
||||
int define (const std::string& aDefinition,
|
||||
const std::string& description);
|
||||
const std::string& getArg (int index);
|
||||
const std::string& getArgument (int index);
|
||||
int getArgCount (void);
|
||||
int getArgumentCount (void);
|
||||
const std::vector<std::string>& getArgList (void);
|
||||
const std::vector<std::string>& getArgumentList (void);
|
||||
bool getBoolean (const std::string& optionName);
|
||||
std::string getCommand (void);
|
||||
const std::string& getCommandLine (void);
|
||||
std::string getDefinition (const std::string& optionName);
|
||||
double getDouble (const std::string& optionName);
|
||||
char getFlag (void);
|
||||
char getChar (const std::string& optionName);
|
||||
float getFloat (const std::string& optionName);
|
||||
int getInt (const std::string& optionName);
|
||||
int getInteger (const std::string& optionName);
|
||||
std::string getString (const std::string& optionName);
|
||||
char getType (const std::string& optionName);
|
||||
int optionsArg (void);
|
||||
std::ostream& print (std::ostream& out);
|
||||
std::ostream& printOptionList (std::ostream& out);
|
||||
std::ostream& printOptionListBooleanState(std::ostream& out);
|
||||
void process (int error_check = 1, int suppress = 0);
|
||||
void process (int argc, char** argv, int error_check = 1,
|
||||
int suppress = 0);
|
||||
void reset (void);
|
||||
void xverify (int argc, char** argv,
|
||||
int error_check = 1,
|
||||
int suppress = 0);
|
||||
void xverify (int error_check = 1, int suppress = 0);
|
||||
void setFlag (char aFlag);
|
||||
void setModified (const std::string& optionName,
|
||||
const std::string& optionValue);
|
||||
void setOptions (int argc, char** argv);
|
||||
void appendOptions (int argc, char** argv);
|
||||
void appendOptions (const std::string& strang);
|
||||
void appendOptions (const std::vector<std::string>& argv);
|
||||
std::ostream& printRegister (std::ostream& out);
|
||||
bool isDefined (const std::string& name);
|
||||
|
||||
protected:
|
||||
int m_options_error_check; // verify command
|
||||
int m_oargc;
|
||||
std::vector<std::string> m_oargv;
|
||||
std::string m_commandString;
|
||||
char m_optionFlag;
|
||||
std::vector<std::string> m_argument;
|
||||
|
||||
std::vector<Option_register*> m_optionRegister;
|
||||
std::map<std::string, int> m_optionList;
|
||||
|
||||
bool m_processedQ;
|
||||
bool m_suppressQ; // prevent --options
|
||||
bool m_optionsArgument; // --options present
|
||||
|
||||
std::vector<std::string> m_extraArgv;
|
||||
std::vector<std::string> m_extraArgv_strings;
|
||||
|
||||
private:
|
||||
int getRegIndex (const std::string& optionName);
|
||||
int optionQ (const std::string& aString, int& argp);
|
||||
int storeOption (int gargp, int& position, int& running);
|
||||
|
||||
};
|
||||
|
||||
} // end of namespace smf
|
||||
|
||||
|
||||
#endif /* _OPTIONS_H_INCLUDED */
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in a new issue