Wrap MusicalTime in a class.

This lets us get a more explicit handle on time conversions, and is the main
step towards using actual beat:tick time and getting away from floating point
precision problems.
This commit is contained in:
David Robillard 2014-11-22 04:05:42 -05:00
parent cae74309a5
commit c1cfa12d6e
44 changed files with 519 additions and 326 deletions

View file

@ -54,11 +54,11 @@ public:
float times, float times,
boost::shared_ptr<const ARDOUR::AutomationList> slist); boost::shared_ptr<const ARDOUR::AutomationList> slist);
ARDOUR::BeatsFramesConverter const & region_relative_time_converter () const { ARDOUR::DoubleBeatsFramesConverter const & region_relative_time_converter () const {
return _region_relative_time_converter; return _region_relative_time_converter;
} }
ARDOUR::BeatsFramesConverter const & source_relative_time_converter () const { ARDOUR::DoubleBeatsFramesConverter const & source_relative_time_converter () const {
return _source_relative_time_converter; return _source_relative_time_converter;
} }
@ -83,10 +83,10 @@ protected:
void exited(); void exited();
private: private:
ARDOUR::BeatsFramesConverter _region_relative_time_converter; ARDOUR::DoubleBeatsFramesConverter _region_relative_time_converter;
ARDOUR::BeatsFramesConverter _source_relative_time_converter; ARDOUR::DoubleBeatsFramesConverter _source_relative_time_converter;
Evoral::Parameter _parameter; Evoral::Parameter _parameter;
boost::shared_ptr<AutomationLine> _line; boost::shared_ptr<AutomationLine> _line;
}; };
#endif /* __gtk_ardour_automation_region_view_h__ */ #endif /* __gtk_ardour_automation_region_view_h__ */

View file

@ -193,7 +193,7 @@ EditNoteDialog::done (int r)
} }
} }
double const t = _region_view->source_relative_time_converter().from (_time_clock.current_time ()); Evoral::MusicalTime const t = _region_view->source_relative_time_converter().from (_time_clock.current_time ());
if (!_time_all.get_sensitive() || _time_all.get_active ()) { if (!_time_all.get_sensitive() || _time_all.get_active ()) {
for (set<NoteBase*>::iterator i = _events.begin(); i != _events.end(); ++i) { for (set<NoteBase*>::iterator i = _events.begin(); i != _events.end(); ++i) {
@ -204,7 +204,7 @@ EditNoteDialog::done (int r)
} }
} }
double const d = _region_view->region_relative_time_converter().from (_length_clock.current_duration ()); Evoral::MusicalTime const d = _region_view->region_relative_time_converter().from (_length_clock.current_duration ());
if (!_length_all.get_sensitive() || _length_all.get_active ()) { if (!_length_all.get_sensitive() || _length_all.get_active ()) {
for (set<NoteBase*>::iterator i = _events.begin(); i != _events.end(); ++i) { for (set<NoteBase*>::iterator i = _events.begin(); i != _events.end(); ++i) {

View file

@ -3901,64 +3901,64 @@ Editor::get_grid_type_as_beats (bool& success, framepos_t position)
switch (_snap_type) { switch (_snap_type) {
case SnapToBeat: case SnapToBeat:
return 1.0; return Evoral::MusicalTime(1.0);
break; break;
case SnapToBeatDiv128: case SnapToBeatDiv128:
return 1.0/128.0; return Evoral::MusicalTime(1.0/128.0);
break; break;
case SnapToBeatDiv64: case SnapToBeatDiv64:
return 1.0/64.0; return Evoral::MusicalTime(1.0/64.0);
break; break;
case SnapToBeatDiv32: case SnapToBeatDiv32:
return 1.0/32.0; return Evoral::MusicalTime(1.0/32.0);
break; break;
case SnapToBeatDiv28: case SnapToBeatDiv28:
return 1.0/28.0; return Evoral::MusicalTime(1.0/28.0);
break; break;
case SnapToBeatDiv24: case SnapToBeatDiv24:
return 1.0/24.0; return Evoral::MusicalTime(1.0/24.0);
break; break;
case SnapToBeatDiv20: case SnapToBeatDiv20:
return 1.0/20.0; return Evoral::MusicalTime(1.0/20.0);
break; break;
case SnapToBeatDiv16: case SnapToBeatDiv16:
return 1.0/16.0; return Evoral::MusicalTime(1.0/16.0);
break; break;
case SnapToBeatDiv14: case SnapToBeatDiv14:
return 1.0/14.0; return Evoral::MusicalTime(1.0/14.0);
break; break;
case SnapToBeatDiv12: case SnapToBeatDiv12:
return 1.0/12.0; return Evoral::MusicalTime(1.0/12.0);
break; break;
case SnapToBeatDiv10: case SnapToBeatDiv10:
return 1.0/10.0; return Evoral::MusicalTime(1.0/10.0);
break; break;
case SnapToBeatDiv8: case SnapToBeatDiv8:
return 1.0/8.0; return Evoral::MusicalTime(1.0/8.0);
break; break;
case SnapToBeatDiv7: case SnapToBeatDiv7:
return 1.0/7.0; return Evoral::MusicalTime(1.0/7.0);
break; break;
case SnapToBeatDiv6: case SnapToBeatDiv6:
return 1.0/6.0; return Evoral::MusicalTime(1.0/6.0);
break; break;
case SnapToBeatDiv5: case SnapToBeatDiv5:
return 1.0/5.0; return Evoral::MusicalTime(1.0/5.0);
break; break;
case SnapToBeatDiv4: case SnapToBeatDiv4:
return 1.0/4.0; return Evoral::MusicalTime(1.0/4.0);
break; break;
case SnapToBeatDiv3: case SnapToBeatDiv3:
return 1.0/3.0; return Evoral::MusicalTime(1.0/3.0);
break; break;
case SnapToBeatDiv2: case SnapToBeatDiv2:
return 1.0/2.0; return Evoral::MusicalTime(1.0/2.0);
break; break;
case SnapToBar: case SnapToBar:
if (_session) { if (_session) {
return _session->tempo_map().meter_at (position).divisions_per_bar(); return Evoral::MusicalTime(_session->tempo_map().meter_at (position).divisions_per_bar());
} }
break; break;
@ -3977,7 +3977,7 @@ Editor::get_grid_type_as_beats (bool& success, framepos_t position)
break; break;
} }
return 0.0; return Evoral::MusicalTime();
} }
framecnt_t framecnt_t

View file

@ -5220,7 +5220,7 @@ NoteCreateDrag::grid_frames (framepos_t t) const
bool success; bool success;
Evoral::MusicalTime grid_beats = _editor->get_grid_type_as_beats (success, t); Evoral::MusicalTime grid_beats = _editor->get_grid_type_as_beats (success, t);
if (!success) { if (!success) {
grid_beats = 1; grid_beats = Evoral::MusicalTime(1);
} }
return _region_view->region_beats_to_region_frames (grid_beats); return _region_view->region_beats_to_region_frames (grid_beats);
@ -5276,13 +5276,13 @@ NoteCreateDrag::finished (GdkEvent*, bool had_movement)
framecnt_t length = (framecnt_t) fabs ((double)(_note[0] - _note[1])); framecnt_t length = (framecnt_t) fabs ((double)(_note[0] - _note[1]));
framecnt_t const g = grid_frames (start); framecnt_t const g = grid_frames (start);
double const one_tick = 1 / Timecode::BBT_Time::ticks_per_beat; Evoral::MusicalTime const one_tick = Evoral::MusicalTime::ticks(1);
if (_editor->snap_mode() == SnapNormal && length < g) { if (_editor->snap_mode() == SnapNormal && length < g) {
length = g - one_tick; length = g - one_tick;
} }
double const length_beats = max (one_tick, _region_view->region_frames_to_region_beats (length)); Evoral::MusicalTime const length_beats = max (one_tick, _region_view->region_frames_to_region_beats (length));
_region_view->create_note_at (start, _drag_rect->y0(), length_beats, false); _region_view->create_note_at (start, _drag_rect->y0(), length_beats, false);
} }

View file

@ -4988,7 +4988,7 @@ Editor::insert_patch_change (bool from_context)
*/ */
MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ()); MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0); Evoral::PatchChange<Evoral::MusicalTime> empty (Evoral::MusicalTime(), 0, 0, 0);
PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD); PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
if (d.run() == RESPONSE_CANCEL) { if (d.run() == RESPONSE_CANCEL) {

View file

@ -30,7 +30,7 @@ namespace ArdourCanvas {
class Hit : public NoteBase class Hit : public NoteBase
{ {
public: public:
typedef Evoral::Note<double> NoteType; typedef Evoral::Note<Evoral::MusicalTime> NoteType;
Hit (MidiRegionView& region, Hit (MidiRegionView& region,
ArdourCanvas::Item* parent, ArdourCanvas::Item* parent,

View file

@ -550,7 +550,7 @@ MidiRegionView::button_release (GdkEventButton* ev)
/* Shorten the length by 1 tick so that we can add a new note at the next /* Shorten the length by 1 tick so that we can add a new note at the next
grid snap without it overlapping this one. grid snap without it overlapping this one.
*/ */
beats -= 1.0 / Timecode::BBT_Time::ticks_per_beat; beats -= Evoral::MusicalTime::tick();
create_note_at (editor.pixel_to_sample (event_x), event_y, beats, true); create_note_at (editor.pixel_to_sample (event_x), event_y, beats, true);
} }
@ -564,7 +564,7 @@ MidiRegionView::button_release (GdkEventButton* ev)
/* Shorten the length by 1 tick so that we can add a new note at the next /* Shorten the length by 1 tick so that we can add a new note at the next
grid snap without it overlapping this one. grid snap without it overlapping this one.
*/ */
beats -= 1.0 / Timecode::BBT_Time::ticks_per_beat; beats -= Evoral::MusicalTime::tick();
create_note_at (editor.pixel_to_sample (event_x), event_y, beats, true); create_note_at (editor.pixel_to_sample (event_x), event_y, beats, true);
@ -728,7 +728,7 @@ MidiRegionView::key_press (GdkEventKey* ev)
bool shorter = Keyboard::modifier_state_contains (ev->state, Keyboard::PrimaryModifier); bool shorter = Keyboard::modifier_state_contains (ev->state, Keyboard::PrimaryModifier);
bool fine = Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier); bool fine = Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier);
change_note_lengths (fine, shorter, 0.0, start, end); change_note_lengths (fine, shorter, Evoral::MusicalTime(), start, end);
return true; return true;
@ -909,7 +909,7 @@ MidiRegionView::show_list_editor ()
* \param snap_t true to snap t to the grid, otherwise false. * \param snap_t true to snap t to the grid, otherwise false.
*/ */
void void
MidiRegionView::create_note_at (framepos_t t, double y, double length, bool snap_t) MidiRegionView::create_note_at (framepos_t t, double y, Evoral::MusicalTime length, bool snap_t)
{ {
if (length < 2 * DBL_EPSILON) { if (length < 2 * DBL_EPSILON) {
return; return;
@ -1521,7 +1521,7 @@ MidiRegionView::end_write()
/** Resolve an active MIDI note (while recording). /** Resolve an active MIDI note (while recording).
*/ */
void void
MidiRegionView::resolve_note(uint8_t note, double end_time) MidiRegionView::resolve_note(uint8_t note, Evoral::MusicalTime end_time)
{ {
if (midi_view()->note_mode() != Sustained) { if (midi_view()->note_mode() != Sustained) {
return; return;
@ -1660,7 +1660,7 @@ MidiRegionView::update_note (Note* ev, bool update_ghost_regions)
ev->set_y1 (y0 + std::max(1., floor(midi_stream_view()->note_height()) - 1)); ev->set_y1 (y0 + std::max(1., floor(midi_stream_view()->note_height()) - 1));
if (note->length() == 0) { if (!note->length()) {
if (_active_notes && note->note() < 128) { if (_active_notes && note->note() < 128) {
// If this note is already active there's a stuck note, // If this note is already active there's a stuck note,
// finish the old note rectangle // finish the old note rectangle
@ -1862,7 +1862,7 @@ patch_applies (const ARDOUR::MidiModel::constPatchChangePtr pc, double time, uin
} }
void void
MidiRegionView::get_patch_key_at (double time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key) const MidiRegionView::get_patch_key_at (Evoral::MusicalTime time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key) const
{ {
// The earliest event not before time // The earliest event not before time
MidiModel::PatchChanges::iterator i = _model->patch_change_lower_bound (time); MidiModel::PatchChanges::iterator i = _model->patch_change_lower_bound (time);
@ -2260,7 +2260,7 @@ MidiRegionView::note_selected (NoteBase* ev, bool add, bool extend)
/* find end of latest note selected, select all between that and the start of "ev" */ /* find end of latest note selected, select all between that and the start of "ev" */
Evoral::MusicalTime earliest = Evoral::MaxMusicalTime; Evoral::MusicalTime earliest = Evoral::MaxMusicalTime;
Evoral::MusicalTime latest = 0; Evoral::MusicalTime latest = Evoral::MusicalTime();
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) { for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
if ((*i)->note()->end_time() > latest) { if ((*i)->note()->end_time() > latest) {
@ -2421,7 +2421,7 @@ MidiRegionView::move_selection(double dx, double dy, double cumulative_dy)
} }
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) { for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
if (Evoral::musical_time_equal ((*i)->note()->time(), earliest)) { if ((*i)->note()->time() == earliest) {
to_play.push_back ((*i)->note()); to_play.push_back ((*i)->note());
} }
(*i)->move_event(dx, dy); (*i)->move_event(dx, dy);
@ -2548,7 +2548,7 @@ MidiRegionView::get_end_position_pixels()
} }
framepos_t framepos_t
MidiRegionView::source_beats_to_absolute_frames(double beats) const MidiRegionView::source_beats_to_absolute_frames(Evoral::MusicalTime beats) const
{ {
/* the time converter will return the frame corresponding to `beats' /* the time converter will return the frame corresponding to `beats'
relative to the start of the source. The start of the source relative to the start of the source. The start of the source
@ -2558,7 +2558,7 @@ MidiRegionView::source_beats_to_absolute_frames(double beats) const
return source_start + _source_relative_time_converter.to (beats); return source_start + _source_relative_time_converter.to (beats);
} }
double Evoral::MusicalTime
MidiRegionView::absolute_frames_to_source_beats(framepos_t frames) const MidiRegionView::absolute_frames_to_source_beats(framepos_t frames) const
{ {
/* the `frames' argument needs to be converted into a frame count /* the `frames' argument needs to be converted into a frame count
@ -2570,12 +2570,12 @@ MidiRegionView::absolute_frames_to_source_beats(framepos_t frames) const
} }
framepos_t framepos_t
MidiRegionView::region_beats_to_region_frames(double beats) const MidiRegionView::region_beats_to_region_frames(Evoral::MusicalTime beats) const
{ {
return _region_relative_time_converter.to(beats); return _region_relative_time_converter.to(beats);
} }
double Evoral::MusicalTime
MidiRegionView::region_frames_to_region_beats(framepos_t frames) const MidiRegionView::region_frames_to_region_beats(framepos_t frames) const
{ {
return _region_relative_time_converter.from(frames); return _region_relative_time_converter.from(frames);
@ -2827,8 +2827,8 @@ MidiRegionView::trim_note (NoteBase* event, Evoral::MusicalTime front_delta, Evo
{ {
bool change_start = false; bool change_start = false;
bool change_length = false; bool change_length = false;
Evoral::MusicalTime new_start = 0; Evoral::MusicalTime new_start;
Evoral::MusicalTime new_length = 0; Evoral::MusicalTime new_length;
/* NOTE: the semantics of the two delta arguments are slightly subtle: /* NOTE: the semantics of the two delta arguments are slightly subtle:
@ -2843,7 +2843,7 @@ MidiRegionView::trim_note (NoteBase* event, Evoral::MusicalTime front_delta, Evo
if (front_delta < 0) { if (front_delta < 0) {
if (event->note()->time() < -front_delta) { if (event->note()->time() < -front_delta) {
new_start = 0; new_start = Evoral::MusicalTime();
} else { } else {
new_start = event->note()->time() + front_delta; // moves earlier new_start = event->note()->time() + front_delta; // moves earlier
} }
@ -2924,7 +2924,7 @@ MidiRegionView::change_note_time (NoteBase* event, Evoral::MusicalTime delta, bo
if (relative) { if (relative) {
if (delta < 0.0) { if (delta < 0.0) {
if (event->note()->time() < -delta) { if (event->note()->time() < -delta) {
new_time = 0; new_time = Evoral::MusicalTime();
} else { } else {
new_time = event->note()->time() + delta; new_time = event->note()->time() + delta;
} }
@ -3053,9 +3053,9 @@ MidiRegionView::transpose (bool up, bool fine, bool allow_smush)
void void
MidiRegionView::change_note_lengths (bool fine, bool shorter, Evoral::MusicalTime delta, bool start, bool end) MidiRegionView::change_note_lengths (bool fine, bool shorter, Evoral::MusicalTime delta, bool start, bool end)
{ {
if (delta == 0.0) { if (!delta) {
if (fine) { if (fine) {
delta = 1.0/128.0; delta = Evoral::MusicalTime(1.0/128.0);
} else { } else {
/* grab the current grid distance */ /* grab the current grid distance */
delta = get_grid_beats(_region->position()); delta = get_grid_beats(_region->position());
@ -3074,7 +3074,9 @@ MidiRegionView::change_note_lengths (bool fine, bool shorter, Evoral::MusicalTim
/* note the negation of the delta for start */ /* note the negation of the delta for start */
trim_note (*i, (start ? -delta : 0), (end ? delta : 0)); trim_note (*i,
(start ? -delta : Evoral::MusicalTime()),
(end ? delta : Evoral::MusicalTime()));
i = next; i = next;
} }
@ -3402,10 +3404,10 @@ MidiRegionView::paste_internal (framepos_t pos, unsigned paste_count, float time
const Evoral::MusicalTime first_time = (*mcb.notes().begin())->time(); const Evoral::MusicalTime first_time = (*mcb.notes().begin())->time();
const Evoral::MusicalTime last_time = (*mcb.notes().rbegin())->end_time(); const Evoral::MusicalTime last_time = (*mcb.notes().rbegin())->end_time();
const Evoral::MusicalTime duration = last_time - first_time; const Evoral::MusicalTime duration = last_time - first_time;
const Evoral::MusicalTime snap_duration = ceil(duration / snap_beats) * snap_beats; const Evoral::MusicalTime snap_duration = duration.snap_to(snap_beats);
const Evoral::MusicalTime paste_offset = paste_count * snap_duration; const Evoral::MusicalTime paste_offset = snap_duration * paste_count;
const Evoral::MusicalTime pos_beats = absolute_frames_to_source_beats(pos) + paste_offset; const Evoral::MusicalTime pos_beats = absolute_frames_to_source_beats(pos) + paste_offset;
Evoral::MusicalTime end_point = 0; Evoral::MusicalTime end_point = Evoral::MusicalTime();
DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("Paste data spans from %1 to %2 (%3) ; paste pos beats = %4 (based on %5 - %6)\n", DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("Paste data spans from %1 to %2 (%3) ; paste pos beats = %4 (based on %5 - %6)\n",
first_time, first_time,
@ -3585,7 +3587,8 @@ MidiRegionView::update_ghost_note (double x, double y)
the start of the source; that is how all note times are stored. the start of the source; that is how all note times are stored.
*/ */
_ghost_note->note()->set_time ( _ghost_note->note()->set_time (
std::max(0.0, absolute_frames_to_source_beats (f + _region->position ()))); std::max(Evoral::MusicalTime(),
absolute_frames_to_source_beats (f + _region->position ())));
_ghost_note->note()->set_length (length); _ghost_note->note()->set_length (length);
_ghost_note->note()->set_note (midi_stream_view()->y_to_note (y)); _ghost_note->note()->set_note (midi_stream_view()->y_to_note (y));
_ghost_note->note()->set_channel (mtv->get_channel_for_add ()); _ghost_note->note()->set_channel (mtv->get_channel_for_add ());
@ -3786,7 +3789,7 @@ MidiRegionView::data_recorded (boost::weak_ptr<MidiSource> w)
if (ev.type() == MIDI_CMD_NOTE_ON) { if (ev.type() == MIDI_CMD_NOTE_ON) {
boost::shared_ptr<NoteType> note ( boost::shared_ptr<NoteType> note (
new NoteType (ev.channel(), time_beats, 0, ev.note(), ev.velocity())); new NoteType (ev.channel(), time_beats, Evoral::MusicalTime(), ev.note(), ev.velocity()));
add_note (note, true); add_note (note, true);
@ -3969,7 +3972,7 @@ MidiRegionView::get_grid_beats(framepos_t pos) const
bool success = false; bool success = false;
Evoral::MusicalTime beats = editor.get_grid_type_as_beats(success, pos); Evoral::MusicalTime beats = editor.get_grid_type_as_beats(success, pos);
if (!success) { if (!success) {
beats = 1; beats = Evoral::MusicalTime(1);
} }
return beats; return beats;
} }

View file

@ -110,7 +110,7 @@ public:
GhostRegion* add_ghost (TimeAxisView&); GhostRegion* add_ghost (TimeAxisView&);
void add_note(const boost::shared_ptr<NoteType> note, bool visible); void add_note(const boost::shared_ptr<NoteType> note, bool visible);
void resolve_note(uint8_t note_num, double end_time); void resolve_note(uint8_t note_num, Evoral::MusicalTime end_time);
void cut_copy_clear (Editing::CutCopyOp); void cut_copy_clear (Editing::CutCopyOp);
bool paste (framepos_t pos, unsigned paste_count, float times, const ::Selection& selection, ItemCounts& counts); bool paste (framepos_t pos, unsigned paste_count, float times, const ::Selection& selection, ItemCounts& counts);
@ -124,7 +124,7 @@ public:
* @key a reference to an instance of MIDI::Name::PatchPrimaryKey whose fields will * @key a reference to an instance of MIDI::Name::PatchPrimaryKey whose fields will
* will be set according to the result of the lookup * will be set according to the result of the lookup
*/ */
void get_patch_key_at (double time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key) const; void get_patch_key_at (Evoral::MusicalTime time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key) const;
/** Convert a given PatchChange into a PatchPrimaryKey /** Convert a given PatchChange into a PatchPrimaryKey
*/ */
@ -258,22 +258,22 @@ public:
framepos_t snap_pixel_to_sample(double x); framepos_t snap_pixel_to_sample(double x);
/** Convert a timestamp in beats into frames (both relative to region position) */ /** Convert a timestamp in beats into frames (both relative to region position) */
framepos_t region_beats_to_region_frames(double beats) const; framepos_t region_beats_to_region_frames(Evoral::MusicalTime beats) const;
/** Convert a timestamp in beats into absolute frames */ /** Convert a timestamp in beats into absolute frames */
framepos_t region_beats_to_absolute_frames(double beats) const { framepos_t region_beats_to_absolute_frames(Evoral::MusicalTime beats) const {
return _region->position() + region_beats_to_region_frames (beats); return _region->position() + region_beats_to_region_frames (beats);
} }
/** Convert a timestamp in frames to beats (both relative to region position) */ /** Convert a timestamp in frames to beats (both relative to region position) */
double region_frames_to_region_beats(framepos_t) const; Evoral::MusicalTime region_frames_to_region_beats(framepos_t) const;
/** Convert a timestamp in beats measured from source start into absolute frames */ /** Convert a timestamp in beats measured from source start into absolute frames */
framepos_t source_beats_to_absolute_frames(double beats) const; framepos_t source_beats_to_absolute_frames(Evoral::MusicalTime beats) const;
/** Convert a timestamp in beats measured from source start into region-relative frames */ /** Convert a timestamp in beats measured from source start into region-relative frames */
framepos_t source_beats_to_region_frames(double beats) const { framepos_t source_beats_to_region_frames(Evoral::MusicalTime beats) const {
return source_beats_to_absolute_frames (beats) - _region->position(); return source_beats_to_absolute_frames (beats) - _region->position();
} }
/** Convert a timestamp in absolute frames to beats measured from source start*/ /** Convert a timestamp in absolute frames to beats measured from source start*/
double absolute_frames_to_source_beats(framepos_t) const; Evoral::MusicalTime absolute_frames_to_source_beats(framepos_t) const;
ARDOUR::BeatsFramesConverter const & region_relative_time_converter () const { ARDOUR::BeatsFramesConverter const & region_relative_time_converter () const {
return _region_relative_time_converter; return _region_relative_time_converter;
@ -309,7 +309,13 @@ public:
void trim_front_starting (); void trim_front_starting ();
void trim_front_ending (); void trim_front_ending ();
void create_note_at (framepos_t, double, double, bool); /** Add a note to the model, and the view, at a canvas (click) coordinate.
* \param t time in frames relative to the position of the region
* \param y vertical position in pixels
* \param length duration of the note in beats
* \param snap_t true to snap t to the grid, otherwise false.
*/
void create_note_at (framepos_t t, double y, Evoral::MusicalTime length, bool snap_t);
void clear_selection (bool signal = true) { clear_selection_except (0, signal); } void clear_selection (bool signal = true) { clear_selection_except (0, signal); }

View file

@ -143,7 +143,7 @@ PatchChangeDialog::instrument_info_changed ()
Evoral::PatchChange<Evoral::MusicalTime> Evoral::PatchChange<Evoral::MusicalTime>
PatchChangeDialog::patch () const PatchChangeDialog::patch () const
{ {
Evoral::MusicalTime t = 0; Evoral::MusicalTime t = Evoral::MusicalTime();
if (_time_converter) { if (_time_converter) {
t = _time_converter->from (_time.current_time ()); t = _time_converter->from (_time.current_time ());

View file

@ -41,7 +41,7 @@ StepEditor::StepEditor (PublicEditor& e, boost::shared_ptr<MidiTrack> t, MidiTim
step_edit_insert_position = 0; step_edit_insert_position = 0;
_step_edit_triplet_countdown = 0; _step_edit_triplet_countdown = 0;
_step_edit_within_chord = 0; _step_edit_within_chord = 0;
_step_edit_chord_duration = 0.0; _step_edit_chord_duration = Evoral::MusicalTime();
step_edit_region_view = 0; step_edit_region_view = 0;
_track->PlaylistChanged.connect (*this, invalidator (*this), _track->PlaylistChanged.connect (*this, invalidator (*this),
@ -60,11 +60,11 @@ StepEditor::start_step_editing ()
{ {
_step_edit_triplet_countdown = 0; _step_edit_triplet_countdown = 0;
_step_edit_within_chord = 0; _step_edit_within_chord = 0;
_step_edit_chord_duration = 0.0; _step_edit_chord_duration = Evoral::MusicalTime();
step_edit_region.reset (); step_edit_region.reset ();
step_edit_region_view = 0; step_edit_region_view = 0;
last_added_pitch = -1; last_added_pitch = -1;
last_added_end = 0; last_added_end = Evoral::MusicalTime();
resync_step_edit_position (); resync_step_edit_position ();
prepare_step_edit_region (); prepare_step_edit_region ();
@ -198,7 +198,7 @@ StepEditor::check_step_edit ()
incoming.read_contents (size, buf); incoming.read_contents (size, buf);
if ((buf[0] & 0xf0) == MIDI_CMD_NOTE_ON) { if ((buf[0] & 0xf0) == MIDI_CMD_NOTE_ON) {
step_add_note (buf[0] & 0xf, buf[1], buf[2], 0.0); step_add_note (buf[0] & 0xf, buf[1], buf[2], Evoral::MusicalTime());
} }
} }
} }
@ -233,7 +233,7 @@ StepEditor::move_step_edit_beat_pos (Evoral::MusicalTime beats)
if (-beats < step_edit_beat_pos) { if (-beats < step_edit_beat_pos) {
step_edit_beat_pos += beats; // its negative, remember step_edit_beat_pos += beats; // its negative, remember
} else { } else {
step_edit_beat_pos = 0; step_edit_beat_pos = Evoral::MusicalTime();
} }
} }
step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos); step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
@ -292,8 +292,8 @@ StepEditor::step_add_note (uint8_t channel, uint8_t pitch, uint8_t velocity, Evo
up by 1 tick from where the last note ended up by 1 tick from where the last note ended
*/ */
at += 1.0/Timecode::BBT_Time::ticks_per_beat; at += Evoral::MusicalTime::ticks(1);
len -= 1.0/Timecode::BBT_Time::ticks_per_beat; len -= Evoral::MusicalTime::ticks(1);
} }
step_edit_region_view->step_add_note (channel, pitch, velocity, at, len); step_edit_region_view->step_add_note (channel, pitch, velocity, at, len);
@ -313,7 +313,7 @@ StepEditor::step_add_note (uint8_t channel, uint8_t pitch, uint8_t velocity, Evo
step_edit_beat_pos += beat_duration; step_edit_beat_pos += beat_duration;
step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos); step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
} else { } else {
step_edit_beat_pos += 1.0/Timecode::BBT_Time::ticks_per_beat; // tiny, but no longer overlapping step_edit_beat_pos += Evoral::MusicalTime::ticks(1); // tiny, but no longer overlapping
_step_edit_chord_duration = max (_step_edit_chord_duration, beat_duration); _step_edit_chord_duration = max (_step_edit_chord_duration, beat_duration);
} }
@ -384,7 +384,7 @@ StepEditor::step_edit_rest (Evoral::MusicalTime beats)
void void
StepEditor::step_edit_beat_sync () StepEditor::step_edit_beat_sync ()
{ {
step_edit_beat_pos = ceil (step_edit_beat_pos); step_edit_beat_pos = step_edit_beat_pos.round_up_to_beat();
step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos); step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
} }
@ -399,7 +399,7 @@ StepEditor::step_edit_bar_sync ()
framepos_t fpos = step_edit_region_view->region_beats_to_absolute_frames (step_edit_beat_pos); framepos_t fpos = step_edit_region_view->region_beats_to_absolute_frames (step_edit_beat_pos);
fpos = _session->tempo_map().round_to_bar (fpos, RoundUpAlways); fpos = _session->tempo_map().round_to_bar (fpos, RoundUpAlways);
step_edit_beat_pos = ceil (step_edit_region_view->region_frames_to_region_beats (fpos - step_edit_region->position())); step_edit_beat_pos = step_edit_region_view->region_frames_to_region_beats (fpos - step_edit_region->position()).round_up_to_beat();
step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos); step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
} }
@ -425,7 +425,7 @@ StepEditor::region_removed (boost::weak_ptr<Region> wr)
step_edit_region.reset(); step_edit_region.reset();
step_edit_region_view = 0; step_edit_region_view = 0;
// force a recompute of the insert position // force a recompute of the insert position
step_edit_beat_pos = -1.0; step_edit_beat_pos = Evoral::MusicalTime(-1);
} }
} }

View file

@ -526,13 +526,13 @@ StepEntry::on_key_release_event (GdkEventKey* ev)
void void
StepEntry::rest_event_handler () StepEntry::rest_event_handler ()
{ {
se->step_edit_rest (0.0); se->step_edit_rest (Evoral::MusicalTime());
} }
Evoral::MusicalTime Evoral::MusicalTime
StepEntry::note_length () StepEntry::note_length ()
{ {
Evoral::MusicalTime base_time = 4.0 / (Evoral::MusicalTime) length_divisor_adjustment.get_value(); double base_time = 4.0 / (double) length_divisor_adjustment.get_value();
RefPtr<Action> act = myactions.find_action ("StepEditing/toggle-triplet"); RefPtr<Action> act = myactions.find_action ("StepEditing/toggle-triplet");
RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic (act); RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic (act);
@ -549,7 +549,7 @@ StepEntry::note_length ()
base_time *= 1 + ((dots - 1.0)/dots); base_time *= 1 + ((dots - 1.0)/dots);
} }
return base_time; return Evoral::MusicalTime(base_time);
} }
uint8_t uint8_t
@ -795,7 +795,7 @@ StepEntry::insert_rest ()
void void
StepEntry::insert_grid_rest () StepEntry::insert_grid_rest ()
{ {
se->step_edit_rest (0.0); se->step_edit_rest (Evoral::MusicalTime());
} }
void void

View file

@ -24,6 +24,7 @@
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp> #include <boost/enable_shared_from_this.hpp>
#include "evoral/types.hpp"
#include "pbd/controllable.h" #include "pbd/controllable.h"
#include "evoral/Control.hpp" #include "evoral/Control.hpp"

View file

@ -27,6 +27,9 @@
#include <glibmm/threads.h> #include <glibmm/threads.h>
#include "evoral/ControlList.hpp"
#include "evoral/Parameter.hpp"
#include "pbd/undo.h" #include "pbd/undo.h"
#include "pbd/xml++.h" #include "pbd/xml++.h"
#include "pbd/statefuldestructible.h" #include "pbd/statefuldestructible.h"
@ -34,8 +37,6 @@
#include "ardour/ardour.h" #include "ardour/ardour.h"
#include "evoral/ControlList.hpp"
namespace ARDOUR { namespace ARDOUR {
class AutomationList; class AutomationList;

View file

@ -20,6 +20,8 @@
*/ */
#include "evoral/TimeConverter.hpp" #include "evoral/TimeConverter.hpp"
#include "evoral/types.hpp"
#include "ardour/libardour_visibility.h" #include "ardour/libardour_visibility.h"
#include "ardour/types.h" #include "ardour/types.h"
@ -34,15 +36,35 @@ class TempoMap;
* from some origin (supplied to the constructor in frames), and converts * from some origin (supplied to the constructor in frames), and converts
* them to the opposite unit, taking tempo changes into account. * them to the opposite unit, taking tempo changes into account.
*/ */
class LIBARDOUR_API BeatsFramesConverter : public Evoral::TimeConverter<double,framepos_t> { class LIBARDOUR_API BeatsFramesConverter
: public Evoral::TimeConverter<Evoral::MusicalTime,framepos_t> {
public: public:
BeatsFramesConverter (TempoMap& tempo_map, framepos_t origin) BeatsFramesConverter (TempoMap& tempo_map, framepos_t origin)
: Evoral::TimeConverter<Evoral::MusicalTime, framepos_t> (origin)
, _tempo_map(tempo_map)
{}
framepos_t to (Evoral::MusicalTime beats) const;
Evoral::MusicalTime from (framepos_t frames) const;
private:
TempoMap& _tempo_map;
};
/** Converter between beats and frames. Takes distances in beats or frames
* from some origin (supplied to the constructor in frames), and converts
* them to the opposite unit, taking tempo changes into account.
*/
class LIBARDOUR_API DoubleBeatsFramesConverter
: public Evoral::TimeConverter<double,framepos_t> {
public:
DoubleBeatsFramesConverter (TempoMap& tempo_map, framepos_t origin)
: Evoral::TimeConverter<double, framepos_t> (origin) : Evoral::TimeConverter<double, framepos_t> (origin)
, _tempo_map(tempo_map) , _tempo_map(tempo_map)
{} {}
framepos_t to (double beats) const; framepos_t to (double beats) const;
double from (framepos_t frames) const; double from (framepos_t frames) const;
private: private:
TempoMap& _tempo_map; TempoMap& _tempo_map;

View file

@ -116,16 +116,11 @@ public:
struct NoteChange { struct NoteChange {
NoteDiffCommand::Property property; NoteDiffCommand::Property property;
NotePtr note; NotePtr note;
uint32_t note_id; uint32_t note_id;
uint8_t old_value; // or...
union { TimeType old_time; // this
uint8_t old_value; uint8_t new_value; // or...
TimeType old_time; TimeType new_time; // this
};
union {
uint8_t new_value;
TimeType new_time;
};
}; };
typedef std::list<NoteChange> ChangeList; typedef std::list<NoteChange> ChangeList;
@ -209,16 +204,16 @@ public:
struct Change { struct Change {
PatchChangePtr patch; PatchChangePtr patch;
Property property; Property property;
gint patch_id; gint patch_id;
TimeType old_time;
union { union {
TimeType old_time;
uint8_t old_channel; uint8_t old_channel;
int old_bank; int old_bank;
uint8_t old_program; uint8_t old_program;
}; };
TimeType new_time;
union { union {
uint8_t new_channel; uint8_t new_channel;
TimeType new_time;
uint8_t new_program; uint8_t new_program;
int new_bank; int new_bank;
}; };
@ -311,7 +306,5 @@ private:
} /* namespace ARDOUR */ } /* namespace ARDOUR */
/* This is a very long comment and stuff oh my god it's so long what are we going to do oh no oh no*/
#endif /* __ardour_midi_model_h__ */ #endif /* __ardour_midi_model_h__ */

View file

@ -23,6 +23,8 @@
#include <vector> #include <vector>
#include "evoral/types.hpp"
#include "ardour/ardour.h" #include "ardour/ardour.h"
#include "ardour/region.h" #include "ardour/region.h"

View file

@ -43,7 +43,7 @@ template<typename T> class MidiRingBuffer;
class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_shared_from_this<MidiSource> class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_shared_from_this<MidiSource>
{ {
public: public:
typedef double TimeType; typedef Evoral::MusicalTime TimeType;
MidiSource (Session& session, std::string name, Source::Flag flags = Source::Flag(0)); MidiSource (Session& session, std::string name, Source::Flag flags = Source::Flag(0));
MidiSource (Session& session, const XMLNode&); MidiSource (Session& session, const XMLNode&);
@ -120,7 +120,7 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
*/ */
virtual void mark_midi_streaming_write_completed ( virtual void mark_midi_streaming_write_completed (
Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption stuck_option, Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption stuck_option,
Evoral::MusicalTime when = 0); Evoral::MusicalTime when = Evoral::MusicalTime());
virtual void session_saved(); virtual void session_saved();
@ -134,8 +134,8 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
bool length_mutable() const { return true; } bool length_mutable() const { return true; }
void set_length_beats(double l) { _length_beats = l; } void set_length_beats(TimeType l) { _length_beats = l; }
double length_beats() const { return _length_beats; } TimeType length_beats() const { return _length_beats; }
virtual void load_model(bool lock=true, bool force_reload=false) = 0; virtual void load_model(bool lock=true, bool force_reload=false) = 0;
virtual void destroy_model() = 0; virtual void destroy_model() = 0;
@ -194,8 +194,8 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
mutable Evoral::Sequence<Evoral::MusicalTime>::const_iterator _model_iter; mutable Evoral::Sequence<Evoral::MusicalTime>::const_iterator _model_iter;
mutable bool _model_iter_valid; mutable bool _model_iter_valid;
mutable double _length_beats; mutable Evoral::MusicalTime _length_beats;
mutable framepos_t _last_read_end; mutable framepos_t _last_read_end;
/** The total duration of the current capture. */ /** The total duration of the current capture. */
framepos_t _capture_length; framepos_t _capture_length;

View file

@ -56,7 +56,8 @@ public:
void mark_streaming_midi_write_started (NoteMode mode); void mark_streaming_midi_write_started (NoteMode mode);
void mark_streaming_write_completed (); void mark_streaming_write_completed ();
void mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption, Evoral::MusicalTime when = 0); void mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption,
Evoral::MusicalTime when = Evoral::MusicalTime());
XMLNode& get_state (); XMLNode& get_state ();
int set_state (const XMLNode&, int version); int set_state (const XMLNode&, int version);
@ -88,8 +89,8 @@ public:
framepos_t position, framepos_t position,
framecnt_t cnt); framecnt_t cnt);
double _last_ev_time_beats; Evoral::MusicalTime _last_ev_time_beats;
framepos_t _last_ev_time_frames; framepos_t _last_ev_time_frames;
/** end time (start + duration) of last call to read_unlocked */ /** end time (start + duration) of last call to read_unlocked */
mutable framepos_t _smf_last_read_end; mutable framepos_t _smf_last_read_end;
/** time (in SMF ticks, 1 tick per _ppqn) of the last event read by read_unlocked */ /** time (in SMF ticks, 1 tick per _ppqn) of the last event read by read_unlocked */

View file

@ -31,26 +31,43 @@ namespace ARDOUR {
* taking tempo changes into account. * taking tempo changes into account.
*/ */
framepos_t framepos_t
BeatsFramesConverter::to (double beats) const BeatsFramesConverter::to (Evoral::MusicalTime beats) const
{ {
if (beats < 0) { if (beats < Evoral::MusicalTime()) {
std::cerr << "negative beats passed to BFC: " << beats << std::endl; std::cerr << "negative beats passed to BFC: " << beats << std::endl;
PBD::stacktrace (std::cerr, 30); PBD::stacktrace (std::cerr, 30);
return 0;
} }
assert (beats >= 0); return _tempo_map.framepos_plus_beats (_origin_b, beats) - _origin_b;
framecnt_t r = _tempo_map.framepos_plus_beats (_origin_b, beats) - _origin_b;
return r;
} }
/** Takes a duration in frames and considers it as a distance from the origin /** Takes a duration in frames and considers it as a distance from the origin
* supplied to the constructor. Returns the equivalent number of beats, * supplied to the constructor. Returns the equivalent number of beats,
* taking tempo changes into account. * taking tempo changes into account.
*/ */
double Evoral::MusicalTime
BeatsFramesConverter::from (framepos_t frames) const BeatsFramesConverter::from (framepos_t frames) const
{ {
double b = _tempo_map.framewalk_to_beats (_origin_b, frames); return _tempo_map.framewalk_to_beats (_origin_b, frames);
return b; }
/** As above, but with beats in double instead (for GUI). */
framepos_t
DoubleBeatsFramesConverter::to (double beats) const
{
if (beats < 0.0) {
std::cerr << "negative beats passed to BFC: " << beats << std::endl;
PBD::stacktrace (std::cerr, 30);
return 0;
}
return _tempo_map.framepos_plus_beats (_origin_b, Evoral::MusicalTime(beats)) - _origin_b;
}
/** As above, but with beats in double instead (for GUI). */
double
DoubleBeatsFramesConverter::from (framepos_t frames) const
{
return _tempo_map.framewalk_to_beats (_origin_b, frames).to_double();
} }
} /* namespace ARDOUR */ } /* namespace ARDOUR */

View file

@ -389,10 +389,11 @@ write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
} }
smfs->append_event_unlocked_beats( smfs->append_event_unlocked_beats(
Evoral::Event<double>(0, Evoral::Event<Evoral::MusicalTime>(
(double)t / (double)source->ppqn(), 0,
size, Evoral::MusicalTime::ticks_at_rate(t, source->ppqn()),
buf)); size,
buf));
if (status.progress < 0.99) { if (status.progress < 0.99) {
status.progress += 0.01; status.progress += 0.01;
@ -403,10 +404,10 @@ write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
/* we wrote something */ /* we wrote something */
const framepos_t pos = 0; const framepos_t pos = 0;
const double length_beats = ceil(t / (double)source->ppqn()); const Evoral::MusicalTime length_beats = Evoral::MusicalTime::ticks_at_rate(t, source->ppqn());
BeatsFramesConverter converter(smfs->session().tempo_map(), pos); BeatsFramesConverter converter(smfs->session().tempo_map(), pos);
smfs->update_length(pos + converter.to(length_beats)); smfs->update_length(pos + converter.to(length_beats.round_up_to_beat()));
smfs->mark_streaming_write_completed (); smfs->mark_streaming_write_completed ();
if (status.cancel) { if (status.cancel) {

View file

@ -927,7 +927,7 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
/* set length in beats to entire capture length */ /* set length in beats to entire capture length */
BeatsFramesConverter converter (_session.tempo_map(), capture_info.front()->start); BeatsFramesConverter converter (_session.tempo_map(), capture_info.front()->start);
const double total_capture_beats = converter.from (total_capture); const Evoral::MusicalTime total_capture_beats = converter.from (total_capture);
_write_source->set_length_beats (total_capture_beats); _write_source->set_length_beats (total_capture_beats);
/* flush to disk: this step differs from the audio path, /* flush to disk: this step differs from the audio path,

View file

@ -226,13 +226,13 @@ MidiModel::NoteDiffCommand::change (const NotePtr note, Property prop,
break; break;
case StartTime: case StartTime:
if (Evoral::musical_time_equal (note->time(), new_time)) { if (note->time() == new_time) {
return; return;
} }
change.old_time = note->time(); change.old_time = note->time();
break; break;
case Length: case Length:
if (Evoral::musical_time_equal (note->length(), new_time)) { if (note->length() == new_time) {
return; return;
} }
change.old_time = note->length(); change.old_time = note->length();
@ -556,7 +556,7 @@ MidiModel::NoteDiffCommand::unmarshal_note (XMLNode *xml_note)
time_str >> time; time_str >> time;
} else { } else {
warning << "note information missing time" << endmsg; warning << "note information missing time" << endmsg;
time = 0; time = MidiModel::TimeType();
} }
if ((prop = xml_note->property("length")) != 0) { if ((prop = xml_note->property("length")) != 0) {
@ -564,7 +564,7 @@ MidiModel::NoteDiffCommand::unmarshal_note (XMLNode *xml_note)
length_str >> length; length_str >> length;
} else { } else {
warning << "note information missing length" << endmsg; warning << "note information missing length" << endmsg;
length = 1; length = MidiModel::TimeType(1);
} }
if ((prop = xml_note->property("velocity")) != 0) { if ((prop = xml_note->property("velocity")) != 0) {
@ -1253,7 +1253,7 @@ MidiModel::PatchChangeDiffCommand::unmarshal_patch_change (XMLNode* n)
{ {
XMLProperty* prop; XMLProperty* prop;
Evoral::event_id_t id = 0; Evoral::event_id_t id = 0;
Evoral::MusicalTime time = 0; Evoral::MusicalTime time = Evoral::MusicalTime();
int channel = 0; int channel = 0;
int program = 0; int program = 0;
int bank = 0; int bank = 0;
@ -1439,7 +1439,7 @@ MidiModel::write_to (boost::shared_ptr<MidiSource> source)
source->drop_model(); source->drop_model();
source->mark_streaming_midi_write_started (note_mode()); source->mark_streaming_midi_write_started (note_mode());
for (Evoral::Sequence<TimeType>::const_iterator i = begin(0, true); i != end(); ++i) { for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
source->append_event_unlocked_beats(*i); source->append_event_unlocked_beats(*i);
} }
@ -1469,7 +1469,7 @@ MidiModel::sync_to_source ()
ms->mark_streaming_midi_write_started (note_mode()); ms->mark_streaming_midi_write_started (note_mode());
for (Evoral::Sequence<TimeType>::const_iterator i = begin(0, true); i != end(); ++i) { for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
ms->append_event_unlocked_beats(*i); ms->append_event_unlocked_beats(*i);
} }
@ -1503,7 +1503,7 @@ MidiModel::write_section_to (boost::shared_ptr<MidiSource> source, Evoral::Music
source->drop_model(); source->drop_model();
source->mark_streaming_midi_write_started (note_mode()); source->mark_streaming_midi_write_started (note_mode());
for (Evoral::Sequence<TimeType>::const_iterator i = begin(0, true); i != end(); ++i) { for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
const Evoral::Event<Evoral::MusicalTime>& ev (*i); const Evoral::Event<Evoral::MusicalTime>& ev (*i);
if (ev.time() >= begin_time && ev.time() < end_time) { if (ev.time() >= begin_time && ev.time() < end_time) {
@ -1662,7 +1662,7 @@ MidiModel::resolve_overlaps_unlocked (const NotePtr note, void* arg)
TimeType ea = note->end_time(); TimeType ea = note->end_time();
const Pitches& p (pitches (note->channel())); const Pitches& p (pitches (note->channel()));
NotePtr search_note(new Note<TimeType>(0, 0, 0, note->note())); NotePtr search_note(new Note<TimeType>(0, TimeType(), TimeType(), note->note()));
set<NotePtr> to_be_deleted; set<NotePtr> to_be_deleted;
bool set_note_length = false; bool set_note_length = false;
bool set_note_time = false; bool set_note_time = false;
@ -1979,7 +1979,7 @@ MidiModel::insert_silence_at_start (TimeType t)
for (Controls::iterator i = controls().begin(); i != controls().end(); ++i) { for (Controls::iterator i = controls().begin(); i != controls().end(); ++i) {
boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (i->second); boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (i->second);
XMLNode& before = ac->alist()->get_state (); XMLNode& before = ac->alist()->get_state ();
i->second->list()->shift (0, t); i->second->list()->shift (0, t.to_double());
XMLNode& after = ac->alist()->get_state (); XMLNode& after = ac->alist()->get_state ();
s->session().add_command (new MementoCommand<AutomationList> (new MidiAutomationListBinder (s, i->first), &before, &after)); s->session().add_command (new MementoCommand<AutomationList> (new MidiAutomationListBinder (s, i->first), &before, &after));
} }

View file

@ -28,6 +28,8 @@
#include <glibmm/fileutils.h> #include <glibmm/fileutils.h>
#include <glibmm/miscutils.h> #include <glibmm/miscutils.h>
#include "evoral/types.hpp"
#include "pbd/xml++.h" #include "pbd/xml++.h"
#include "pbd/basename.h" #include "pbd/basename.h"
@ -78,7 +80,7 @@ MidiRegion::register_properties ()
/* Basic MidiRegion constructor (many channels) */ /* Basic MidiRegion constructor (many channels) */
MidiRegion::MidiRegion (const SourceList& srcs) MidiRegion::MidiRegion (const SourceList& srcs)
: Region (srcs) : Region (srcs)
, _start_beats (Properties::start_beats, 0) , _start_beats (Properties::start_beats, Evoral::MusicalTime())
, _length_beats (Properties::length_beats, midi_source(0)->length_beats()) , _length_beats (Properties::length_beats, midi_source(0)->length_beats())
{ {
register_properties (); register_properties ();
@ -92,7 +94,7 @@ MidiRegion::MidiRegion (const SourceList& srcs)
MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other) MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other)
: Region (other) : Region (other)
, _start_beats (Properties::start_beats, other->_start_beats) , _start_beats (Properties::start_beats, other->_start_beats)
, _length_beats (Properties::length_beats, (Evoral::MusicalTime) 0) , _length_beats (Properties::length_beats, Evoral::MusicalTime())
{ {
update_length_beats (); update_length_beats ();
register_properties (); register_properties ();
@ -105,14 +107,14 @@ MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other)
/** Create a new MidiRegion that is part of an existing one */ /** Create a new MidiRegion that is part of an existing one */
MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other, frameoffset_t offset) MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other, frameoffset_t offset)
: Region (other, offset) : Region (other, offset)
, _start_beats (Properties::start_beats, (Evoral::MusicalTime) 0) , _start_beats (Properties::start_beats, Evoral::MusicalTime())
, _length_beats (Properties::length_beats, (Evoral::MusicalTime) 0) , _length_beats (Properties::length_beats, Evoral::MusicalTime())
{ {
BeatsFramesConverter bfc (_session.tempo_map(), _position); BeatsFramesConverter bfc (_session.tempo_map(), _position);
Evoral::MusicalTime const offset_beats = bfc.from (offset); Evoral::MusicalTime const offset_beats = bfc.from (offset);
_start_beats = other->_start_beats + offset_beats; _start_beats = other->_start_beats.val() + offset_beats;
_length_beats = other->_length_beats - offset_beats; _length_beats = other->_length_beats.val() - offset_beats;
register_properties (); register_properties ();
@ -216,7 +218,7 @@ MidiRegion::set_position_internal (framepos_t pos, bool allow_bbt_recompute)
/* zero length regions don't exist - so if _length_beats is zero, this object /* zero length regions don't exist - so if _length_beats is zero, this object
is under construction. is under construction.
*/ */
if (_length_beats) { if (_length_beats.val() == Evoral::MusicalTime()) {
/* leave _length_beats alone, and change _length to reflect the state of things /* leave _length_beats alone, and change _length to reflect the state of things
at the new position (tempo map may dictate a different number of frames at the new position (tempo map may dictate a different number of frames
*/ */
@ -440,7 +442,7 @@ MidiRegion::fix_negative_start ()
model()->insert_silence_at_start (c.from (-_start)); model()->insert_silence_at_start (c.from (-_start));
_start = 0; _start = 0;
_start_beats = 0; _start_beats = Evoral::MusicalTime();
} }
/** Transpose the notes in this region by a given number of semitones */ /** Transpose the notes in this region by a given number of semitones */

View file

@ -153,13 +153,13 @@ MidiSource::set_state (const XMLNode& node, int /*version*/)
bool bool
MidiSource::empty () const MidiSource::empty () const
{ {
return _length_beats == 0; return !_length_beats;
} }
framecnt_t framecnt_t
MidiSource::length (framepos_t pos) const MidiSource::length (framepos_t pos) const
{ {
if (_length_beats == 0) { if (!_length_beats) {
return 0; return 0;
} }
@ -198,7 +198,7 @@ MidiSource::midi_read (Evoral::EventSink<framepos_t>& dst,
if (_model) { if (_model) {
// Find appropriate model iterator // Find appropriate model iterator
Evoral::Sequence<double>::const_iterator& i = _model_iter; Evoral::Sequence<Evoral::MusicalTime>::const_iterator& i = _model_iter;
if (_last_read_end == 0 || start != _last_read_end || !_model_iter_valid) { if (_last_read_end == 0 || start != _last_read_end || !_model_iter_valid) {
// Cached iterator is invalid, search for the first event past start // Cached iterator is invalid, search for the first event past start
i = _model->begin(converter.from(start), false, filtered); i = _model->begin(converter.from(start), false, filtered);

View file

@ -173,7 +173,7 @@ MidiStateTracker::resolve_notes (MidiSource& src, Evoral::MusicalTime time)
this, (int) note, (int) channel, time)); this, (int) note, (int) channel, time));
_active_notes[note + 128 * channel]--; _active_notes[note + 128 * channel]--;
/* don't stack events up at the same time */ /* don't stack events up at the same time */
time += 1.0/128.0; time += Evoral::MusicalTime::tick();
} }
} }
} }

View file

@ -95,9 +95,9 @@ MidiStretch::run (boost::shared_ptr<Region> r, Progress*)
/* Note: pass true into force_discrete for the begin() iterator so that the model doesn't /* Note: pass true into force_discrete for the begin() iterator so that the model doesn't
* do interpolation of controller data when we stretch. * do interpolation of controller data when we stretch.
*/ */
for (Evoral::Sequence<MidiModel::TimeType>::const_iterator i = old_model->begin (0, true); for (Evoral::Sequence<MidiModel::TimeType>::const_iterator i = old_model->begin (MidiModel::TimeType(), true);
i != old_model->end(); ++i) { i != old_model->end(); ++i) {
const double new_time = i->time() * _request.time_fraction; const MidiModel::TimeType new_time = i->time() * (double)_request.time_fraction;
// FIXME: double copy // FIXME: double copy
Evoral::Event<MidiModel::TimeType> ev(*i, true); Evoral::Event<MidiModel::TimeType> ev(*i, true);

View file

@ -58,6 +58,8 @@ Quantize::operator () (boost::shared_ptr<MidiModel> model,
double position, double position,
std::vector<Evoral::Sequence<Evoral::MusicalTime>::Notes>& seqs) std::vector<Evoral::Sequence<Evoral::MusicalTime>::Notes>& seqs)
{ {
/* TODO: Rewrite this to be precise with fixed point? */
/* Calculate offset from start of model to next closest quantize step, /* Calculate offset from start of model to next closest quantize step,
to quantize relative to actual session beats (etc.) rather than from the to quantize relative to actual session beats (etc.) rather than from the
start of the model. start of the model.
@ -77,8 +79,8 @@ Quantize::operator () (boost::shared_ptr<MidiModel> model,
*/ */
for (Evoral::Sequence<MidiModel::TimeType>::Notes::iterator i = (*s).begin(); i != (*s).end(); ++i) { for (Evoral::Sequence<MidiModel::TimeType>::Notes::iterator i = (*s).begin(); i != (*s).end(); ++i) {
double new_start = round (((*i)->time() - offset) / _start_grid) * _start_grid + offset; double new_start = round (((*i)->time().to_double() - offset) / _start_grid) * _start_grid + offset;
double new_end = round (((*i)->end_time() - offset) / _end_grid) * _end_grid + offset; double new_end = round (((*i)->end_time().to_double() - offset) / _end_grid) * _end_grid + offset;
if (_swing > 0.0 && !even) { if (_swing > 0.0 && !even) {
@ -104,18 +106,18 @@ Quantize::operator () (boost::shared_ptr<MidiModel> model,
} }
double delta = new_start - (*i)->time(); double delta = new_start - (*i)->time().to_double();
if (fabs (delta) >= _threshold) { if (fabs (delta) >= _threshold) {
if (_snap_start) { if (_snap_start) {
delta *= _strength; delta *= _strength;
cmd->change ((*i), MidiModel::NoteDiffCommand::StartTime, cmd->change ((*i), MidiModel::NoteDiffCommand::StartTime,
(*i)->time() + delta); (*i)->time().to_double() + delta);
} }
} }
if (_snap_end) { if (_snap_end) {
delta = new_end - (*i)->end_time(); delta = new_end - (*i)->end_time().to_double();
if (fabs (delta) >= _threshold) { if (fabs (delta) >= _threshold) {
double new_dur = new_end - new_start; double new_dur = new_end - new_start;

View file

@ -225,7 +225,7 @@ SMFSource::read_unlocked (Evoral::EventSink<framepos_t>& destination,
BeatsFramesConverter converter(_session.tempo_map(), source_start); BeatsFramesConverter converter(_session.tempo_map(), source_start);
const uint64_t start_ticks = (uint64_t)(converter.from(start) * ppqn()); const uint64_t start_ticks = converter.from(start).to_ticks();
DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start in ticks %1\n", start_ticks)); DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start in ticks %1\n", start_ticks));
if (_smf_last_read_end == 0 || start != _smf_last_read_end) { if (_smf_last_read_end == 0 || start != _smf_last_read_end) {
@ -273,7 +273,7 @@ SMFSource::read_unlocked (Evoral::EventSink<framepos_t>& destination,
/* Note that we add on the source start time (in session frames) here so that ev_frame_time /* Note that we add on the source start time (in session frames) here so that ev_frame_time
is in session frames. is in session frames.
*/ */
const framepos_t ev_frame_time = converter.to(time / (double)ppqn()) + source_start; const framepos_t ev_frame_time = converter.to(Evoral::MusicalTime::ticks_at_rate(time, ppqn())) + source_start;
if (ev_frame_time < start + duration) { if (ev_frame_time < start + duration) {
destination.write (ev_frame_time, ev_type, ev_size, ev_buffer); destination.write (ev_frame_time, ev_type, ev_size, ev_buffer);
@ -377,9 +377,9 @@ SMFSource::write_unlocked (MidiRingBuffer<framepos_t>& source,
return cnt; return cnt;
} }
/** Append an event with a timestamp in beats (double) */ /** Append an event with a timestamp in beats */
void void
SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev) SMFSource::append_event_unlocked_beats (const Evoral::Event<Evoral::MusicalTime>& ev)
{ {
if (!_writing || ev.size() == 0) { if (!_writing || ev.size() == 0) {
return; return;
@ -389,10 +389,10 @@ SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev)
name().c_str(), ev.id(), ev.time(), ev.size()); name().c_str(), ev.id(), ev.time(), ev.size());
for (size_t i = 0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");*/ for (size_t i = 0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");*/
double time = ev.time(); Evoral::MusicalTime time = ev.time();
if (time < _last_ev_time_beats) { if (time < _last_ev_time_beats) {
const double difference = _last_ev_time_beats - time; const Evoral::MusicalTime difference = _last_ev_time_beats - time;
if (difference / (double)ppqn() < 1.0) { if (difference.to_double() / (double)ppqn() < 1.0) {
/* Close enough. This problem occurs because Sequence is not /* Close enough. This problem occurs because Sequence is not
actually ordered due to fuzzy time comparison. I'm pretty sure actually ordered due to fuzzy time comparison. I'm pretty sure
this is inherently a bad idea which causes problems all over the this is inherently a bad idea which causes problems all over the
@ -401,7 +401,7 @@ SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev)
} else { } else {
/* Out of order by more than a tick. */ /* Out of order by more than a tick. */
warning << string_compose(_("Skipping event with unordered beat time %1 < %2 (off by %3 beats, %4 ticks)"), warning << string_compose(_("Skipping event with unordered beat time %1 < %2 (off by %3 beats, %4 ticks)"),
ev.time(), _last_ev_time_beats, difference, difference / (double)ppqn()) ev.time(), _last_ev_time_beats, difference, difference.to_double() / (double)ppqn())
<< endmsg; << endmsg;
return; return;
} }
@ -421,8 +421,8 @@ SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev)
_length_beats = max(_length_beats, time); _length_beats = max(_length_beats, time);
const double delta_time_beats = time - _last_ev_time_beats; const Evoral::MusicalTime delta_time_beats = time - _last_ev_time_beats;
const uint32_t delta_time_ticks = (uint32_t)lrint(delta_time_beats * (double)ppqn()); const uint32_t delta_time_ticks = delta_time_beats.to_ticks(ppqn());
Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id); Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
_last_ev_time_beats = time; _last_ev_time_beats = time;
@ -448,9 +448,9 @@ SMFSource::append_event_unlocked_frames (const Evoral::Event<framepos_t>& ev, fr
return; return;
} }
BeatsFramesConverter converter(_session.tempo_map(), position); BeatsFramesConverter converter(_session.tempo_map(), position);
const double ev_time_beats = converter.from(ev.time()); const Evoral::MusicalTime ev_time_beats = converter.from(ev.time());
Evoral::event_id_t event_id; Evoral::event_id_t event_id;
if (ev.id() < 0) { if (ev.id() < 0) {
event_id = Evoral::next_event_id(); event_id = Evoral::next_event_id();
@ -459,10 +459,10 @@ SMFSource::append_event_unlocked_frames (const Evoral::Event<framepos_t>& ev, fr
} }
if (_model) { if (_model) {
const Evoral::Event<double> beat_ev (ev.event_type(), const Evoral::Event<Evoral::MusicalTime> beat_ev (ev.event_type(),
ev_time_beats, ev_time_beats,
ev.size(), ev.size(),
const_cast<uint8_t*>(ev.buffer())); const_cast<uint8_t*>(ev.buffer()));
_model->append (beat_ev, event_id); _model->append (beat_ev, event_id);
} }
@ -470,7 +470,7 @@ SMFSource::append_event_unlocked_frames (const Evoral::Event<framepos_t>& ev, fr
const Evoral::MusicalTime last_time_beats = converter.from (_last_ev_time_frames); const Evoral::MusicalTime last_time_beats = converter.from (_last_ev_time_frames);
const Evoral::MusicalTime delta_time_beats = ev_time_beats - last_time_beats; const Evoral::MusicalTime delta_time_beats = ev_time_beats - last_time_beats;
const uint32_t delta_time_ticks = (uint32_t)(lrint(delta_time_beats * (double)ppqn())); const uint32_t delta_time_ticks = delta_time_beats.to_ticks(ppqn());
Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id); Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
_last_ev_time_frames = ev.time(); _last_ev_time_frames = ev.time();
@ -516,7 +516,7 @@ SMFSource::mark_streaming_midi_write_started (NoteMode mode)
MidiSource::mark_streaming_midi_write_started (mode); MidiSource::mark_streaming_midi_write_started (mode);
Evoral::SMF::begin_write (); Evoral::SMF::begin_write ();
_last_ev_time_beats = 0.0; _last_ev_time_beats = Evoral::MusicalTime();
_last_ev_time_frames = 0; _last_ev_time_frames = 0;
} }
@ -586,8 +586,8 @@ SMFSource::safe_midi_file_extension (const string& file)
} }
static bool compare_eventlist ( static bool compare_eventlist (
const std::pair< Evoral::Event<double>*, gint >& a, const std::pair< Evoral::Event<Evoral::MusicalTime>*, gint >& a,
const std::pair< Evoral::Event<double>*, gint >& b) { const std::pair< Evoral::Event<Evoral::MusicalTime>*, gint >& b) {
return ( a.first->time() < b.first->time() ); return ( a.first->time() < b.first->time() );
} }
@ -620,7 +620,7 @@ SMFSource::load_model (bool lock, bool force_reload)
Evoral::SMF::seek_to_start(); Evoral::SMF::seek_to_start();
uint64_t time = 0; /* in SMF ticks */ uint64_t time = 0; /* in SMF ticks */
Evoral::Event<double> ev; Evoral::Event<Evoral::MusicalTime> ev;
uint32_t scratch_size = 0; // keep track of scratch and minimize reallocs uint32_t scratch_size = 0; // keep track of scratch and minimize reallocs
@ -632,7 +632,7 @@ SMFSource::load_model (bool lock, bool force_reload)
bool have_event_id; bool have_event_id;
// TODO simplify event allocation // TODO simplify event allocation
std::list< std::pair< Evoral::Event<double>*, gint > > eventlist; std::list< std::pair< Evoral::Event<Evoral::MusicalTime>*, gint > > eventlist;
for (unsigned i = 1; i <= num_tracks(); ++i) { for (unsigned i = 1; i <= num_tracks(); ++i) {
if (seek_to_track(i)) continue; if (seek_to_track(i)) continue;
@ -658,8 +658,8 @@ SMFSource::load_model (bool lock, bool force_reload)
if (!have_event_id) { if (!have_event_id) {
event_id = Evoral::next_event_id(); event_id = Evoral::next_event_id();
} }
uint32_t event_type = midi_parameter_type(buf[0]); const uint32_t event_type = midi_parameter_type(buf[0]);
double event_time = time / (double) ppqn(); const Evoral::MusicalTime event_time = Evoral::MusicalTime::ticks_at_rate(time, ppqn());
#ifndef NDEBUG #ifndef NDEBUG
std::string ss; std::string ss;
@ -674,7 +674,7 @@ SMFSource::load_model (bool lock, bool force_reload)
#endif #endif
eventlist.push_back(make_pair ( eventlist.push_back(make_pair (
new Evoral::Event<double> ( new Evoral::Event<Evoral::MusicalTime> (
event_type, event_time, event_type, event_time,
size, buf, true) size, buf, true)
, event_id)); , event_id));
@ -693,7 +693,7 @@ SMFSource::load_model (bool lock, bool force_reload)
eventlist.sort(compare_eventlist); eventlist.sort(compare_eventlist);
std::list< std::pair< Evoral::Event<double>*, gint > >::iterator it; std::list< std::pair< Evoral::Event<Evoral::MusicalTime>*, gint > >::iterator it;
for (it=eventlist.begin(); it!=eventlist.end(); ++it) { for (it=eventlist.begin(); it!=eventlist.end(); ++it) {
_model->append (*it->first, it->second); _model->append (*it->first, it->second);
delete it->first; delete it->first;

View file

@ -1891,10 +1891,11 @@ TempoMap::framepos_plus_beats (framepos_t pos, Evoral::MusicalTime beats) const
framecnt_t distance_frames = (next_tempo == metrics.end() ? max_framepos : ((*next_tempo)->frame() - pos)); framecnt_t distance_frames = (next_tempo == metrics.end() ? max_framepos : ((*next_tempo)->frame() - pos));
/* Distance to the end in beats */ /* Distance to the end in beats */
Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate); Evoral::MusicalTime distance_beats = Evoral::MusicalTime::ticks_at_rate(
distance_frames, tempo->frames_per_beat (_frame_rate));
/* Amount to subtract this time */ /* Amount to subtract this time */
double const delta = min (distance_beats, beats); Evoral::MusicalTime const delta = min (distance_beats, beats);
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tdistance to %1 = %2 (%3 beats)\n", DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tdistance to %1 = %2 (%3 beats)\n",
(next_tempo == metrics.end() ? max_framepos : (*next_tempo)->frame()), (next_tempo == metrics.end() ? max_framepos : (*next_tempo)->frame()),
@ -1902,7 +1903,7 @@ TempoMap::framepos_plus_beats (framepos_t pos, Evoral::MusicalTime beats) const
/* Update */ /* Update */
beats -= delta; beats -= delta;
pos += delta * tempo->frames_per_beat (_frame_rate); pos += delta.to_ticks(tempo->frames_per_beat (_frame_rate));
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tnow at %1, %2 beats left\n", pos, beats)); DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tnow at %1, %2 beats left\n", pos, beats));
@ -1999,10 +2000,11 @@ TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats) const
framecnt_t distance_frames = (pos - tempo->frame()); framecnt_t distance_frames = (pos - tempo->frame());
/* Distance to the start in beats */ /* Distance to the start in beats */
Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate); Evoral::MusicalTime distance_beats = Evoral::MusicalTime::ticks_at_rate(
distance_frames, tempo->frames_per_beat (_frame_rate));
/* Amount to subtract this time */ /* Amount to subtract this time */
double const sub = min (distance_beats, beats); Evoral::MusicalTime const sub = min (distance_beats, beats);
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tdistance to %1 = %2 (%3 beats)\n", DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tdistance to %1 = %2 (%3 beats)\n",
tempo->frame(), distance_frames, distance_beats)); tempo->frame(), distance_frames, distance_beats));
@ -2035,7 +2037,7 @@ TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats) const
} }
} else { } else {
pos -= llrint (beats * tempo->frames_per_beat (_frame_rate)); pos -= llrint (beats * tempo->frames_per_beat (_frame_rate));
beats = 0; beats = Evoral::MusicalTime();
} }
} }
@ -2216,7 +2218,7 @@ TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
string_compose ("frame %1 walk by %2 frames, start with tempo = %3 @ %4\n", string_compose ("frame %1 walk by %2 frames, start with tempo = %3 @ %4\n",
pos, distance, *((const Tempo*)tempo), tempo->frame())); pos, distance, *((const Tempo*)tempo), tempo->frame()));
Evoral::MusicalTime beats = 0; Evoral::MusicalTime beats = Evoral::MusicalTime();
while (distance) { while (distance) {
@ -2234,8 +2236,8 @@ TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
distance_to_end = end - pos; distance_to_end = end - pos;
} }
/* Amount to subtract this time */ /* Amount to subtract this time in frames */
double const sub = min (distance, distance_to_end); framecnt_t const sub = min (distance, distance_to_end);
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("to reach end at %1 (end ? %2), distance= %3 sub=%4\n", end, (next_tempo == metrics.end()), DEBUG_TRACE (DEBUG::TempoMath, string_compose ("to reach end at %1 (end ? %2), distance= %3 sub=%4\n", end, (next_tempo == metrics.end()),
distance_to_end, sub)); distance_to_end, sub));
@ -2244,7 +2246,7 @@ TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
pos += sub; pos += sub;
distance -= sub; distance -= sub;
assert (tempo); assert (tempo);
beats += sub / tempo->frames_per_beat (_frame_rate); beats += Evoral::MusicalTime::ticks_at_rate(sub, tempo->frames_per_beat (_frame_rate));
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("now at %1, beats = %2 distance left %3\n", DEBUG_TRACE (DEBUG::TempoMath, string_compose ("now at %1, beats = %2 distance left %3\n",
pos, beats, distance)); pos, beats, distance));

View file

@ -7,6 +7,7 @@ CPPUNIT_TEST_SUITE_REGISTRATION (FrameposMinusBeatsTest);
using namespace std; using namespace std;
using namespace ARDOUR; using namespace ARDOUR;
using namespace Timecode; using namespace Timecode;
using namespace Evoral;
/* Basic tests with no tempo / meter changes */ /* Basic tests with no tempo / meter changes */
void void
@ -25,11 +26,11 @@ FrameposMinusBeatsTest::singleTempoTest ()
map.add_tempo (tempo, BBT_Time (1, 1, 0)); map.add_tempo (tempo, BBT_Time (1, 1, 0));
/* Subtract 1 beat from beat 3 of the first bar */ /* Subtract 1 beat from beat 3 of the first bar */
framepos_t r = map.framepos_minus_beats (frames_per_beat * 2, 1); framepos_t r = map.framepos_minus_beats (frames_per_beat * 2, MusicalTime(1));
CPPUNIT_ASSERT_EQUAL (r, framepos_t (frames_per_beat * 1)); CPPUNIT_ASSERT_EQUAL (r, framepos_t (frames_per_beat * 1));
/* Subtract 4 beats from 3 beats in, to go beyond zero */ /* Subtract 4 beats from 3 beats in, to go beyond zero */
r = map.framepos_minus_beats (frames_per_beat * 3, 4); r = map.framepos_minus_beats (frames_per_beat * 3, MusicalTime(4));
CPPUNIT_ASSERT_EQUAL (r, framepos_t (- frames_per_beat)); CPPUNIT_ASSERT_EQUAL (r, framepos_t (- frames_per_beat));
} }
@ -69,15 +70,15 @@ FrameposMinusBeatsTest::doubleTempoTest ()
/* Now some tests */ /* Now some tests */
/* Subtract 1 beat from 1|2 */ /* Subtract 1 beat from 1|2 */
framepos_t r = map.framepos_minus_beats (24e3, 1); framepos_t r = map.framepos_minus_beats (24e3, MusicalTime(1));
CPPUNIT_ASSERT_EQUAL (r, framepos_t (0)); CPPUNIT_ASSERT_EQUAL (r, framepos_t (0));
/* Subtract 2 beats from 4|2 (over the tempo change) */ /* Subtract 2 beats from 4|2 (over the tempo change) */
r = map.framepos_minus_beats (288e3 + 12e3, 2); r = map.framepos_minus_beats (288e3 + 12e3, MusicalTime(2));
CPPUNIT_ASSERT_EQUAL (r, framepos_t (288e3 - 24e3)); CPPUNIT_ASSERT_EQUAL (r, framepos_t (288e3 - 24e3));
/* Subtract 2.5 beats from 4|2 (over the tempo change) */ /* Subtract 2.5 beats from 4|2 (over the tempo change) */
r = map.framepos_minus_beats (288e3 + 12e3, 2.5); r = map.framepos_minus_beats (288e3 + 12e3, MusicalTime(2.5));
CPPUNIT_ASSERT_EQUAL (r, framepos_t (288e3 - 24e3 - 12e3)); CPPUNIT_ASSERT_EQUAL (r, framepos_t (288e3 - 24e3 - 12e3));
} }
@ -123,15 +124,15 @@ FrameposMinusBeatsTest::doubleTempoWithMeterTest ()
/* Now some tests */ /* Now some tests */
/* Subtract 1 beat from 1|2 */ /* Subtract 1 beat from 1|2 */
framepos_t r = map.framepos_minus_beats (24e3, 1); framepos_t r = map.framepos_minus_beats (24e3, MusicalTime(1));
CPPUNIT_ASSERT_EQUAL (r, framepos_t (0)); CPPUNIT_ASSERT_EQUAL (r, framepos_t (0));
/* Subtract 2 beats from 4|2 (over the tempo change) */ /* Subtract 2 beats from 4|2 (over the tempo change) */
r = map.framepos_minus_beats (288e3 + 12e3, 2); r = map.framepos_minus_beats (288e3 + 12e3, MusicalTime(2));
CPPUNIT_ASSERT_EQUAL (r, framepos_t (288e3 - 24e3)); CPPUNIT_ASSERT_EQUAL (r, framepos_t (288e3 - 24e3));
/* Subtract 2.5 beats from 4|2 (over the tempo change) */ /* Subtract 2.5 beats from 4|2 (over the tempo change) */
r = map.framepos_minus_beats (288e3 + 12e3, 2.5); r = map.framepos_minus_beats (288e3 + 12e3, MusicalTime(2.5));
CPPUNIT_ASSERT_EQUAL (r, framepos_t (288e3 - 24e3 - 12e3)); CPPUNIT_ASSERT_EQUAL (r, framepos_t (288e3 - 24e3 - 12e3));
} }

View file

@ -25,11 +25,11 @@ FrameposPlusBeatsTest::singleTempoTest ()
map.add_tempo (tempo, BBT_Time (1, 1, 0)); map.add_tempo (tempo, BBT_Time (1, 1, 0));
/* Add 1 beat to beat 3 of the first bar */ /* Add 1 beat to beat 3 of the first bar */
framepos_t r = map.framepos_plus_beats (frames_per_beat * 2, 1); framepos_t r = map.framepos_plus_beats (frames_per_beat * 2, Evoral::MusicalTime(1));
CPPUNIT_ASSERT_EQUAL (framepos_t (frames_per_beat * 3), r); CPPUNIT_ASSERT_EQUAL (framepos_t (frames_per_beat * 3), r);
/* Add 4 beats to a -ve frame of 1 beat before zero */ /* Add 4 beats to a -ve frame of 1 beat before zero */
r = map.framepos_plus_beats (-frames_per_beat * 1, 4); r = map.framepos_plus_beats (-frames_per_beat * 1, Evoral::MusicalTime(4));
CPPUNIT_ASSERT_EQUAL (framepos_t (frames_per_beat * 3), r); CPPUNIT_ASSERT_EQUAL (framepos_t (frames_per_beat * 3), r);
} }
@ -69,15 +69,15 @@ FrameposPlusBeatsTest::doubleTempoTest ()
/* Now some tests */ /* Now some tests */
/* Add 1 beat to 1|2 */ /* Add 1 beat to 1|2 */
framepos_t r = map.framepos_plus_beats (24e3, 1); framepos_t r = map.framepos_plus_beats (24e3, Evoral::MusicalTime(1));
CPPUNIT_ASSERT_EQUAL (framepos_t (48e3), r); CPPUNIT_ASSERT_EQUAL (framepos_t (48e3), r);
/* Add 2 beats to 3|4 (over the tempo change) */ /* Add 2 beats to 3|4 (over the tempo change) */
r = map.framepos_plus_beats (264e3, 2); r = map.framepos_plus_beats (264e3, Evoral::MusicalTime(2));
CPPUNIT_ASSERT_EQUAL (framepos_t (264e3 + 24e3 + 12e3), r); CPPUNIT_ASSERT_EQUAL (framepos_t (264e3 + 24e3 + 12e3), r);
/* Add 2.5 beats to 3|3|960 (over the tempo change) */ /* Add 2.5 beats to 3|3|960 (over the tempo change) */
r = map.framepos_plus_beats (264e3 - 12e3, 2.5); r = map.framepos_plus_beats (264e3 - 12e3, Evoral::MusicalTime(2.5));
CPPUNIT_ASSERT_EQUAL (framepos_t (264e3 + 24e3 + 12e3), r); CPPUNIT_ASSERT_EQUAL (framepos_t (264e3 + 24e3 + 12e3), r);
} }
@ -123,15 +123,15 @@ FrameposPlusBeatsTest::doubleTempoWithMeterTest ()
/* Now some tests */ /* Now some tests */
/* Add 1 beat to 1|2 */ /* Add 1 beat to 1|2 */
framepos_t r = map.framepos_plus_beats (24e3, 1); framepos_t r = map.framepos_plus_beats (24e3, Evoral::MusicalTime(1));
CPPUNIT_ASSERT_EQUAL (framepos_t (48e3), r); CPPUNIT_ASSERT_EQUAL (framepos_t (48e3), r);
/* Add 2 beats to 3|4 (over the tempo change) */ /* Add 2 beats to 3|4 (over the tempo change) */
r = map.framepos_plus_beats (264e3, 2); r = map.framepos_plus_beats (264e3, Evoral::MusicalTime(2));
CPPUNIT_ASSERT_EQUAL (framepos_t (264e3 + 24e3 + 12e3), r); CPPUNIT_ASSERT_EQUAL (framepos_t (264e3 + 24e3 + 12e3), r);
/* Add 2.5 beats to 3|3|960 (over the tempo change) */ /* Add 2.5 beats to 3|3|960 (over the tempo change) */
r = map.framepos_plus_beats (264e3 - 12e3, 2.5); r = map.framepos_plus_beats (264e3 - 12e3, Evoral::MusicalTime(2.5));
CPPUNIT_ASSERT_EQUAL (framepos_t (264e3 + 24e3 + 12e3), r); CPPUNIT_ASSERT_EQUAL (framepos_t (264e3 + 24e3 + 12e3), r);
} }

View file

@ -48,7 +48,7 @@ template<typename Time>
class LIBEVORAL_API Event { class LIBEVORAL_API Event {
public: public:
#ifdef EVORAL_EVENT_ALLOC #ifdef EVORAL_EVENT_ALLOC
Event (EventType type=0, Time time=0, uint32_t size=0, uint8_t* buf=NULL, bool alloc=false); Event (EventType type=0, Time time=Time(), uint32_t size=0, uint8_t* buf=NULL, bool alloc=false);
/** Copy \a copy. /** Copy \a copy.
* *
@ -114,11 +114,11 @@ public:
} }
inline void clear() { inline void clear() {
_type = 0; _type = 0;
_original_time = 0; _original_time = Time();
_nominal_time = 0; _nominal_time = Time();
_size = 0; _size = 0;
_buf = NULL; _buf = NULL;
} }
#else #else
@ -154,9 +154,6 @@ protected:
#endif #endif
}; };
} // namespace Evoral
template<typename Time> template<typename Time>
/*LIBEVORAL_API*/ std::ostream& operator<<(std::ostream& o, const Evoral::Event<Time>& ev) { /*LIBEVORAL_API*/ std::ostream& operator<<(std::ostream& o, const Evoral::Event<Time>& ev) {
o << "Event #" << ev.id() << " type = " << ev.event_type() << " @ " << ev.time(); o << "Event #" << ev.id() << " type = " << ev.event_type() << " @ " << ev.time();
@ -168,6 +165,7 @@ template<typename Time>
return o; return o;
} }
} // namespace Evoral
#endif // EVORAL_EVENT_HPP #endif // EVORAL_EVENT_HPP

View file

@ -39,16 +39,16 @@ class LIBEVORAL_LOCAL Note {
class LIBEVORAL_TEMPLATE_API Note { class LIBEVORAL_TEMPLATE_API Note {
#endif #endif
public: public:
Note(uint8_t chan=0, Time time=0, Time len=0, uint8_t note=0, uint8_t vel=0x40); Note(uint8_t chan=0, Time time=Time(), Time len=Time(), uint8_t note=0, uint8_t vel=0x40);
Note(const Note<Time>& copy); Note(const Note<Time>& copy);
~Note(); ~Note();
const Note<Time>& operator=(const Note<Time>& copy); const Note<Time>& operator=(const Note<Time>& copy);
inline bool operator==(const Note<Time>& other) { inline bool operator==(const Note<Time>& other) {
return musical_time_equal (time(), other.time()) && return time() == other.time() &&
note() == other.note() && note() == other.note() &&
musical_time_equal (length(), other.length()) && length() == other.length() &&
velocity() == other.velocity() && velocity() == other.velocity() &&
off_velocity() == other.off_velocity() && off_velocity() == other.off_velocity() &&
channel() == other.channel(); channel() == other.channel();
@ -109,8 +109,6 @@ private:
MIDIEvent<Time> _off_event; MIDIEvent<Time> _off_event;
}; };
} // namespace Evoral
template<typename Time> template<typename Time>
/*LIBEVORAL_API*/ std::ostream& operator<<(std::ostream& o, const Evoral::Note<Time>& n) { /*LIBEVORAL_API*/ std::ostream& operator<<(std::ostream& o, const Evoral::Note<Time>& n) {
o << "Note #" << n.id() << ": pitch = " << (int) n.note() o << "Note #" << n.id() << ": pitch = " << (int) n.note()
@ -120,6 +118,8 @@ template<typename Time>
return o; return o;
} }
} // namespace Evoral
#ifdef COMPILER_MSVC #ifdef COMPILER_MSVC
#include "../src/Note.impl" #include "../src/Note.impl"
#endif #endif

View file

@ -120,7 +120,7 @@ public:
uint8_t channel () const { return _program_change.buffer()[0] & 0xf; } uint8_t channel () const { return _program_change.buffer()[0] & 0xf; }
inline bool operator< (const PatchChange<Time>& o) const { inline bool operator< (const PatchChange<Time>& o) const {
if (!musical_time_equal (time(), o.time())) { if (time() != o.time()) {
return time() < o.time(); return time() < o.time();
} }
@ -132,7 +132,7 @@ public:
} }
inline bool operator== (const PatchChange<Time>& o) const { inline bool operator== (const PatchChange<Time>& o) const {
return (musical_time_equal (time(), o.time()) && program() == o.program() && bank() == o.bank()); return (time() == o.time() && program() == o.program() && bank() == o.bank());
} }
/** The PatchChange is made up of messages() MIDI messages; this method returns them by index. /** The PatchChange is made up of messages() MIDI messages; this method returns them by index.

View file

@ -105,7 +105,7 @@ public:
ResolveStuckNotes ResolveStuckNotes
}; };
void end_write (StuckNoteOption, Time when = 0); void end_write (StuckNoteOption, Time when = Time());
void append(const Event<Time>& ev, Evoral::event_id_t evid); void append(const Event<Time>& ev, Evoral::event_id_t evid);
@ -127,7 +127,7 @@ public:
struct EarlierNoteComparator { struct EarlierNoteComparator {
inline bool operator()(const boost::shared_ptr< const Note<Time> > a, inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
const boost::shared_ptr< const Note<Time> > b) const { const boost::shared_ptr< const Note<Time> > b) const {
return musical_time_less_than (a->time(), b->time()); return a->time() < b->time();
} }
}; };
@ -135,7 +135,7 @@ public:
typedef const Note<Time>* value_type; typedef const Note<Time>* value_type;
inline bool operator()(const boost::shared_ptr< const Note<Time> > a, inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
const boost::shared_ptr< const Note<Time> > b) const { const boost::shared_ptr< const Note<Time> > b) const {
return musical_time_greater_than (a->time(), b->time()); return a->time() > b->time();
} }
}; };
@ -143,7 +143,7 @@ public:
typedef const Note<Time>* value_type; typedef const Note<Time>* value_type;
inline bool operator()(const boost::shared_ptr< const Note<Time> > a, inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
const boost::shared_ptr< const Note<Time> > b) const { const boost::shared_ptr< const Note<Time> > b) const {
return musical_time_greater_than (a->end_time(), b->end_time()); return a->end_time() > b->end_time();
} }
}; };
@ -187,7 +187,7 @@ public:
struct EarlierSysExComparator { struct EarlierSysExComparator {
inline bool operator() (constSysExPtr a, constSysExPtr b) const { inline bool operator() (constSysExPtr a, constSysExPtr b) const {
return musical_time_less_than (a->time(), b->time()); return a->time() < b->time();
} }
}; };
@ -200,7 +200,7 @@ public:
struct EarlierPatchChangeComparator { struct EarlierPatchChangeComparator {
inline bool operator() (constPatchChangePtr a, constPatchChangePtr b) const { inline bool operator() (constPatchChangePtr a, constPatchChangePtr b) const {
return musical_time_less_than (a->time(), b->time()); return a->time() < b->time();
} }
}; };
@ -262,7 +262,7 @@ public:
}; };
const_iterator begin ( const_iterator begin (
Time t = 0, Time t = Time(),
bool force_discrete = false, bool force_discrete = false,
std::set<Evoral::Parameter> const & f = std::set<Evoral::Parameter> ()) const { std::set<Evoral::Parameter> const & f = std::set<Evoral::Parameter> ()) const {
return const_iterator (*this, t, force_discrete, f); return const_iterator (*this, t, force_discrete, f);

View file

@ -19,15 +19,18 @@
#ifndef EVORAL_TYPES_HPP #ifndef EVORAL_TYPES_HPP
#define EVORAL_TYPES_HPP #define EVORAL_TYPES_HPP
#include <float.h>
#include <math.h>
#include <stdint.h> #include <stdint.h>
#include <list>
#include <cmath>
#include <cfloat>
#include "pbd/debug.h" #include <iostream>
#include <limits>
#include <list>
#include "evoral/visibility.h" #include "evoral/visibility.h"
#include "pbd/debug.h"
namespace Evoral { namespace Evoral {
/** ID of an event (note or other). This must be operable on by glib /** ID of an event (note or other). This must be operable on by glib
@ -36,47 +39,174 @@ namespace Evoral {
typedef int32_t event_id_t; typedef int32_t event_id_t;
/** Musical time: beats relative to some defined origin */ /** Musical time: beats relative to some defined origin */
typedef double MusicalTime; class LIBEVORAL_API MusicalTime {
public:
MusicalTime() : _time(0.0) {}
const MusicalTime MaxMusicalTime = DBL_MAX; /** Create from a real number of beats. */
const MusicalTime MinMusicalTime = DBL_MIN; explicit MusicalTime(double time) : _time(time) {}
static inline bool musical_time_equal (MusicalTime a, MusicalTime b) { /** Create from an integer number of beats. */
/* acceptable tolerance is 1 tick. Nice if there was no magic number here static MusicalTime beats(int32_t beats) {
* -> Timecode::BBT_Time::ticks_per_beat */ return MusicalTime((double)beats);
return fabs (a - b) <= (1.0/1920.0);
}
static inline bool musical_time_less_than (MusicalTime a, MusicalTime b) {
/* acceptable tolerance is 1 tick. Nice if there was no magic number here */
if (fabs (a - b) <= (1.0/1920.0)) {
return false; /* effectively identical */
} else {
return a < b;
} }
}
static inline bool musical_time_greater_than (MusicalTime a, MusicalTime b) { /** Create from ticks at the standard PPQN. */
/* acceptable tolerance is 1 tick. Nice if there was no magic number here */ static MusicalTime ticks(uint32_t ticks) {
if (fabs (a - b) <= (1.0/1920.0)) { return MusicalTime(ticks / _ppqn);
return false; /* effectively identical */
} else {
return a > b;
} }
}
static inline bool musical_time_greater_or_equal_to (MusicalTime a, MusicalTime b) { /** Create from ticks at a given rate.
/* acceptable tolerance is 1 tick. Nice if there was no magic number here */ *
if (fabs (a - b) <= (1.0/1920.0)) { * Note this can also be used to create from frames by setting ppqn to the
return true; /* effectively identical, note the "or_equal_to" */ * number of samples per beat.
} else { */
return a >= b; static MusicalTime ticks_at_rate(uint64_t ticks, uint32_t ppqn) {
return MusicalTime((double)ticks / (double)ppqn);
} }
}
MusicalTime& operator=(const MusicalTime& other) {
_time = other._time;
return *this;
}
MusicalTime round_up_to_beat() const {
return Evoral::MusicalTime(ceil(_time));
}
MusicalTime round_down_to_beat() const {
return Evoral::MusicalTime(floor(_time));
}
MusicalTime snap_to(const Evoral::MusicalTime& snap) const {
return MusicalTime(ceil(_time / snap._time) * snap._time);
}
inline bool operator==(const MusicalTime& b) const {
/* Acceptable tolerance is 1 tick. */
return fabs(_time - b._time) <= (1.0/_ppqn);
}
inline bool operator==(double t) const {
/* Acceptable tolerance is 1 tick. */
return fabs(_time - t) <= (1.0/_ppqn);
}
inline bool operator==(int beats) const {
/* Acceptable tolerance is 1 tick. */
return fabs(_time - beats) <= (1.0/_ppqn);
}
inline bool operator!=(const MusicalTime& b) const {
return !operator==(b);
}
inline bool operator<(const MusicalTime& b) const {
/* Acceptable tolerance is 1 tick. */
if (fabs(_time - b._time) <= (1.0/_ppqn)) {
return false; /* Effectively identical. */
} else {
return _time < b._time;
}
}
inline bool operator<=(const MusicalTime& b) const {
return operator==(b) || operator<(b);
}
inline bool operator>(const MusicalTime& b) const {
/* Acceptable tolerance is 1 tick. */
if (fabs(_time - b._time) <= (1.0/_ppqn)) {
return false; /* Effectively identical. */
} else {
return _time > b._time;
}
}
inline bool operator>=(const MusicalTime& b) const {
/* Acceptable tolerance is 1 tick. */
if (fabs(_time - b._time) <= (1.0/_ppqn)) {
return true; /* Effectively identical. */
} else {
return _time >= b._time;
}
}
MusicalTime operator+(const MusicalTime& b) const {
return MusicalTime(_time + b._time);
}
MusicalTime operator-(const MusicalTime& b) const {
return MusicalTime(_time - b._time);
}
MusicalTime operator-() const {
return MusicalTime(-_time);
}
template<typename Number>
MusicalTime operator*(Number factor) const {
return MusicalTime(_time * factor);
}
MusicalTime& operator+=(const MusicalTime& b) {
_time += b._time;
return *this;
}
MusicalTime& operator-=(const MusicalTime& b) {
_time -= b._time;
return *this;
}
double to_double() const { return _time; }
uint64_t to_ticks() const { return lrint(_time * _ppqn); }
uint64_t to_ticks(uint32_t ppqn) const { return lrint(_time * ppqn); }
operator bool() const { return _time != 0; }
static MusicalTime min() { return MusicalTime(DBL_MIN); }
static MusicalTime max() { return MusicalTime(DBL_MAX); }
static MusicalTime tick() { return MusicalTime(1.0 / _ppqn); }
private:
static const double _ppqn = 1920.0; /* TODO: Make configurable. */
double _time;
};
const MusicalTime MaxMusicalTime = Evoral::MusicalTime::max();
const MusicalTime MinMusicalTime = Evoral::MusicalTime::min();
/** Type of an event (opaque, mapped by application) */ /** Type of an event (opaque, mapped by application) */
typedef uint32_t EventType; typedef uint32_t EventType;
/*
TIL, several horrible hours later, that sometimes the compiler looks in the
namespace of a type (Evoral::MusicalTime in this case) for an operator, and
does *NOT* look in the global namespace.
C++ is proof that hell exists and we are living in it. In any case, move
these to the global namespace and PBD::Property's loopy
virtual-method-in-a-template will bite you.
*/
inline std::ostream&
operator<<(std::ostream& os, const MusicalTime& t)
{
os << t.to_double();
return os;
}
inline std::istream&
operator>>(std::istream& is, MusicalTime& t)
{
double beats;
is >> beats;
t = MusicalTime(beats);
return is;
}
} // namespace Evoral } // namespace Evoral
namespace PBD { namespace PBD {
@ -84,7 +214,16 @@ namespace PBD {
LIBEVORAL_API extern uint64_t Sequence; LIBEVORAL_API extern uint64_t Sequence;
LIBEVORAL_API extern uint64_t Note; LIBEVORAL_API extern uint64_t Note;
LIBEVORAL_API extern uint64_t ControlList; LIBEVORAL_API extern uint64_t ControlList;
LIBEVORAL_API extern uint64_t MusicalTime;
} }
} }
namespace std {
template<>
struct numeric_limits<Evoral::MusicalTime> {
static Evoral::MusicalTime min() { return Evoral::MusicalTime::min(); }
static Evoral::MusicalTime max() { return Evoral::MusicalTime::max(); }
};
}
#endif // EVORAL_TYPES_HPP #endif // EVORAL_TYPES_HPP

View file

@ -156,6 +156,7 @@ Event<Timestamp>::set_original_time (Timestamp t)
#endif // EVORAL_EVENT_ALLOC #endif // EVORAL_EVENT_ALLOC
template class Event<Evoral::MusicalTime>; template class Event<Evoral::MusicalTime>;
template class Event<double>;
template class Event<int64_t>; template class Event<int64_t>;
} // namespace Evoral } // namespace Evoral

View file

@ -39,8 +39,8 @@ Note<Time>::Note(uint8_t chan, Time t, Time l, uint8_t n, uint8_t v)
_off_event.buffer()[1] = n; _off_event.buffer()[1] = n;
_off_event.buffer()[2] = 0x40; _off_event.buffer()[2] = 0x40;
assert(musical_time_equal (time(),t)); assert(time() == t);
assert(musical_time_equal (length(), l)); assert(length() == l);
assert(note() == n); assert(note() == n);
assert(velocity() == v); assert(velocity() == v);
assert(_on_event.channel() == _off_event.channel()); assert(_on_event.channel() == _off_event.channel());
@ -67,9 +67,9 @@ Note<Time>::Note(const Note<Time>& copy)
memcpy(_off_event_buffer, copy._off_event_buffer, 3); memcpy(_off_event_buffer, copy._off_event_buffer, 3);
*/ */
assert(musical_time_equal (time(),copy.time())); assert(time() == copy.time());
assert(musical_time_equal (end_time(), copy.end_time())); assert(end_time() == copy.end_time());
assert(musical_time_equal (length(), copy.length())); assert(length() == copy.length());
assert(note() == copy.note()); assert(note() == copy.note());
assert(velocity() == copy.velocity()); assert(velocity() == copy.velocity());
assert(_on_event.channel() == _off_event.channel()); assert(_on_event.channel() == _off_event.channel());
@ -95,9 +95,9 @@ Note<Time>::operator=(const Note<Time>& other)
_on_event = other._on_event; _on_event = other._on_event;
_off_event = other._off_event; _off_event = other._off_event;
assert(musical_time_equal (time(),other.time())); assert(time() == other.time());
assert(musical_time_equal (end_time(), other.end_time())); assert(end_time() == other.end_time());
assert(musical_time_equal (length(), other.length())); assert(length() == other.length());
assert(note() == other.note()); assert(note() == other.note());
assert(velocity() == other.velocity()); assert(velocity() == other.velocity());
assert(_on_event.channel() == _off_event.channel()); assert(_on_event.channel() == _off_event.channel());

View file

@ -129,9 +129,9 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>& seq, Time t
double x, y; double x, y;
bool ret; bool ret;
if (_force_discrete || i->second->list()->interpolation() == ControlList::Discrete) { if (_force_discrete || i->second->list()->interpolation() == ControlList::Discrete) {
ret = i->second->list()->rt_safe_earliest_event_discrete_unlocked (t, x, y, true); ret = i->second->list()->rt_safe_earliest_event_discrete_unlocked (t.to_double(), x, y, true);
} else { } else {
ret = i->second->list()->rt_safe_earliest_event_unlocked(t, x, y, true); ret = i->second->list()->rt_safe_earliest_event_unlocked(t.to_double(), x, y, true);
} }
if (!ret) { if (!ret) {
DEBUG_TRACE (DEBUG::Sequence, string_compose ("Iterator: CC %1 (size %2) has no events past %3\n", DEBUG_TRACE (DEBUG::Sequence, string_compose ("Iterator: CC %1 (size %2) has no events past %3\n",
@ -188,10 +188,10 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>& seq, Time t
} }
if (_control_iter != _control_iters.end() if (_control_iter != _control_iters.end()
&& earliest_control.list && earliest_control.x >= t && earliest_control.list && earliest_control.x >= t.to_double()
&& (earliest_control.x < earliest_t || _type == NIL)) { && (earliest_control.x < earliest_t.to_double() || _type == NIL)) {
_type = CONTROL; _type = CONTROL;
earliest_t = earliest_control.x; earliest_t = Time(earliest_control.x);
} }
switch (_type) { switch (_type) {
@ -357,9 +357,9 @@ Sequence<Time>::const_iterator::operator++()
// Use the next earliest controller iff it's earlier than the note event // Use the next earliest controller iff it's earlier than the note event
if (_control_iter != _control_iters.end() && _control_iter->x != DBL_MAX) { if (_control_iter != _control_iters.end() && _control_iter->x != DBL_MAX) {
if (_type == NIL || _control_iter->x < earliest_t) { if (_type == NIL || _control_iter->x < earliest_t.to_double()) {
_type = CONTROL; _type = CONTROL;
earliest_t = _control_iter->x; earliest_t = Time(_control_iter->x);
} }
} }
@ -470,7 +470,7 @@ Sequence<Time>::Sequence(const TypeMap& type_map)
, _overlap_pitch_resolution (FirstOnFirstOff) , _overlap_pitch_resolution (FirstOnFirstOff)
, _writing(false) , _writing(false)
, _type_map(type_map) , _type_map(type_map)
, _end_iter(*this, DBL_MAX, false, std::set<Evoral::Parameter> ()) , _end_iter(*this, std::numeric_limits<Time>::max(), false, std::set<Evoral::Parameter> ())
, _percussive(false) , _percussive(false)
, _lowest_note(127) , _lowest_note(127)
, _highest_note(0) , _highest_note(0)
@ -492,7 +492,7 @@ Sequence<Time>::Sequence(const Sequence<Time>& other)
, _overlap_pitch_resolution (other._overlap_pitch_resolution) , _overlap_pitch_resolution (other._overlap_pitch_resolution)
, _writing(false) , _writing(false)
, _type_map(other._type_map) , _type_map(other._type_map)
, _end_iter(*this, DBL_MAX, false, std::set<Evoral::Parameter> ()) , _end_iter(*this, std::numeric_limits<Time>::max(), false, std::set<Evoral::Parameter> ())
, _percussive(other._percussive) , _percussive(other._percussive)
, _lowest_note(other._lowest_note) , _lowest_note(other._lowest_note)
, _highest_note(other._highest_note) , _highest_note(other._highest_note)
@ -537,7 +537,7 @@ Sequence<Time>::control_to_midi_event(
// initialize the event pointer with a new event, if necessary // initialize the event pointer with a new event, if necessary
if (!ev) { if (!ev) {
ev = boost::shared_ptr< Event<Time> >(new Event<Time>(event_type, 0, 3, NULL, true)); ev = boost::shared_ptr< Event<Time> >(new Event<Time>(event_type, Time(), 3, NULL, true));
} }
uint8_t midi_type = _type_map.parameter_midi_type(iter.list->parameter()); uint8_t midi_type = _type_map.parameter_midi_type(iter.list->parameter());
@ -549,7 +549,7 @@ Sequence<Time>::control_to_midi_event(
assert(iter.list->parameter().id() <= INT8_MAX); assert(iter.list->parameter().id() <= INT8_MAX);
assert(iter.y <= INT8_MAX); assert(iter.y <= INT8_MAX);
ev->set_time(iter.x); ev->set_time(Time(iter.x));
ev->realloc(3); ev->realloc(3);
ev->buffer()[0] = MIDI_CMD_CONTROL + iter.list->parameter().channel(); ev->buffer()[0] = MIDI_CMD_CONTROL + iter.list->parameter().channel();
ev->buffer()[1] = (uint8_t)iter.list->parameter().id(); ev->buffer()[1] = (uint8_t)iter.list->parameter().id();
@ -561,7 +561,7 @@ Sequence<Time>::control_to_midi_event(
assert(iter.list->parameter().channel() < 16); assert(iter.list->parameter().channel() < 16);
assert(iter.y <= INT8_MAX); assert(iter.y <= INT8_MAX);
ev->set_time(iter.x); ev->set_time(Time(iter.x));
ev->realloc(2); ev->realloc(2);
ev->buffer()[0] = MIDI_CMD_PGM_CHANGE + iter.list->parameter().channel(); ev->buffer()[0] = MIDI_CMD_PGM_CHANGE + iter.list->parameter().channel();
ev->buffer()[1] = (uint8_t)iter.y; ev->buffer()[1] = (uint8_t)iter.y;
@ -572,7 +572,7 @@ Sequence<Time>::control_to_midi_event(
assert(iter.list->parameter().channel() < 16); assert(iter.list->parameter().channel() < 16);
assert(iter.y < (1<<14)); assert(iter.y < (1<<14));
ev->set_time(iter.x); ev->set_time(Time(iter.x));
ev->realloc(3); ev->realloc(3);
ev->buffer()[0] = MIDI_CMD_BENDER + iter.list->parameter().channel(); ev->buffer()[0] = MIDI_CMD_BENDER + iter.list->parameter().channel();
ev->buffer()[1] = uint16_t(iter.y) & 0x7F; // LSB ev->buffer()[1] = uint16_t(iter.y) & 0x7F; // LSB
@ -584,7 +584,7 @@ Sequence<Time>::control_to_midi_event(
assert(iter.list->parameter().channel() < 16); assert(iter.list->parameter().channel() < 16);
assert(iter.y <= INT8_MAX); assert(iter.y <= INT8_MAX);
ev->set_time(iter.x); ev->set_time(Time(iter.x));
ev->realloc(2); ev->realloc(2);
ev->buffer()[0] = MIDI_CMD_CHANNEL_PRESSURE + iter.list->parameter().channel(); ev->buffer()[0] = MIDI_CMD_CHANNEL_PRESSURE + iter.list->parameter().channel();
ev->buffer()[1] = (uint8_t)iter.y; ev->buffer()[1] = (uint8_t)iter.y;
@ -653,7 +653,7 @@ Sequence<Time>::end_write (StuckNoteOption option, Time when)
typename Notes::iterator next = n; typename Notes::iterator next = n;
++next; ++next;
if ((*n)->length() == 0) { if (!(*n)->length()) {
switch (option) { switch (option) {
case Relax: case Relax:
break; break;
@ -737,7 +737,7 @@ Sequence<Time>::remove_note_unlocked(const constNotePtr note)
typename Sequence<Time>::Notes::iterator i; typename Sequence<Time>::Notes::iterator i;
for (i = note_lower_bound(note->time()); i != _notes.end() && musical_time_equal ((*i)->time(), note->time()); ++i) { for (i = note_lower_bound(note->time()); i != _notes.end() && (*i)->time() == note->time(); ++i) {
if (*i == note) { if (*i == note) {
@ -832,7 +832,7 @@ Sequence<Time>::remove_note_unlocked(const constNotePtr note)
* so the search_note has all other properties unset. * so the search_note has all other properties unset.
*/ */
NotePtr search_note (new Note<Time>(0, 0, 0, note->note(), 0)); NotePtr search_note (new Note<Time>(0, Time(), Time(), note->note(), 0));
for (j = p.lower_bound (search_note); j != p.end() && (*j)->note() == note->note(); ++j) { for (j = p.lower_bound (search_note); j != p.end() && (*j)->note() == note->note(); ++j) {
@ -861,7 +861,7 @@ Sequence<Time>::remove_patch_change_unlocked (const constPatchChangePtr p)
{ {
typename Sequence<Time>::PatchChanges::iterator i = patch_change_lower_bound (p->time ()); typename Sequence<Time>::PatchChanges::iterator i = patch_change_lower_bound (p->time ());
while (i != _patch_changes.end() && (musical_time_equal ((*i)->time(), p->time()))) { while (i != _patch_changes.end() && ((*i)->time() == p->time())) {
typename Sequence<Time>::PatchChanges::iterator tmp = i; typename Sequence<Time>::PatchChanges::iterator tmp = i;
++tmp; ++tmp;
@ -906,7 +906,7 @@ Sequence<Time>::append(const Event<Time>& event, event_id_t evid)
const MIDIEvent<Time>& ev = (const MIDIEvent<Time>&)event; const MIDIEvent<Time>& ev = (const MIDIEvent<Time>&)event;
assert(_notes.empty() || musical_time_greater_or_equal_to(ev.time(), (*_notes.rbegin())->time())); assert(_notes.empty() || ev.time() >= (*_notes.rbegin())->time());
assert(_writing); assert(_writing);
if (!midi_event_is_valid(ev.buffer(), ev.size())) { if (!midi_event_is_valid(ev.buffer(), ev.size())) {
@ -915,10 +915,10 @@ Sequence<Time>::append(const Event<Time>& event, event_id_t evid)
} }
if (ev.is_note_on()) { if (ev.is_note_on()) {
NotePtr note(new Note<Time>(ev.channel(), ev.time(), 0, ev.note(), ev.velocity())); NotePtr note(new Note<Time>(ev.channel(), ev.time(), Time(), ev.note(), ev.velocity()));
append_note_on_unlocked (note, evid); append_note_on_unlocked (note, evid);
} else if (ev.is_note_off()) { } else if (ev.is_note_off()) {
NotePtr note(new Note<Time>(ev.channel(), ev.time(), 0, ev.note(), ev.velocity())); NotePtr note(new Note<Time>(ev.channel(), ev.time(), Time(), ev.note(), ev.velocity()));
/* XXX note: event ID is discarded because we merge the on+off events into /* XXX note: event ID is discarded because we merge the on+off events into
a single note object a single note object
*/ */
@ -1053,7 +1053,7 @@ Sequence<Time>::append_note_off_unlocked (NotePtr note)
NotePtr nn = *n; NotePtr nn = *n;
if (note->note() == nn->note() && nn->channel() == note->channel()) { if (note->note() == nn->note() && nn->channel() == note->channel()) {
assert(musical_time_greater_or_equal_to(note->time(), nn->time())); assert(note->time() >= nn->time());
nn->set_length (note->time() - nn->time()); nn->set_length (note->time() - nn->time());
nn->set_off_velocity (note->velocity()); nn->set_off_velocity (note->velocity());
@ -1080,7 +1080,7 @@ Sequence<Time>::append_control_unlocked(const Parameter& param, Time time, doubl
DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 %2 @ %3 = %4 # controls: %5\n", DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 %2 @ %3 = %4 # controls: %5\n",
this, _type_map.to_symbol(param), time, value, _controls.size())); this, _type_map.to_symbol(param), time, value, _controls.size()));
boost::shared_ptr<Control> c = control(param, true); boost::shared_ptr<Control> c = control(param, true);
c->list()->add (time, value); c->list()->add (time.to_double(), value);
/* XXX control events should use IDs */ /* XXX control events should use IDs */
} }
@ -1148,7 +1148,7 @@ bool
Sequence<Time>::contains_unlocked (const NotePtr& note) const Sequence<Time>::contains_unlocked (const NotePtr& note) const
{ {
const Pitches& p (pitches (note->channel())); const Pitches& p (pitches (note->channel()));
NotePtr search_note(new Note<Time>(0, 0, 0, note->note())); NotePtr search_note(new Note<Time>(0, Time(), Time(), note->note()));
for (typename Pitches::const_iterator i = p.lower_bound (search_note); for (typename Pitches::const_iterator i = p.lower_bound (search_note);
i != p.end() && (*i)->note() == note->note(); ++i) { i != p.end() && (*i)->note() == note->note(); ++i) {
@ -1177,7 +1177,7 @@ Sequence<Time>::overlaps_unlocked (const NotePtr& note, const NotePtr& without)
Time ea = note->end_time(); Time ea = note->end_time();
const Pitches& p (pitches (note->channel())); const Pitches& p (pitches (note->channel()));
NotePtr search_note(new Note<Time>(0, 0, 0, note->note())); NotePtr search_note(new Note<Time>(0, Time(), Time(), note->note()));
for (typename Pitches::const_iterator i = p.lower_bound (search_note); for (typename Pitches::const_iterator i = p.lower_bound (search_note);
i != p.end() && (*i)->note() == note->note(); ++i) { i != p.end() && (*i)->note() == note->note(); ++i) {
@ -1214,9 +1214,9 @@ template<typename Time>
typename Sequence<Time>::Notes::const_iterator typename Sequence<Time>::Notes::const_iterator
Sequence<Time>::note_lower_bound (Time t) const Sequence<Time>::note_lower_bound (Time t) const
{ {
NotePtr search_note(new Note<Time>(0, t, 0, 0, 0)); NotePtr search_note(new Note<Time>(0, t, Time(), 0, 0));
typename Sequence<Time>::Notes::const_iterator i = _notes.lower_bound(search_note); typename Sequence<Time>::Notes::const_iterator i = _notes.lower_bound(search_note);
assert(i == _notes.end() || musical_time_greater_or_equal_to((*i)->time(), t)); assert(i == _notes.end() || (*i)->time() >= t);
return i; return i;
} }
@ -1227,7 +1227,7 @@ Sequence<Time>::patch_change_lower_bound (Time t) const
{ {
PatchChangePtr search (new PatchChange<Time> (t, 0, 0, 0)); PatchChangePtr search (new PatchChange<Time> (t, 0, 0, 0));
typename Sequence<Time>::PatchChanges::const_iterator i = _patch_changes.lower_bound (search); typename Sequence<Time>::PatchChanges::const_iterator i = _patch_changes.lower_bound (search);
assert (i == _patch_changes.end() || musical_time_greater_or_equal_to ((*i)->time(), t)); assert (i == _patch_changes.end() || (*i)->time() >= t);
return i; return i;
} }
@ -1238,7 +1238,7 @@ Sequence<Time>::sysex_lower_bound (Time t) const
{ {
SysExPtr search (new Event<Time> (0, t)); SysExPtr search (new Event<Time> (0, t));
typename Sequence<Time>::SysExes::const_iterator i = _sysexes.lower_bound (search); typename Sequence<Time>::SysExes::const_iterator i = _sysexes.lower_bound (search);
assert (i == _sysexes.end() || musical_time_greater_or_equal_to((*i)->time(), t)); assert (i == _sysexes.end() || (*i)->time() >= t);
return i; return i;
} }
@ -1249,9 +1249,9 @@ template<typename Time>
typename Sequence<Time>::Notes::iterator typename Sequence<Time>::Notes::iterator
Sequence<Time>::note_lower_bound (Time t) Sequence<Time>::note_lower_bound (Time t)
{ {
NotePtr search_note(new Note<Time>(0, t, 0, 0, 0)); NotePtr search_note(new Note<Time>(0, t, Time(), 0, 0));
typename Sequence<Time>::Notes::iterator i = _notes.lower_bound(search_note); typename Sequence<Time>::Notes::iterator i = _notes.lower_bound(search_note);
assert(i == _notes.end() || musical_time_greater_or_equal_to((*i)->time(), t)); assert(i == _notes.end() || (*i)->time() >= t);
return i; return i;
} }
@ -1262,7 +1262,7 @@ Sequence<Time>::patch_change_lower_bound (Time t)
{ {
PatchChangePtr search (new PatchChange<Time> (t, 0, 0, 0)); PatchChangePtr search (new PatchChange<Time> (t, 0, 0, 0));
typename Sequence<Time>::PatchChanges::iterator i = _patch_changes.lower_bound (search); typename Sequence<Time>::PatchChanges::iterator i = _patch_changes.lower_bound (search);
assert (i == _patch_changes.end() || musical_time_greater_or_equal_to ((*i)->time(), t)); assert (i == _patch_changes.end() || (*i)->time() >= t);
return i; return i;
} }
@ -1273,7 +1273,7 @@ Sequence<Time>::sysex_lower_bound (Time t)
{ {
SysExPtr search (new Event<Time> (0, t)); SysExPtr search (new Event<Time> (0, t));
typename Sequence<Time>::SysExes::iterator i = _sysexes.lower_bound (search); typename Sequence<Time>::SysExes::iterator i = _sysexes.lower_bound (search);
assert (i == _sysexes.end() || musical_time_greater_or_equal_to((*i)->time(), t)); assert (i == _sysexes.end() || (*i)->time() >= t);
return i; return i;
} }
@ -1311,7 +1311,7 @@ Sequence<Time>::get_notes_by_pitch (Notes& n, NoteOperator op, uint8_t val, int
} }
const Pitches& p (pitches (c)); const Pitches& p (pitches (c));
NotePtr search_note(new Note<Time>(0, 0, 0, val, 0)); NotePtr search_note(new Note<Time>(0, Time(), Time(), val, 0));
typename Pitches::const_iterator i; typename Pitches::const_iterator i;
switch (op) { switch (op) {
case PitchEqual: case PitchEqual:

View file

@ -29,27 +29,25 @@ SMFTest::takeFiveTest ()
smf.seek_to_start(); smf.seek_to_start();
uint64_t time = 0; /* in SMF ticks */ uint64_t time = 0; /* in SMF ticks */
Evoral::Event<double> ev; Evoral::Event<Evoral::MusicalTime> ev;
const double frames_per_beat = 100.0;
uint32_t delta_t = 0; uint32_t delta_t = 0;
uint32_t size = 0; uint32_t size = 0;
uint8_t* buf = NULL; uint8_t* buf = NULL;
int ret; int ret;
while ((ret = smf.read_event(&delta_t, &size, &buf)) >= 0) { while ((ret = smf.read_event(&delta_t, &size, &buf)) >= 0) {
ev.set(buf, size, 0.0); ev.set(buf, size, Evoral::MusicalTime());
time += delta_t; time += delta_t;
if (ret > 0) { // didn't skip (meta) event if (ret > 0) { // didn't skip (meta) event
//cerr << "read smf event type " << hex << int(buf[0]) << endl; //cerr << "read smf event type " << hex << int(buf[0]) << endl;
// make ev.time absolute time in frames ev.set_time(Evoral::MusicalTime::ticks_at_rate(time, smf.ppqn()));
ev.set_time(time * frames_per_beat / (double)smf.ppqn());
ev.set_event_type(type_map->midi_event_type(buf[0])); ev.set_event_type(type_map->midi_event_type(buf[0]));
seq->append(ev, next_event_id ()); seq->append(ev, next_event_id ());
} }
} }
seq->end_write (Sequence<Time>::Relax, false); seq->end_write (Sequence<Time>::Relax,
Evoral::MusicalTime::ticks_at_rate(time, smf.ppqn()));
CPPUNIT_ASSERT(!seq->empty()); CPPUNIT_ASSERT(!seq->empty());
} }

View file

@ -21,6 +21,7 @@
#include <sigc++/sigc++.h> #include <sigc++/sigc++.h>
#include <cppunit/TestFixture.h> #include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/HelperMacros.h>
#include "evoral/types.hpp"
#include "evoral/SMF.hpp" #include "evoral/SMF.hpp"
#include "SequenceTest.hpp" #include "SequenceTest.hpp"
@ -56,7 +57,7 @@ class SMFTest : public CppUnit::TestFixture
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
public: public:
typedef double Time; typedef Evoral::MusicalTime Time;
void setUp() { void setUp() {
type_map = new DummyTypeMap(); type_map = new DummyTypeMap();

View file

@ -5,6 +5,7 @@
CPPUNIT_TEST_SUITE_REGISTRATION(SequenceTest); CPPUNIT_TEST_SUITE_REGISTRATION(SequenceTest);
using namespace std; using namespace std;
using namespace Evoral;
void void
SequenceTest::createTest () SequenceTest::createTest ()
@ -75,7 +76,7 @@ SequenceTest::iteratorSeekTest ()
} }
bool on = true; bool on = true;
for (Sequence<Time>::const_iterator i = seq->begin(600); i != seq->end(); ++i) { for (Sequence<Time>::const_iterator i = seq->begin(Evoral::MusicalTime(600)); i != seq->end(); ++i) {
if (on) { if (on) {
CPPUNIT_ASSERT(((const MIDIEvent<Time>&)*i).is_note_on()); CPPUNIT_ASSERT(((const MIDIEvent<Time>&)*i).is_note_on());
CPPUNIT_ASSERT_EQUAL(i->time(), Time((num_notes + 6) * 100)); CPPUNIT_ASSERT_EQUAL(i->time(), Time((num_notes + 6) * 100));
@ -136,7 +137,7 @@ SequenceTest::controlInterpolationTest ()
sink.write(i->time(), i->event_type(), i->size(), i->buffer()); sink.write(i->time(), i->event_type(), i->size(), i->buffer());
} }
CPPUNIT_ASSERT(sink.events.size() == 128 * 2 - 1); CPPUNIT_ASSERT(sink.events.size() == 128 * 2 - 1);
Time last_time = 0; Time last_time(0);
int16_t last_value = -1; int16_t last_value = -1;
bool ascending = true; bool ascending = true;
for (CCTestSink<Time>::Events::const_iterator i = sink.events.begin(); for (CCTestSink<Time>::Events::const_iterator i = sink.events.begin();

View file

@ -39,7 +39,7 @@ public:
}; };
} }
bool is_integer (const Evoral::Parameter& /*param*/) const { return true; } bool is_integer (const Parameter& /*param*/) const { return true; }
Parameter new_parameter(uint32_t type, uint8_t channel, uint32_t id) const { Parameter new_parameter(uint32_t type, uint8_t channel, uint32_t id) const {
Parameter p(type, channel, id); Parameter p(type, channel, id);
@ -119,7 +119,7 @@ class SequenceTest : public CppUnit::TestFixture
CPPUNIT_TEST_SUITE_END (); CPPUNIT_TEST_SUITE_END ();
public: public:
typedef double Time; typedef MusicalTime Time;
typedef std::vector< boost::shared_ptr< Note<Time> > > Notes; typedef std::vector< boost::shared_ptr< Note<Time> > > Notes;
void setUp () { void setUp () {
@ -129,8 +129,9 @@ public:
assert(seq); assert(seq);
for (int i = 0; i < 12; i++) { for (int i = 0; i < 12; i++) {
test_notes.push_back(boost::shared_ptr<Note<Time> > test_notes.push_back(
(new Note<Time>(0, i * 100, 100, 64 + i, 64))); boost::shared_ptr<Note<Time> >(
new Note<Time>(0, MusicalTime(i * 100), MusicalTime(100), 64 + i, 64)));
} }
} }

View file

@ -95,7 +95,7 @@ Patch::get_state (void)
node->add_property("Name", _name); node->add_property("Name", _name);
/* /*
typedef std::list< boost::shared_ptr< Evoral::MIDIEvent<double> > > PatchMidiCommands; typedef std::list< boost::shared_ptr< Evoral::MIDIEvent<Evoral::MusicalTime> > > PatchMidiCommands;
XMLNode* commands = node->add_child("PatchMIDICommands"); XMLNode* commands = node->add_child("PatchMIDICommands");
for (PatchMidiCommands::const_iterator event = _patch_midi_commands.begin(); for (PatchMidiCommands::const_iterator event = _patch_midi_commands.begin();
event != _patch_midi_commands.end(); event != _patch_midi_commands.end();