/* the next two are duplicate items with different names for use in two different contexts */
- ActionManager::register_action (editor_actions, X_("addExistingAudioFiles"), _("Add Existing Media"), mem_fun (*this, &Editor::external_audio_dialog));
+ ActionManager::register_action (editor_actions, X_("addExistingAudioFiles"), _("Import Existing Media"), mem_fun (*this, &Editor::external_audio_dialog));
act = ActionManager::register_action (editor_actions, X_("addExternalAudioToRegionList"), _("Add External Media"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportAsRegion));
ActionManager::session_sensitive_actions.push_back (act);
}
}
- cout << "TARGET REGIONS: " << target_regions << endl;
+ // kludge (for MIDI we're abusing "channel" for "track" here)
+ if (paths.front().rfind(".mid") != Glib::ustring::npos)
+ target_regions = -1;
if (target_regions == 1) {
void
-MidiTimeAxisView::update_range() {
+MidiTimeAxisView::update_range()
+{
MidiGhostRegion* mgr;
for(list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
}
}
+void
+MidiTimeAxisView::show_existing_automation ()
+{
+ if (midi_track()) {
+ const set<Parameter> params = midi_track()->midi_diskstream()->
+ midi_playlist()->contained_automation();
+
+ for (set<Parameter>::const_iterator i = params.begin(); i != params.end(); ++i)
+ create_automation_child(*i, true);
+ }
+
+ RouteTimeAxisView::show_existing_automation ();
+}
+
/** Prompt for a controller with a dialog and add an automation track for it
*/
void
{
if (param.type() == MidiCCAutomation) {
- /* FIXME: don't create AutomationList for track itself */
+ /* FIXME: don't create AutomationList for track itself
+ * (not actually needed or used, since the automation is region-ey) */
boost::shared_ptr<AutomationControl> c = _route->control(param);
_route->add_control(c);
}
+ AutomationTracks::iterator existing = _automation_tracks.find(param);
+ if (existing != _automation_tracks.end())
+ return;
+
boost::shared_ptr<AutomationTimeAxisView> track(new AutomationTimeAxisView (_session,
_route, _route, c,
editor,
guint32 show_at (double y, int& nth, Gtk::VBox *parent);
void hide ();
+ void show_existing_automation ();
void add_controller_track ();
void create_automation_child (ARDOUR::Parameter param, bool show);
#include <ardour/ardour.h>
#include <ardour/playlist.h>
+#include <ardour/parameter.h>
namespace ARDOUR
{
void set_note_mode (NoteMode m) { _note_mode = m; }
+ std::set<Parameter> contained_automation();
+
protected:
/* playlist "callbacks" */
throw (std::logic_error, PrematureEOF, CorruptFile);
void close();
+
+ static uint32_t read_var_len(FILE* fd) throw (PrematureEOF);
protected:
/** size of SMF header, including MTrk chunk header */
static const uint32_t HEADER_SIZE = 22;
- uint32_t read_var_len() const throw(PrematureEOF);
-
std::string _filename;
FILE* _fd;
//TimeUnit _unit;
{
/* Only do the range lookup if x is in a different range than last time
* this was called (or if the search cache has been marked "dirty" (left<0) */
- if ((_search_cache.left < 0) ||
+ if (!_events.empty() && ((_search_cache.left < 0) ||
((_search_cache.left > start) ||
- (_search_cache.right < end))) {
+ (_search_cache.right < end)))) {
const ControlEvent start_point (start, 0);
const ControlEvent end_point (end, 0);
{
//cerr << "earliest_event(" << start << ", " << end << ", " << x << ", " << y << ", " << inclusive << endl;
- if (_events.size() < 2)
+ if (_events.size() == 0)
+ return false;
+ else if (_events.size() == 1)
return rt_safe_earliest_event_discrete_unlocked(start, end, x, y, inclusive);
// Hack to avoid infinitely repeating the same event
{
MidiEvent ev(0.0, 4, NULL, true);
- uint64_t t = 0;
- uint32_t delta_t = 0;
- uint32_t size = 0;
-
status.progress = 0.0f;
try {
boost::shared_ptr<SMFSource> smfs = boost::dynamic_pointer_cast<SMFSource>(newfiles[i-1]);
source->seek_to_track(i);
+
+ uint64_t t = 0;
+ uint32_t delta_t = 0;
+ uint32_t size = 0;
while (!status.cancel) {
//cerr << "Using cached iterator at " << _next_read << endl;
}
- if (_read_iter == end()) {
- //cerr << this << " MM::read: at end @ " << _read_iter->time() << endl;
- } else {
- //cerr << this << " MM::read: at " << _read_iter->time() << endl;
- }
-
_next_read = start + nframes;
while (_read_iter != end() && _read_iter->time() < start + nframes) {
return changed;
}
+set<Parameter>
+MidiPlaylist::contained_automation()
+{
+ /* this function is never called from a realtime thread, so
+ its OK to block (for short intervals).
+ */
+
+ Glib::Mutex::Lock rm (region_lock);
+
+ set<Parameter> ret;
+
+ for (RegionList::const_iterator r = regions.begin(); r != regions.end(); ++r) {
+ boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(*r);
+
+ for (Automatable::Controls::iterator c = mr->controls().begin();
+ c != mr->controls().end(); ++c) {
+ ret.insert(c->first);
+ }
+ }
+
+ return ret;
+}
+
+
bool
MidiPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
{
static uint8_t last_status = 0;
static uint32_t last_size = 0;
- *delta_time = read_var_len();
+ *delta_time = read_var_len(_fd);
int status = fgetc(_fd);
if (status == EOF)
throw PrematureEOF();
if (feof(_fd))
throw PrematureEOF();
uint8_t type = fgetc(_fd);
- const uint32_t size = read_var_len();
+ const uint32_t size = read_var_len(_fd);
/*cerr.flags(ios::hex);
cerr << "SMF - meta 0x" << (int)type << ", size = ";
cerr.flags(ios::dec);
uint32_t
-SMFReader::read_var_len() const throw(PrematureEOF)
+SMFReader::read_var_len(FILE* fd) throw (PrematureEOF)
{
- if (feof(_fd))
+ if (feof(fd))
throw PrematureEOF();
uint32_t value;
uint8_t c;
- if ( (value = getc(_fd)) & 0x80 ) {
+ if ( (value = getc(fd)) & 0x80 ) {
value &= 0x7F;
do {
- if (feof(_fd))
+ if (feof(fd))
throw PrematureEOF();
- value = (value << 7) + ((c = getc(_fd)) & 0x7F);
+ value = (value << 7) + ((c = getc(fd)) & 0x7F);
} while (c & 0x80);
}
#include <ardour/midi_util.h>
#include <ardour/tempo.h>
#include <ardour/audioengine.h>
+#include <ardour/smf_reader.h>
#include "i18n.h"
assert(size);
assert(buf);
- *delta_t = read_var_len();
- assert(!feof(_fd));
+ try {
+ *delta_t = SMFReader::read_var_len(_fd);
+ } catch (...) {
+ return -1; // Premature EOF
+ }
+
+ if (feof(_fd)) {
+ return -1; // Premature EOF
+ }
const int status = fgetc(_fd);
- assert(status != EOF); // FIXME die gracefully
+
+ if (status == EOF) {
+ return -1; // Premature EOF
+ }
//printf("Status @ %X = %X\n", (unsigned)ftell(_fd) - 1, status);
if (status == 0xFF) {
- assert(!feof(_fd));
+ if (feof(_fd)) {
+ return -1; // Premature EOF
+ }
const int type = fgetc(_fd);
if ((unsigned char)type == 0x2F) {
- //cerr << _name << " hit EOT" << endl;
- return -1;
+ return -1; // hit end of track
} else {
*size = 0;
return 0;
void
SMFSource::append_event_unlocked(const MidiEvent& ev)
{
- printf("%s - append chan = %u, time = %lf, size = %u, data = ", _path.c_str(),
+ /*printf("%s - append chan = %u, time = %lf, size = %u, data = ", _path.c_str(),
(unsigned)ev.channel(), ev.time(), ev.size());
for (size_t i=0; i < ev.size(); ++i) {
printf("%X ", ev.buffer()[i]);
}
- printf("\n");
+ printf("\n");*/
assert(ev.time() >= 0);
assert(ev.time() >= _last_ev_time);
return ret;
}
-uint32_t
-SMFSource::read_var_len() const
-{
- assert(!feof(_fd));
-
- uint32_t value;
- unsigned char c;
-
- if ( (value = getc(_fd)) & 0x80 ) {
- value &= 0x7F;
- do {
- assert(!feof(_fd));
- value = (value << 7) + ((c = getc(_fd)) & 0x7F);
- } while (c & 0x80);
- }
-
- return value;
-}
-
void
SMFSource::load_model(bool lock, bool force_reload)
{