Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use channel pressure as aftertouch #170

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
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
40 changes: 34 additions & 6 deletions mopo/src/arpeggiator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,19 @@ namespace mopo {
}

// Check if it's time to play the next note.
// FIXME: handle channel
if (getNumNotes() && new_phase >= 1) {
int offset = utils::iclamp((1 - phase_) / delta_phase, 0, buffer_size_ - 1);
std::pair<mopo_float, mopo_float> note = getNextNote();
note_handler_->noteOn(note.first, note.second, offset);
last_played_note_ = note.first;
std::tuple<mopo_float, mopo_float, int, mopo_float> note = getNextNote();
note_handler_->noteOn(std::get<0>(note), std::get<1>(note), offset, std::get<2>(note), std::get<3>(note));
last_played_note_ = std::get<0>(note);
phase_ = new_phase - 1.0;
}
else
phase_ = new_phase;
}

std::pair<mopo_float, mopo_float> Arpeggiator::getNextNote() {
std::tuple<mopo_float, mopo_float, int, mopo_float> Arpeggiator::getNextNote() {
int octaves = utils::imax(1, input(kOctaves)->at(0));
Pattern type =
static_cast<Pattern>(static_cast<int>(input(kPattern)->at(0)));
Expand Down Expand Up @@ -115,7 +116,10 @@ namespace mopo {
mopo_float base_note = pattern->at(note_index_);
mopo_float note = base_note + mopo::NOTES_PER_OCTAVE * current_octave_;
mopo_float velocity = active_notes_[base_note];
return std::pair<mopo_float, mopo_float>(note, velocity);
int channel = channel_[base_note];
mopo_float aftertouch = aftertouch_[base_note];

return std::tuple<mopo_float, mopo_float, int, mopo_float>(note, velocity, channel, aftertouch);
}

CircularQueue<mopo_float>& Arpeggiator::getPressedNotes() {
Expand Down Expand Up @@ -152,6 +156,8 @@ namespace mopo {

void Arpeggiator::allNotesOff(int sample) {
active_notes_.clear();
channel_.clear();
aftertouch_.clear();
pressed_notes_.clear();
sustained_notes_.clear();
ascending_.clear();
Expand All @@ -160,7 +166,7 @@ namespace mopo {
note_handler_->allNotesOff();
}

void Arpeggiator::noteOn(mopo_float note, mopo_float velocity, int sample, int channel) {
void Arpeggiator::noteOn(mopo_float note, mopo_float velocity, int sample, int channel, mopo_float aftertouch) {
if (active_notes_.count(note))
return;
if (pressed_notes_.size() == 0) {
Expand All @@ -169,6 +175,8 @@ namespace mopo {
phase_ = 1.0;
}
active_notes_[note] = velocity;
channel_[note] = channel;
aftertouch_[note] = aftertouch;
pressed_notes_.push_back(note);
addNoteToPatterns(note);
}
Expand All @@ -181,10 +189,30 @@ namespace mopo {
sustained_notes_.push_back(note);
else {
active_notes_.erase(note);
channel_.erase(note);
aftertouch_.erase(note);
removeNoteFromPatterns(note);
}

pressed_notes_.remove(note);
return kVoiceOff;
}

void Arpeggiator::setAftertouch(mopo_float note, mopo_float aftertouch, int sample) {
// TODO: take channel into account
for (const auto &n : pressed_notes_) {
if (n == note) {
aftertouch_[n] = aftertouch;
}
}
}

void Arpeggiator::setPressure(mopo_float pressure, int channel, int sample) {
MOPO_ASSERT(channel >= 0 && channel <= mopo::NUM_MIDI_CHANNELS);
for (const auto &n : pressed_notes_) {
if (channel_[n] == channel) {
aftertouch_[n] = pressure;
}
}
}
} // namespace mopo
13 changes: 11 additions & 2 deletions mopo/src/arpeggiator.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,21 @@ namespace mopo {

int getNumNotes() { return pressed_notes_.size(); }
CircularQueue<mopo_float>& getPressedNotes();
std::pair<mopo_float, mopo_float> getNextNote();
// tuple: note, velocity, channel, aftertouch
std::tuple<mopo_float, mopo_float, int, mopo_float> getNextNote();
void addNoteToPatterns(mopo_float note);
void removeNoteFromPatterns(mopo_float note);

void allNotesOff(int sample = 0) override;
void noteOn(mopo_float note, mopo_float velocity = 1,
int sample = 0, int channel = 0) override;
int sample = 0, int channel = 0, mopo_float aftertouch = 0) override;
VoiceEvent noteOff(mopo_float note, int sample = 0) override;
void sustainOn();
void sustainOff();

void setAftertouch(mopo_float note, mopo_float aftertouch, int sample = 0);
void setPressure(mopo_float pressure, int channel = 0, int sample = 0);


private:
Arpeggiator() : Processor(0, 0) { }
Expand All @@ -89,8 +94,12 @@ namespace mopo {
std::vector<mopo_float> decending_;

std::map<mopo_float, mopo_float> active_notes_;
std::map<mopo_float, int> channel_;
std::map<mopo_float, mopo_float> aftertouch_;

CircularQueue<mopo_float> pressed_notes_;
CircularQueue<mopo_float> sustained_notes_;

};
} // namespace mopo

Expand Down
2 changes: 1 addition & 1 deletion mopo/src/note_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ namespace mopo {
virtual ~NoteHandler() { }
virtual void allNotesOff(int sample = 0) = 0;
virtual void noteOn(mopo_float note, mopo_float velocity = 1,
int sample = 0, int channel = 0) = 0;
int sample = 0, int channel = 0, mopo_float aftertouch = 0) = 0;
virtual VoiceEvent noteOff(mopo_float note, int sample = 0) = 0;
};
} // namespace mopo
Expand Down
14 changes: 11 additions & 3 deletions mopo/src/voice_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ namespace mopo {
return 0;
}

void VoiceHandler::noteOn(mopo_float note, mopo_float velocity, int sample, int channel) {
void VoiceHandler::noteOn(mopo_float note, mopo_float velocity, int sample, int channel, mopo_float aftertouch) {
MOPO_ASSERT(sample >= 0 && sample < buffer_size_);
MOPO_ASSERT(channel >= 0 && channel < NUM_MIDI_CHANNELS);

Expand All @@ -299,7 +299,7 @@ namespace mopo {

if (last_played_note_ < 0)
last_played_note_ = note;
voice->activate(note, velocity, last_played_note_, pressed_notes_.size(), sample, channel);
voice->activate(note, velocity, last_played_note_, pressed_notes_.size(), sample, channel, aftertouch);
active_voices_.push_back(voice);
last_played_note_ = note;
}
Expand All @@ -323,7 +323,7 @@ namespace mopo {
pressed_notes_.pop_back();
pressed_notes_.push_front(old_note);
new_voice->activate(old_note, voice->state().velocity, last_played_note_,
pressed_notes_.size() + 1, sample);
pressed_notes_.size() + 1, sample);
last_played_note_ = old_note;

voice_event = kVoiceReset;
Expand All @@ -342,6 +342,14 @@ namespace mopo {
voice->setAftertouch(aftertouch, sample);
}
}

void VoiceHandler::setPressure(mopo_float pressure, int channel, int sample) {
MOPO_ASSERT(channel >= 0 && channel <= mopo::NUM_MIDI_CHANNELS);
for (Voice* voice : active_voices_) {
if (voice->state().channel == channel)
voice->setAftertouch(pressure, sample);
}
}

void VoiceHandler::setPolyphony(size_t polyphony) {
while (all_voices_.size() < polyphony) {
Expand Down
7 changes: 4 additions & 3 deletions mopo/src/voice_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,15 @@ namespace mopo {

void activate(mopo_float note, mopo_float velocity,
mopo_float last_note, int note_pressed = 0,
int sample = 0, int channel = 0) {
int sample = 0, int channel = 0, mopo_float aftertouch = 0) {
event_sample_ = sample;
state_.event = kVoiceOn;
state_.note = note;
state_.velocity = velocity;
state_.last_note = last_note;
state_.note_pressed = note_pressed;
state_.channel = channel;
aftertouch_ = velocity;
aftertouch_ = aftertouch;
aftertouch_sample_ = sample;
key_state_ = kHeld;
}
Expand Down Expand Up @@ -143,9 +143,10 @@ namespace mopo {

void allNotesOff(int sample = 0) override;
virtual void noteOn(mopo_float note, mopo_float velocity = 1,
int sample = 0, int channel = 0) override;
int sample = 0, int channel = 0, mopo_float aftertouch = 0) override;
virtual VoiceEvent noteOff(mopo_float note, int sample = 0) override;
void setAftertouch(mopo_float note, mopo_float aftertouch, int sample = 0);
void setPressure(mopo_float pressure, int channel = 0, int sample = 0);
void sustainOn();
void sustainOff(int sample = 0);

Expand Down
11 changes: 10 additions & 1 deletion src/common/midi_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ void MidiManager::removeNextBlockOfMessages(MidiBuffer& buffer, int num_samples)
midi_collector_.removeNextBlockOfMessages(buffer, num_samples);
}

void MidiManager::processMidiMessage(const MidiMessage& midi_message, int sample_position) {
void MidiManager::processMidiMessage(const MidiMessage& midi_message, int sample_position) {
if (midi_message.isProgramChange()) {
current_patch_ = midi_message.getProgramChangeNumber();
File patch = LoadSave::loadPatch(current_bank_, current_folder_, current_patch_,
Expand All @@ -114,11 +114,20 @@ void MidiManager::processMidiMessage(const MidiMessage& midi_message, int sample
engine_->sustainOn();
else if (midi_message.isSustainPedalOff())
engine_->sustainOff();
// "aftertouch" is pressure per note
else if (midi_message.isAftertouch()) {
mopo::mopo_float note = midi_message.getNoteNumber();
mopo::mopo_float value = (1.0 * midi_message.getAfterTouchValue()) / mopo::MIDI_SIZE;
engine_->setAftertouch(note, value);
}
// "pressure" is aftertouch for a whole channel (e.g. keyboard send only one value even if several keys are pressed)
// TODO: create a separate modifier
else if (midi_message.isChannelPressure()) {
mopo::mopo_float note = midi_message.getNoteNumber();
mopo::mopo_float value = (1.0 * midi_message.getChannelPressureValue()) / (mopo::MIDI_SIZE - 1.0);
// channel - 1 as with NoteOn above
engine_->setPressure(value, midi_message.getChannel() - 1, sample_position);
}
else if (midi_message.isPitchWheel()) {
double percent = (1.0 * midi_message.getPitchWheelValue()) / PITCH_WHEEL_RESOLUTION;
double value = 2 * percent - 1.0;
Expand Down
15 changes: 12 additions & 3 deletions src/synthesis/helm_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,11 +376,11 @@ namespace mopo {
arpeggiator_->allNotesOff(sample);
}

void HelmEngine::noteOn(mopo_float note, mopo_float velocity, int sample, int channel) {
void HelmEngine::noteOn(mopo_float note, mopo_float velocity, int sample, int channel, mopo_float aftertouch) {
if (arp_on_->value())
arpeggiator_->noteOn(note, velocity, sample);
arpeggiator_->noteOn(note, velocity, sample, channel, aftertouch);
else
voice_handler_->noteOn(note, velocity, sample, channel);
voice_handler_->noteOn(note, velocity, sample, channel, aftertouch);
}

VoiceEvent HelmEngine::noteOff(mopo_float note, int sample) {
Expand All @@ -396,8 +396,17 @@ namespace mopo {
void HelmEngine::setPitchWheel(mopo_float value, int channel) {
voice_handler_->setPitchWheel(value, channel);
}

void HelmEngine::setPressure(mopo_float value, int channel, int sample) {
if (arp_on_->value())
arpeggiator_->setPressure(value, channel, sample);
voice_handler_->setPressure(value, channel, sample);
}

void HelmEngine::setAftertouch(mopo_float note, mopo_float value, int sample) {
// TODO: take channel into account
if (arp_on_->value())
arpeggiator_->setAftertouch(note, value, sample);
voice_handler_->setAftertouch(note, value, sample);
}

Expand Down
3 changes: 2 additions & 1 deletion src/synthesis/helm_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,14 @@ namespace mopo {
// Keyboard events.
void allNotesOff(int sample = 0) override;
void noteOn(mopo_float note, mopo_float velocity = 1.0,
int sample = 0, int channel = 0) override;
int sample = 0, int channel = 0, mopo_float aftertouch = 0) override;
VoiceEvent noteOff(mopo_float note, int sample = 0) override;
void setModWheel(mopo_float value, int channel = 0);
void setPitchWheel(mopo_float value, int channel = 0);
void setBpm(mopo_float bpm);
void correctToTime(mopo_float samples) override;
void setAftertouch(mopo_float note, mopo_float value, int sample = 0);
void setPressure(mopo_float value, int channel = 0, int sample = 0);

// Sustain pedal events.
void sustainOn();
Expand Down
4 changes: 2 additions & 2 deletions src/synthesis/helm_voice_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -756,10 +756,10 @@ namespace mopo {
}
}

void HelmVoiceHandler::noteOn(mopo_float note, mopo_float velocity, int sample, int channel) {
void HelmVoiceHandler::noteOn(mopo_float note, mopo_float velocity, int sample, int channel, mopo_float aftertouch) {
if (getPressedNotes().size() < polyphony() || legato_->value() == 0.0)
note_retriggered_.trigger(note, sample);
VoiceHandler::noteOn(note, velocity, sample, channel);
VoiceHandler::noteOn(note, velocity, sample, channel, aftertouch);
}

VoiceEvent HelmVoiceHandler::noteOff(mopo_float note, int sample) {
Expand Down
2 changes: 1 addition & 1 deletion src/synthesis/helm_voice_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ namespace mopo {

void process() override;
void noteOn(mopo_float note, mopo_float velocity = 1,
int sample = 0, int channel = 0) override;
int sample = 0, int channel = 0, mopo_float aftertouch = 0) override;
VoiceEvent noteOff(mopo_float note, int sample = 0) override;
bool shouldAccumulate(Output* output) override;
void setModWheel(mopo_float value, int channel = 0);
Expand Down