Skip to content

Commit

Permalink
Merge branch 'pr43/swesterfeld-midi-events-uint-offset' - closes #26
Browse files Browse the repository at this point in the history
* pr43/swesterfeld-midi-events-uint-offset:
  devices/liquidsfz/liquidsfz.cc: avoid using printf (use printerr instead)
  ASE: midievent.hh: fix clang tidy problem (add typename)
  devices/saturation/saturation.cc: midi event frame offsets are now unsigned
  devices/liquidsfz/liquidsfz.cc: midi event frame offsets are now unsigned
  devices/blepsynth/blepsynth.cc: midi event frame offsets are now unsigned
  ASE: midilib.cc: midi event frame offsets are now always positive (#26)
  ASE: clapplugin.cc: midi event frame offsets are now always positive (#26)
  ASE: midievent: avoid negative frame offsets in midi events
	Use unsigned data type for midi event offset, see issue #26.
  ase/memory.cc: avoid constexpr std::string use that needs clang++-17

Signed-off-by: Tim Janik <[email protected]>
  • Loading branch information
tim-janik committed Feb 14, 2024
2 parents 02e6083 + 25c0f8a commit 714ea0c
Show file tree
Hide file tree
Showing 8 changed files with 38 additions and 41 deletions.
16 changes: 8 additions & 8 deletions ase/clapplugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -555,55 +555,55 @@ ClapAudioProcessor::convert_clap_events (const clap_process_t &process, const bo
case MidiMessage::NOTE_OFF:
case MidiMessage::AFTERTOUCH:
if (as_clapnotes && ev.type == MidiEvent::AFTERTOUCH) {
expr = setup_expression (&input_events_[j++], MAX (ev.frame, 0), 0);
expr = setup_expression (&input_events_[j++], ev.frame, 0);
expr->expression_id = CLAP_NOTE_EXPRESSION_PRESSURE;
expr->note_id = ev.noteid;
expr->channel = ev.channel;
expr->key = ev.key;
expr->value = ev.velocity;
} else if (as_clapnotes) {
evnote = setup_evnote (&input_events_[j++], MAX (ev.frame, 0), 0);
evnote = setup_evnote (&input_events_[j++], ev.frame, 0);
evnote->header.type = ev.type == MidiEvent::NOTE_ON ? CLAP_EVENT_NOTE_ON : CLAP_EVENT_NOTE_OFF;
evnote->note_id = ev.noteid;
evnote->channel = ev.channel;
evnote->key = ev.key;
evnote->velocity = ev.velocity;
} else {
midi1 = setup_midi1 (&input_events_[j++], MAX (ev.frame, 0), 0);
midi1 = setup_midi1 (&input_events_[j++], ev.frame, 0);
midi1->data[0] = uint8_t (ev.type) | (ev.channel & 0xf);
midi1->data[1] = ev.key;
midi1->data[2] = std::min (uint8_t (ev.velocity * 127), uint8_t (127));
}
break;
case MidiMessage::ALL_NOTES_OFF:
if (as_clapnotes) {
evnote = setup_evnote (&input_events_[j++], MAX (ev.frame, 0), 0);
evnote = setup_evnote (&input_events_[j++], ev.frame, 0);
evnote->header.type = CLAP_EVENT_NOTE_CHOKE;
evnote->note_id = -1;
evnote->channel = -1;
evnote->key = -1;
evnote->velocity = 0;
} else {
midi1 = setup_midi1 (&input_events_[j++], MAX (ev.frame, 0), 0);
midi1 = setup_midi1 (&input_events_[j++], ev.frame, 0);
midi1->data[0] = 0xB0 | (ev.channel & 0xf);
midi1->data[1] = 123;
midi1->data[2] = 0;
}
break;
case MidiMessage::CONTROL_CHANGE:
midi1 = setup_midi1 (&input_events_[j++], MAX (ev.frame, 0), 0);
midi1 = setup_midi1 (&input_events_[j++], ev.frame, 0);
midi1->data[0] = 0xB0 | (ev.channel & 0xf);
midi1->data[1] = ev.param;
midi1->data[2] = ev.cval;
break;
case MidiMessage::CHANNEL_PRESSURE:
midi1 = setup_midi1 (&input_events_[j++], MAX (ev.frame, 0), 0);
midi1 = setup_midi1 (&input_events_[j++], ev.frame, 0);
midi1->data[0] = 0xD0 | (ev.channel & 0xf);
midi1->data[1] = std::min (uint8_t (ev.velocity * 127), uint8_t (127));
midi1->data[2] = 0;
break;
case MidiMessage::PITCH_BEND:
midi1 = setup_midi1 (&input_events_[j++], MAX (ev.frame, 0), 0);
midi1 = setup_midi1 (&input_events_[j++], ev.frame, 0);
midi1->data[0] = 0xE0 | (ev.channel & 0xf);
midi1->data[1] = std::min (uint8_t (ev.velocity * 127), uint8_t (127));
midi1->data[2] = 0;
Expand Down
4 changes: 2 additions & 2 deletions ase/memory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -567,9 +567,9 @@ class CStringTable {
StrPtrMap quarks_;
std::vector<const String*> strings_;
std::shared_mutex mutex_;
static constexpr String empty_string;
CStringTable()
{
static String empty_string;
strings_ = { &empty_string }; // ID==0
quarks_[&empty_string] = 0;
}
Expand Down Expand Up @@ -608,7 +608,7 @@ CStringTable::lookup (uint quark) noexcept
const std::unique_lock ulock (mutex_);
if (quark < strings_.size()) [[likely]]
return *strings_[quark];
return empty_string;
return *strings_[0]; // empty_string;
}

/// Assign a std::string to a CString, after deduplication, its memory is never released.
Expand Down
21 changes: 12 additions & 9 deletions ase/midievent.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,32 +50,32 @@ MidiEvent::to_string () const
switch (type)
{
case PARAM_VALUE:
return string_format ("%+4d ch=%-2u %s param=%d pvalue=%.5f",
return string_format ("%4u ch=%-2u %s param=%d pvalue=%.5f",
frame, channel, "PARAM_VALUE", param, pvalue);
case NOTE_OFF: if (!et) et = "NOTE_OFF";
/* fall-through */
case NOTE_ON: if (!et) et = "NOTE_ON";
/* fall-through */
case AFTERTOUCH: if (!et) et = "AFTERTOUCH";
return string_format ("%+4d ch=%-2u %-10s pitch=%d vel=%f tune=%f id=%x",
return string_format ("%4u ch=%-2u %-10s pitch=%d vel=%f tune=%f id=%x",
frame, channel, et, key, velocity, tuning, noteid);
case CONTROL_CHANGE: if (!et) et = "CONTROL_CHANGE";
return string_format ("%+4d ch=%-2u %s control=%d value=%f (%02x) {%u}",
return string_format ("%4u ch=%-2u %s control=%d value=%f (%02x) {%u}",
frame, channel, et, param, value, cval, fragment);
case PROGRAM_CHANGE: if (!et) et = "PROGRAM_CHANGE";
return string_format ("%+4d ch=%-2u %s program=%d",
return string_format ("%4u ch=%-2u %s program=%d",
frame, channel, et, param);
case CHANNEL_PRESSURE: if (!et) et = "CHANNEL_PRESSURE";
/* fall-through */
case PITCH_BEND: if (!et) et = "PITCH_BEND";
return string_format ("%+4d ch=%-2u %s value=%+f",
return string_format ("%4u ch=%-2u %s value=%+f",
frame, channel, et, value);
case SYSEX: if (!et) et = "SYSEX";
return string_format ("%+4d %s (unhandled)", frame, et);
return string_format ("%4u %s (unhandled)", frame, et);
}
static_assert (sizeof (MidiEvent) >= 2 * sizeof (uint64_t));
const uint64_t *uu = reinterpret_cast<const uint64_t*> (this);
return string_format ("%+4d MidiEvent-%u (%08x %08x)", frame, type, uu[0], uu[1]);
return string_format ("%4u MidiEvent-%u (%08x %08x)", frame, type, uu[0], uu[1]);
}

MidiEvent
Expand Down Expand Up @@ -190,7 +190,10 @@ MidiEventOutput::append (int16_t frame, const MidiEvent &event)
bool
MidiEventOutput::append_unsorted (int16_t frame, const MidiEvent &event)
{
const int64_t last_event_stamp = !events_.empty() ? events_.back().frame : -2048;
// we discard timing information by ignoring negative frame offsets here (#26)
// when we implement recording, we might want to preserve the exact timestamp
frame = std::max<int16_t> (frame, 0);
const int64_t last_event_stamp = !events_.empty() ? events_.back().frame : 0;
events_.push_back (event);
events_.back().frame = frame;
return frame < last_event_stamp;
Expand All @@ -209,7 +212,7 @@ MidiEventOutput::ensure_order ()
int64_t
MidiEventOutput::last_frame () const
{
return !events_.empty() ? events_.back().frame : -2048;
return !events_.empty() ? events_.back().frame : 0;
}

} // Ase
6 changes: 3 additions & 3 deletions ase/midievent.hh
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ enum class MidiMessage : int32_t {
/// MidiEvent data structure.
struct MidiEvent {
using enum MidiEventType;
static_assert (AUDIO_BLOCK_MAX_RENDER_SIZE <= 2048); // -2048…+2047 fits frame
int frame : 12; ///< Offset into current block, delayed if negative
static_assert (AUDIO_BLOCK_MAX_RENDER_SIZE <= 4096); // 0…+4095 fits frame
uint frame : 12; ///< Offset into current block, delayed if negative
uint channel : 4; ///< 0…15 for standard events
MidiEventType type; ///< MidiEvent type, one of the MidiEventType members
union {
Expand Down Expand Up @@ -118,7 +118,7 @@ class MidiEventReader : QueueMultiplexer<MAXQUEUES,std::vector<MidiEvent>::const
using Base = QueueMultiplexer<MAXQUEUES,std::vector<MidiEvent>::const_iterator>;
ASE_CLASS_NON_COPYABLE (MidiEventReader);
public:
using iterator = Base::iterator;
using iterator = typename Base::iterator;
using Base::assign;
size_t events_pending () const { return this->count_pending(); }
iterator begin () { return this->Base::begin(); }
Expand Down
4 changes: 2 additions & 2 deletions ase/midilib.cc
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class MidiProducerImpl : public MidiProducerIface {
TickEvent tnote = future_stack.back();
future_stack.pop_back();
const int64 frame = transport.sample_from_tick (tnote.tick - begin_tick);
assert_paranoid (frame >= -2048 && frame <= 2047);
assert_paranoid (frame >= 0 && frame <= 4095);
MDEBUG ("POP: t=%d ev=%s f=%d\n", tnote.tick, tnote.event.to_string(), frame);
evout.append_unsorted (frame, tnote.event);
}
Expand All @@ -171,7 +171,7 @@ class MidiProducerImpl : public MidiProducerIface {
if (etick < end_tick)
{
const int64 frame = transport.sample_from_tick (etick - begin_tick);
assert_paranoid (frame >= -2048 && frame <= 2047);
assert_paranoid (frame >= 0 && frame <= 4095);
// interleave with earlier MIDI through events
evout.append_unsorted (frame, event);
MDEBUG ("NOW: t=%d ev=%s f=%d\n", etick, event.to_string(), frame);
Expand Down
6 changes: 2 additions & 4 deletions devices/blepsynth/blepsynth.cc
Original file line number Diff line number Diff line change
Expand Up @@ -996,11 +996,9 @@ class BlepSynth : public AudioProcessor {
MidiEventInput evinput = midi_event_input();
for (const auto &ev : evinput)
{
uint frame = std::max<int> (ev.frame, 0); // TODO: should be unsigned anyway, issue #26

// process any audio that is before the event
render_audio (left_out + offset, right_out + offset, frame - offset);
offset = frame;
render_audio (left_out + offset, right_out + offset, ev.frame - offset);
offset = ev.frame;

switch (ev.message())
{
Expand Down
16 changes: 7 additions & 9 deletions devices/liquidsfz/liquidsfz.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ class LiquidSFZLoader
{
if (want_sfz_ != have_sfz_)
{
printf ("LiquidSFZ: loading %s...", want_sfz_.c_str());
fflush (stdout);
printerr ("LiquidSFZ: loading %s...", want_sfz_.c_str());
bool result = synth_.load (want_sfz_);
printf ("%s\n", result ? "OK" : "FAIL");
printerr ("%s\n", result ? "OK" : "FAIL");
// TODO: handle load error

have_sfz_ = want_sfz_;
Expand All @@ -51,22 +50,22 @@ class LiquidSFZLoader
state_.store (STATE_IDLE);
}
}
printf ("run() done\n");
printerr ("LiquidSFZ: run() done\n");
}
public:
LiquidSFZLoader (Synth &synth) :
synth_ (synth)
{
thread_ = std::thread (&LiquidSFZLoader::run, this);
want_sfz_.reserve (4096); // avoid allocations in audio thread
printf ("LiquidSFZLoader()\n");
printerr ("LiquidSFZLoader()\n");
}
~LiquidSFZLoader()
{
quit_.store (1);
sem_.post();
thread_.join();
printf ("~LiquidSFZLoader()\n");
printerr ("~LiquidSFZLoader()\n");
}
// called from audio thread
bool
Expand Down Expand Up @@ -182,14 +181,13 @@ class LiquidSFZ : public AudioProcessor {
MidiEventInput evinput = midi_event_input();
for (const auto &ev : evinput)
{
const int time_stamp = std::max<int> (ev.frame, 0);
switch (ev.message())
{
case MidiMessage::NOTE_OFF:
synth_.add_event_note_off (time_stamp, ev.channel, ev.key);
synth_.add_event_note_off (ev.frame, ev.channel, ev.key);
break;
case MidiMessage::NOTE_ON:
synth_.add_event_note_on (time_stamp, ev.channel, ev.key, std::clamp (irintf (ev.velocity * 127), 0, 127));
synth_.add_event_note_on (ev.frame, ev.channel, ev.key, std::clamp (irintf (ev.velocity * 127), 0, 127));
break;
case MidiMessage::ALL_NOTES_OFF:
case MidiMessage::ALL_SOUND_OFF:
Expand Down
6 changes: 2 additions & 4 deletions devices/saturation/saturation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,9 @@ class Saturation : public AudioProcessor {
MidiEventInput evinput = midi_event_input();
for (const auto &ev : evinput)
{
uint frame = std::max<int> (ev.frame, 0); // TODO: should be unsigned anyway, issue #26

// process any audio that is before the event
render_audio (left_in + offset, right_in + offset, left_out + offset, right_out + offset, frame - offset);
offset = frame;
render_audio (left_in + offset, right_in + offset, left_out + offset, right_out + offset, ev.frame - offset);
offset = ev.frame;

switch (ev.message())
{
Expand Down

0 comments on commit 714ea0c

Please sign in to comment.