2#include "trkn/tracktion.hh"
38 aseclip_ (aseclip), clip_state_ (aseclip_.clip_->state)
50 if (property == tracktion::engine::IDs::name)
52 else if (property == tracktion::engine::IDs::start ||
53 property == tracktion::engine::IDs::length ||
54 property == tracktion::engine::IDs::offset)
60 else if (property == tracktion::engine::IDs::mute)
62 else if (property == tracktion::engine::IDs::volDb || property == tracktion::engine::IDs::gain)
64 else if (property == tracktion::engine::IDs::pan)
72 void valueTreeChildOrderChanged (
juce::ValueTree&,
int,
int)
override {}
77ClipImpl::ClipImpl (tracktion::Clip &clip) :
84ClipImpl::from_trkn (tracktion::Clip &c)
86 ClipImpl *clip = SelectableHandle::find_selectable_handle<ClipImpl> (c);
88 return shared_ptr_cast<ClipImpl> (clip);
89 ClipImplP clipp = ClipImpl::make_shared (c);
95 state_listener_ =
nullptr;
99ClipImpl::project ()
const
101 if (
auto c = clip_.get())
102 if (
auto t = c->getTrack())
103 if (
auto timpl = SelectableHandle::find_selectable_handle<TrackImpl> (*t))
104 return timpl->project();
109ClipImpl::needs_serialize()
const
121ClipImpl::clip_index ()
const
123 if (
auto c = clip_.get())
124 if (
auto t = c->getTrack())
125 if (
auto timpl = SelectableHandle::find_selectable_handle<TrackImpl> (*t))
126 return timpl->clip_index (*
this);
134 auto &ts = clip_->edit.tempoSequence;
137 double duration_beats = end_beats - start_beats;
139 if (duration_beats > 0)
141 auto start_time = ts.toTime (tracktion::BeatPosition::fromBeats (start_beats));
142 auto duration_time = ts.toTime (tracktion::BeatPosition::fromBeats (duration_beats));
149 clip_->setStart (start_time,
false,
true);
150 clip_->setLength (tracktion::TimeDuration::fromSeconds(duration_time.inSeconds()),
true);
152 auto end_time = ts.toTime (tracktion::BeatPosition::fromBeats (end_beats));
153 clip_->setLength (end_time - start_time,
true);
164ClipImpl::all_notes (
const ClipNoteS ¬es)
166 ClipNoteS current = all_notes();
168 for (
auto &n : current) n.duration = 0;
170 ClipNoteS batch = current;
171 batch.insert (batch.end(), notes.begin(), notes.end());
176ClipImpl::all_notes ()
const
179 if (!clip_.get())
return notes;
181 if (!mclip)
return notes;
184 int channel = mclip->getMidiChannel().getChannelNumber() - 1;
186 for (
auto n : mclip->getSequence().getNotes())
190 cn.channel = channel;
191 cn.key = n->getNoteNumber();
192 cn.velocity = n->getVelocity() / 127.0f;
197 notes.push_back (cn);
203ClipImpl::end_tick ()
const
205 if (!clip_.get())
return 0;
210ClipImpl::end_tick (
int64 etick)
212 if (!clip_.get())
return;
219 if (!clip_.get())
return 0;
220 auto &ts = clip_->edit.tempoSequence;
221 return ts.toBeats (clip_->getPosition().getStart()).inBeats() *
TRANSPORT_PPQN;
227 if (!clip_.get())
return 0;
228 auto &ts = clip_->edit.tempoSequence;
229 return ts.toBeats (clip_->getPosition().getEnd()).inBeats() *
TRANSPORT_PPQN;
235 if (!clip_.get())
return false;
236 return clip_->isMuted();
242 if (!clip_.get())
return;
243 auto &um = clip_->edit.getUndoManager();
244 um.beginNewTransaction (
"Set Clip Muted");
245 clip_->setMuted (muted);
251 if (!clip_.get())
return 0.0;
254 return mclip->getVolumeDb();
264 if (!clip_.get())
return;
265 auto &um = clip_->edit.getUndoManager();
266 um.beginNewTransaction (
"Set Clip Volume");
269 mclip->setVolumeDb (
float (db));
281 if (!clip_.get())
return 0.0;
291 if (!clip_.get())
return;
292 auto &um = clip_->edit.getUndoManager();
293 um.beginNewTransaction (
"Set Clip Pan");
296 aclip->
setPan (
float (panval));
307ClipImpl::update_telemetry ()
312ClipImpl::OrderedEventsP
315 ClipNoteS notes = all_notes();
322 if (!clip_.get())
return -1;
326 auto &um = clip_->edit.getUndoManager();
327 um.beginNewTransaction (
juce::String (undogroup.
empty() ?
"Change Notes" : undogroup));
329 for (
const auto ¬e : batch)
331 if (note.duration == 0)
333 auto &seq = mclip->getSequence();
334 for (
auto n : seq.getNotes())
336 if (std::abs(n->getStartBeat().inBeats() *
TRANSPORT_PPQN - note.tick) < 1 &&
337 n->getNoteNumber() == note.key)
339 seq.removeNote (*n, &um);
344 else if (note.id <= 0)
346 mclip->getSequence().addNote (note.key,
348 tracktion::BeatDuration::fromBeats (
double (note.duration) /
TRANSPORT_PPQN),
355 auto &seq = mclip->getSequence();
356 for (
auto n : seq.getNotes())
358 if (std::abs(n->getStartBeat().inBeats() *
TRANSPORT_PPQN - note.tick) < 1 &&
359 n->getNoteNumber() == note.key)
361 n->setStartAndLength (tracktion::BeatPosition::fromBeats (
double (note.tick) /
TRANSPORT_PPQN),
362 tracktion::BeatDuration::fromBeats (
double (note.duration) /
TRANSPORT_PPQN),
364 n->setVelocity (note.velocity * 127, &um);
365 n->setNoteNumber (note.key, &um);
382 int64_t bar_ticks = p ? p->bar_ticks() : 0;
387 loop_end_ = bar_ticks * 2;
389 last_ = loop_end_ - start_offset_ + LOOPS * (loop_end_ - loop_start_);
401 xtick_ = target_tick;
406 xtick_ =
std::min (target_tick, play_length());
408 itick_ = start_offset_;
411 if (itick_ >= loop_end_)
417 int64 delta = xtick_;
421 if (itick_ == loop_end_)
423 itick_ = loop_start_;
427 const int64 frac = delta % (loop_end_ - loop_start_);
438 printerr (
"generate: %d < %d (%+d) && %d > %d (%+d) (loop: %d %d) i=%d\n", xtick_, last_, xtick_ < last_,
439 target_tick, xtick_, target_tick > xtick_,
440 loop_start_, loop_end_, itick_);
441 const int64 old_xtick = xtick_;
442 return_unless (xtick_ < last_ && target_tick > xtick_, xtick_ - old_xtick);
452 itick_ = start_offset_;
458 const int64 delta = itick_ < loop_end_ ?
std::min (ticks, loop_end_ - itick_) : ticks;
460 const int64 x = xtick_;
462 const int64 a = itick_;
464 const int64 b = itick_;
465 if (itick_ == loop_end_)
466 itick_ = loop_start_;
468 if (receiver && !muted_)
471 const ClipNote *
event = events_->lookup_after (index);
472 while (event && event->tick < b)
474 MidiEvent midievent = make_note_on (event->channel, event->key, event->velocity, event->fine_tune, event->id);
475 const int64 noteon_tick = x +
event->tick - a;
476 receiver (noteon_tick, midievent);
477 midievent.
type = MidiEvent::NOTE_OFF;
478 receiver (noteon_tick + event->duration, midievent);
480 if (event == &*events_->end())
485 return xtick_ - old_xtick;
489stringify_clip_note (
const ClipNote &n)
494 n.tick, n.duration, n.velocity, n.fine_tune);
void setup(const ClipImpl &clip)
Create generator from clip.
int64 generate(int64 target_tick, const Receiver &receiver)
Advance tick and call receiver for generated events.
void jumpto(int64 target_tick)
Assign new play_position() (and clip_position()), preserves all other state.
void set_muted(bool muted) override
Set clip muted state, emits notify:muted.
void assign_range(int64 starttick, int64 stoptick) override
Change start_tick() and stop_tick(); emits notify:start_tick, notify:stop_tick.
int64 start_tick() const override
Get the first tick intended for playback (this is >= 0), changes on notify:start_tick.
ClipNoteS list_all_notes() override
List all notes of this Clip; changes on notify:notes.
int32 change_batch(const ClipNoteS ¬es, const String &undogroup) override
Change note id according to the arguments or add a new note if id < 0; emits notify:notes.
double volume() const override
Get clip volume in dB.
bool is_muted() const override
Check if clip is muted.
int64 stop_tick() const override
Get the tick to stop playback, not events should be played after this, changes on notify:stop_tick.
void serialize(WritNode &xs) override
Serialize members and childern.
TelemetryFieldS telemetry() const override
Retrieve clip telemetry locations.
double pan() const override
Get clip pan (-1.0 to 1.0).
OrderedEventsP tick_events() const
Retrieve const vector with all notes ordered by tick.
void emit_notify(const String &detail) override
Emit notify:detail, multiple notifications maybe coalesced if a CoalesceNotifies instance exists.
void serialize(WritNode &xs) override
Serialize members and childern.
One entry in a Writ serialization document.
void addListener(Listener *listener)
void removeListener(Listener *listener)
float getPan() const noexcept
float getGainDB() const noexcept
BeatPosition getStartBeat() const
#define assert_return(expr,...)
Return from the current function if expr is unmet and issue an assertion warning.
#define return_unless(cond,...)
Return silently if cond does not evaluate to true with return value ...
The Anklang C++ API namespace.
std::string string_format(const char *format, const Args &...args) __attribute__((__format__(__printf__
Format a string similar to sprintf(3) with support for std::string and std::ostringstream convertible...
int32_t int32
A 32-bit signed integer.
int64_t int64
A 64-bit unsigned integer, use PRI*64 in format strings.
constexpr const int64 TRANSPORT_PPQN
Maximum number of sample frames to calculate in Processor::render().
Part specific note event representation.
int64 tick
UI selection flag.
bool selected
Musical note as MIDI key, 0 .. 127.
float velocity
Duration in number of ticks.
bool operator==(const ClipNote &) const
Fine Tune, -100 .. +100.
int64 duration
Position in ticks.
float fine_tune
Velocity, 0 .. +1.
MidiEvent data structure.
MidiEventType type
MidiEvent type, one of the MidiEventType members.