/*
- Copyright (C) 1999-2004 Paul Davis
+ Copyright (C) 1999-2004 Paul Davis
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
#include "ardour/timestamps.h"
#include "pbd/error.h"
-#include <glibmm/thread.h>
+#include "pbd/enumwriter.h"
#include "ardour/ardour.h"
-#include "ardour/session.h"
#include "ardour/audio_diskstream.h"
+#include "ardour/butler.h"
+#include "ardour/debug.h"
+#include "ardour/session_event.h"
#include "i18n.h"
using namespace ARDOUR;
using namespace PBD;
-MultiAllocSingleReleasePool Session::Event::pool ("event", sizeof (Session::Event), 512);
-
-static const char* event_names[] = {
- "SetTransportSpeed",
- "SetDiskstreamSpeed",
- "Locate",
- "LocateRoll",
- "LocateRollLocate",
- "SetLoop",
- "PunchIn",
- "PunchOut",
- "RangeStop",
- "RangeLocate",
- "Overwrite",
- "SetSlaveSource",
- "Audition",
- "InputConfigurationChange",
- "SetAudioRange",
- "SetMusicRange",
- "SetPlayRange",
- "StopOnce",
- "AutoLoop"
-};
+PerThreadPool* SessionEvent::pool;
void
-Session::add_event (nframes_t frame, Event::Type type, nframes_t target_frame)
+SessionEvent::init_event_pool ()
{
- Event* ev = new Event (type, Event::Add, frame, target_frame, 0);
+ pool = new PerThreadPool;
+}
+
+void
+SessionEvent::create_per_thread_pool (const std::string& name, uint32_t nitems)
+{
+ /* this is a per-thread call that simply creates a thread-private ptr to
+ a CrossThreadPool for use by this thread whenever events are allocated/released
+ from SessionEvent::pool()
+ */
+ pool->create_per_thread_pool (name, sizeof (SessionEvent), nitems);
+}
+
+void *
+SessionEvent::operator new (size_t)
+{
+ CrossThreadPool* p = pool->per_thread_pool ();
+ SessionEvent* ev = static_cast<SessionEvent*> (p->alloc ());
+ ev->own_pool = p;
+ return ev;
+}
+
+void
+SessionEvent::operator delete (void *ptr, size_t /*size*/)
+{
+ Pool* p = pool->per_thread_pool ();
+ SessionEvent* ev = static_cast<SessionEvent*> (ptr);
+
+ if (p == ev->own_pool) {
+ p->release (ptr);
+ } else {
+ ev->own_pool->push (ev);
+ }
+}
+
+void
+SessionEventManager::add_event (framepos_t frame, SessionEvent::Type type, framepos_t target_frame)
+{
+ SessionEvent* ev = new SessionEvent (type, SessionEvent::Add, frame, target_frame, 0);
queue_event (ev);
}
void
-Session::remove_event (nframes_t frame, Event::Type type)
+SessionEventManager::remove_event (framepos_t frame, SessionEvent::Type type)
{
- Event* ev = new Event (type, Event::Remove, frame, 0, 0);
+ SessionEvent* ev = new SessionEvent (type, SessionEvent::Remove, frame, 0, 0);
queue_event (ev);
}
void
-Session::replace_event (Event::Type type, nframes_t frame, nframes_t target)
+SessionEventManager::replace_event (SessionEvent::Type type, framepos_t frame, framepos_t target)
{
- Event* ev = new Event (type, Event::Replace, frame, target, 0);
+ SessionEvent* ev = new SessionEvent (type, SessionEvent::Replace, frame, target, 0);
queue_event (ev);
}
void
-Session::clear_events (Event::Type type)
+SessionEventManager::clear_events (SessionEvent::Type type)
{
- Event* ev = new Event (type, Event::Clear, 0, 0, 0);
+ SessionEvent* ev = new SessionEvent (type, SessionEvent::Clear, 0, 0, 0);
queue_event (ev);
}
void
-Session::dump_events () const
+SessionEventManager::dump_events () const
{
cerr << "EVENT DUMP" << endl;
for (Events::const_iterator i = events.begin(); i != events.end(); ++i) {
if ((Events::const_iterator) next_event == events.end()) {
cerr << "none" << endl;
} else {
- cerr << "at " << (*next_event)->action_frame << ' '
- << (*next_event)->type << " target = "
+ cerr << "at " << (*next_event)->action_frame << ' '
+ << (*next_event)->type << " target = "
<< (*next_event)->target_frame << endl;
}
cerr << "Immediate events pending:\n";
}
void
-Session::queue_event (Event* ev)
-{
- if (_state_of_the_state & Loading) {
- merge_event (ev);
- } else {
- pending_events.write (&ev, 1);
- }
-}
-
-void
-Session::merge_event (Event* ev)
+SessionEventManager::merge_event (SessionEvent* ev)
{
switch (ev->action) {
- case Event::Remove:
+ case SessionEvent::Remove:
_remove_event (ev);
delete ev;
return;
- case Event::Replace:
+ case SessionEvent::Replace:
_replace_event (ev);
return;
- case Event::Clear:
+ case SessionEvent::Clear:
_clear_event_type (ev->type);
delete ev;
return;
-
- case Event::Add:
+
+ case SessionEvent::Add:
break;
}
process_event (ev);
return;
}
-
+
switch (ev->type) {
- case Event::AutoLoop:
- case Event::StopOnce:
+ case SessionEvent::AutoLoop:
+ case SessionEvent::StopOnce:
_clear_event_type (ev->type);
break;
default:
for (Events::iterator i = events.begin(); i != events.end(); ++i) {
if ((*i)->type == ev->type && (*i)->action_frame == ev->action_frame) {
- error << string_compose(_("Session: cannot have two events of type %1 at the same frame (%2)."),
- event_names[ev->type], ev->action_frame) << endmsg;
+ error << string_compose(_("Session: cannot have two events of type %1 at the same frame (%2)."),
+ enum_2_string (ev->type), ev->action_frame) << endmsg;
return;
}
}
}
events.insert (events.begin(), ev);
- events.sort (Event::compare);
+ events.sort (SessionEvent::compare);
next_event = events.begin();
set_next_event ();
}
/** @return true when @a ev is deleted. */
bool
-Session::_replace_event (Event* ev)
+SessionEventManager::_replace_event (SessionEvent* ev)
{
bool ret = false;
Events::iterator i;
events.insert (events.begin(), ev);
}
- events.sort (Event::compare);
+ events.sort (SessionEvent::compare);
next_event = events.end();
set_next_event ();
/** @return true when @a ev is deleted. */
bool
-Session::_remove_event (Session::Event* ev)
+SessionEventManager::_remove_event (SessionEvent* ev)
{
bool ret = false;
Events::iterator i;
-
+
for (i = events.begin(); i != events.end(); ++i) {
if ((*i)->type == ev->type && (*i)->action_frame == ev->action_frame) {
if ((*i) == ev) {
}
void
-Session::_clear_event_type (Event::Type type)
+SessionEventManager::_clear_event_type (SessionEvent::Type type)
{
Events::iterator i, tmp;
-
+
for (i = events.begin(); i != events.end(); ) {
tmp = i;
set_next_event ();
}
-void
-Session::set_next_event ()
-{
- if (events.empty()) {
- next_event = events.end();
- return;
- }
-
- if (next_event == events.end()) {
- next_event = events.begin();
- }
-
- if ((*next_event)->action_frame > _transport_frame) {
- next_event = events.begin();
- }
-
- for (; next_event != events.end(); ++next_event) {
- if ((*next_event)->action_frame >= _transport_frame) {
- break;
- }
- }
-}
-
-void
-Session::process_event (Event* ev)
-{
- bool remove = true;
- bool del = true;
-
- /* if we're in the middle of a state change (i.e. waiting
- for the butler thread to complete the non-realtime
- part of the change), we'll just have to queue this
- event for a time when the change is complete.
- */
-
- if (non_realtime_work_pending()) {
-
- /* except locates, which we have the capability to handle */
-
- if (ev->type != Event::Locate) {
- immediate_events.insert (immediate_events.end(), ev);
- _remove_event (ev);
- return;
- }
- }
-
- //printf("Processing event: %s\n", event_names[ev->type]);
-
- switch (ev->type) {
- case Event::SetLoop:
- set_play_loop (ev->yes_or_no);
- break;
-
- case Event::AutoLoop:
- if (play_loop) {
- start_locate (ev->target_frame, true, false, Config->get_seamless_loop());
- }
- remove = false;
- del = false;
- break;
-
- case Event::Locate:
- if (ev->yes_or_no) {
- // cerr << "forced locate to " << ev->target_frame << endl;
- locate (ev->target_frame, false, true, false);
- } else {
- // cerr << "soft locate to " << ev->target_frame << endl;
- start_locate (ev->target_frame, false, true, false);
- }
- _send_smpte_update = true;
- break;
-
- case Event::LocateRoll:
- if (ev->yes_or_no) {
- // cerr << "forced locate to+roll " << ev->target_frame << endl;
- locate (ev->target_frame, true, true, false);
- } else {
- // cerr << "soft locate to+roll " << ev->target_frame << endl;
- start_locate (ev->target_frame, true, true, false);
- }
- _send_smpte_update = true;
- break;
-
- case Event::LocateRollLocate:
- // locate is handled by ::request_roll_at_and_return()
- _requested_return_frame = ev->target_frame;
- request_locate (ev->target2_frame, true);
- break;
-
-
- case Event::SetTransportSpeed:
- set_transport_speed (ev->speed, ev->yes_or_no);
- break;
-
- case Event::PunchIn:
- // cerr << "PunchIN at " << transport_frame() << endl;
- if (Config->get_punch_in() && record_status() == Enabled) {
- enable_record ();
- }
- remove = false;
- del = false;
- break;
-
- case Event::PunchOut:
- // cerr << "PunchOUT at " << transport_frame() << endl;
- if (Config->get_punch_out()) {
- step_back_from_record ();
- }
- remove = false;
- del = false;
- break;
-
- case Event::StopOnce:
- if (!non_realtime_work_pending()) {
- stop_transport (ev->yes_or_no);
- _clear_event_type (Event::StopOnce);
- }
- remove = false;
- del = false;
- break;
-
- case Event::RangeStop:
- if (!non_realtime_work_pending()) {
- stop_transport (ev->yes_or_no);
- }
- remove = false;
- del = false;
- break;
-
- case Event::RangeLocate:
- start_locate (ev->target_frame, true, true, false);
- remove = false;
- del = false;
- break;
-
- case Event::Overwrite:
- overwrite_some_buffers (static_cast<Diskstream*>(ev->ptr));
- break;
-
- case Event::SetDiskstreamSpeed:
- set_diskstream_speed (static_cast<Diskstream*> (ev->ptr), ev->speed);
- break;
-
- case Event::SetSlaveSource:
- set_slave_source (ev->slave);
- break;
-
- case Event::Audition:
- set_audition (ev->region);
- // drop reference to region
- ev->region.reset ();
- break;
-
- case Event::InputConfigurationChange:
- post_transport_work = PostTransportWork (post_transport_work | PostTransportInputChange);
- schedule_butler_transport_work ();
- break;
-
- case Event::SetAudioRange:
- current_audio_range = ev->audio_range;
- setup_auto_play ();
- break;
-
- case Event::SetPlayRange:
- set_play_range (ev->yes_or_no);
- break;
-
- default:
- fatal << string_compose(_("Programming error: illegal event type in process_event (%1)"), ev->type) << endmsg;
- /*NOTREACHED*/
- break;
- };
-
- if (remove) {
- del = del && !_remove_event (ev);
- }
-
- if (del) {
- delete ev;
- }
-}