mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-20 13:46:30 +01:00
Save MIDI files to interchange/sessionname/midifiles (instead of audiofiles).
Fix some uninitialized variables in Streamview. Tempo-based SMF source (internally only). Horrible crash on MIDI record finish. git-svn-id: svn://localhost/ardour2/trunk@1955 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
e9de0dec8a
commit
7852cc219c
12 changed files with 96 additions and 21 deletions
|
|
@ -87,13 +87,14 @@ MidiRegionView::init (Gdk::Color& basic_color, bool wfd)
|
||||||
|
|
||||||
set_colors ();
|
set_colors ();
|
||||||
|
|
||||||
boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion> (_region);
|
if (wfd) {
|
||||||
mr->midi_source(0)->load_model();
|
midi_region()->midi_source(0)->load_model();
|
||||||
|
|
||||||
begin_write();
|
begin_write();
|
||||||
for (size_t i=0; i < mr->midi_source(0)->model().n_events(); ++i)
|
for (size_t i=0; i < midi_region()->midi_source(0)->model().n_events(); ++i)
|
||||||
add_event(mr->midi_source(0)->model().event_at(i));
|
add_event(midi_region()->midi_source(0)->model().event_at(i));
|
||||||
end_write();
|
end_write();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MidiRegionView::~MidiRegionView ()
|
MidiRegionView::~MidiRegionView ()
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,8 @@ StreamView::StreamView (RouteTimeAxisView& tv)
|
||||||
, region_color(_trackview.color())
|
, region_color(_trackview.color())
|
||||||
, stream_base_color(0xFFFFFFFF)
|
, stream_base_color(0xFFFFFFFF)
|
||||||
, layers(1)
|
, layers(1)
|
||||||
|
, height(tv.height)
|
||||||
|
, layer_display(Overlaid)
|
||||||
, last_rec_data_frame(0)
|
, last_rec_data_frame(0)
|
||||||
{
|
{
|
||||||
/* set_position() will position the group */
|
/* set_position() will position the group */
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,8 @@ bool TimeAxisView::need_size_info = true;
|
||||||
TimeAxisView::TimeAxisView (ARDOUR::Session& sess, PublicEditor& ed, TimeAxisView* rent, Canvas& canvas)
|
TimeAxisView::TimeAxisView (ARDOUR::Session& sess, PublicEditor& ed, TimeAxisView* rent, Canvas& canvas)
|
||||||
: AxisView (sess),
|
: AxisView (sess),
|
||||||
editor (ed),
|
editor (ed),
|
||||||
|
y_position(0),
|
||||||
|
order(0),
|
||||||
controls_table (2, 8)
|
controls_table (2, 8)
|
||||||
{
|
{
|
||||||
if (need_size_info) {
|
if (need_size_info) {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ namespace ARDOUR {
|
||||||
|
|
||||||
extern const char* const old_sound_dir_name;
|
extern const char* const old_sound_dir_name;
|
||||||
extern const char* const sound_dir_name;
|
extern const char* const sound_dir_name;
|
||||||
|
extern const char* const midi_dir_name;
|
||||||
extern const char* const dead_sound_dir_name;
|
extern const char* const dead_sound_dir_name;
|
||||||
extern const char* const interchange_dir_name;
|
extern const char* const interchange_dir_name;
|
||||||
extern const char* const peak_dir_name;
|
extern const char* const peak_dir_name;
|
||||||
|
|
|
||||||
|
|
@ -256,6 +256,7 @@ class Session : public PBD::StatefulDestructible
|
||||||
sigc::signal<void> DirtyChanged;
|
sigc::signal<void> DirtyChanged;
|
||||||
|
|
||||||
std::string sound_dir (bool with_path = true) const;
|
std::string sound_dir (bool with_path = true) const;
|
||||||
|
std::string midi_dir (bool with_path = true) const;
|
||||||
std::string peak_dir () const;
|
std::string peak_dir () const;
|
||||||
std::string dead_sound_dir () const;
|
std::string dead_sound_dir () const;
|
||||||
std::string automation_dir () const;
|
std::string automation_dir () const;
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,13 @@ public:
|
||||||
*/
|
*/
|
||||||
const path sound_path () const;
|
const path sound_path () const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the absolute path to the directory in which
|
||||||
|
* the session stores MIDI files, ie
|
||||||
|
* root_path()/interchange/session_name/midifiles
|
||||||
|
*/
|
||||||
|
const path midi_path () const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The absolute path to the directory in which all
|
* @return The absolute path to the directory in which all
|
||||||
* peak files are stored for a session.
|
* peak files are stored for a session.
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,8 @@ class SMFSource : public MidiSource {
|
||||||
void load_model(bool lock=true);
|
void load_model(bool lock=true);
|
||||||
void destroy_model();
|
void destroy_model();
|
||||||
|
|
||||||
|
uint16_t ppqn() const { return _ppqn; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
int init (string idstr, bool must_exist);
|
int init (string idstr, bool must_exist);
|
||||||
|
|
@ -110,6 +112,8 @@ class SMFSource : public MidiSource {
|
||||||
uint32_t read_var_len() const;
|
uint32_t read_var_len() const;
|
||||||
int read_event(MidiEvent& ev) const;
|
int read_event(MidiEvent& ev) const;
|
||||||
|
|
||||||
|
static const uint16_t _ppqn = 19200;
|
||||||
|
|
||||||
uint16_t _channel;
|
uint16_t _channel;
|
||||||
string _path;
|
string _path;
|
||||||
Flag _flags;
|
Flag _flags;
|
||||||
|
|
|
||||||
|
|
@ -195,7 +195,7 @@ class TempoMap : public PBD::StatefulDestructible
|
||||||
|
|
||||||
BBTPointList *get_points (nframes_t start, nframes_t end) const;
|
BBTPointList *get_points (nframes_t start, nframes_t end) const;
|
||||||
|
|
||||||
void bbt_time (nframes_t when, BBT_Time&) const;
|
void bbt_time (nframes_t when, BBT_Time&) const;
|
||||||
nframes_t frame_time (const BBT_Time&) const;
|
nframes_t frame_time (const BBT_Time&) const;
|
||||||
nframes_t bbt_duration_at (nframes_t, const BBT_Time&, int dir) const;
|
nframes_t bbt_duration_at (nframes_t, const BBT_Time&, int dir) const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ namespace ARDOUR {
|
||||||
|
|
||||||
const char* const old_sound_dir_name = X_("sounds");
|
const char* const old_sound_dir_name = X_("sounds");
|
||||||
const char* const sound_dir_name = X_("audiofiles");
|
const char* const sound_dir_name = X_("audiofiles");
|
||||||
|
const char* const midi_dir_name = X_("audiofiles");
|
||||||
const char* const peak_dir_name = X_("peaks");
|
const char* const peak_dir_name = X_("peaks");
|
||||||
const char* const dead_sound_dir_name = X_("dead_sounds");
|
const char* const dead_sound_dir_name = X_("dead_sounds");
|
||||||
const char* const interchange_dir_name = X_("interchange");
|
const char* const interchange_dir_name = X_("interchange");
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,19 @@ SessionDirectory::sound_path () const
|
||||||
return l_sound_path;
|
return l_sound_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const path
|
||||||
|
SessionDirectory::midi_path () const
|
||||||
|
{
|
||||||
|
// the new style sound directory
|
||||||
|
path l_midi_path(m_root_path);
|
||||||
|
|
||||||
|
l_midi_path /= interchange_dir_name;
|
||||||
|
l_midi_path /= basename(m_root_path);
|
||||||
|
l_midi_path /= midi_dir_name;
|
||||||
|
|
||||||
|
return l_midi_path;
|
||||||
|
}
|
||||||
|
|
||||||
const path
|
const path
|
||||||
SessionDirectory::peak_path () const
|
SessionDirectory::peak_path () const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2036,6 +2036,33 @@ Session::sound_dir (bool with_path) const
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
Session::midi_dir (bool with_path) const
|
||||||
|
{
|
||||||
|
string res;
|
||||||
|
string full;
|
||||||
|
|
||||||
|
if (with_path) {
|
||||||
|
res = _path;
|
||||||
|
} else {
|
||||||
|
full = _path;
|
||||||
|
}
|
||||||
|
|
||||||
|
res += interchange_dir_name;
|
||||||
|
res += '/';
|
||||||
|
res += legalize_for_path (_name);
|
||||||
|
res += '/';
|
||||||
|
res += midi_dir_name;
|
||||||
|
|
||||||
|
if (with_path) {
|
||||||
|
full = res;
|
||||||
|
} else {
|
||||||
|
full += res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
Session::peak_dir () const
|
Session::peak_dir () const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,8 @@
|
||||||
#include <ardour/session.h>
|
#include <ardour/session.h>
|
||||||
#include <ardour/midi_ring_buffer.h>
|
#include <ardour/midi_ring_buffer.h>
|
||||||
#include <ardour/midi_util.h>
|
#include <ardour/midi_util.h>
|
||||||
|
#include <ardour/tempo.h>
|
||||||
|
#include <ardour/audioengine.h>
|
||||||
|
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
|
||||||
|
|
@ -178,9 +180,9 @@ SMFSource::flush_header ()
|
||||||
|
|
||||||
assert(_fd);
|
assert(_fd);
|
||||||
|
|
||||||
const uint16_t type = GUINT16_TO_BE(0); // SMF Type 0 (single track)
|
const uint16_t type = GUINT16_TO_BE(0); // SMF Type 0 (single track)
|
||||||
const uint16_t ntracks = GUINT16_TO_BE(1); // Number of tracks (always 1 for Type 0)
|
const uint16_t ntracks = GUINT16_TO_BE(1); // Number of tracks (always 1 for Type 0)
|
||||||
const uint16_t division = GUINT16_TO_BE(1920); // FIXME FIXME FIXME PPQN
|
const uint16_t division = GUINT16_TO_BE(_ppqn); // Pulses per beat
|
||||||
|
|
||||||
char data[6];
|
char data[6];
|
||||||
memcpy(data, &type, 2);
|
memcpy(data, &type, 2);
|
||||||
|
|
@ -241,8 +243,8 @@ SMFSource::find_first_event_after(nframes_t start)
|
||||||
*
|
*
|
||||||
* File position MUST be at the beginning of a delta time, or this will die very messily.
|
* File position MUST be at the beginning of a delta time, or this will die very messily.
|
||||||
* ev.buffer must be of size ev.size, and large enough for the event. The returned event
|
* ev.buffer must be of size ev.size, and large enough for the event. The returned event
|
||||||
* will have it's time field set to it's delta time (so it's the caller's responsibility
|
* will have it's time field set to it's delta time, in SMF tempo-based ticks, using the
|
||||||
* to calculate a real time for the event).
|
* rate given by ppqn() (it is the caller's responsibility to calculate a real time).
|
||||||
*
|
*
|
||||||
* Returns event length (including status byte) on success, 0 if event was
|
* Returns event length (including status byte) on success, 0 if event was
|
||||||
* skipped (eg a meta event), or -1 on EOF (or end of track).
|
* skipped (eg a meta event), or -1 on EOF (or end of track).
|
||||||
|
|
@ -287,12 +289,14 @@ SMFSource::read_event(MidiEvent& ev) const
|
||||||
return ev.size;
|
return ev.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** All stamps in audio frames */
|
||||||
nframes_t
|
nframes_t
|
||||||
SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset) const
|
SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset) const
|
||||||
{
|
{
|
||||||
//cerr << "SMF - read " << start << ", count=" << cnt << ", offset=" << stamp_offset << endl;
|
//cerr << "SMF - read " << start << ", count=" << cnt << ", offset=" << stamp_offset << endl;
|
||||||
|
|
||||||
nframes_t time = 0;
|
// 64 bits ought to be enough for anybody
|
||||||
|
uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn
|
||||||
|
|
||||||
_read_data_count = 0;
|
_read_data_count = 0;
|
||||||
|
|
||||||
|
|
@ -307,6 +311,12 @@ SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, n
|
||||||
|
|
||||||
fseek(_fd, _header_size, 0);
|
fseek(_fd, _header_size, 0);
|
||||||
|
|
||||||
|
// FIXME: assumes tempo never changes after start
|
||||||
|
const double frames_per_beat = _session.tempo_map().tempo_at(_timeline_position).frames_per_beat(
|
||||||
|
_session.engine().frame_rate());
|
||||||
|
|
||||||
|
uint64_t start_ticks = (uint64_t)((start / frames_per_beat) * _ppqn);
|
||||||
|
|
||||||
while (!feof(_fd)) {
|
while (!feof(_fd)) {
|
||||||
int ret = read_event(ev);
|
int ret = read_event(ev);
|
||||||
if (ret == -1) { // EOF
|
if (ret == -1) { // EOF
|
||||||
|
|
@ -323,11 +333,12 @@ SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, n
|
||||||
time += ev.time; // accumulate delta time
|
time += ev.time; // accumulate delta time
|
||||||
ev.time = time; // set ev.time to actual time (relative to source start)
|
ev.time = time; // set ev.time to actual time (relative to source start)
|
||||||
|
|
||||||
if (ev.time >= start) {
|
if (ev.time >= start_ticks) {
|
||||||
if (ev.time > start + cnt) {
|
if (ev.time < start_ticks + (cnt / frames_per_beat)) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
ev.time += stamp_offset;
|
ev.time = (nframes_t)(((ev.time / (double)_ppqn) * frames_per_beat)) + stamp_offset;
|
||||||
|
// write event time in absolute frames
|
||||||
dst.write(ev.time, ev.size, ev.buffer);
|
dst.write(ev.time, ev.size, ev.buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -338,6 +349,7 @@ SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, n
|
||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** All stamps in audio frames */
|
||||||
nframes_t
|
nframes_t
|
||||||
SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
|
SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
|
||||||
{
|
{
|
||||||
|
|
@ -349,13 +361,16 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
|
||||||
|
|
||||||
fseek(_fd, 0, SEEK_END);
|
fseek(_fd, 0, SEEK_END);
|
||||||
|
|
||||||
// FIXME: start of source time?
|
// FIXME: assumes tempo never changes after start
|
||||||
|
const double frames_per_beat = _session.tempo_map().tempo_at(_timeline_position).frames_per_beat(
|
||||||
|
_session.engine().frame_rate());
|
||||||
|
|
||||||
for (size_t i=0; i < buf.size(); ++i) {
|
for (size_t i=0; i < buf.size(); ++i) {
|
||||||
MidiEvent& ev = buf[i];
|
MidiEvent& ev = buf[i];
|
||||||
assert(ev.time >= _timeline_position);
|
assert(ev.time >= _timeline_position);
|
||||||
ev.time -= _timeline_position;
|
ev.time -= _timeline_position;
|
||||||
uint32_t delta_time = ev.time - _last_ev_time;
|
assert(ev.time >= _last_ev_time);
|
||||||
|
const uint32_t delta_time = (uint32_t)(ev.time - _last_ev_time) / frames_per_beat * _ppqn;
|
||||||
|
|
||||||
/*printf("SMF - writing event, delta = %u, size = %zu, data = ",
|
/*printf("SMF - writing event, delta = %u, size = %zu, data = ",
|
||||||
delta_time, ev.size);
|
delta_time, ev.size);
|
||||||
|
|
@ -366,10 +381,11 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
|
||||||
*/
|
*/
|
||||||
size_t stamp_size = write_var_len(delta_time);
|
size_t stamp_size = write_var_len(delta_time);
|
||||||
fwrite(ev.buffer, 1, ev.size, _fd);
|
fwrite(ev.buffer, 1, ev.size, _fd);
|
||||||
_last_ev_time += delta_time;
|
|
||||||
_track_size += stamp_size + ev.size;
|
|
||||||
|
|
||||||
|
_track_size += stamp_size + ev.size;
|
||||||
_write_data_count += ev.size;
|
_write_data_count += ev.size;
|
||||||
|
|
||||||
|
_last_ev_time = ev.time;
|
||||||
}
|
}
|
||||||
|
|
||||||
fflush(_fd);
|
fflush(_fd);
|
||||||
|
|
@ -765,7 +781,7 @@ SMFSource::load_model(bool lock)
|
||||||
|
|
||||||
fseek(_fd, _header_size, 0);
|
fseek(_fd, _header_size, 0);
|
||||||
|
|
||||||
nframes_t time = 0;
|
double time = 0;
|
||||||
MidiEvent ev;
|
MidiEvent ev;
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue