6#define MDEBUG(...) Ase::debug ("midifeed", __VA_ARGS__)
36 int64 generator_start_ = -1;
37 bool must_flush =
false;
44 position_block_ = SERVER->telemem_allocate (
sizeof (
Position));
45 position_ =
new (position_block_.block_start)
Position {};
46 future_stack.reserve (64);
50 position_->~Position();
52 SERVER->telemem_release (position_block_);
68 const int64 last_play_position = position_->current >= 0 ? feed_->generators[position_->current].play_position() : 0;
73 if (position_->current >= 0)
75 if (feed_ &&
size_t (position_->current) < feed_->generators.size())
76 feed_->generators[position_->current].jumpto (last_play_position);
79 must_flush = must_flush || position_->current != -1;
80 position_->current = -1;
88 position_->current = -1;
89 position_->tick = -M52MAX;
96 if (feed_ && feed_->generators.size())
98 if (position_->current < 0)
100 position_->current = 0;
101 generator_start_ =
transport().current_bar_tick;
102 feed_->generators[position_->current].jumpto (0);
108 stop (
bool restart)
override
110 position_->tick = -M52MAX;
114 position_->current = -1;
115 generator_start_ = -1;
131 for (
ssize_t i = future_stack.size() - 1; i >= 0; i--)
134 const int64 frame0 = 0;
135 if (tnote.event.
type == MidiEvent::NOTE_OFF)
138 MDEBUG (
"FLUSH: t=%d ev=%s f=%d\n", tnote.tick, tnote.event.to_string(), frame0);
141 future_stack.resize (0);
144 while (future_stack.size() && future_stack.back().tick < end_tick)
147 future_stack.pop_back();
148 const int64 frame =
transport.sample_from_tick (tnote.tick - begin_tick);
150 MDEBUG (
"POP: t=%d ev=%s f=%d\n", tnote.tick, tnote.event.to_string(), frame);
156 MDEBUG (
"THROUGH: f=%+3d ev=%s\n", mevent.frame, mevent.to_string());
157 evout.
append (mevent.frame, mevent);
161 bpm > 0 && position_->current >= 0 &&
162 generator_start_ >= 0))
165 while (position_->current >= 0 &&
166 generator_start_ + feed_->generators[position_->current].play_position() < end_tick)
170 const int64 etick = generator_start_ + cliptick;
171 if (etick < end_tick)
173 const int64 frame =
transport.sample_from_tick (etick - begin_tick);
176 evout.append_unsorted (frame, event);
177 MDEBUG (
"NOW: t=%d ev=%s f=%d\n", etick, event.to_string(), frame);
183 MDEBUG (
"FUT: t=%d ev=%s f=%d\n", etick, event.to_string(),
transport.sample_from_tick (etick - begin_tick));
187 const int64 advanced = feed_->generators[position_->current].generate (end_tick - generator_start_, qevent);
190 if (feed_->generators[position_->current].done())
192 const int64 play_point = generator_start_ + feed_->generators[position_->current].play_position();
194 position_->current = feed_->scout.advance (position_->current);
195 if (position_->current >= 0)
197 generator_start_ =
transport.current_bar_tick;
198 while (generator_start_ < play_point)
199 generator_start_ +=
transport.tick_sig.bar_ticks();
200 feed_->generators[position_->current].jumpto (0);
201 if (feed_->generators[position_->current].done())
202 position_->current = -1;
204 if (position_->current == -1)
205 generator_start_ = -1;
206 position_->next = -1;
209 if (position_->current >= 0)
210 position_->tick = feed_->generators[position_->current].clip_position();
212 position_->tick = -M52MAX;
219 position ()
const override
225static auto midilib_midiinputimpl = register_audio_processor<MidiProducerImpl>();
void remove_all_buses()
Remove existing bus configurations, useful at the start of configure().
void prepare_event_input()
Prepare the AudioProcessor to receive Event objects during render() via get_event_input().
MidiEventInput midi_event_input()
Access the current MidiEvent inputs during render(), needs prepare_event_input().
MidiEventOutput & midi_event_output()
Access the current output EventStream during render(), needs prepare_event_output().
const AudioTransport & transport() const
Sample rate mixing frequency in Hz as unsigned, used for render().
void prepare_event_output()
Prepare the AudioProcessor to produce Event objects during render() via get_event_output().
Generator for MIDI events.
A stream of writable MidiEvent structures.
bool append_unsorted(int16_t frame, const MidiEvent &event)
Dangerous! Append a MidiEvent while ignoring sort order, violates constraints.
void ensure_order()
Fix event order after append_unsorted() returned true.
void append(int16_t frame, const MidiEvent &event)
Append an MidiEvent with conscutive frame time stamp.
An in-order MidiEvent reader for multiple MidiEvent sources.
void render(uint n_frames) override
Method called for every audio buffer to be processed.
void initialize(SpeakerArrangement busses) override
Mandatory method to setup parameters and I/O busses.
void reset(uint64 target_stamp) override
Reset all state variables.
#define ASE_UNLIKELY(expr)
Compiler hint to optimize for expr evaluating to false.
#define ASE_ISLIKELY(expr)
Compiler hint to optimize for expr evaluating to true.
#define assert_paranoid(expr)
Issue an assertion warning if expr evaluates to false, check might be disabled in production.
std::vector< T >::iterator insert_sorted(std::vector< T > &vec, const T &value, Compare compare)
Insert value into sorted vec using binary_lookup_insertion_pos() with compare.
The Anklang C++ API namespace.
uint64_t uint64
A 64-bit unsigned integer, use PRI*64 in format strings.
SpeakerArrangement
Flags to indicate channel arrangements of a bus.
int64_t int64
A 64-bit unsigned integer, use PRI*64 in format strings.
uint32_t uint
Provide 'uint' as convenience type.
Detailed information and common properties of AudioProcessor subclasses.
Transport information for AudioSignal processing.
float current_bpm
Running tempo in beats per minute.
Reference for an allocated memory block.
MidiEvent data structure.
MidiEventType type
MidiEvent type, one of the MidiEventType members.