Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions vst/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ smtg_add_vst3plugin(tram8-bridge
source/cids.h
source/midi_engine.h
source/midi_engine.cpp
source/state_format.h
source/processor.h
source/processor.cpp
source/controller.h
Expand Down
24 changes: 11 additions & 13 deletions vst/source/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "pluginterfaces/base/ibstream.h"
#include "plugview.h"
#include "public.sdk/source/vst/vstparameters.h"
#include "state_format.h"

#include <cstdio>

Expand Down Expand Up @@ -123,20 +124,17 @@ tresult PLUGIN_API Controller::setComponentState(IBStream* state) {
if (!state)
return kResultFalse;

int32_t stateWords[kNumGates * MidiEngine::kStateWordsPerGate];
if (!readStateWords(state, stateWords))
return kResultFalse;

for (int i = 0; i < 8; i++) {
int32 chVal = 0, noteVal = 0, modeVal = 0, dacChVal = -1, ccNumVal = 1;
if (state->read(&chVal, sizeof(int32)) != kResultOk)
break;
if (state->read(&noteVal, sizeof(int32)) != kResultOk)
break;
if (state->read(&modeVal, sizeof(int32)) != kResultOk)
break;
if (state->read(&dacChVal, sizeof(int32)) != kResultOk) {
dacChVal = -1;
ccNumVal = 1;
} else if (state->read(&ccNumVal, sizeof(int32)) != kResultOk) {
ccNumVal = 1;
}
int off = i * MidiEngine::kStateWordsPerGate;
int32 chVal = stateWords[off + 0];
int32 noteVal = stateWords[off + 1];
int32 modeVal = stateWords[off + 2];
int32 dacChVal = stateWords[off + 3];
int32 ccNumVal = stateWords[off + 4];

int chStep = chVal + 1;
if (chStep < 0)
Expand Down
30 changes: 4 additions & 26 deletions vst/source/processor.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "processor.h"
#include "cids.h"
#include "../../protocol/tram8_sysex.h"
#include "state_format.h"
#include "pluginterfaces/base/ibstream.h"
#include "pluginterfaces/vst/ivstevents.h"
#include "pluginterfaces/vst/ivstparameterchanges.h"
Expand Down Expand Up @@ -182,38 +183,15 @@ tresult PLUGIN_API Processor::getState(IBStream* state) {
return kResultFalse;
int32_t buf[kNumGates * MidiEngine::kStateWordsPerGate];
engine_.serialize(buf);
return state->write(buf, sizeof(buf)) == kResultOk ? kResultOk : kResultFalse;
return writeStateWords(state, buf) ? kResultOk : kResultFalse;
}

tresult PLUGIN_API Processor::setState(IBStream* state) {
if (!state)
return kResultFalse;
int32_t buf[kNumGates * MidiEngine::kStateWordsPerGate];
engine_.serialize(buf);

for (int i = 0; i < kNumGates; i++) {
int32_t ch, note, mode;
int32_t dCh = -1, ccN = 1;
if (state->read(&ch, sizeof(ch)) != kResultOk)
break;
if (state->read(&note, sizeof(note)) != kResultOk)
break;
if (state->read(&mode, sizeof(mode)) != kResultOk)
break;
if (state->read(&dCh, sizeof(dCh)) != kResultOk) {
dCh = -1;
ccN = 1;
} else if (state->read(&ccN, sizeof(ccN)) != kResultOk) {
ccN = 1;
}

int off = i * MidiEngine::kStateWordsPerGate;
buf[off + 0] = ch;
buf[off + 1] = note;
buf[off + 2] = mode;
buf[off + 3] = dCh;
buf[off + 4] = ccN;
}
if (!readStateWords(state, buf))
return kResultFalse;

engine_.deserialize(buf);
return kResultOk;
Expand Down
112 changes: 112 additions & 0 deletions vst/source/state_format.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#pragma once

#include "midi_engine.h"
#include "pluginterfaces/base/ibstream.h"

#include <cstdint>

namespace tram8 {

static constexpr int32_t kStateMagic = 0x54523853; // "TR8S"
static constexpr int32_t kStateVersion = 1;
static constexpr int kLegacyStateWordsPerGate = 3;

inline bool streamReadInt32(Steinberg::IBStream* stream, int32_t& value) {
Steinberg::int32 bytesRead = 0;
return stream->read(&value, sizeof(value), &bytesRead) == Steinberg::kResultOk && bytesRead == sizeof(value);
}

inline bool streamWriteInt32(Steinberg::IBStream* stream, int32_t value) {
Steinberg::int32 bytesWritten = 0;
return stream->write(&value, sizeof(value), &bytesWritten) == Steinberg::kResultOk && bytesWritten == sizeof(value);
}

inline bool streamRemainingBytes(Steinberg::IBStream* stream, Steinberg::int64& remaining) {
Steinberg::int64 start = 0;
Steinberg::int64 end = 0;
if (stream->tell(&start) != Steinberg::kResultOk)
return false;
if (stream->seek(0, Steinberg::IBStream::kIBSeekEnd, &end) != Steinberg::kResultOk)
return false;
if (stream->seek(start, Steinberg::IBStream::kIBSeekSet) != Steinberg::kResultOk)
return false;
remaining = end - start;
return remaining >= 0;
}

inline bool readLegacyStateWords(Steinberg::IBStream* stream, int32_t firstWord, int wordsPerGate, int32_t* out) {
for (int gate = 0; gate < kNumGates; gate++) {
int32_t ch = firstWord;
if (gate != 0 && !streamReadInt32(stream, ch))
return false;

int32_t note = 0;
int32_t mode = 0;
int32_t dacChannel = -1;
int32_t ccNumber = 1;
if (!streamReadInt32(stream, note) || !streamReadInt32(stream, mode))
return false;
if (wordsPerGate == MidiEngine::kStateWordsPerGate &&
(!streamReadInt32(stream, dacChannel) || !streamReadInt32(stream, ccNumber))) {
return false;
}

int off = gate * MidiEngine::kStateWordsPerGate;
out[off + 0] = ch;
out[off + 1] = note;
out[off + 2] = mode;
out[off + 3] = dacChannel;
out[off + 4] = ccNumber;
}
return true;
}

inline bool readStateWords(Steinberg::IBStream* stream, int32_t* out) {
Steinberg::int64 remaining = 0;
bool hasSize = streamRemainingBytes(stream, remaining);

int32_t first = 0;
if (!streamReadInt32(stream, first))
return false;

constexpr Steinberg::int64 kVersionedBytes =
(2 + kNumGates * MidiEngine::kStateWordsPerGate) * (Steinberg::int64)sizeof(int32_t);
constexpr Steinberg::int64 kLegacyBytes =
(kNumGates * MidiEngine::kStateWordsPerGate) * (Steinberg::int64)sizeof(int32_t);
constexpr Steinberg::int64 kLegacy3Bytes = (kNumGates * kLegacyStateWordsPerGate) * (Steinberg::int64)sizeof(int32_t);

if (first == kStateMagic) {
if (hasSize && remaining != kVersionedBytes)
return false;
int32_t version = 0;
if (!streamReadInt32(stream, version) || version != kStateVersion)
return false;
for (int i = 0; i < kNumGates * MidiEngine::kStateWordsPerGate; i++) {
if (!streamReadInt32(stream, out[i]))
return false;
}
return true;
}

if (hasSize) {
if (remaining == kLegacyBytes)
return readLegacyStateWords(stream, first, MidiEngine::kStateWordsPerGate, out);
if (remaining == kLegacy3Bytes)
return readLegacyStateWords(stream, first, kLegacyStateWordsPerGate, out);
return false;
}

return readLegacyStateWords(stream, first, MidiEngine::kStateWordsPerGate, out);
}

inline bool writeStateWords(Steinberg::IBStream* stream, const int32_t* words) {
if (!streamWriteInt32(stream, kStateMagic) || !streamWriteInt32(stream, kStateVersion))
return false;
for (int i = 0; i < kNumGates * MidiEngine::kStateWordsPerGate; i++) {
if (!streamWriteInt32(stream, words[i]))
return false;
}
return true;
}

} // namespace tram8
2 changes: 1 addition & 1 deletion vst/tests/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
CXX = c++
CXXFLAGS = -Wall -Wextra -std=c++17 -g -I../source
CXXFLAGS = -Wall -Wextra -std=c++17 -g -I../source -I../external/vst3sdk

TESTS = test_midi_engine

Expand Down
Loading
Loading