// Copyright 2021 Jean Pierre Cimalando // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // SPDX-License-Identifier: Apache-2.0 // #include "ysfx_midi.hpp" #include #include void ysfx_midi_reserve(ysfx_midi_buffer_t *midi, uint32_t capacity, bool extensible) { std::vector data; data.reserve(capacity); std::swap(data, midi->data); midi->extensible = extensible; ysfx_midi_rewind(midi); } void ysfx_midi_clear(ysfx_midi_buffer_t *midi) { midi->data.clear(); ysfx_midi_rewind(midi); } bool ysfx_midi_push(ysfx_midi_buffer_t *midi, const ysfx_midi_event_t *event) { if (event->size > ysfx_midi_message_max_size) return false; if (event->bus >= ysfx_max_midi_buses) return false; ysfx_midi_header_t header; if (!midi->extensible) { size_t writable = midi->data.capacity() - midi->data.size(); if (writable < sizeof(header) + event->size) return false; } const uint8_t *data = event->data; const uint8_t *headp = (const uint8_t *)&header; header.bus = event->bus; header.offset = event->offset; header.size = event->size; midi->data.insert(midi->data.end(), headp, headp + sizeof(header)); midi->data.insert(midi->data.end(), data, data + header.size); return true; } void ysfx_midi_rewind(ysfx_midi_buffer_t *midi) { midi->read_pos = 0; for (uint32_t i = 0; i < ysfx_max_midi_buses; ++i) midi->read_pos_for_bus[i] = 0; } bool ysfx_midi_get_next(ysfx_midi_buffer_t *midi, ysfx_midi_event_t *event) { size_t *pos_ptr = &midi->read_pos; size_t pos = *pos_ptr; size_t avail = midi->data.size() - pos; ysfx_midi_header_t header; if (avail == 0) return false; assert(avail >= sizeof(header)); memcpy(&header, &midi->data[pos], sizeof(header)); assert(avail >= sizeof(header) + header.size); event->bus = header.bus; event->offset = header.offset; event->size = header.size; event->data = &midi->data[pos + sizeof(header)]; *pos_ptr = pos + (sizeof(header) + header.size); return true; } bool ysfx_midi_get_next_from_bus(ysfx_midi_buffer_t *midi, uint32_t bus, ysfx_midi_event_t *event) { if (bus >= ysfx_max_midi_buses) return false; size_t *pos_ptr = &midi->read_pos_for_bus[bus]; size_t pos = *pos_ptr; size_t avail = midi->data.size() - pos; ysfx_midi_header_t header; bool found = false; while (!found && avail > 0) { assert(avail >= sizeof(header)); memcpy(&header, &midi->data[pos], sizeof(header)); assert(avail >= sizeof(header) + header.size); found = header.bus == bus; if (!found) { pos += sizeof(header) + header.size; avail -= sizeof(header) + header.size; } } if (!found) { *pos_ptr = pos; return false; } event->bus = header.bus; event->offset = header.offset; event->size = header.size; event->data = &midi->data[pos + sizeof(header)]; *pos_ptr = pos + (sizeof(header) + header.size); return true; } bool ysfx_midi_push_begin(ysfx_midi_buffer_t *midi, uint32_t bus, uint32_t offset, ysfx_midi_push_t *mp) { ysfx_midi_header_t header; mp->midi = midi; mp->start = midi->data.size(); mp->count = 0; mp->eob = false; if (!midi->extensible) { size_t writable = midi->data.capacity() - midi->data.size(); if (writable < sizeof(header)) { mp->eob = true; return false; } } header.bus = bus; header.offset = offset; header.size = 0; const uint8_t *headp = (const uint8_t *)&header; midi->data.insert(midi->data.end(), headp, headp + sizeof(header)); return true; } bool ysfx_midi_push_data(ysfx_midi_push_t *mp, const uint8_t *data, uint32_t size) { if (mp->eob) return false; if (size > ysfx_midi_message_max_size || mp->count + size > ysfx_midi_message_max_size) { mp->eob = true; return false; } ysfx_midi_buffer_t *midi = mp->midi; if (!midi->extensible) { size_t writable = midi->data.capacity() - midi->data.size(); if (writable < size) { mp->eob = true; return false; } } midi->data.insert(midi->data.end(), data, data + size); mp->count += size; return true; } bool ysfx_midi_push_end(ysfx_midi_push_t *mp) { if (mp->eob) { mp->midi->data.resize(mp->start); return false; } ysfx_midi_header_t header; uint8_t *headp = &mp->midi->data[mp->start]; memcpy(&header, headp, sizeof(header)); header.size = mp->count; memcpy(headp, &header, sizeof(header)); return true; } //------------------------------------------------------------------------------ uint32_t ysfx_midi_sizeof(uint8_t id) { if ((id >> 7) == 0) { return 0; } else if ((id >> 4) != 0b1111) { static const uint8_t sizetable[8] = { 3, 3, 3, 3, 2, 2, 3, }; return sizetable[(id >> 4) & 0b111]; } else { static const uint8_t sizetable[16] = { 0, 2, 3, 2, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, }; return sizetable[id & 0b1111]; } }