mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-07 23:35:03 +01:00
Move all beats <-> frames time conversion into a single object that can be passed around.
This has 3 main benefits: - All conversion code is in one place (less duplication, potential bugs) - The conversion method can be passed to things that are ignorant of the actual time units involved, information required, etc. (In the future it would be nice to have user selectable tempo/frame time) - It should be relatively simple now to support tempo changes part-way through a MIDI region (at least architecturally speaking) git-svn-id: svn://localhost/ardour2/branches/3.0@4594 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
beb3eea62b
commit
3963d2b0b2
13 changed files with 206 additions and 80 deletions
|
|
@ -1305,7 +1305,7 @@ class Editor : public PublicEditor
|
|||
|
||||
/* import specific info */
|
||||
|
||||
struct EditorImportStatus : public ARDOUR::Session::import_status {
|
||||
struct EditorImportStatus : public ARDOUR::Session::ImportStatus {
|
||||
Editing::ImportMode mode;
|
||||
nframes64_t pos;
|
||||
int target_tracks;
|
||||
|
|
|
|||
|
|
@ -641,9 +641,6 @@ MidiRegionView::display_program_change_flags()
|
|||
}
|
||||
}
|
||||
break;
|
||||
} else if (control->first.type() == MidiCCAutomation) {
|
||||
//cerr << " found CC Automation of channel " << int(control->first.channel())
|
||||
// << " and id " << control->first.id() << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1391,17 +1388,13 @@ MidiRegionView::get_position_pixels()
|
|||
nframes64_t
|
||||
MidiRegionView::beats_to_frames(double beats) const
|
||||
{
|
||||
const Meter& m = trackview.session().tempo_map().meter_at(_region->position());
|
||||
const Tempo& t = trackview.session().tempo_map().tempo_at(_region->position());
|
||||
return lrint(beats * m.frames_per_bar(t, trackview.session().frame_rate()) / m.beats_per_bar());
|
||||
return midi_region()->midi_source()->converter().to(beats);
|
||||
}
|
||||
|
||||
double
|
||||
MidiRegionView::frames_to_beats(nframes64_t frames) const
|
||||
{
|
||||
const Meter& m = trackview.session().tempo_map().meter_at(_region->position());
|
||||
const Tempo& t = trackview.session().tempo_map().tempo_at(_region->position());
|
||||
return frames / m.frames_per_bar(t, trackview.session().frame_rate()) * m.beats_per_bar();
|
||||
return midi_region()->midi_source()->converter().from(frames);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ audio_library.cc
|
|||
audio_playlist.cc
|
||||
audio_playlist_importer.cc
|
||||
audio_port.cc
|
||||
audio_region_importer.cc
|
||||
audio_track.cc
|
||||
audio_track_importer.cc
|
||||
audioanalyser.cc
|
||||
|
|
@ -45,13 +46,13 @@ audioengine.cc
|
|||
audiofile_tagger.cc
|
||||
audiofilesource.cc
|
||||
audioregion.cc
|
||||
audio_region_importer.cc
|
||||
audiosource.cc
|
||||
auditioner.cc
|
||||
automatable.cc
|
||||
automation.cc
|
||||
automation_control.cc
|
||||
automation_list.cc
|
||||
beats_frames_converter.cc
|
||||
broadcast_info.cc
|
||||
buffer.cc
|
||||
buffer_set.cc
|
||||
|
|
@ -65,8 +66,8 @@ cycle_timer.cc
|
|||
default_click.cc
|
||||
directory_names.cc
|
||||
diskstream.cc
|
||||
element_importer.cc
|
||||
element_import_handler.cc
|
||||
element_importer.cc
|
||||
enums.cc
|
||||
event_type_map.cc
|
||||
export_channel.cc
|
||||
|
|
@ -162,8 +163,8 @@ svn_revision.cc
|
|||
tape_file_matcher.cc
|
||||
template_utils.cc
|
||||
tempo.cc
|
||||
ticker.cc
|
||||
tempo_map_importer.cc
|
||||
ticker.cc
|
||||
track.cc
|
||||
transient_detector.cc
|
||||
user_bundle.cc
|
||||
|
|
|
|||
52
libs/ardour/ardour/beats_frames_converter.h
Normal file
52
libs/ardour/ardour/beats_frames_converter.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright (C) 2009 Paul Davis
|
||||
Author: Dave Robillard
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id: midiregion.h 733 2006-08-01 17:19:38Z drobilla $
|
||||
*/
|
||||
|
||||
#include <evoral/TimeConverter.hpp>
|
||||
#include <ardour/types.h>
|
||||
|
||||
#ifndef __ardour_beats_frames_converter_h__
|
||||
#define __ardour_beats_frames_converter_h__
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class Session;
|
||||
|
||||
class BeatsFramesConverter : public Evoral::TimeConverter<double,nframes_t> {
|
||||
public:
|
||||
BeatsFramesConverter(Session& session, nframes_t origin)
|
||||
: _session(session)
|
||||
, _origin(origin)
|
||||
{}
|
||||
|
||||
nframes_t to(double beats) const;
|
||||
double from(nframes_t frames) const;
|
||||
|
||||
nframes_t origin() const { return _origin; }
|
||||
void set_origin(nframes_t origin) { _origin = origin; }
|
||||
|
||||
private:
|
||||
Session& _session;
|
||||
nframes_t _origin;
|
||||
};
|
||||
|
||||
} /* namespace ARDOUR */
|
||||
|
||||
#endif /* __ardour_beats_frames_converter_h__ */
|
||||
|
|
@ -30,8 +30,7 @@
|
|||
#include <ardour/ardour.h>
|
||||
#include <ardour/buffer.h>
|
||||
#include <ardour/source.h>
|
||||
|
||||
using std::string;
|
||||
#include <ardour/beats_frames_converter.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
|
|
@ -44,7 +43,7 @@ class MidiSource : public Source
|
|||
public:
|
||||
typedef double TimeType;
|
||||
|
||||
MidiSource (Session& session, string name);
|
||||
MidiSource (Session& session, std::string name);
|
||||
MidiSource (Session& session, const XMLNode&);
|
||||
virtual ~MidiSource ();
|
||||
|
||||
|
|
@ -66,13 +65,13 @@ class MidiSource : public Source
|
|||
virtual void mark_streaming_write_started ();
|
||||
virtual void mark_streaming_write_completed ();
|
||||
|
||||
uint64_t timeline_position () { return _timeline_position; }
|
||||
void set_timeline_position (nframes_t when) { _timeline_position = when; }
|
||||
uint64_t timeline_position () { return _timeline_position; }
|
||||
void set_timeline_position (nframes_t when);
|
||||
|
||||
virtual void session_saved();
|
||||
|
||||
string captured_for() const { return _captured_for; }
|
||||
void set_captured_for (string str) { _captured_for = str; }
|
||||
std::string captured_for() const { return _captured_for; }
|
||||
void set_captured_for (std::string str) { _captured_for = str; }
|
||||
|
||||
uint32_t read_data_count() const { return _read_data_count; }
|
||||
uint32_t write_data_count() const { return _write_data_count; }
|
||||
|
|
@ -96,6 +95,8 @@ class MidiSource : public Source
|
|||
void set_model(boost::shared_ptr<MidiModel> m) { _model = m; }
|
||||
void drop_model() { _model.reset(); }
|
||||
|
||||
BeatsFramesConverter& converter() { return _converter; }
|
||||
|
||||
protected:
|
||||
virtual void flush_midi() = 0;
|
||||
|
||||
|
|
@ -104,10 +105,12 @@ class MidiSource : public Source
|
|||
virtual nframes_t write_unlocked (MidiRingBuffer<nframes_t>& dst, nframes_t cnt) = 0;
|
||||
|
||||
mutable Glib::Mutex _lock;
|
||||
string _captured_for;
|
||||
std::string _captured_for;
|
||||
uint64_t _timeline_position;
|
||||
mutable uint32_t _read_data_count; ///< modified in read()
|
||||
mutable uint32_t _write_data_count; ///< modified in write()
|
||||
|
||||
BeatsFramesConverter _converter;
|
||||
|
||||
boost::shared_ptr<MidiModel> _model;
|
||||
bool _writing;
|
||||
|
|
@ -116,7 +119,7 @@ class MidiSource : public Source
|
|||
mutable nframes_t _last_read_end;
|
||||
|
||||
private:
|
||||
bool file_changed (string path);
|
||||
bool file_changed (std::string path);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -610,7 +610,7 @@ class Session : public PBD::StatefulDestructible
|
|||
|
||||
/* source management */
|
||||
|
||||
struct import_status : public InterThreadInfo {
|
||||
struct ImportStatus : public InterThreadInfo {
|
||||
string doing_what;
|
||||
|
||||
/* control info */
|
||||
|
|
@ -624,8 +624,8 @@ class Session : public PBD::StatefulDestructible
|
|||
SourceList sources;
|
||||
};
|
||||
|
||||
void import_audiofiles (import_status&);
|
||||
bool sample_rate_convert (import_status&, string infile, string& outfile);
|
||||
void import_audiofiles (ImportStatus&);
|
||||
bool sample_rate_convert (ImportStatus&, string infile, string& outfile);
|
||||
string build_tmp_convert_name (string file);
|
||||
|
||||
boost::shared_ptr<ExportHandler> get_export_handler ();
|
||||
|
|
|
|||
|
|
@ -336,7 +336,7 @@ AudioRegionImporter::prepare_sources ()
|
|||
return;
|
||||
}
|
||||
|
||||
Session::import_status status;
|
||||
Session::ImportStatus status;
|
||||
|
||||
// Get sources that still need to be imported
|
||||
for (std::list<string>::iterator it = filenames.begin(); it != filenames.end(); ++it) {
|
||||
|
|
|
|||
54
libs/ardour/beats_frames_converter.cc
Normal file
54
libs/ardour/beats_frames_converter.cc
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
Copyright (C) 2009 Paul Davis
|
||||
Author: Dave Robillard
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id: midiregion.h 733 2006-08-01 17:19:38Z drobilla $
|
||||
*/
|
||||
|
||||
#include <ardour/audioengine.h>
|
||||
#include <ardour/beats_frames_converter.h>
|
||||
#include <ardour/session.h>
|
||||
#include <ardour/tempo.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
nframes_t
|
||||
BeatsFramesConverter::to(double beats) const
|
||||
{
|
||||
// FIXME: assumes tempo never changes after origin
|
||||
const Tempo& tempo = _session.tempo_map().tempo_at(_origin);
|
||||
const double frames_per_beat = tempo.frames_per_beat(
|
||||
_session.engine().frame_rate(),
|
||||
_session.tempo_map().meter_at(_origin));
|
||||
|
||||
return lrint(beats * frames_per_beat);
|
||||
}
|
||||
|
||||
double
|
||||
BeatsFramesConverter::from(nframes_t frames) const
|
||||
{
|
||||
// FIXME: assumes tempo never changes after origin
|
||||
const Tempo& tempo = _session.tempo_map().tempo_at(_origin);
|
||||
const double frames_per_beat = tempo.frames_per_beat(
|
||||
_session.engine().frame_rate(),
|
||||
_session.tempo_map().meter_at(_origin));
|
||||
|
||||
return frames / frames_per_beat;
|
||||
}
|
||||
|
||||
} /* namespace ARDOUR */
|
||||
|
||||
|
|
@ -257,7 +257,7 @@ compose_status_message (const string& path,
|
|||
}
|
||||
|
||||
static void
|
||||
write_audio_data_to_new_files (ImportableSource* source, Session::import_status& status,
|
||||
write_audio_data_to_new_files (ImportableSource* source, Session::ImportStatus& status,
|
||||
vector<boost::shared_ptr<Source> >& newfiles)
|
||||
{
|
||||
const nframes_t nframes = ResampledImportableSource::blocksize;
|
||||
|
|
@ -309,8 +309,8 @@ write_audio_data_to_new_files (ImportableSource* source, Session::import_status&
|
|||
}
|
||||
|
||||
static void
|
||||
write_midi_data_to_new_files (Evoral::SMF* source, Session::import_status& status,
|
||||
vector<boost::shared_ptr<Source> >& newfiles)
|
||||
write_midi_data_to_new_files (Evoral::SMF* source, Session::ImportStatus& status,
|
||||
vector<boost::shared_ptr<Source> >& newfiles)
|
||||
{
|
||||
uint32_t buf_size = 4;
|
||||
uint8_t* buf = (uint8_t*)malloc(buf_size);
|
||||
|
|
@ -354,20 +354,14 @@ write_midi_data_to_new_files (Evoral::SMF* source, Session::import_status& statu
|
|||
if (status.progress < 0.99)
|
||||
status.progress += 0.01;
|
||||
}
|
||||
|
||||
nframes_t timeline_position = 0; // FIXME: ?
|
||||
|
||||
// FIXME: kluuuuudge: assumes tempo never changes after start
|
||||
const double frames_per_beat = smfs->session().tempo_map().tempo_at(
|
||||
timeline_position).frames_per_beat(
|
||||
smfs->session().engine().frame_rate(),
|
||||
smfs->session().tempo_map().meter_at(timeline_position));
|
||||
|
||||
smfs->update_length(0, (nframes_t) ceil ((t / (double)source->ppqn()) * frames_per_beat));
|
||||
const double length_beats = ceil(t / (double)source->ppqn());
|
||||
smfs->update_length(0, smfs->converter().to(length_beats));
|
||||
smfs->end_write();
|
||||
|
||||
if (status.cancel)
|
||||
if (status.cancel) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (...) {
|
||||
|
|
@ -382,11 +376,11 @@ remove_file_source (boost::shared_ptr<Source> source)
|
|||
}
|
||||
|
||||
// This function is still unable to cleanly update an existing source, even though
|
||||
// it is possible to set the import_status flag accordingly. The functinality
|
||||
// it is possible to set the ImportStatus flag accordingly. The functinality
|
||||
// is disabled at the GUI until the Source implementations are able to provide
|
||||
// the necessary API.
|
||||
void
|
||||
Session::import_audiofiles (import_status& status)
|
||||
Session::import_audiofiles (ImportStatus& status)
|
||||
{
|
||||
uint32_t cnt = 1;
|
||||
typedef vector<boost::shared_ptr<Source> > Sources;
|
||||
|
|
|
|||
|
|
@ -52,16 +52,20 @@ sigc::signal<void,MidiSource *> MidiSource::MidiSourceCreated;
|
|||
MidiSource::MidiSource (Session& s, string name)
|
||||
: Source (s, name, DataType::MIDI)
|
||||
, _timeline_position(0)
|
||||
, _read_data_count(0)
|
||||
, _write_data_count(0)
|
||||
, _converter(s, _timeline_position)
|
||||
, _writing (false)
|
||||
, _last_read_end(0)
|
||||
{
|
||||
_read_data_count = 0;
|
||||
_write_data_count = 0;
|
||||
}
|
||||
|
||||
MidiSource::MidiSource (Session& s, const XMLNode& node)
|
||||
: Source (s, node)
|
||||
, _timeline_position(0)
|
||||
, _read_data_count(0)
|
||||
, _write_data_count(0)
|
||||
, _converter(s, _timeline_position)
|
||||
, _writing (false)
|
||||
, _last_read_end(0)
|
||||
{
|
||||
|
|
@ -110,12 +114,7 @@ MidiSource::midi_read (MidiRingBuffer<nframes_t>& dst, nframes_t start, nframes_
|
|||
|
||||
Glib::Mutex::Lock lm (_lock);
|
||||
if (_model) {
|
||||
// FIXME: assumes tempo never changes after start
|
||||
const Tempo& tempo = _session.tempo_map().tempo_at(_timeline_position);
|
||||
const double frames_per_beat = tempo.frames_per_beat(
|
||||
_session.engine().frame_rate(),
|
||||
_session.tempo_map().meter_at(_timeline_position));
|
||||
#define BEATS_TO_FRAMES(t) (((t) * frames_per_beat) + stamp_offset - negative_stamp_offset)
|
||||
#define BEATS_TO_FRAMES(t) (_converter.to(t) + stamp_offset - negative_stamp_offset)
|
||||
|
||||
Evoral::Sequence<double>::const_iterator& i = _model_iter;
|
||||
|
||||
|
|
@ -161,6 +160,13 @@ MidiSource::file_changed (string path)
|
|||
return !e1;
|
||||
}
|
||||
|
||||
void
|
||||
MidiSource::set_timeline_position (nframes_t when)
|
||||
{
|
||||
_timeline_position = when;
|
||||
_converter.set_origin(when);
|
||||
}
|
||||
|
||||
void
|
||||
MidiSource::mark_streaming_midi_write_started (NoteMode mode, nframes_t start_frame)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -62,19 +62,12 @@ Quantize::run (boost::shared_ptr<Region> r)
|
|||
|
||||
boost::shared_ptr<MidiModel> model = src->model();
|
||||
|
||||
// FIXME: Model really needs to be switched to beat time (double) ASAP
|
||||
|
||||
const Tempo& t = session.tempo_map().tempo_at(r->start());
|
||||
const Meter& m = session.tempo_map().meter_at(r->start());
|
||||
|
||||
double q_frames = _q * (m.frames_per_bar(t, session.frame_rate()) / (double)m.beats_per_bar());
|
||||
|
||||
for (Evoral::Sequence<MidiModel::TimeType>::Notes::iterator i = model->notes().begin();
|
||||
i != model->notes().end(); ++i) {
|
||||
const double new_time = lrint((*i)->time() / q_frames) * q_frames;
|
||||
double new_dur = lrint((*i)->length() / q_frames) * q_frames;
|
||||
const double new_time = lrint((*i)->time() / _q) * _q;
|
||||
double new_dur = lrint((*i)->length() / _q) * _q;
|
||||
if (new_dur == 0.0)
|
||||
new_dur = q_frames;
|
||||
new_dur = _q;
|
||||
|
||||
(*i)->set_time(new_time);
|
||||
(*i)->set_length(new_dur);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@
|
|||
#include <ardour/midi_ring_buffer.h>
|
||||
#include <ardour/session.h>
|
||||
#include <ardour/smf_source.h>
|
||||
#include <ardour/tempo.h>
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
|
|
@ -145,13 +144,7 @@ SMFSource::read_unlocked (MidiRingBuffer<nframes_t>& dst, nframes_t start, nfram
|
|||
|
||||
size_t scratch_size = 0; // keep track of scratch to minimize reallocs
|
||||
|
||||
// FIXME: assumes tempo never changes after start
|
||||
const Tempo& tempo = _session.tempo_map().tempo_at(_timeline_position);
|
||||
const double frames_per_beat = tempo.frames_per_beat(
|
||||
_session.engine().frame_rate(),
|
||||
_session.tempo_map().meter_at(_timeline_position));
|
||||
|
||||
const uint64_t start_ticks = (uint64_t)((start / frames_per_beat) * ppqn());
|
||||
const uint64_t start_ticks = (uint64_t)(_converter.from(start) * ppqn());
|
||||
|
||||
if (_last_read_end == 0 || start != _last_read_end) {
|
||||
cerr << "SMFSource::read_unlocked seeking to " << start << endl;
|
||||
|
|
@ -183,8 +176,7 @@ SMFSource::read_unlocked (MidiRingBuffer<nframes_t>& dst, nframes_t start, nfram
|
|||
ev_type = EventTypeMap::instance().midi_event_type(ev_buffer[0]);
|
||||
|
||||
assert(time >= start_ticks);
|
||||
const nframes_t ev_frame_time = (nframes_t)(
|
||||
((time / (double)ppqn()) * frames_per_beat)) + stamp_offset;
|
||||
const nframes_t ev_frame_time = _converter.to(time / (double)ppqn()) + stamp_offset;
|
||||
|
||||
if (ev_frame_time < start + dur) {
|
||||
dst.write(ev_frame_time - negative_stamp_offset, ev_type, ev_size, ev_buffer);
|
||||
|
|
@ -323,24 +315,19 @@ SMFSource::append_event_unlocked_frames(const Evoral::Event<nframes_t>& ev)
|
|||
return;
|
||||
}
|
||||
|
||||
// FIXME: assumes tempo never changes after start
|
||||
const Tempo& tempo = _session.tempo_map().tempo_at(_timeline_position);
|
||||
const double frames_per_beat = tempo.frames_per_beat(
|
||||
_session.engine().frame_rate(),
|
||||
_session.tempo_map().meter_at(_timeline_position));
|
||||
const nframes_t delta_time_frames = ev.time() - _last_ev_time_frames;
|
||||
const double delta_time_beats = _converter.from(delta_time_frames);
|
||||
const uint32_t delta_time_ticks = (uint32_t)(lrint(delta_time_beats * (double)ppqn()));
|
||||
|
||||
uint32_t delta_time = (uint32_t)((ev.time() - _last_ev_time_frames)
|
||||
/ frames_per_beat * (double)ppqn());
|
||||
|
||||
Evoral::SMF::append_event_delta(delta_time, ev.size(), ev.buffer());
|
||||
Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer());
|
||||
_last_ev_time_frames = ev.time();
|
||||
|
||||
_write_data_count += ev.size();
|
||||
|
||||
if (_model) {
|
||||
double beat_time = ev.time() / frames_per_beat;
|
||||
const double ev_time_beats = _converter.from(ev.time());
|
||||
const Evoral::Event<double> beat_ev(
|
||||
ev.event_type(), beat_time, ev.size(), (uint8_t*)ev.buffer());
|
||||
ev.event_type(), ev_time_beats, ev.size(), (uint8_t*)ev.buffer());
|
||||
_model->append(beat_ev);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
43
libs/evoral/evoral/TimeConverter.hpp
Normal file
43
libs/evoral/evoral/TimeConverter.hpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/* This file is part of Evoral.
|
||||
* Copyright (C) 2009 Dave Robillard <http://drobilla.net>
|
||||
* Copyright (C) 2009 Paul Davis
|
||||
*
|
||||
* Evoral is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* Evoral is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef EVORAL_TIME_CONVERTER_HPP
|
||||
#define EVORAL_TIME_CONVERTER_HPP
|
||||
|
||||
namespace Evoral {
|
||||
|
||||
/** A bidirectional converter between two different time units.
|
||||
*
|
||||
* Think of the conversion method names as if they are written in-between
|
||||
* the two template parameters (i.e. "A <name> B").
|
||||
*/
|
||||
template<typename A, typename B>
|
||||
class TimeConverter {
|
||||
public:
|
||||
virtual ~TimeConverter() {}
|
||||
|
||||
/** Convert A time to B time (A to B) */
|
||||
virtual B to(A a) const = 0;
|
||||
|
||||
/** Convert B time to A time (A from B) */
|
||||
virtual A from(B b) const = 0;
|
||||
};
|
||||
|
||||
} // namespace Evoral
|
||||
|
||||
#endif // EVORAL_TIME_CONVERTER_HPP
|
||||
Loading…
Add table
Add a link
Reference in a new issue