DummyBackend: MIDI Event Generators

This commit is contained in:
Robin Gareus
2014-09-24 01:04:19 +02:00
parent 99a484f193
commit b355f01aa5
3 changed files with 884 additions and 46 deletions

View File

@@ -24,6 +24,7 @@
#include <glibmm.h>
#include "dummy_audiobackend.h"
#include "dummy_midi_seq.h"
#include "pbd/error.h"
#include "ardour/port_manager.h"
@@ -48,6 +49,7 @@ DummyAudioBackend::DummyAudioBackend (AudioEngine& e, AudioBackendInfo& info)
, _n_outputs (0)
, _n_midi_inputs (0)
, _n_midi_outputs (0)
, _enable_midi_generators (false)
, _systemic_input_latency (0)
, _systemic_output_latency (0)
, _processed_samples (0)
@@ -267,9 +269,11 @@ std::vector<std::string>
DummyAudioBackend::enumerate_midi_options () const
{
if (_midi_options.empty()) {
_midi_options.push_back (_("1 in, 1 out"));
_midi_options.push_back (_("2 in, 2 out"));
_midi_options.push_back (_("8 in, 8 out"));
_midi_options.push_back (_("No MIDI I/O"));
_midi_options.push_back (_("1 in, 1 out, Silence"));
_midi_options.push_back (_("2 in, 2 out, Silence"));
_midi_options.push_back (_("8 in, 8 out, Silence"));
_midi_options.push_back (_("Midi Event Generators"));
}
return _midi_options;
}
@@ -277,15 +281,20 @@ DummyAudioBackend::enumerate_midi_options () const
int
DummyAudioBackend::set_midi_option (const std::string& opt)
{
if (opt == _("1 in, 1 out")) {
_enable_midi_generators = false;
if (opt == _("1 in, 1 out, Silence")) {
_n_midi_inputs = _n_midi_outputs = 1;
}
else if (opt == _("2 in, 2 out")) {
else if (opt == _("2 in, 2 out, Silence")) {
_n_midi_inputs = _n_midi_outputs = 2;
}
else if (opt == _("8 in, 8 out")) {
else if (opt == _("8 in, 8 out, Silence")) {
_n_midi_inputs = _n_midi_outputs = 8;
}
else if (opt == _("Midi Event Generators")) {
_n_midi_inputs = _n_midi_outputs = NUM_MIDI_EVENT_GENERATORS;
_enable_midi_generators = true;
}
else {
_n_midi_inputs = _n_midi_outputs = 0;
}
@@ -322,6 +331,7 @@ DummyAudioBackend::_start (bool /*for_latency_measurement*/)
PBD::info << _("DummyAudioBackend: port '") << (*it)->name () << "' exists." << endmsg;
}
_system_inputs.clear();
_system_midi_in.clear();
_ports.clear();
}
@@ -672,8 +682,8 @@ DummyAudioBackend::register_system_ports()
const int a_ins = _n_inputs > 0 ? _n_inputs : 8;
const int a_out = _n_outputs > 0 ? _n_outputs : 8;
const int m_ins = _n_midi_inputs > 0 ? _n_midi_inputs : 2;
const int m_out = _n_midi_outputs > 0 ? _n_midi_outputs : 2;
const int m_ins = _n_midi_inputs;
const int m_out = _n_midi_outputs;
/* audio ports */
lr.min = lr.max = _samples_per_period + _systemic_input_latency;
@@ -704,6 +714,10 @@ DummyAudioBackend::register_system_ports()
PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
if (!p) return -1;
set_latency_range (p, false, lr);
_system_midi_in.push_back (static_cast<DummyMidiPort*>(p));
if (_enable_midi_generators) {
static_cast<DummyMidiPort*>(p)->setup_generator (i % NUM_MIDI_EVENT_GENERATORS, _samplerate);
}
}
lr.min = lr.max = _samples_per_period + _systemic_output_latency;
@@ -722,6 +736,7 @@ DummyAudioBackend::unregister_ports (bool system_only)
{
size_t i = 0;
_system_inputs.clear();
_system_midi_in.clear();
while (i < _ports.size ()) {
DummyPort* port = _ports[i];
if (! system_only || (port->is_physical () && port->is_terminal ())) {
@@ -1061,6 +1076,9 @@ DummyAudioBackend::main_process_thread ()
for (std::vector<DummyAudioPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it) {
(*it)->next_period();
}
for (std::vector<DummyMidiPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it) {
(*it)->next_period();
}
if (engine.process_callback (_samples_per_period)) {
return 0;
@@ -1174,6 +1192,8 @@ DummyPort::DummyPort (DummyAudioBackend &b, const std::string& name, PortFlags f
: _dummy_backend (b)
, _name (name)
, _flags (flags)
, _rseed (0)
, _gen_cycle (false)
{
_capture_latency_range.min = 0;
_capture_latency_range.max = 0;
@@ -1295,12 +1315,41 @@ bool DummyPort::is_physically_connected () const
return false;
}
void DummyPort::setup_random_number_generator ()
{
_rseed = g_get_monotonic_time() % UINT_MAX;
}
inline uint32_t
DummyPort::randi ()
{
// 31bit Park-Miller-Carta Pseudo-Random Number Generator
// http://www.firstpr.com.au/dsp/rand31/
uint32_t hi, lo;
lo = 16807 * (_rseed & 0xffff);
hi = 16807 * (_rseed >> 16);
lo += (hi & 0x7fff) << 16;
lo += hi >> 15;
#if 1
lo = (lo & 0x7fffffff) + (lo >> 31);
#else
if (lo > 0x7fffffff) { lo -= 0x7fffffff; }
#endif
return (_rseed = lo);
}
inline float
DummyPort::randf ()
{
return (randi() / 1073741824.f) - 1.f;
}
/******************************************************************************/
DummyAudioPort::DummyAudioPort (DummyAudioBackend &b, const std::string& name, PortFlags flags)
: DummyPort (b, name, flags)
, _gen_type (Silence)
, _gen_cycle (false)
, _b0 (0)
, _b1 (0)
, _b2 (0)
@@ -1324,8 +1373,8 @@ DummyAudioPort::~DummyAudioPort () {
void DummyAudioPort::setup_generator (GeneratorType const g, float const samplerate)
{
DummyPort::setup_random_number_generator();
_gen_type = g;
_rseed = g_get_monotonic_time() % UINT_MAX;
switch (_gen_type) {
case PinkNoise:
@@ -1346,31 +1395,6 @@ void DummyAudioPort::setup_generator (GeneratorType const g, float const sampler
}
}
inline uint32_t
DummyAudioPort::randi ()
{
// 31bit Park-Miller-Carta Pseudo-Random Number Generator
// http://www.firstpr.com.au/dsp/rand31/
uint32_t hi, lo;
lo = 16807 * (_rseed & 0xffff);
hi = 16807 * (_rseed >> 16);
lo += (hi & 0x7fff) << 16;
lo += hi >> 15;
#if 1
lo = (lo & 0x7fffffff) + (lo >> 31);
#else
if (lo > 0x7fffffff) { lo -= 0x7fffffff; }
#endif
return (_rseed = lo);
}
inline float
DummyAudioPort::randf ()
{
return (randi() / 1073741824.f) - 1.f;
}
float DummyAudioPort::grandf ()
{
// Gaussian White Noise
@@ -1500,6 +1524,9 @@ void* DummyAudioPort::get_buffer (pframes_t n_samples)
DummyMidiPort::DummyMidiPort (DummyAudioBackend &b, const std::string& name, PortFlags flags)
: DummyPort (b, name, flags)
, _midi_seq_spb (0)
, _midi_seq_time (0)
, _midi_seq_pos (0)
{
_buffer.clear ();
}
@@ -1512,13 +1539,75 @@ struct MidiEventSorter {
}
};
void* DummyMidiPort::get_buffer (pframes_t /* nframes */)
void DummyMidiPort::setup_generator (int seq_id, const float sr)
{
DummyPort::setup_random_number_generator();
switch (seq_id) {
case 1:
_midi_seq_dat = DummyMidiData::s1;
break;
case 2:
_midi_seq_dat = DummyMidiData::s2;
break;
case 3:
_midi_seq_dat = DummyMidiData::s3;
break;
default:
_midi_seq_dat = DummyMidiData::s0;
break;
}
_midi_seq_spb = sr * .5; // 120 BPM, beat_time 1.0 per beat.
_midi_seq_pos = 0;
_midi_seq_time = 0;
}
void DummyMidiPort::midi_generate (const pframes_t n_samples)
{
Glib::Threads::Mutex::Lock lm (generator_lock);
if (_gen_cycle) {
return;
}
_buffer.clear ();
_gen_cycle = true;
if (_midi_seq_spb == 0 || !_midi_seq_dat) {
return;
}
while (1) {
const int32_t ev_beat_time = _midi_seq_dat[_midi_seq_pos].beat_time * _midi_seq_spb - _midi_seq_time;
if (ev_beat_time < 0) {
break;
}
if ((pframes_t) ev_beat_time >= n_samples) {
break;
}
_buffer.push_back (boost::shared_ptr<DummyMidiEvent>(new DummyMidiEvent (
ev_beat_time, _midi_seq_dat[_midi_seq_pos].event, 3
)));
++_midi_seq_pos;
if (_midi_seq_dat[_midi_seq_pos].event[0] == 0xff && _midi_seq_dat[_midi_seq_pos].event[1] == 0xff) {
_midi_seq_time -= _midi_seq_dat[_midi_seq_pos].beat_time * _midi_seq_spb;
_midi_seq_pos = 0;
}
}
_midi_seq_time += n_samples;
}
void* DummyMidiPort::get_buffer (pframes_t n_samples)
{
if (is_input ()) {
_buffer.clear ();
for (std::vector<DummyPort*>::const_iterator i = get_connections ().begin ();
i != get_connections ().end ();
++i) {
DummyMidiPort * source = static_cast<DummyMidiPort*>(*i);
if (source->is_physical() && source->is_terminal()) {
source->get_buffer(n_samples); // generate signal.
}
const DummyMidiBuffer src = static_cast<const DummyMidiPort*>(*i)->const_buffer ();
for (DummyMidiBuffer::const_iterator it = src.begin (); it != src.end (); ++it) {
_buffer.push_back (boost::shared_ptr<DummyMidiEvent>(new DummyMidiEvent (**it)));
@@ -1526,7 +1615,9 @@ void* DummyMidiPort::get_buffer (pframes_t /* nframes */)
}
std::sort (_buffer.begin (), _buffer.end (), MidiEventSorter());
} else if (is_output () && is_physical () && is_terminal()) {
_buffer.clear ();
if (!_gen_cycle) {
midi_generate(n_samples);
}
}
return &_buffer;
}

View File

@@ -37,6 +37,13 @@ namespace ARDOUR {
class DummyAudioBackend;
namespace DummyMidiData {
typedef struct _MIDISequence {
float beat_time;
uint8_t event[3];
} MIDISequence;
};
class DummyMidiEvent {
public:
DummyMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size);
@@ -83,6 +90,7 @@ class DummyPort {
void disconnect_all ();
virtual void* get_buffer (pframes_t nframes) = 0;
void next_period () { _gen_cycle = false; }
const LatencyRange& latency_range (bool for_playback) const
{
@@ -112,6 +120,17 @@ class DummyPort {
void _connect (DummyPort* , bool);
void _disconnect (DummyPort* , bool);
protected:
// random number generator
void setup_random_number_generator ();
inline float randf ();
inline uint32_t randi ();
uint32_t _rseed;
// signal generator
volatile bool _gen_cycle;
Glib::Threads::Mutex generator_lock;
}; // class DummyPort
class DummyAudioPort : public DummyPort {
@@ -133,7 +152,6 @@ class DummyAudioPort : public DummyPort {
PonyNoise,
SineWave,
};
void next_period () { _gen_cycle = false; }
void setup_generator (GeneratorType const, float const);
private:
@@ -142,8 +160,6 @@ class DummyAudioPort : public DummyPort {
// signal generator ('fake' physical inputs)
void generate (const pframes_t n_samples);
GeneratorType _gen_type;
Glib::Threads::Mutex generator_lock;
volatile bool _gen_cycle;
// generator buffers
// pink-noise filters
@@ -153,11 +169,6 @@ class DummyAudioPort : public DummyPort {
uint32_t _tbl_length;
uint32_t _tbl_offset;
// random number generator
inline float randf ();
inline uint32_t randi ();
uint32_t _rseed;
// gaussian noise generator
float grandf ();
bool _pass;
@@ -175,8 +186,17 @@ class DummyMidiPort : public DummyPort {
void* get_buffer (pframes_t nframes);
const DummyMidiBuffer const_buffer () const { return _buffer; }
void setup_generator (int, float const);
private:
DummyMidiBuffer _buffer;
// midi event generator ('fake' physical inputs)
void midi_generate (const pframes_t n_samples);
float _midi_seq_spb; // samples per beat
int32_t _midi_seq_time;
uint32_t _midi_seq_pos;
DummyMidiData::MIDISequence const * _midi_seq_dat;
}; // class DummyMidiPort
class DummyAudioBackend : public AudioBackend {
@@ -346,6 +366,7 @@ class DummyAudioBackend : public AudioBackend {
uint32_t _n_midi_inputs;
uint32_t _n_midi_outputs;
bool _enable_midi_generators;
uint32_t _systemic_input_latency;
uint32_t _systemic_output_latency;
@@ -373,9 +394,9 @@ class DummyAudioBackend : public AudioBackend {
void unregister_ports (bool system_only = false);
std::vector<DummyAudioPort *> _system_inputs;
std::vector<DummyMidiPort *> _system_midi_in;
std::vector<DummyPort *> _ports;
struct PortConnectData {
std::string a;
std::string b;

View File

@@ -0,0 +1,726 @@
/*
* Copyright (C) 2014 Robin Gareus <robin@gareus.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __libbackend_dummy_midi_seq_h__
#define __libbackend_dummy_midi_seq_h__
#include "dummy_audiobackend.h"
namespace ARDOUR { namespace DummyMidiData {
#define NUM_MIDI_EVENT_GENERATORS 4
const MIDISequence s0[] = { // some arbitrary short sequence
{ 0.00, {0x90, 64, 0x7f} },
{ 0.50, {0x80, 64, 0x00} },
{ 1.00, {0x90, 66, 0x7f} },
{ 1.50, {0x80, 66, 0x00} },
{ 2.00, {0x90, 68, 0x7f} },
{ 3.50, {0x80, 68, 0x00} },
{ 3.75, {0x90, 71, 0x7f} },
{ 4.00, {0x80, 71, 0x00} },
{ 4.00, {0xff, 255, 0xff} }, // sentinel
};
const MIDISequence s1[] = { // Cmaj7 - iterate all channels
{ 0.00, {0x90, 60, 0x7f} },
{ 0.25, {0x90, 64, 0x7f} },
{ 0.50, {0x90, 67, 0x7f} },
{ 0.75, {0x90, 71, 0x7f} },
{ 1.00, {0x90, 72, 0x7f} },
{ 1.00, {0x80, 60, 0x00} },
{ 1.25, {0x80, 64, 0x00} },
{ 1.50, {0x80, 67, 0x00} },
{ 1.75, {0x80, 71, 0x00} },
{ 2.00, {0x80, 72, 0x00} },
{ 2.00, {0x91, 60, 0x7f} },
{ 2.25, {0x91, 64, 0x7f} },
{ 2.50, {0x91, 67, 0x7f} },
{ 2.75, {0x91, 71, 0x7f} },
{ 3.00, {0x91, 72, 0x7f} },
{ 3.00, {0x81, 60, 0x00} },
{ 3.25, {0x81, 64, 0x00} },
{ 3.50, {0x81, 67, 0x00} },
{ 3.75, {0x81, 71, 0x00} },
{ 4.00, {0x81, 72, 0x00} },
{ 4.00, {0x92, 60, 0x7f} },
{ 4.25, {0x92, 64, 0x7f} },
{ 4.50, {0x92, 67, 0x7f} },
{ 4.75, {0x92, 71, 0x7f} },
{ 5.00, {0x92, 72, 0x7f} },
{ 5.00, {0x82, 60, 0x00} },
{ 5.25, {0x82, 64, 0x00} },
{ 5.50, {0x82, 67, 0x00} },
{ 5.75, {0x82, 71, 0x00} },
{ 6.00, {0x82, 72, 0x00} },
{ 6.00, {0x93, 60, 0x7f} },
{ 6.25, {0x93, 64, 0x7f} },
{ 6.50, {0x93, 67, 0x7f} },
{ 6.75, {0x93, 71, 0x7f} },
{ 7.00, {0x93, 72, 0x7f} },
{ 7.00, {0x83, 60, 0x00} },
{ 7.25, {0x83, 64, 0x00} },
{ 7.50, {0x83, 67, 0x00} },
{ 7.75, {0x83, 71, 0x00} },
{ 8.00, {0x83, 72, 0x00} },
{ 8.00, {0x94, 60, 0x7f} },
{ 8.25, {0x94, 64, 0x7f} },
{ 8.50, {0x94, 67, 0x7f} },
{ 8.75, {0x94, 71, 0x7f} },
{ 9.00, {0x94, 72, 0x7f} },
{ 9.00, {0x84, 60, 0x00} },
{ 9.25, {0x84, 64, 0x00} },
{ 9.50, {0x84, 67, 0x00} },
{ 9.75, {0x84, 71, 0x00} },
{10.00, {0x84, 72, 0x00} },
{10.00, {0x95, 60, 0x7f} },
{10.25, {0x95, 64, 0x7f} },
{10.50, {0x95, 67, 0x7f} },
{10.75, {0x95, 71, 0x7f} },
{11.00, {0x95, 72, 0x7f} },
{11.00, {0x85, 60, 0x00} },
{11.25, {0x85, 64, 0x00} },
{11.50, {0x85, 67, 0x00} },
{11.75, {0x85, 71, 0x00} },
{12.00, {0x85, 72, 0x00} },
{12.00, {0x96, 60, 0x7f} },
{12.25, {0x96, 64, 0x7f} },
{12.50, {0x96, 67, 0x7f} },
{12.75, {0x96, 71, 0x7f} },
{13.00, {0x96, 72, 0x7f} },
{13.00, {0x86, 60, 0x00} },
{13.25, {0x86, 64, 0x00} },
{13.50, {0x86, 67, 0x00} },
{13.75, {0x86, 71, 0x00} },
{14.00, {0x86, 72, 0x00} },
{14.00, {0x97, 60, 0x7f} },
{14.25, {0x97, 64, 0x7f} },
{14.50, {0x97, 67, 0x7f} },
{14.75, {0x97, 71, 0x7f} },
{15.00, {0x97, 72, 0x7f} },
{15.00, {0x87, 60, 0x00} },
{15.25, {0x87, 64, 0x00} },
{15.50, {0x87, 67, 0x00} },
{15.75, {0x87, 71, 0x00} },
{16.00, {0x87, 72, 0x00} },
{16.00, {0x98, 60, 0x7f} },
{16.25, {0x98, 64, 0x7f} },
{16.50, {0x98, 67, 0x7f} },
{16.75, {0x98, 71, 0x7f} },
{17.00, {0x98, 72, 0x7f} },
{17.00, {0x88, 60, 0x00} },
{17.25, {0x88, 64, 0x00} },
{17.50, {0x88, 67, 0x00} },
{17.75, {0x88, 71, 0x00} },
{18.00, {0x88, 72, 0x00} },
{18.00, {0x99, 60, 0x7f} },
{18.25, {0x99, 64, 0x7f} },
{18.50, {0x99, 67, 0x7f} },
{18.75, {0x99, 71, 0x7f} },
{19.00, {0x99, 72, 0x7f} },
{19.00, {0x89, 60, 0x00} },
{19.25, {0x89, 64, 0x00} },
{19.50, {0x89, 67, 0x00} },
{19.75, {0x89, 71, 0x00} },
{20.00, {0x89, 72, 0x00} },
{20.00, {0x9a, 60, 0x7f} },
{20.25, {0x9a, 64, 0x7f} },
{20.50, {0x9a, 67, 0x7f} },
{20.75, {0x9a, 71, 0x7f} },
{21.00, {0x9a, 72, 0x7f} },
{21.00, {0x8a, 60, 0x00} },
{21.25, {0x8a, 64, 0x00} },
{21.50, {0x8a, 67, 0x00} },
{21.75, {0x8a, 71, 0x00} },
{22.00, {0x8a, 72, 0x00} },
{22.00, {0x9b, 60, 0x7f} },
{22.25, {0x9b, 64, 0x7f} },
{22.50, {0x9b, 67, 0x7f} },
{22.75, {0x9b, 71, 0x7f} },
{23.00, {0x9b, 72, 0x7f} },
{23.00, {0x8b, 60, 0x00} },
{23.25, {0x8b, 64, 0x00} },
{23.50, {0x8b, 67, 0x00} },
{23.75, {0x8b, 71, 0x00} },
{24.00, {0x8b, 72, 0x00} },
{24.00, {0x9c, 60, 0x7f} },
{24.25, {0x9c, 64, 0x7f} },
{24.50, {0x9c, 67, 0x7f} },
{24.75, {0x9c, 71, 0x7f} },
{25.00, {0x9c, 72, 0x7f} },
{25.00, {0x8c, 60, 0x00} },
{25.25, {0x8c, 64, 0x00} },
{25.50, {0x8c, 67, 0x00} },
{25.75, {0x8c, 71, 0x00} },
{26.00, {0x8c, 72, 0x00} },
{26.00, {0x9d, 60, 0x7f} },
{26.25, {0x9d, 64, 0x7f} },
{26.50, {0x9d, 67, 0x7f} },
{26.75, {0x9d, 71, 0x7f} },
{27.00, {0x9d, 72, 0x7f} },
{27.00, {0x8d, 60, 0x00} },
{27.25, {0x8d, 64, 0x00} },
{27.50, {0x8d, 67, 0x00} },
{27.75, {0x8d, 71, 0x00} },
{28.00, {0x8d, 72, 0x00} },
{28.00, {0x9e, 60, 0x7f} },
{28.25, {0x9e, 64, 0x7f} },
{28.50, {0x9e, 67, 0x7f} },
{28.75, {0x9e, 71, 0x7f} },
{29.00, {0x9e, 72, 0x7f} },
{29.00, {0x8e, 60, 0x00} },
{29.25, {0x8e, 64, 0x00} },
{29.50, {0x8e, 67, 0x00} },
{29.75, {0x8e, 71, 0x00} },
{30.00, {0x8e, 72, 0x00} },
{30.00, {0x9f, 60, 0x7f} },
{30.25, {0x9f, 64, 0x7f} },
{30.50, {0x9f, 67, 0x7f} },
{30.75, {0x9f, 71, 0x7f} },
{31.00, {0x9f, 72, 0x7f} },
{31.00, {0x8f, 60, 0x00} },
{31.25, {0x8f, 64, 0x00} },
{31.50, {0x8f, 67, 0x00} },
{31.75, {0x8f, 71, 0x00} },
{32.00, {0x8f, 72, 0x00} },
{32.00, {0xff, 255, 0xff} }, // sentinel
};
const MIDISequence s2[] = { // channel 1, sweep all notes
{ 0.00, {0x90, 0, 0x7f} },
{ 0.25, {0x80, 0, 0x00} },
{ 0.25, {0x90, 1, 0x7f} },
{ 0.50, {0x80, 1, 0x00} },
{ 0.50, {0x90, 2, 0x7f} },
{ 0.75, {0x80, 2, 0x00} },
{ 0.75, {0x90, 3, 0x7f} },
{ 1.00, {0x80, 3, 0x00} },
{ 1.00, {0x90, 4, 0x7f} },
{ 1.25, {0x80, 4, 0x00} },
{ 1.25, {0x90, 5, 0x7f} },
{ 1.50, {0x80, 5, 0x00} },
{ 1.50, {0x90, 6, 0x7f} },
{ 1.75, {0x80, 6, 0x00} },
{ 1.75, {0x90, 7, 0x7f} },
{ 2.00, {0x80, 7, 0x00} },
{ 2.00, {0x90, 8, 0x7f} },
{ 2.25, {0x80, 8, 0x00} },
{ 2.25, {0x90, 9, 0x7f} },
{ 2.50, {0x80, 9, 0x00} },
{ 2.50, {0x90, 10, 0x7f} },
{ 2.75, {0x80, 10, 0x00} },
{ 2.75, {0x90, 11, 0x7f} },
{ 3.00, {0x80, 11, 0x00} },
{ 3.00, {0x90, 12, 0x7f} },
{ 3.25, {0x80, 12, 0x00} },
{ 3.25, {0x90, 13, 0x7f} },
{ 3.50, {0x80, 13, 0x00} },
{ 3.50, {0x90, 14, 0x7f} },
{ 3.75, {0x80, 14, 0x00} },
{ 3.75, {0x90, 15, 0x7f} },
{ 4.00, {0x80, 15, 0x00} },
{ 4.00, {0x90, 16, 0x7f} },
{ 4.25, {0x80, 16, 0x00} },
{ 4.25, {0x90, 17, 0x7f} },
{ 4.50, {0x80, 17, 0x00} },
{ 4.50, {0x90, 18, 0x7f} },
{ 4.75, {0x80, 18, 0x00} },
{ 4.75, {0x90, 19, 0x7f} },
{ 5.00, {0x80, 19, 0x00} },
{ 5.00, {0x90, 20, 0x7f} },
{ 5.25, {0x80, 20, 0x00} },
{ 5.25, {0x90, 21, 0x7f} },
{ 5.50, {0x80, 21, 0x00} },
{ 5.50, {0x90, 22, 0x7f} },
{ 5.75, {0x80, 22, 0x00} },
{ 5.75, {0x90, 23, 0x7f} },
{ 6.00, {0x80, 23, 0x00} },
{ 6.00, {0x90, 24, 0x7f} },
{ 6.25, {0x80, 24, 0x00} },
{ 6.25, {0x90, 25, 0x7f} },
{ 6.50, {0x80, 25, 0x00} },
{ 6.50, {0x90, 26, 0x7f} },
{ 6.75, {0x80, 26, 0x00} },
{ 6.75, {0x90, 27, 0x7f} },
{ 7.00, {0x80, 27, 0x00} },
{ 7.00, {0x90, 28, 0x7f} },
{ 7.25, {0x80, 28, 0x00} },
{ 7.25, {0x90, 29, 0x7f} },
{ 7.50, {0x80, 29, 0x00} },
{ 7.50, {0x90, 30, 0x7f} },
{ 7.75, {0x80, 30, 0x00} },
{ 7.75, {0x90, 31, 0x7f} },
{ 8.00, {0x80, 31, 0x00} },
{ 8.00, {0x90, 32, 0x7f} },
{ 8.25, {0x80, 32, 0x00} },
{ 8.25, {0x90, 33, 0x7f} },
{ 8.50, {0x80, 33, 0x00} },
{ 8.50, {0x90, 34, 0x7f} },
{ 8.75, {0x80, 34, 0x00} },
{ 8.75, {0x90, 35, 0x7f} },
{ 9.00, {0x80, 35, 0x00} },
{ 9.00, {0x90, 36, 0x7f} },
{ 9.25, {0x80, 36, 0x00} },
{ 9.25, {0x90, 37, 0x7f} },
{ 9.50, {0x80, 37, 0x00} },
{ 9.50, {0x90, 38, 0x7f} },
{ 9.75, {0x80, 38, 0x00} },
{ 9.75, {0x90, 39, 0x7f} },
{10.00, {0x80, 39, 0x00} },
{10.00, {0x90, 40, 0x7f} },
{10.25, {0x80, 40, 0x00} },
{10.25, {0x90, 41, 0x7f} },
{10.50, {0x80, 41, 0x00} },
{10.50, {0x90, 42, 0x7f} },
{10.75, {0x80, 42, 0x00} },
{10.75, {0x90, 43, 0x7f} },
{11.00, {0x80, 43, 0x00} },
{11.00, {0x90, 44, 0x7f} },
{11.25, {0x80, 44, 0x00} },
{11.25, {0x90, 45, 0x7f} },
{11.50, {0x80, 45, 0x00} },
{11.50, {0x90, 46, 0x7f} },
{11.75, {0x80, 46, 0x00} },
{11.75, {0x90, 47, 0x7f} },
{12.00, {0x80, 47, 0x00} },
{12.00, {0x90, 48, 0x7f} },
{12.25, {0x80, 48, 0x00} },
{12.25, {0x90, 49, 0x7f} },
{12.50, {0x80, 49, 0x00} },
{12.50, {0x90, 50, 0x7f} },
{12.75, {0x80, 50, 0x00} },
{12.75, {0x90, 51, 0x7f} },
{13.00, {0x80, 51, 0x00} },
{13.00, {0x90, 52, 0x7f} },
{13.25, {0x80, 52, 0x00} },
{13.25, {0x90, 53, 0x7f} },
{13.50, {0x80, 53, 0x00} },
{13.50, {0x90, 54, 0x7f} },
{13.75, {0x80, 54, 0x00} },
{13.75, {0x90, 55, 0x7f} },
{14.00, {0x80, 55, 0x00} },
{14.00, {0x90, 56, 0x7f} },
{14.25, {0x80, 56, 0x00} },
{14.25, {0x90, 57, 0x7f} },
{14.50, {0x80, 57, 0x00} },
{14.50, {0x90, 58, 0x7f} },
{14.75, {0x80, 58, 0x00} },
{14.75, {0x90, 59, 0x7f} },
{15.00, {0x80, 59, 0x00} },
{15.00, {0x90, 60, 0x7f} },
{15.25, {0x80, 60, 0x00} },
{15.25, {0x90, 61, 0x7f} },
{15.50, {0x80, 61, 0x00} },
{15.50, {0x90, 62, 0x7f} },
{15.75, {0x80, 62, 0x00} },
{15.75, {0x90, 63, 0x7f} },
{16.00, {0x80, 63, 0x00} },
{16.00, {0x90, 64, 0x7f} },
{16.25, {0x80, 64, 0x00} },
{16.25, {0x90, 65, 0x7f} },
{16.50, {0x80, 65, 0x00} },
{16.50, {0x90, 66, 0x7f} },
{16.75, {0x80, 66, 0x00} },
{16.75, {0x90, 67, 0x7f} },
{17.00, {0x80, 67, 0x00} },
{17.00, {0x90, 68, 0x7f} },
{17.25, {0x80, 68, 0x00} },
{17.25, {0x90, 69, 0x7f} },
{17.50, {0x80, 69, 0x00} },
{17.50, {0x90, 70, 0x7f} },
{17.75, {0x80, 70, 0x00} },
{17.75, {0x90, 71, 0x7f} },
{18.00, {0x80, 71, 0x00} },
{18.00, {0x90, 72, 0x7f} },
{18.25, {0x80, 72, 0x00} },
{18.25, {0x90, 73, 0x7f} },
{18.50, {0x80, 73, 0x00} },
{18.50, {0x90, 74, 0x7f} },
{18.75, {0x80, 74, 0x00} },
{18.75, {0x90, 75, 0x7f} },
{19.00, {0x80, 75, 0x00} },
{19.00, {0x90, 76, 0x7f} },
{19.25, {0x80, 76, 0x00} },
{19.25, {0x90, 77, 0x7f} },
{19.50, {0x80, 77, 0x00} },
{19.50, {0x90, 78, 0x7f} },
{19.75, {0x80, 78, 0x00} },
{19.75, {0x90, 79, 0x7f} },
{20.00, {0x80, 79, 0x00} },
{20.00, {0x90, 80, 0x7f} },
{20.25, {0x80, 80, 0x00} },
{20.25, {0x90, 81, 0x7f} },
{20.50, {0x80, 81, 0x00} },
{20.50, {0x90, 82, 0x7f} },
{20.75, {0x80, 82, 0x00} },
{20.75, {0x90, 83, 0x7f} },
{21.00, {0x80, 83, 0x00} },
{21.00, {0x90, 84, 0x7f} },
{21.25, {0x80, 84, 0x00} },
{21.25, {0x90, 85, 0x7f} },
{21.50, {0x80, 85, 0x00} },
{21.50, {0x90, 86, 0x7f} },
{21.75, {0x80, 86, 0x00} },
{21.75, {0x90, 87, 0x7f} },
{22.00, {0x80, 87, 0x00} },
{22.00, {0x90, 88, 0x7f} },
{22.25, {0x80, 88, 0x00} },
{22.25, {0x90, 89, 0x7f} },
{22.50, {0x80, 89, 0x00} },
{22.50, {0x90, 90, 0x7f} },
{22.75, {0x80, 90, 0x00} },
{22.75, {0x90, 91, 0x7f} },
{23.00, {0x80, 91, 0x00} },
{23.00, {0x90, 92, 0x7f} },
{23.25, {0x80, 92, 0x00} },
{23.25, {0x90, 93, 0x7f} },
{23.50, {0x80, 93, 0x00} },
{23.50, {0x90, 94, 0x7f} },
{23.75, {0x80, 94, 0x00} },
{23.75, {0x90, 95, 0x7f} },
{24.00, {0x80, 95, 0x00} },
{24.00, {0x90, 96, 0x7f} },
{24.25, {0x80, 96, 0x00} },
{24.25, {0x90, 97, 0x7f} },
{24.50, {0x80, 97, 0x00} },
{24.50, {0x90, 98, 0x7f} },
{24.75, {0x80, 98, 0x00} },
{24.75, {0x90, 99, 0x7f} },
{25.00, {0x80, 99, 0x00} },
{25.00, {0x90, 100, 0x7f} },
{25.25, {0x80, 100, 0x00} },
{25.25, {0x90, 101, 0x7f} },
{25.50, {0x80, 101, 0x00} },
{25.50, {0x90, 102, 0x7f} },
{25.75, {0x80, 102, 0x00} },
{25.75, {0x90, 103, 0x7f} },
{26.00, {0x80, 103, 0x00} },
{26.00, {0x90, 104, 0x7f} },
{26.25, {0x80, 104, 0x00} },
{26.25, {0x90, 105, 0x7f} },
{26.50, {0x80, 105, 0x00} },
{26.50, {0x90, 106, 0x7f} },
{26.75, {0x80, 106, 0x00} },
{26.75, {0x90, 107, 0x7f} },
{27.00, {0x80, 107, 0x00} },
{27.00, {0x90, 108, 0x7f} },
{27.25, {0x80, 108, 0x00} },
{27.25, {0x90, 109, 0x7f} },
{27.50, {0x80, 109, 0x00} },
{27.50, {0x90, 110, 0x7f} },
{27.75, {0x80, 110, 0x00} },
{27.75, {0x90, 111, 0x7f} },
{28.00, {0x80, 111, 0x00} },
{28.00, {0x90, 112, 0x7f} },
{28.25, {0x80, 112, 0x00} },
{28.25, {0x90, 113, 0x7f} },
{28.50, {0x80, 113, 0x00} },
{28.50, {0x90, 114, 0x7f} },
{28.75, {0x80, 114, 0x00} },
{28.75, {0x90, 115, 0x7f} },
{29.00, {0x80, 115, 0x00} },
{29.00, {0x90, 116, 0x7f} },
{29.25, {0x80, 116, 0x00} },
{29.25, {0x90, 117, 0x7f} },
{29.50, {0x80, 117, 0x00} },
{29.50, {0x90, 118, 0x7f} },
{29.75, {0x80, 118, 0x00} },
{29.75, {0x90, 119, 0x7f} },
{30.00, {0x80, 119, 0x00} },
{30.00, {0x90, 120, 0x7f} },
{30.25, {0x80, 120, 0x00} },
{30.25, {0x90, 121, 0x7f} },
{30.50, {0x80, 121, 0x00} },
{30.50, {0x90, 122, 0x7f} },
{30.75, {0x80, 122, 0x00} },
{30.75, {0x90, 123, 0x7f} },
{31.00, {0x80, 123, 0x00} },
{31.00, {0x90, 124, 0x7f} },
{31.25, {0x80, 124, 0x00} },
{31.25, {0x90, 125, 0x7f} },
{31.50, {0x80, 125, 0x00} },
{31.50, {0x90, 126, 0x7f} },
{31.75, {0x80, 126, 0x00} },
{31.75, {0x90, 127, 0x7f} },
{32.00, {0x80, 127, 0x00} },
{32.00, {0xff, 255, 0xff} }, // sentinel
};
const MIDISequence s3[] = { // velocity sweep
{ 0.000, {0x90, 60, 0x00} },
{ 0.125, {0x80, 60, 0x00} },
{ 0.125, {0x90, 61, 0x01} },
{ 0.250, {0x80, 61, 0x00} },
{ 0.250, {0x90, 60, 0x02} },
{ 0.375, {0x80, 60, 0x00} },
{ 0.375, {0x90, 61, 0x03} },
{ 0.500, {0x80, 61, 0x00} },
{ 0.500, {0x90, 60, 0x04} },
{ 0.625, {0x80, 60, 0x00} },
{ 0.625, {0x90, 61, 0x05} },
{ 0.750, {0x80, 61, 0x00} },
{ 0.750, {0x90, 60, 0x06} },
{ 0.875, {0x80, 60, 0x00} },
{ 0.875, {0x90, 61, 0x07} },
{ 1.000, {0x80, 61, 0x00} },
{ 1.000, {0x90, 60, 0x08} },
{ 1.125, {0x80, 60, 0x00} },
{ 1.125, {0x90, 61, 0x09} },
{ 1.250, {0x80, 61, 0x00} },
{ 1.250, {0x90, 60, 0x0a} },
{ 1.375, {0x80, 60, 0x00} },
{ 1.375, {0x90, 61, 0x0b} },
{ 1.500, {0x80, 61, 0x00} },
{ 1.500, {0x90, 60, 0x0c} },
{ 1.625, {0x80, 60, 0x00} },
{ 1.625, {0x90, 61, 0x0d} },
{ 1.750, {0x80, 61, 0x00} },
{ 1.750, {0x90, 60, 0x0e} },
{ 1.875, {0x80, 60, 0x00} },
{ 1.875, {0x90, 61, 0x0f} },
{ 2.000, {0x80, 61, 0x00} },
{ 2.000, {0x90, 60, 0x10} },
{ 2.125, {0x80, 60, 0x00} },
{ 2.125, {0x90, 61, 0x11} },
{ 2.250, {0x80, 61, 0x00} },
{ 2.250, {0x90, 60, 0x12} },
{ 2.375, {0x80, 60, 0x00} },
{ 2.375, {0x90, 61, 0x13} },
{ 2.500, {0x80, 61, 0x00} },
{ 2.500, {0x90, 60, 0x14} },
{ 2.625, {0x80, 60, 0x00} },
{ 2.625, {0x90, 61, 0x15} },
{ 2.750, {0x80, 61, 0x00} },
{ 2.750, {0x90, 60, 0x16} },
{ 2.875, {0x80, 60, 0x00} },
{ 2.875, {0x90, 61, 0x17} },
{ 3.000, {0x80, 61, 0x00} },
{ 3.000, {0x90, 60, 0x18} },
{ 3.125, {0x80, 60, 0x00} },
{ 3.125, {0x90, 61, 0x19} },
{ 3.250, {0x80, 61, 0x00} },
{ 3.250, {0x90, 60, 0x1a} },
{ 3.375, {0x80, 60, 0x00} },
{ 3.375, {0x90, 61, 0x1b} },
{ 3.500, {0x80, 61, 0x00} },
{ 3.500, {0x90, 60, 0x1c} },
{ 3.625, {0x80, 60, 0x00} },
{ 3.625, {0x90, 61, 0x1d} },
{ 3.750, {0x80, 61, 0x00} },
{ 3.750, {0x90, 60, 0x1e} },
{ 3.875, {0x80, 60, 0x00} },
{ 3.875, {0x90, 61, 0x1f} },
{ 4.000, {0x80, 61, 0x00} },
{ 4.000, {0x90, 60, 0x20} },
{ 4.125, {0x80, 60, 0x00} },
{ 4.125, {0x90, 61, 0x21} },
{ 4.250, {0x80, 61, 0x00} },
{ 4.250, {0x90, 60, 0x22} },
{ 4.375, {0x80, 60, 0x00} },
{ 4.375, {0x90, 61, 0x23} },
{ 4.500, {0x80, 61, 0x00} },
{ 4.500, {0x90, 60, 0x24} },
{ 4.625, {0x80, 60, 0x00} },
{ 4.625, {0x90, 61, 0x25} },
{ 4.750, {0x80, 61, 0x00} },
{ 4.750, {0x90, 60, 0x26} },
{ 4.875, {0x80, 60, 0x00} },
{ 4.875, {0x90, 61, 0x27} },
{ 5.000, {0x80, 61, 0x00} },
{ 5.000, {0x90, 60, 0x28} },
{ 5.125, {0x80, 60, 0x00} },
{ 5.125, {0x90, 61, 0x29} },
{ 5.250, {0x80, 61, 0x00} },
{ 5.250, {0x90, 60, 0x2a} },
{ 5.375, {0x80, 60, 0x00} },
{ 5.375, {0x90, 61, 0x2b} },
{ 5.500, {0x80, 61, 0x00} },
{ 5.500, {0x90, 60, 0x2c} },
{ 5.625, {0x80, 60, 0x00} },
{ 5.625, {0x90, 61, 0x2d} },
{ 5.750, {0x80, 61, 0x00} },
{ 5.750, {0x90, 60, 0x2e} },
{ 5.875, {0x80, 60, 0x00} },
{ 5.875, {0x90, 61, 0x2f} },
{ 6.000, {0x80, 61, 0x00} },
{ 6.000, {0x90, 60, 0x30} },
{ 6.125, {0x80, 60, 0x00} },
{ 6.125, {0x90, 61, 0x31} },
{ 6.250, {0x80, 61, 0x00} },
{ 6.250, {0x90, 60, 0x32} },
{ 6.375, {0x80, 60, 0x00} },
{ 6.375, {0x90, 61, 0x33} },
{ 6.500, {0x80, 61, 0x00} },
{ 6.500, {0x90, 60, 0x34} },
{ 6.625, {0x80, 60, 0x00} },
{ 6.625, {0x90, 61, 0x35} },
{ 6.750, {0x80, 61, 0x00} },
{ 6.750, {0x90, 60, 0x36} },
{ 6.875, {0x80, 60, 0x00} },
{ 6.875, {0x90, 61, 0x37} },
{ 7.000, {0x80, 61, 0x00} },
{ 7.000, {0x90, 60, 0x38} },
{ 7.125, {0x80, 60, 0x00} },
{ 7.125, {0x90, 61, 0x39} },
{ 7.250, {0x80, 61, 0x00} },
{ 7.250, {0x90, 60, 0x3a} },
{ 7.375, {0x80, 60, 0x00} },
{ 7.375, {0x90, 61, 0x3b} },
{ 7.500, {0x80, 61, 0x00} },
{ 7.500, {0x90, 60, 0x3c} },
{ 7.625, {0x80, 60, 0x00} },
{ 7.625, {0x90, 61, 0x3d} },
{ 7.750, {0x80, 61, 0x00} },
{ 7.750, {0x90, 60, 0x3e} },
{ 7.875, {0x80, 60, 0x00} },
{ 7.875, {0x90, 61, 0x3f} },
{ 8.000, {0x80, 61, 0x00} },
{ 8.000, {0x90, 60, 0x40} },
{ 8.125, {0x80, 60, 0x00} },
{ 8.125, {0x90, 61, 0x41} },
{ 8.250, {0x80, 61, 0x00} },
{ 8.250, {0x90, 60, 0x42} },
{ 8.375, {0x80, 60, 0x00} },
{ 8.375, {0x90, 61, 0x43} },
{ 8.500, {0x80, 61, 0x00} },
{ 8.500, {0x90, 60, 0x44} },
{ 8.625, {0x80, 60, 0x00} },
{ 8.625, {0x90, 61, 0x45} },
{ 8.750, {0x80, 61, 0x00} },
{ 8.750, {0x90, 60, 0x46} },
{ 8.875, {0x80, 60, 0x00} },
{ 8.875, {0x90, 61, 0x47} },
{ 9.000, {0x80, 61, 0x00} },
{ 9.000, {0x90, 60, 0x48} },
{ 9.125, {0x80, 60, 0x00} },
{ 9.125, {0x90, 61, 0x49} },
{ 9.250, {0x80, 61, 0x00} },
{ 9.250, {0x90, 60, 0x4a} },
{ 9.375, {0x80, 60, 0x00} },
{ 9.375, {0x90, 61, 0x4b} },
{ 9.500, {0x80, 61, 0x00} },
{ 9.500, {0x90, 60, 0x4c} },
{ 9.625, {0x80, 60, 0x00} },
{ 9.625, {0x90, 61, 0x4d} },
{ 9.750, {0x80, 61, 0x00} },
{ 9.750, {0x90, 60, 0x4e} },
{ 9.875, {0x80, 60, 0x00} },
{ 9.875, {0x90, 61, 0x4f} },
{10.000, {0x80, 61, 0x00} },
{10.000, {0x90, 60, 0x50} },
{10.125, {0x80, 60, 0x00} },
{10.125, {0x90, 61, 0x51} },
{10.250, {0x80, 61, 0x00} },
{10.250, {0x90, 60, 0x52} },
{10.375, {0x80, 60, 0x00} },
{10.375, {0x90, 61, 0x53} },
{10.500, {0x80, 61, 0x00} },
{10.500, {0x90, 60, 0x54} },
{10.625, {0x80, 60, 0x00} },
{10.625, {0x90, 61, 0x55} },
{10.750, {0x80, 61, 0x00} },
{10.750, {0x90, 60, 0x56} },
{10.875, {0x80, 60, 0x00} },
{10.875, {0x90, 61, 0x57} },
{11.000, {0x80, 61, 0x00} },
{11.000, {0x90, 60, 0x58} },
{11.125, {0x80, 60, 0x00} },
{11.125, {0x90, 61, 0x59} },
{11.250, {0x80, 61, 0x00} },
{11.250, {0x90, 60, 0x5a} },
{11.375, {0x80, 60, 0x00} },
{11.375, {0x90, 61, 0x5b} },
{11.500, {0x80, 61, 0x00} },
{11.500, {0x90, 60, 0x5c} },
{11.625, {0x80, 60, 0x00} },
{11.625, {0x90, 61, 0x5d} },
{11.750, {0x80, 61, 0x00} },
{11.750, {0x90, 60, 0x5e} },
{11.875, {0x80, 60, 0x00} },
{11.875, {0x90, 61, 0x5f} },
{12.000, {0x80, 61, 0x00} },
{12.000, {0x90, 60, 0x60} },
{12.125, {0x80, 60, 0x00} },
{12.125, {0x90, 61, 0x61} },
{12.250, {0x80, 61, 0x00} },
{12.250, {0x90, 60, 0x62} },
{12.375, {0x80, 60, 0x00} },
{12.375, {0x90, 61, 0x63} },
{12.500, {0x80, 61, 0x00} },
{12.500, {0x90, 60, 0x64} },
{12.625, {0x80, 60, 0x00} },
{12.625, {0x90, 61, 0x65} },
{12.750, {0x80, 61, 0x00} },
{12.750, {0x90, 60, 0x66} },
{12.875, {0x80, 60, 0x00} },
{12.875, {0x90, 61, 0x67} },
{13.000, {0x80, 61, 0x00} },
{13.000, {0x90, 60, 0x68} },
{13.125, {0x80, 60, 0x00} },
{13.125, {0x90, 61, 0x69} },
{13.250, {0x80, 61, 0x00} },
{13.250, {0x90, 60, 0x6a} },
{13.375, {0x80, 60, 0x00} },
{13.375, {0x90, 61, 0x6b} },
{13.500, {0x80, 61, 0x00} },
{13.500, {0x90, 60, 0x6c} },
{13.625, {0x80, 60, 0x00} },
{13.625, {0x90, 61, 0x6d} },
{13.750, {0x80, 61, 0x00} },
{13.750, {0x90, 60, 0x6e} },
{13.875, {0x80, 60, 0x00} },
{13.875, {0x90, 61, 0x6f} },
{14.000, {0x80, 61, 0x00} },
{14.000, {0x90, 60, 0x70} },
{14.125, {0x80, 60, 0x00} },
{14.125, {0x90, 61, 0x71} },
{14.250, {0x80, 61, 0x00} },
{14.250, {0x90, 60, 0x72} },
{14.375, {0x80, 60, 0x00} },
{14.375, {0x90, 61, 0x73} },
{14.500, {0x80, 61, 0x00} },
{14.500, {0x90, 60, 0x74} },
{14.625, {0x80, 60, 0x00} },
{14.625, {0x90, 61, 0x75} },
{14.750, {0x80, 61, 0x00} },
{14.750, {0x90, 60, 0x76} },
{14.875, {0x80, 60, 0x00} },
{14.875, {0x90, 61, 0x77} },
{15.000, {0x80, 61, 0x00} },
{15.000, {0x90, 60, 0x78} },
{15.125, {0x80, 60, 0x00} },
{15.125, {0x90, 61, 0x79} },
{15.250, {0x80, 61, 0x00} },
{15.250, {0x90, 60, 0x7a} },
{15.375, {0x80, 60, 0x00} },
{15.375, {0x90, 61, 0x7b} },
{15.500, {0x80, 61, 0x00} },
{15.500, {0x90, 60, 0x7c} },
{15.625, {0x80, 60, 0x00} },
{15.625, {0x90, 61, 0x7d} },
{15.750, {0x80, 61, 0x00} },
{15.750, {0x90, 60, 0x7e} },
{15.875, {0x80, 60, 0x00} },
{15.875, {0x90, 61, 0x7f} },
{16.000, {0x80, 61, 0x00} },
{16.000, {0xff, 255, 0xff} }, // sentinel
};
}} // namespace
#endif