13
0

add missing file

This commit is contained in:
Paul Davis 2018-11-03 23:19:13 -04:00
parent c41c622b37
commit 07640ff488

View File

@ -0,0 +1,408 @@
/*
* Copyright (C) 2018 Paul Davis <paul@linuxaudiosystems.com>
*
* 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <cassert>
#include "ardour/audioengine.h"
#include "ardour/midi_buffer.h"
#include "ardour/midi_state_tracker.h"
#include "ardour/step_sequencer.h"
#include "ardour/tempo.h"
using namespace ARDOUR;
using namespace std;
static int notenum = 60;
Step::Step (StepSequence &s, Temporal::Beats const & b)
: _sequence (s)
, _enabled (true)
, _nominal_beat (b)
, _skipped (false)
, _mode (AbsolutePitch)
{
std::cerr << "step @ " << b << std::endl;
for (size_t n = 0; n < _notes_per_step; ++n) {
_notes[n].number = -1;
}
/* XXX HACK XXXX */
_notes[0].number = notenum++;
for (size_t n = 0; n < _parameters_per_step; ++n) {
_parameters[n].parameter = -1;
}
}
Step::~Step ()
{
}
StepSequencer&
Step::sequencer() const
{
return _sequence.sequencer();
}
void
Step::set_mode (Mode m)
{
_mode = m;
}
void
Step::set_beat (Temporal::Beats const & b)
{
_nominal_beat = b;
}
void
Step::set_note (double note, double velocity, int32_t duration, int n)
{
assert (n < _notes_per_step);
_notes[n].number = note;
_notes[n].velocity = velocity;
_notes[n].duration = duration;
}
void
Step::set_chord (size_t note_cnt, double* notes)
{
}
void
Step::set_parameter (int number, double value, int n)
{
assert (n < _parameters_per_step);
_parameters[n].parameter = number;
_parameters[n].value = value;
}
void
Step::set_enabled (bool yn)
{
_enabled = yn;
}
bool
Step::run (MidiBuffer& buf, bool running, samplepos_t start_sample, samplepos_t end_sample, MidiStateTracker& tracker)
{
for (size_t n = 0; n < _notes_per_step; ++n) {
check_parameter (n, buf, running, start_sample, end_sample);
}
for (size_t n = 0; n < _notes_per_step; ++n) {
check_note (n, buf, running, start_sample, end_sample, tracker);
}
if (running) {
samplepos_t scheduled_samples = sequencer().tempo_map().sample_at_beat (_scheduled_beat.to_double());
if (scheduled_samples >= start_sample && scheduled_samples < end_sample) {
/* this step was covered by the run() range, so update its next
* scheduled time.
*/
_scheduled_beat += sequencer().duration();
}
}
return true;
}
void
Step::check_parameter (size_t n, MidiBuffer& buf, bool running, samplepos_t start_sample, samplepos_t end_sample)
{
}
void
Step::check_note (size_t n, MidiBuffer& buf, bool running, samplepos_t start_sample, samplepos_t end_sample, MidiStateTracker& tracker)
{
Note& note (_notes[n]);
if (note.number < 0) {
/* note not set .. ignore */
return;
}
/* figure out when this note would sound */
Temporal::Beats note_on_time = _scheduled_beat;
note_on_time += note.offset;
if (running && !note.on) {
/* don't play silent notes */
if (note.velocity == 0) {
return;
}
samplepos_t on_samples = sequencer().tempo_map().sample_at_beat (note_on_time.to_double());
if (on_samples >= start_sample && on_samples < end_sample) {
uint8_t mbuf[3];
/* prepare 3 MIDI bytes for note on */
mbuf[0] = 0x90 | _sequence.channel();
switch (_mode) {
case AbsolutePitch:
mbuf[1] = note.number;
break;
case RelativePitch:
mbuf[1] = _sequence.root() + note.interval;
break;
}
mbuf[2] = (uint8_t) floor (note.velocity * 127.0);
/* Put it into the MIDI buffer */
buf.write (on_samples - start_sample, Evoral::MIDI_EVENT, 3, mbuf);
tracker.add (mbuf[1], _sequence.channel());
/* keep track (even though other things will at different levels */
note.on = true;
/* compute note off time based on our duration */
note.off_at = note_on_time;
if (note.duration == 1) {
note.off_at += Temporal::Beats (0, _sequence.step_size().to_ticks() - 1);
} else {
note.off_at += Temporal::Beats (0, _sequence.step_size().to_ticks() / note.duration);
}
}
}
if (note.on) {
samplepos_t off_samples = sequencer().tempo_map().sample_at_beat (note.off_at.to_double());
if (off_samples >= start_sample && off_samples < end_sample) {
uint8_t mbuf[3];
/* prepare 3 MIDI bytes for note off */
mbuf[0] = 0x80 | _sequence.channel();
switch (_mode) {
case AbsolutePitch:
mbuf[1] = note.number;
break;
case RelativePitch:
mbuf[1] = _sequence.root() + note.interval;
break;
}
mbuf[2] = note.velocity;
buf.write (off_samples - start_sample, Evoral::MIDI_EVENT, 3, mbuf);
tracker.remove (mbuf[1], _sequence.channel());
/* record keeping */
note.on = false;
note.off_at = Temporal::Beats();
}
}
}
void
Step::set_timeline_offset (Temporal::Beats const & start, Temporal::Beats const & offset)
{
timeline_offset = offset;
if (_nominal_beat < offset) {
_scheduled_beat = start + _nominal_beat + sequencer().duration(); /* schedule into the next loop iteration */
} else {
_scheduled_beat = start + _nominal_beat; /* schedule into the current loop iteration */
}
/* MIDI state tracker will deal with any stuck notes */
for (size_t n = 0; n < _notes_per_step; ++n) {
_notes[n].on = false;
_notes[n].off_at = Temporal::Beats();
}
}
/**/
StepSequence::StepSequence (StepSequencer& s, size_t nsteps, Temporal::Beats const & step_size, Temporal::Beats const & bar_size)
: _sequencer (s)
, _start (0)
, _end (nsteps)
, _channel (0)
, _step_size (step_size)
, _bar_size (bar_size)
, _root (64)
, _mode (MusicalMode::IonianMajor)
{
Temporal::Beats beats;
for (size_t s = 0; s < nsteps; ++s) {
_steps.push_back (new Step (*this, beats));
beats += step_size;
}
end_beat = beats;
}
StepSequence::~StepSequence ()
{
for (Steps::iterator i = _steps.begin(); i != _steps.end(); ++i) {
delete *i;
}
}
void
StepSequence::startup (Temporal::Beats const & start, Temporal::Beats const & offset)
{
for (Steps::iterator i = _steps.begin(); i != _steps.end(); ++i) {
(*i)->set_timeline_offset (start, offset);
}
}
void
StepSequence::reset ()
{
}
void
StepSequence::set_channel (int c)
{
_channel = c;
}
Temporal::Beats
StepSequence::wrap (Temporal::Beats const & b) const
{
if (b < end_beat) {
return b;
}
return b - end_beat;
}
bool
StepSequence::run (MidiBuffer& buf, bool running, samplepos_t start_sample, samplepos_t end_sample, MidiStateTracker& tracker)
{
for (Steps::iterator s = _steps.begin(); s != _steps.end(); ++s) {
(*s)->run (buf, running, start_sample, end_sample, tracker);
}
return true;
}
void
StepSequence::adjust_step_pitch (int step, int amt)
{
if (step >= _steps.size()) {
return;
}
_steps[step]->_notes[0].number += amt;
if (_steps[step]->_notes[0].number > 127.0) {
_steps[step]->_notes[0].number = 127.0;
}
if (_steps[step]->_notes[0].number < 0.0) {
_steps[step]->_notes[0].number = 0.0;
}
}
/**/
StepSequencer::StepSequencer (TempoMap& tmap, size_t nseqs, size_t nsteps, Temporal::Beats const & step_size, Temporal::Beats const & bar_size)
: _tempo_map (tmap)
, _step_size (step_size)
, _start (0)
, _end (nsteps)
{
for (size_t n = 0; n < nseqs; ++n) {
_sequences.push_back (new StepSequence (*this, nsteps, step_size, bar_size));
}
}
StepSequencer::~StepSequencer ()
{
for (StepSequences::iterator i = _sequences.begin(); i != _sequences.end(); ++i) {
delete *i;
}
}
bool
StepSequencer::run (MidiBuffer& buf, bool running, samplepos_t start_sample, samplepos_t end_sample, MidiStateTracker& tracker)
{
Glib::Threads::Mutex::Lock lm (_sequence_lock);
for (StepSequences::iterator s = _sequences.begin(); s != _sequences.end(); ++s) {
(*s)->run (buf, running, start_sample, end_sample, tracker);
}
return true;
}
void
StepSequencer::sync ()
{
}
void
StepSequencer::reset ()
{
{
Glib::Threads::Mutex::Lock lm1 (_sequence_lock);
for (StepSequences::iterator s = _sequences.begin(); s != _sequences.end(); ++s) {
(*s)->reset ();
}
}
}
Temporal::Beats
StepSequencer::duration() const
{
return _step_size * (_end - _start) ;
}
void
StepSequencer::startup (Temporal::Beats const & start, Temporal::Beats const & offset)
{
{
Glib::Threads::Mutex::Lock lm1 (_sequence_lock);
for (StepSequences::iterator s = _sequences.begin(); s != _sequences.end(); ++s) {
(*s)->startup (start, offset);
}
}
}
void
StepSequencer::adjust_step_pitch (int seq, int step, int amt)
{
_sequences.front()->adjust_step_pitch (step, amt);
}