summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2007-10-16 21:01:12 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2007-10-16 21:01:12 +0000
commitf3cf31009a3b52fa126356b6f826958393c6a956 (patch)
treefa5e9af4e1537acfa11dfd3b4f29b0c7463c5ad1
parent14dcc3f0170f8c723bcef0a59562adce0e8e7596 (diff)
virtualize Port object; clean up automation tracks from track deletion
git-svn-id: svn://localhost/ardour2/trunk@2556 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--SConstruct9
-rw-r--r--gtk2_ardour/ardour-sae.menus320
-rw-r--r--gtk2_ardour/main.cc1
-rw-r--r--gtk2_ardour/mixer_ui.cc2
-rw-r--r--gtk2_ardour/route_time_axis.cc6
-rw-r--r--libs/ardour/SConscript81
-rw-r--r--libs/ardour/ardour/audio_port.h35
-rw-r--r--libs/ardour/ardour/audioengine.h4
-rw-r--r--libs/ardour/ardour/jack_audio_port.h49
-rw-r--r--libs/ardour/ardour/jack_midi_port.h53
-rw-r--r--libs/ardour/ardour/midi_port.h12
-rw-r--r--libs/ardour/ardour/port.h110
-rw-r--r--libs/ardour/audio_port.cc11
-rw-r--r--libs/ardour/audioengine.cc171
-rw-r--r--libs/ardour/io.cc2
-rw-r--r--libs/ardour/jack_audio_port.cc41
-rw-r--r--libs/ardour/jack_midi_port.cc94
-rw-r--r--libs/ardour/jack_port.cc111
-rw-r--r--libs/ardour/midi_port.cc77
-rw-r--r--libs/ardour/port.cc30
-rw-r--r--libs/ardour/session.cc10
-rw-r--r--libs/pbd/SConscript2
-rw-r--r--libs/pbd/boost-debug/shared_ptr.hpp491
-rw-r--r--libs/pbd/pbd/stacktrace.h87
-rw-r--r--libs/pbd/stacktrace.cc5
25 files changed, 1428 insertions, 386 deletions
diff --git a/SConstruct b/SConstruct
index 5f6bde5103..25cd217222 100644
--- a/SConstruct
+++ b/SConstruct
@@ -722,6 +722,15 @@ def prep_libcheck(topenv, libinfo):
prep_libcheck(env, env)
#
+# glibc backtrace API, needed everywhere if we want to do shared_ptr<T> debugging
+#
+
+conf = Configure (env)
+if conf.CheckCHeader('execinfo.h'):
+ conf.env.Append(CXXFLAGS="-DHAVE_EXECINFO")
+env = conf.Finish ()
+
+#
# Check for libusb
libraries['usb'] = LibraryInfo ()
diff --git a/gtk2_ardour/ardour-sae.menus b/gtk2_ardour/ardour-sae.menus
new file mode 100644
index 0000000000..511ce3aa0d
--- /dev/null
+++ b/gtk2_ardour/ardour-sae.menus
@@ -0,0 +1,320 @@
+<ui>
+
+ <menubar name='Main' action='MainMenu'>
+ <menu name='Session' action='Session'>
+ <menuitem action='New'/>
+ <menuitem action='Open'/>
+ <menuitem action='Recent'/>
+ <menuitem action='Close'/>
+ <separator/>
+ <menuitem action='Save'/>
+ <menuitem action='Snapshot'/>
+ <menuitem action='SaveTemplate'/>
+ <separator/>
+ <menuitem action='AddTrackBus'/>
+ <separator/>
+ <menu name='Cleanup' action='Cleanup'>
+ <menuitem action='CleanupUnused'/>
+ <menuitem action='FlushWastebasket'/>
+ </menu>
+ </menu>
+ <menu name='Files' action='Files'>
+ <menuitem action='addExistingAudioFiles'/>
+ <separator/>
+ <menuitem action='ExportSession'/>
+ <menuitem action='ExportSelection'/>
+ <menuitem action='ExportRangeMarkers'/>
+ </menu>
+ <menu name='Transport' action='Transport'>
+ <menuitem action='ToggleRoll'/>
+ <menuitem action='ToggleRollForgetCapture'/>
+ <menuitem action='Loop'/>
+ <menuitem action='PlaySelection'/>
+ <menuitem action='set-playhead'/>
+ <menuitem action='Forward'/>
+ <menuitem action='Rewind'/>
+ <menuitem action='GotoZero'/>
+ <menuitem action='GotoStart'/>
+ <menuitem action='GotoEnd'/>
+ <separator/>
+ <menuitem action='Record'/>
+ <separator/>
+ <menuitem action='TransitionToRoll'/>
+ <menuitem action='TransitionToReverse'/>
+ <separator/>
+ <menuitem action='jump-forward-to-mark'/>
+ <menuitem action='jump-backward-to-mark'/>
+ <menuitem action='add-location-from-playhead'/>
+ <separator/>
+ <menuitem action='playhead-to-next-region-start'/>
+ <menuitem action='playhead-to-next-region-end'/>
+ <menuitem action='playhead-to-previous-region-start'/>
+ <menuitem action='playhead-to-previous-region-end'/>
+ <menuitem action='playhead-to-next-region-sync'/>
+ <menuitem action='playhead-to-previous-region-sync'/>
+ <menuitem action='center-playhead'/>
+ <menuitem action='playhead-to-edit'/>
+ <separator/>
+ <menuitem action='playhead-to-range-start'/>
+ <menuitem action='playhead-to-range-end'/>
+ <menu action='TransportOptions'>
+ <menuitem action='ToggleTimeMaster'/>
+ <menuitem action='TogglePunchIn'/>
+ <menuitem action='TogglePunchOut'/>
+ <menuitem action='ToggleAutoInput'/>
+ <menuitem action='ToggleAutoPlay'/>
+ <menuitem action='ToggleAutoReturn'/>
+ <menuitem action='ToggleClick'/>
+ <menuitem action='toggle-follow-playhead'/>
+ <menuitem action='ToggleVideoSync'/>
+ </menu>
+ </menu>
+ <menu name='Edit' action='Edit'>
+ <menuitem action='undo'/>
+ <menuitem action='redo'/>
+ <menuitem action='editor-cut'/>
+ <menuitem action='editor-delete'/>
+ <menuitem action='editor-copy'/>
+ <menuitem action='editor-paste'/>
+ <menuitem action='set-edit-cursor'/>
+ <menuitem action='remove-last-capture'/>
+ <separator/>
+ <menu action="EditSelectRangeOptions">
+ <menuitem action='extend-range-to-start-of-region'/>
+ <menuitem action='extend-range-to-end-of-region'/>
+ <menuitem action='start-range'/>
+ <menuitem action='finish-range'/>
+ <menuitem action='finish-add-range'/>
+ </menu>
+ <menu action="EditSelectRegionOptions">
+ <menuitem action='select-all'/>
+ <menuitem action='select-all-after-edit-cursor'/>
+ <menuitem action='select-all-before-edit-cursor'/>
+ <menuitem action='select-all-after-playhead'/>
+ <menuitem action='select-all-before-playhead'/>
+ <menuitem action='select-all-between-cursors'/>
+ <menuitem action='select-all-in-punch-range'/>
+ <menuitem action='select-all-in-loop-range'/>
+ </menu>
+ <menu action='EditCursorMovementOptions'>
+ <menuitem action='edit-cursor-to-next-region-start'/>
+ <menuitem action='edit-cursor-to-next-region-end'/>
+ <menuitem action='edit-cursor-to-previous-region-start'/>
+ <menuitem action='edit-cursor-to-previous-region-end'/>
+ <menuitem action='edit-cursor-to-next-region-sync'/>
+ <menuitem action='edit-cursor-to-previous-region-sync'/>
+ <menuitem action='center-edit-cursor'/>
+ <menuitem action='edit-to-playhead'/>
+ <menuitem action='edit-cursor-to-range-start'/>
+ <menuitem action='edit-cursor-to-range-end'/>
+ </menu>
+ <menu name='KeyMouse Actions' action='KeyMouse Actions'>
+ <menuitem action='audition-at-mouse'/>
+ <menuitem action='brush-at-mouse'/>
+ <menuitem action='mute-unmute-region'/>
+ <separator/>
+ <menuitem action='set-mouse-mode-object'/>
+ <menuitem action='set-mouse-mode-range'/>
+ <menuitem action='set-mouse-mode-gain'/>
+ <menuitem action='set-mouse-mode-zoom'/>
+ <menuitem action='set-mouse-mode-timefx'/>
+ </menu>
+ <separator/>
+ <menuitem action='ToggleOptionsEditor'/>
+ </menu>
+ <menu name='Regions' action='Regions'>
+ <menuitem action='crop'/>
+ <menuitem action='duplicate-region'/>
+ <menuitem action='insert-region'/>
+ <menuitem action='normalize-region'/>
+ <separator/>
+ <menuitem action="nudge-forward"/>
+ <menuitem action="nudge-next-forward"/>
+ <menuitem action="nudge-backward"/>
+ <menuitem action="nudge-next-backward"/>
+ <menuitem action='split-region'/>
+ <menuitem action='set-region-sync-position'/>
+ </menu>
+ <menu name='View' action = 'View'>
+ <menu name='ZoomFocus' action='ZoomFocus'>
+ <menuitem action='zoom-focus-left'/>
+ <menuitem action='zoom-focus-right'/>
+ <menuitem action='zoom-focus-center'/>
+ <menuitem action='zoom-focus-playhead'/>
+ <menuitem action='zoom-focus-edit'/>
+ </menu>
+ <menu name='SnapMode' action='SnapMode'>
+ <menuitem action='snap-normal'/>
+ <menuitem action='snap-magnetic'/>
+ </menu>
+ <menu name='SnapTo' action='SnapTo'>
+ <menuitem action='snap-to-frame'/>
+ <menuitem action='snap-to-cd-frame'/>
+ <menuitem action='snap-to-smpte-frame'/>
+ <menuitem action='snap-to-smpte-seconds'/>
+ <menuitem action='snap-to-smpte-minutes'/>
+ <menuitem action='snap-to-seconds'/>
+ <menuitem action='snap-to-minutes'/>
+ <menuitem action='snap-to-thirtyseconds'/>
+ <menuitem action='snap-to-asixteenthbeat'/>
+ <menuitem action='snap-to-eighths'/>
+ <menuitem action='snap-to-quarters'/>
+ <menuitem action='snap-to-thirds'/>
+ <menuitem action='snap-to-beat'/>
+ <menuitem action='snap-to-bar'/>
+ <menuitem action='snap-to-mark'/>
+ <menuitem action='snap-to-edit-cursor'/>
+ <menuitem action='snap-to-region-start'/>
+ <menuitem action='snap-to-region-end'/>
+ <menuitem action='snap-to-region-sync'/>
+ <menuitem action='snap-to-region-boundary'/>
+ </menu>
+ <separator/>
+
+ <menuitem action='temporal-zoom-in'/>
+ <menuitem action='temporal-zoom-out'/>
+ <menuitem action='zoom-to-session'/>
+ <menuitem action='scroll-tracks-down'/>
+ <menuitem action='scroll-tracks-up'/>
+ <menuitem action='scroll-tracks-down'/>
+ <menuitem action='step-tracks-up'/>
+ <menuitem action='step-tracks-down'/>
+ <separator/>
+ <menuitem action='scroll-forward'/>
+ <menuitem action='scroll-backward'/>
+ <separator/>
+ <menuitem action='scroll-playhead-forward'/>
+ <menuitem action='scroll-playhead-backward'/>
+ <separator/>
+ <menuitem action='show-editor-mixer'/>
+ <menuitem action='SyncEditorAndMixerTrackOrder'/>
+ <menuitem action='ToggleLogoVisibility'/>
+ </menu>
+ <menu name='JACK' action='JACK'>
+ <menuitem action='JACKDisconnect'/>
+ <menuitem action='JACKReconnect'/>
+ <menu name='Latency' action='Latency'>
+ <menuitem action='JACKLatency32'/>
+ <menuitem action='JACKLatency64'/>
+ <menuitem action='JACKLatency128'/>
+ <menuitem action='JACKLatency256'/>
+ <menuitem action='JACKLatency512'/>
+ <menuitem action='JACKLatency1024'/>
+ <menuitem action='JACKLatency2048'/>
+ <menuitem action='JACKLatency4096'/>
+ <menuitem action='JACKLatency8192'/>
+ </menu>
+ </menu>
+ <menu name='Windows' action = 'Windows'>
+ <menuitem action='ToggleMaximalEditor'/>
+ <separator/>
+ <menuitem action='goto-editor'/>
+ <menuitem action='goto-mixer'/>
+ <menuitem action='ToggleInspector'/>
+ <menuitem action='ToggleLocations'/>
+ <menuitem action='ToggleThemeManager'/>
+ <menuitem action='ToggleBigClock'/>
+ <separator/>
+ </menu>
+ <menu name='Options' action='Options'>
+ <menu action='AudioFileFormat'>
+ <menu action='AudioFileFormatData'>
+ <menuitem action='FileDataFormatFloat'/>
+ <menuitem action='FileDataFormat24bit'/>
+ <menuitem action='FileDataFormat16bit'/>
+ </menu>
+ <menu action='AudioFileFormatHeader'>
+ <menuitem action='FileHeaderFormatBWF'/>
+ <menuitem action='FileHeaderFormatWAVE'/>
+ <menuitem action='FileHeaderFormatWAVE64'/>
+ <menuitem action='FileHeaderFormatCAF'/>
+ </menu>
+ </menu>
+ <menu action='Monitoring'>
+ <menuitem action='UseHardwareMonitoring'/>
+ <menuitem action='UseSoftwareMonitoring'/>
+ <menuitem action='UseExternalMonitoring'/>
+ </menu>
+ <menu action='Metering'>
+ <menu action='MeteringFallOffRate'>
+ <menuitem action='MeterFalloffOff'/>
+ <menuitem action='MeterFalloffSlowest'/>
+ <menuitem action='MeterFalloffSlow'/>
+ <menuitem action='MeterFalloffMedium'/>
+ <menuitem action='MeterFalloffFast'/>
+ <menuitem action='MeterFalloffFaster'/>
+ <menuitem action='MeterFalloffFastest'/>
+ </menu>
+ <menu action='MeteringHoldTime'>
+ <menuitem action='MeterHoldOff'/>
+ <menuitem action='MeterHoldShort'/>
+ <menuitem action='MeterHoldMedium'/>
+ <menuitem action='MeterHoldLong'/>
+ </menu>
+ </menu>
+ <menu action='Solo'>
+ <menuitem action='LatchedSolo'/>
+ </menu>
+ </menu>
+ <menu name='Help' action='Help'>
+ <menuitem action='About'/>
+ </menu>
+ </menubar>
+
+ <popup name='redirectmenu'>
+ <menuitem action='newplugin'/>
+ <menuitem action='newinsert'/>
+ <menuitem action='newsend'/>
+ <separator/>
+ <menuitem action='clear'/>
+ <separator/>
+ <menuitem action='cut'/>
+ <menuitem action='copy'/>
+ <menuitem action='paste'/>
+ <menuitem action='delete'/>
+ <separator/>
+ <menuitem action='rename'/>
+ <separator/>
+ <menuitem action='selectall'/>
+ <menuitem action='deselectall'/>
+ <separator/>
+ <menuitem action='activate'/>
+ <menuitem action='deactivate'/>
+ <separator/>
+ <menuitem action='activate_all'/>
+ <menuitem action='deactivate_all'/>
+ <separator/>
+ <menuitem action='edit'/>
+ </popup>
+
+ <popup name='ShuttleUnitPopup'>
+ <menuitem action='SetShuttleUnitsPercentage'/>
+ <menuitem action='SetShuttleUnitsSemitones'/>
+ </popup>
+
+ <popup name='RegionListMenu'>
+ <menuitem action='rlAudition'/>
+ <menuitem action='rlHide'/>
+ <menuitem action='rlRemove'/>
+ <separator/>
+ <menuitem action='rlShowAll'/>
+ <menuitem action='rlShowAuto'/>
+ <menu name='Sort' action='RegionListSort'>
+ <menuitem action='SortAscending'/>
+ <menuitem action='SortDescending'/>
+ <separator/>
+ <menuitem action='SortByRegionName'/>
+ <menuitem action='SortByRegionLength'/>
+ <menuitem action='SortByRegionPosition'/>
+ <menuitem action='SortByRegionTimestamp'/>
+ <menuitem action='SortByRegionStartinFile'/>
+ <menuitem action='SortByRegionEndinFile'/>
+ <menuitem action='SortBySourceFileName'/>
+ <menuitem action='SortBySourceFileLength'/>
+ <menuitem action='SortBySourceFileCreationDate'/>
+ <menuitem action='SortBySourceFilesystem'/>
+ </menu>
+ <separator/>
+ <menuitem action='addExternalAudioToRegionList'/>
+ </popup>
+</ui>
diff --git a/gtk2_ardour/main.cc b/gtk2_ardour/main.cc
index 5203346d57..32e14420ff 100644
--- a/gtk2_ardour/main.cc
+++ b/gtk2_ardour/main.cc
@@ -324,3 +324,4 @@ int main (int argc, char *argv[])
#ifdef VST_SUPPORT
} // end of extern C block
#endif
+
diff --git a/gtk2_ardour/mixer_ui.cc b/gtk2_ardour/mixer_ui.cc
index e3f6cae6ac..d37ab40a3c 100644
--- a/gtk2_ardour/mixer_ui.cc
+++ b/gtk2_ardour/mixer_ui.cc
@@ -340,7 +340,7 @@ void
Mixer_UI::remove_strip (MixerStrip* strip)
{
ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::remove_strip), strip));
-
+
TreeModel::Children rows = track_model->children();
TreeModel::Children::iterator ri;
list<MixerStrip *>::iterator i;
diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc
index d2e316f626..b5f04f537b 100644
--- a/gtk2_ardour/route_time_axis.cc
+++ b/gtk2_ardour/route_time_axis.cc
@@ -223,6 +223,12 @@ RouteTimeAxisView::~RouteTimeAxisView ()
delete _view;
_view = 0;
}
+
+ for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
+ delete i->second;
+ }
+
+ _automation_tracks.clear ();
}
void
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript
index 465138d90d..556c6c3c9b 100644
--- a/libs/ardour/SConscript
+++ b/libs/ardour/SConscript
@@ -27,47 +27,26 @@ ardour.Append(POTFILE = domain + '.pot')
ardour.Append(CPPPATH = '#libs/surfaces/control_protocol')
ardour_files=Split("""
-bundle.cc
-chan_count.cc
-diskstream.cc
-directory_names.cc
-filename_extensions.cc
-filesystem_paths.cc
-find_session.cc
-tape_file_matcher.cc
-template_utils.cc
-track.cc
+amp.cc
+audio_buffer.cc
audio_diskstream.cc
audio_library.cc
audio_playlist.cc
+audio_port.cc
audio_track.cc
audioengine.cc
-port.cc
-audio_port.cc
-midi_port.cc
-port_set.cc
-buffer.cc
-audio_buffer.cc
-midi_buffer.cc
-buffer_set.cc
-meter.cc
-amp.cc
-panner.cc
-filter.cc
audiofilesource.cc
audioregion.cc
audiosource.cc
-midi_source.cc
-midi_diskstream.cc
-midi_playlist.cc
-midi_track.cc
-midi_region.cc
-midi_model.cc
-note.cc
-smf_source.cc
auditioner.cc
+automatable.cc
automation.cc
+automation_control.cc
automation_event.cc
+buffer.cc
+buffer_set.cc
+bundle.cc
+chan_count.cc
configuration.cc
control_protocol_manager.cc
control_protocol_search_path.cc
@@ -75,34 +54,55 @@ crossfade.cc
curve.cc
cycle_timer.cc
default_click.cc
+directory_names.cc
+diskstream.cc
enums.cc
+filename_extensions.cc
+filesystem_paths.cc
+filter.cc
+find_session.cc
gain.cc
gdither.cc
globals.cc
import.cc
-automatable.cc
-automation_control.cc
-processor.cc
-io_processor.cc
-plugin_insert.cc
-port_insert.cc
io.cc
+io_processor.cc
+jack_port.cc
+jack_audio_port.cc
+jack_midi_port.cc
jack_slave.cc
ladspa_plugin.cc
location.cc
+meter.cc
+midi_buffer.cc
+midi_diskstream.cc
+midi_model.cc
+midi_playlist.cc
+midi_port.cc
+midi_region.cc
+midi_source.cc
+midi_track.cc
+mix.cc
mtc_slave.cc
named_selection.cc
+note.cc
+panner.cc
pcm_utils.cc
playlist.cc
playlist_factory.cc
plugin.cc
+plugin_insert.cc
plugin_manager.cc
+port.cc
+port_insert.cc
+port_set.cc
+processor.cc
+quantize.cc
recent_sessions.cc
region.cc
region_factory.cc
-reverse.cc
resampled_source.cc
-quantize.cc
+reverse.cc
route.cc
route_group.cc
send.cc
@@ -122,14 +122,17 @@ session_timefx.cc
session_transport.cc
session_utils.cc
silentfilesource.cc
+smf_source.cc
sndfile_helpers.cc
sndfilesource.cc
source.cc
source_factory.cc
+tape_file_matcher.cc
+template_utils.cc
tempo.cc
+track.cc
utils.cc
version.cc
-mix.cc
""")
arch_specific_objects = [ ]
diff --git a/libs/ardour/ardour/audio_port.h b/libs/ardour/ardour/audio_port.h
index d480eaf193..c6df9e0a2f 100644
--- a/libs/ardour/ardour/audio_port.h
+++ b/libs/ardour/ardour/audio_port.h
@@ -24,7 +24,6 @@
#include <sigc++/signal.h>
#include <pbd/failed_constructor.h>
#include <ardour/ardour.h>
-#include <jack/jack.h>
#include <ardour/port.h>
#include <ardour/audio_buffer.h>
@@ -32,19 +31,9 @@ namespace ARDOUR {
class AudioEngine;
-class AudioPort : public Port {
+class AudioPort : public virtual Port {
public:
- virtual ~AudioPort() {
- free (_port);
- }
-
- void cycle_start(nframes_t nframes) {
- _buffer.set_data ((Sample*) jack_port_get_buffer (_port, nframes), nframes);
- }
-
- void cycle_end() {}
-
- DataType type() const { return DataType(DataType::AUDIO); }
+ DataType type() const { return DataType::AUDIO; }
Buffer& get_buffer () {
return _buffer;
@@ -69,8 +58,8 @@ class AudioPort : public Port {
reset_overs ();
}
- float peak_db() const { return _peak_db; }
- jack_default_audio_sample_t peak() const { return _peak; }
+ float peak_db() const { return _peak_db; }
+ Sample peak() const { return _peak; }
uint32_t short_overs () const { return _short_overs; }
uint32_t long_overs () const { return _long_overs; }
@@ -81,21 +70,21 @@ class AudioPort : public Port {
protected:
friend class AudioEngine;
- AudioPort (jack_port_t *port);
+ AudioPort ();
void reset ();
/* engine isn't supposed to access below here */
AudioBuffer _buffer;
- nframes_t _overlen;
- jack_default_audio_sample_t _peak;
- float _peak_db;
- uint32_t _short_overs;
- uint32_t _long_overs;
+ nframes_t _overlen;
+ Sample _peak;
+ float _peak_db;
+ uint32_t _short_overs;
+ uint32_t _long_overs;
- static nframes_t _long_over_length;
- static nframes_t _short_over_length;
+ static nframes_t _long_over_length;
+ static nframes_t _short_over_length;
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h
index cb5a6d72ce..17ba9f9614 100644
--- a/libs/ardour/ardour/audioengine.h
+++ b/libs/ardour/ardour/audioengine.h
@@ -51,7 +51,7 @@ class AudioEngine : public sigc::trackable
AudioEngine (std::string client_name);
virtual ~AudioEngine ();
- jack_client_t* jack() const { return _jack; }
+ jack_client_t* jack() const;
bool connected() const { return _jack != 0; }
bool is_realtime () const;
@@ -219,6 +219,8 @@ class AudioEngine : public sigc::trackable
SerializedRCUManager<Ports> ports;
+ Port *register_port (DataType type, const std::string& portname, bool input);
+
int process_callback (nframes_t nframes);
void remove_all_ports ();
diff --git a/libs/ardour/ardour/jack_audio_port.h b/libs/ardour/ardour/jack_audio_port.h
new file mode 100644
index 0000000000..8a636bb7aa
--- /dev/null
+++ b/libs/ardour/ardour/jack_audio_port.h
@@ -0,0 +1,49 @@
+/*
+ Copyright (C) 2002 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
+ 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: port.h 712 2006-07-28 01:08:57Z drobilla $
+*/
+
+#ifndef __ardour_jack_audio_port_h__
+#define __ardour_jack_audio_port_h__
+
+#include <sigc++/signal.h>
+#include <pbd/failed_constructor.h>
+#include <ardour/ardour.h>
+#include <ardour/jack_port.h>
+#include <ardour/audio_port.h>
+
+namespace ARDOUR {
+
+class AudioEngine;
+class JackAudioPort : public AudioPort, public JackPort {
+ public:
+ void cycle_start(nframes_t nframes) {
+ _buffer.set_data ((Sample*) jack_port_get_buffer (_port, nframes), nframes);
+ }
+
+ int reestablish ();
+
+ protected:
+ friend class AudioEngine;
+
+ JackAudioPort (const std::string& name, Flags flags);
+};
+
+} // namespace ARDOUR
+
+#endif /* __ardour_jack_audio_port_h__ */
diff --git a/libs/ardour/ardour/jack_midi_port.h b/libs/ardour/ardour/jack_midi_port.h
new file mode 100644
index 0000000000..5508ae2b17
--- /dev/null
+++ b/libs/ardour/ardour/jack_midi_port.h
@@ -0,0 +1,53 @@
+/*
+ Copyright (C) 2002 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
+ 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: port.h 712 2006-07-28 01:08:57Z drobilla $
+*/
+
+#ifndef __ardour_jack_midi_port_h__
+#define __ardour_jack_midi_port_h__
+
+#include <sigc++/signal.h>
+#include <pbd/failed_constructor.h>
+#include <ardour/ardour.h>
+#include <jack/jack.h>
+#include <jack/midiport.h>
+#include <ardour/port.h>
+#include <ardour/jack_port.h>
+#include <ardour/midi_port.h>
+#include <ardour/midi_buffer.h>
+
+namespace ARDOUR {
+
+class MidiEngine;
+
+class JackMidiPort : public JackPort, public MidiPort {
+ public:
+ void cycle_start(nframes_t nframes);
+ void cycle_end();
+
+ protected:
+ friend class AudioEngine;
+
+ JackMidiPort (const std::string&, Flags);
+
+ nframes_t _nframes_this_cycle;
+};
+
+} // namespace ARDOUR
+
+#endif /* __ardour_jack_midi_port_h__ */
diff --git a/libs/ardour/ardour/midi_port.h b/libs/ardour/ardour/midi_port.h
index b7730f0d16..48ebf31eef 100644
--- a/libs/ardour/ardour/midi_port.h
+++ b/libs/ardour/ardour/midi_port.h
@@ -24,8 +24,6 @@
#include <sigc++/signal.h>
#include <pbd/failed_constructor.h>
#include <ardour/ardour.h>
-#include <jack/jack.h>
-#include <jack/midiport.h>
#include <ardour/port.h>
#include <ardour/midi_buffer.h>
@@ -33,11 +31,11 @@ namespace ARDOUR {
class MidiEngine;
-class MidiPort : public Port {
+class MidiPort : public virtual Port {
public:
virtual ~MidiPort();
- DataType type() const { return DataType(DataType::MIDI); }
+ DataType type() const { return DataType::MIDI; }
Buffer& get_buffer() {
return _buffer;
@@ -47,21 +45,17 @@ class MidiPort : public Port {
return _buffer;
}
- void cycle_start(nframes_t nframes);
- void cycle_end();
-
size_t capacity() { return _buffer.capacity(); }
size_t size() { return _buffer.size(); }
protected:
friend class AudioEngine;
- MidiPort (jack_port_t *port);
+ MidiPort (nframes_t bufsize);
/* engine isn't supposed to access below here */
MidiBuffer _buffer;
- nframes_t _nframes_this_cycle;
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/port.h b/libs/ardour/ardour/port.h
index cae198758b..c1e502727f 100644
--- a/libs/ardour/ardour/port.h
+++ b/libs/ardour/ardour/port.h
@@ -31,65 +31,39 @@ namespace ARDOUR {
class AudioEngine;
class Buffer;
-/** Abstract base for all outside ports (eg Jack ports)
+/** Abstract base for ports
*/
-class Port : public sigc::trackable {
+class Port : public virtual sigc::trackable {
public:
- virtual ~Port() {
- free (_port);
- }
-
- virtual DataType type() const = 0;
+ enum Flags {
+ IsInput = JackPortIsInput,
+ IsOutput = JackPortIsOutput,
+ IsPhysical = JackPortIsPhysical,
+ IsTerminal = JackPortIsTerminal,
+ CanMonitor = JackPortCanMonitor
+ };
- virtual void cycle_start(nframes_t nframes) {}
- virtual void cycle_end() {}
+ virtual ~Port() {}
- virtual Buffer& get_buffer() = 0;
-
std::string name() const {
return _name;
}
- std::string short_name() {
- return jack_port_short_name (_port);
- }
-
- int set_name (std::string str);
- JackPortFlags flags() const {
+ Flags flags() const {
return _flags;
}
- bool is_mine (jack_client_t *client) {
- return jack_port_is_mine (client, _port);
- }
-
- int connected () const {
- return jack_port_connected (_port);
- }
-
- bool connected_to (const std::string& portname) const {
- return jack_port_connected_to (_port, portname.c_str());
- }
-
- const char ** get_connections () const {
- return jack_port_get_connections (_port);
- }
-
bool receives_input() const {
- return _flags & JackPortIsInput;
+ return _flags & IsInput;
}
bool sends_output () const {
return _flags & JackPortIsOutput;
}
-
- bool monitoring_input () const {
- return jack_port_monitoring_input (_port);
- }
bool can_monitor () const {
- return _flags & JackPortCanMonitor;
+ return _flags & CanMonitor;
}
void enable_metering() {
@@ -100,28 +74,23 @@ class Port : public sigc::trackable {
if (_metering) { _metering--; }
}
- void ensure_monitor_input (bool yn) {
-
-#ifdef HAVE_JACK_PORT_ENSURE_MONITOR
- jack_port_ensure_monitor (_port, yn);
-#else
- jack_port_request_monitor(_port, yn);
-#endif
-
- }
-
- /*XXX completely bloody useless imho*/
- void request_monitor_input (bool yn) {
- jack_port_request_monitor (_port, yn);
- }
-
- nframes_t latency () const {
- return jack_port_get_latency (_port);
- }
-
- void set_latency (nframes_t nframes) {
- jack_port_set_latency (_port, nframes);
- }
+ virtual DataType type() const = 0;
+ virtual void cycle_start(nframes_t nframes) {}
+ virtual void cycle_end() {}
+ virtual Buffer& get_buffer() = 0;
+ virtual std::string short_name() = 0;
+ virtual int set_name (std::string str) = 0;
+ virtual bool is_mine (jack_client_t *client) = 0;
+ virtual int reestablish () = 0;
+ virtual int connected () const = 0;
+ virtual bool connected_to (const std::string& portname) const = 0;
+ virtual const char ** get_connections () const = 0;
+ virtual bool monitoring_input () const = 0;
+ virtual void ensure_monitor_input (bool yn) = 0;
+ virtual void request_monitor_input (bool yn) = 0;
+ virtual nframes_t latency () const = 0;
+ virtual nframes_t total_latency () const = 0;
+ virtual void set_latency (nframes_t nframes) = 0;
sigc::signal<void,bool> MonitorInputChanged;
sigc::signal<void,bool> ClockSyncChanged;
@@ -129,22 +98,19 @@ class Port : public sigc::trackable {
protected:
friend class AudioEngine;
- Port (jack_port_t *port);
-
+ Port ();
+
+ virtual int disconnect () = 0;
+ virtual void recompute_total_latency() const = 0;
virtual void reset ();
/* engine isn't supposed to access below here */
- /* cache these 3 from JACK so we can access them for reconnecting */
- JackPortFlags _flags;
- std::string _type;
- std::string _name;
-
- jack_port_t* _port;
-
+ Flags _flags;
+ std::string _type;
+ std::string _name;
unsigned short _metering;
-
- bool _last_monitor : 1;
+ bool _last_monitor;
};
} // namespace ARDOUR
diff --git a/libs/ardour/audio_port.cc b/libs/ardour/audio_port.cc
index ae64995000..23c8ab8335 100644
--- a/libs/ardour/audio_port.cc
+++ b/libs/ardour/audio_port.cc
@@ -26,13 +26,10 @@ using namespace std;
nframes_t AudioPort::_short_over_length = 2;
nframes_t AudioPort::_long_over_length = 10;
-AudioPort::AudioPort(jack_port_t* p)
- : Port(p)
- , _buffer(0)
+AudioPort::AudioPort()
+ : _buffer (0)
{
- DataType dt(_type);
- assert(dt == DataType::AUDIO);
-
+ _type = DataType::AUDIO;
reset();
}
@@ -40,7 +37,7 @@ void
AudioPort::reset()
{
Port::reset();
- if (_flags & JackPortIsOutput) {
+ if (_flags & IsOutput) {
if (_buffer.capacity() > 0) {
_buffer.clear();
}
diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc
index 2a4b36f7d8..63a51b76c4 100644
--- a/libs/ardour/audioengine.cc
+++ b/libs/ardour/audioengine.cc
@@ -31,8 +31,8 @@
#include <ardour/audioengine.h>
#include <ardour/buffer.h>
#include <ardour/port.h>
-#include <ardour/audio_port.h>
-#include <ardour/midi_port.h>
+#include <ardour/jack_audio_port.h>
+#include <ardour/jack_midi_port.h>
#include <ardour/session.h>
#include <ardour/cycle_timer.h>
#include <ardour/utils.h>
@@ -83,6 +83,7 @@ AudioEngine::AudioEngine (string client_name)
start_metering_thread();
+ JackPort::set_engine (this);
}
AudioEngine::~AudioEngine ()
@@ -99,6 +100,12 @@ AudioEngine::~AudioEngine ()
}
}
+jack_client_t*
+AudioEngine::jack() const
+{
+ return _jack;
+}
+
void
_thread_init_callback (void *arg)
{
@@ -501,89 +508,45 @@ AudioEngine::remove_session ()
}
Port *
-AudioEngine::register_input_port (DataType type, const string& portname)
+AudioEngine::register_port (DataType type, const string& portname, bool input)
{
- if (!_running) {
- if (!_has_run) {
- fatal << _("register input port called before engine was started") << endmsg;
- /*NOTREACHED*/
- } else {
- return 0;
- }
- }
-
- jack_port_t *p = jack_port_register (_jack, portname.c_str(), type.to_jack_type(), JackPortIsInput, 0);
-
- if (p) {
+ Port* newport = 0;
- Port* newport = 0;
-
+ try {
if (type == DataType::AUDIO)
- newport = new AudioPort (p);
+ newport = new JackAudioPort (portname, (input ? Port::IsInput : Port::IsOutput));
else if (type == DataType::MIDI)
- newport = new MidiPort (p);
+ newport = new JackMidiPort (portname, (input ? Port::IsInput : Port::IsOutput));
else
throw unknown_type();
-
+
if (newport != 0) {
RCUWriter<Ports> writer (ports);
boost::shared_ptr<Ports> ps = writer.get_copy ();
ps->insert (ps->begin(), newport);
/* writer goes out of scope, forces update */
}
-
+
return newport;
+ }
- } else {
+ catch (...) {
throw PortRegistrationFailure();
}
+}
- return 0;
+Port *
+AudioEngine::register_input_port (DataType type, const string& portname)
+{
+ return register_port (type, portname, true);
}
Port *
AudioEngine::register_output_port (DataType type, const string& portname)
{
- if (!_running) {
- if (!_has_run) {
- fatal << _("register output port called before engine was started") << endmsg;
- /*NOTREACHED*/
- } else {
- return 0;
- }
- }
-
- jack_port_t* p = 0;
-
- if ((p = jack_port_register (_jack, portname.c_str(),
- type.to_jack_type(), JackPortIsOutput, 0)) != 0) {
-
- Port* newport = 0;
-
- if (type == DataType::AUDIO)
- newport = new AudioPort (p);
- else if (type == DataType::MIDI)
- newport = new MidiPort (p);
- else
- throw unknown_type ();
-
- if (newport != 0) {
- RCUWriter<Ports> writer (ports);
- boost::shared_ptr<Ports> ps = writer.get_copy ();
- ps->insert (ps->begin(), newport);
- /* writer goes out of scope, forces update */
- }
-
- return newport;
-
- } else {
- throw PortRegistrationFailure ();
- }
-
- return 0;
+ return register_port (type, portname, false);
}
-
int
AudioEngine::unregister_port (Port& port)
{
@@ -594,29 +557,25 @@ AudioEngine::unregister_port (Port& port)
return 0;
}
- int ret = jack_port_unregister (_jack, port._port);
-
- if (ret == 0) {
-
- {
-
- RCUWriter<Ports> writer (ports);
- boost::shared_ptr<Ports> ps = writer.get_copy ();
-
- for (Ports::iterator i = ps->begin(); i != ps->end(); ++i) {
- if ((*i) == &port) {
- ps->erase (i);
- break;
- }
+ {
+
+ RCUWriter<Ports> writer (ports);
+ boost::shared_ptr<Ports> ps = writer.get_copy ();
+
+ for (Ports::iterator i = ps->begin(); i != ps->end(); ++i) {
+ if ((*i) == &port) {
+ remove_connections_for (port);
+ cerr << "eraseing " << (*i)->name() << endl;
+ delete *i;
+ ps->erase (i);
+ break;
}
-
- /* writer goes out of scope, forces update */
}
-
- remove_connections_for (port);
+
+ /* writer goes out of scope, forces update */
}
- return ret;
+ return 0;
}
int
@@ -693,7 +652,7 @@ AudioEngine::disconnect (Port& port)
}
}
- int ret = jack_port_disconnect (_jack, port._port);
+ int ret = port.disconnect ();
if (ret == 0) {
remove_connections_for (port);
@@ -916,22 +875,9 @@ AudioEngine::get_nth_physical (DataType type, uint32_t n, int flag)
ARDOUR::nframes_t
AudioEngine::get_port_total_latency (const Port& port)
{
- if (!_jack) {
- fatal << _("get_port_total_latency() called with no JACK client connection") << endmsg;
- /*NOTREACHED*/
- }
-
- if (!_running) {
- if (!_has_run) {
- fatal << _("get_port_total_latency() called before engine was started") << endmsg;
- /*NOTREACHED*/
- }
- }
-
- return jack_port_get_total_latency (_jack, port._port);
+ return port.total_latency ();
}
-
void
AudioEngine::update_total_latency (const Port& port)
{
@@ -947,9 +893,7 @@ AudioEngine::update_total_latency (const Port& port)
}
}
-#ifdef HAVE_JACK_RECOMPUTE_LATENCY
- jack_recompute_total_latency (_jack, port._port);
-#endif
+ port.recompute_total_latency ();
}
void
@@ -1025,14 +969,6 @@ AudioEngine::remove_all_ports ()
{
/* process lock MUST be held */
- if (_jack) {
- boost::shared_ptr<Ports> p = ports.reader();
-
- for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
- jack_port_unregister (_jack, (*i)->_port);
- }
- }
-
{
RCUWriter<Ports> writer (ports);
boost::shared_ptr<Ports> ps = writer.get_copy ();
@@ -1152,31 +1088,14 @@ AudioEngine::reconnect_to_jack ()
for (i = p->begin(); i != p->end(); ++i) {
- /* XXX hack hack hack */
-
- string long_name = (*i)->name();
- string short_name;
-
- short_name = long_name.substr (long_name.find_last_of (':') + 1);
-
- if (((*i)->_port = jack_port_register (_jack, short_name.c_str(), (*i)->type().to_jack_type(), (*i)->flags(), 0)) == 0) {
- error << string_compose (_("could not reregister %1"), (*i)->name()) << endmsg;
+ if ((*i)->reestablish ()) {
break;
- } else {
- }
-
- (*i)->reset ();
-
- if ((*i)->flags() & JackPortIsOutput) {
- (*i)->get_buffer().silence (jack_get_buffer_size (_jack), 0);
- }
+ }
}
if (i != p->end()) {
/* failed */
- for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
- jack_port_unregister (_jack, (*i)->_port);
- }
+ remove_all_ports ();
return -1;
}
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc
index bff8c18bc9..0c4ee41496 100644
--- a/libs/ardour/io.cc
+++ b/libs/ardour/io.cc
@@ -198,6 +198,8 @@ IO::IO (Session& s, const XMLNode& node, DataType dt)
IO::~IO ()
{
+ cerr << "Deleting IO called " << _name << endl;
+
Glib::Mutex::Lock guard (m_meter_signal_lock);
Glib::Mutex::Lock lm (io_lock);
diff --git a/libs/ardour/jack_audio_port.cc b/libs/ardour/jack_audio_port.cc
new file mode 100644
index 0000000000..83a6875f7d
--- /dev/null
+++ b/libs/ardour/jack_audio_port.cc
@@ -0,0 +1,41 @@
+/*
+ Copyright (C) 2006 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
+ 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.
+*/
+
+#include <cassert>
+#include <ardour/audioengine.h>
+#include <ardour/jack_audio_port.h>
+
+using namespace ARDOUR;
+
+JackAudioPort::JackAudioPort(const std::string& name, Flags flgs)
+ : JackPort (name, DataType::AUDIO, flgs)
+{
+
+}
+
+int
+JackAudioPort::reestablish ()
+{
+ int ret = JackPort::reestablish ();
+
+ if (ret == 0 && _flags & IsOutput) {
+ _buffer.silence (jack_get_buffer_size (engine->jack()));
+ }
+
+ return ret;
+}
diff --git a/libs/ardour/jack_midi_port.cc b/libs/ardour/jack_midi_port.cc
new file mode 100644
index 0000000000..90ee93371d
--- /dev/null
+++ b/libs/ardour/jack_midi_port.cc
@@ -0,0 +1,94 @@
+/*
+ Copyright (C) 2006 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
+ 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.
+*/
+
+#include <cassert>
+#include <ardour/jack_midi_port.h>
+
+using namespace ARDOUR;
+JackMidiPort::JackMidiPort (const std::string& name, Flags flgs)
+ : JackPort (name, DataType::MIDI, flgs)
+ , MidiPort (4096) // FIXME FIXME FIXME Jack needs to tell us this
+ , _nframes_this_cycle(0)
+{
+}
+
+void
+JackMidiPort::cycle_start (nframes_t nframes)
+{
+ _buffer.clear();
+ assert(_buffer.size() == 0);
+
+ _nframes_this_cycle = nframes;
+
+ if (_flags & JackPortIsOutput) {
+ _buffer.silence(nframes);
+ assert(_buffer.size() == 0);
+ return;
+ }
+
+ // We're an input - copy Jack events to internal buffer
+
+ void* jack_buffer = jack_port_get_buffer(_port, nframes);
+ const nframes_t event_count
+ = jack_midi_get_event_count(jack_buffer);
+
+ assert(event_count < _buffer.capacity());
+
+ jack_midi_event_t ev;
+
+ for (nframes_t i=0; i < event_count; ++i) {
+
+ jack_midi_event_get(&ev, jack_buffer, i);
+
+ _buffer.push_back(ev);
+ }
+
+ assert(_buffer.size() == event_count);
+
+ //if (_buffer.size() > 0)
+ // cerr << "MIDIPort got " << event_count << " events." << endl;
+}
+
+void
+JackMidiPort::cycle_end()
+{
+ if (_flags & JackPortIsInput) {
+ _nframes_this_cycle = 0;
+ return;
+ }
+
+ // We're an output - copy events from internal buffer to Jack buffer
+
+ void* jack_buffer = jack_port_get_buffer(_port, _nframes_this_cycle);
+
+ //const nframes_t event_count = _buffer.size();
+ //if (event_count > 0)
+ // cerr << "MIDIPort writing " << event_count << " events." << endl;
+
+ jack_midi_clear_buffer(jack_buffer);
+
+ for (MidiBuffer::iterator i = _buffer.begin(); i != _buffer.end(); ++i) {
+ const MidiEvent& ev = *i;
+ // event times should be frames, relative to cycle start
+ assert(ev.time() >= 0);
+ assert(ev.time() < _nframes_this_cycle);
+ jack_midi_event_write(jack_buffer, (jack_nframes_t)ev.time(), ev.buffer(), ev.size());
+ }
+
+ _nframes_this_cycle = 0;
+}
diff --git a/libs/ardour/jack_port.cc b/libs/ardour/jack_port.cc
new file mode 100644
index 0000000000..7f56e396ce
--- /dev/null
+++ b/libs/ardour/jack_port.cc
@@ -0,0 +1,111 @@
+/*
+ Copyright (C) 2002-2006 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
+ 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.
+
+*/
+
+#include <pbd/error.h>
+
+#include <ardour/jack_port.h>
+#include <ardour/audioengine.h>
+
+#include "i18n.h"
+
+using namespace ARDOUR;
+using namespace PBD;
+using namespace std;
+
+AudioEngine* JackPort::engine = 0;
+
+JackPort::JackPort (const std::string& name, DataType type, Flags flgs)
+ : _port (0)
+{
+ _port = jack_port_register (engine->jack(), name.c_str(), type.to_jack_type(), flgs, 0);
+
+ if (_port == 0) {
+ throw failed_constructor();
+ }
+
+ _flags = flgs;
+ _type = type;
+ _name = jack_port_name (_port);
+}
+
+JackPort::~JackPort ()
+{
+ cerr << "deleting jack port " << _name << endl;
+
+ jack_port_unregister (engine->jack(), _port);
+}
+
+int
+JackPort::set_name (string str)
+{
+ int ret;
+
+ if ((ret = jack_port_set_name (_port, str.c_str())) == 0) {
+ _name = str;
+ }
+
+ return ret;
+}
+
+int
+JackPort::disconnect ()
+{
+ return jack_port_disconnect (engine->jack(), _port);
+}
+
+void
+JackPort::set_engine (AudioEngine* e)
+{
+ engine = e;
+}
+
+nframes_t
+JackPort::total_latency () const
+{
+ return jack_port_get_total_latency (engine->jack(), _port);
+}
+
+int
+JackPort::reestablish ()
+{
+ string short_name;
+
+ short_name = _name.substr (_name.find_last_of (':') + 1);
+
+ _port = jack_port_register (engine->jack(), short_name.c_str(), type().to_jack_type(), _flags, 0);
+
+ if (_port == 0) {
+ error << string_compose (_("could not reregister %1"), _name) << endmsg;
+ return -1;
+ }
+
+ reset ();
+
+
+ return 0;
+}
+
+void
+JackPort::recompute_total_latency () const
+{
+#ifdef HAVE_JACK_RECOMPUTE_LATENCY
+ jack_recompute_total_latency (engine->jack(), _port);
+#endif
+}
+
diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc
index 3f03cfe880..df4ab19008 100644
--- a/libs/ardour/midi_port.cc
+++ b/libs/ardour/midi_port.cc
@@ -25,87 +25,16 @@
using namespace ARDOUR;
using namespace std;
-MidiPort::MidiPort(jack_port_t* p)
- : Port(p)
- , _buffer(4096) // FIXME FIXME FIXME Jack needs to tell us this
- , _nframes_this_cycle(0)
+MidiPort::MidiPort (nframes_t bufsize)
+ : _buffer (bufsize)
{
- DataType dt(_type);
- assert(dt == DataType::MIDI);
-
+ _type = DataType::MIDI;
reset();
}
-
MidiPort::~MidiPort()
{
}
-void
-MidiPort::cycle_start (nframes_t nframes)
-{
- _buffer.clear();
- assert(_buffer.size() == 0);
-
- _nframes_this_cycle = nframes;
-
- if (_flags & JackPortIsOutput) {
- _buffer.silence(nframes);
- assert(_buffer.size() == 0);
- return;
- }
-
- // We're an input - copy Jack events to internal buffer
-
- void* jack_buffer = jack_port_get_buffer(_port, nframes);
-
- const nframes_t event_count
- = jack_midi_get_event_count(jack_buffer);
-
- assert(event_count < _buffer.capacity());
-
- jack_midi_event_t ev;
-
- for (nframes_t i=0; i < event_count; ++i) {
-
- jack_midi_event_get(&ev, jack_buffer, i);
-
- _buffer.push_back(ev);
- }
-
- assert(_buffer.size() == event_count);
-
- //if (_buffer.size() > 0)
- // cerr << "MIDIPort got " << event_count << " events." << endl;
-}
-
-void
-MidiPort::cycle_end()
-{
- if (_flags & JackPortIsInput) {
- _nframes_this_cycle = 0;
- return;
- }
-
- // We're an output - copy events from internal buffer to Jack buffer
-
- void* jack_buffer = jack_port_get_buffer(_port, _nframes_this_cycle);
-
- //const nframes_t event_count = _buffer.size();
- //if (event_count > 0)
- // cerr << "MIDIPort writing " << event_count << " events." << endl;
-
- jack_midi_clear_buffer(jack_buffer);
-
- for (MidiBuffer::iterator i = _buffer.begin(); i != _buffer.end(); ++i) {
- const MidiEvent& ev = *i;
- // event times should be frames, relative to cycle start
- assert(ev.time() >= 0);
- assert(ev.time() < _nframes_this_cycle);
- jack_midi_event_write(jack_buffer, (jack_nframes_t)ev.time(), ev.buffer(), ev.size());
- }
-
- _nframes_this_cycle = 0;
-}
diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc
index d9c93c250b..bfc1eaf279 100644
--- a/libs/ardour/port.cc
+++ b/libs/ardour/port.cc
@@ -22,20 +22,10 @@
using namespace ARDOUR;
using namespace std;
-Port::Port (jack_port_t *p)
- : _port (p)
- , _metering(0)
- , _last_monitor(false)
+Port::Port ()
+ : _metering (0)
+ , _last_monitor (false)
{
- if (_port == 0) {
- throw failed_constructor();
- }
-
- _flags = JackPortFlags (jack_port_flags (_port));
- _type = jack_port_type (_port);
- _name = jack_port_name (_port);
-
- reset ();
}
void
@@ -43,17 +33,3 @@ Port::reset ()
{
_last_monitor = false;
}
-
-int
-Port::set_name (string str)
-{
- int ret;
-
- if ((ret = jack_port_set_name (_port, str.c_str())) == 0) {
- _name = str;
- }
-
- return ret;
-}
-
-
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index abd8a0abba..1382fa3f0a 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -2089,13 +2089,14 @@ Session::remove_route (shared_ptr<Route> route)
find_current_end ();
+ // We need to disconnect the routes inputs and outputs
+
+ route->disconnect_inputs (0);
+ route->disconnect_outputs (0);
+
update_latency_compensation (false, false);
set_dirty();
- // We need to disconnect the routes inputs and outputs
- route->disconnect_inputs(NULL);
- route->disconnect_outputs(NULL);
-
/* get rid of it from the dead wood collection in the route list manager */
/* XXX i think this is unsafe as it currently stands, but i am not sure. (pd, october 2nd, 2006) */
@@ -4240,3 +4241,4 @@ Session::foreach_bundle (sigc::slot<void, boost::shared_ptr<Bundle> > sl)
sl (*i);
}
}
+
diff --git a/libs/pbd/SConscript b/libs/pbd/SConscript
index d513dfc762..feaabd97ff 100644
--- a/libs/pbd/SConscript
+++ b/libs/pbd/SConscript
@@ -54,8 +54,6 @@ xml++.cc
conf = Configure(pbd)
if conf.CheckFunc('getmntent'):
conf.env.Append(CCFLAGS="-DHAVE_GETMNTENT")
-if conf.CheckCHeader('execinfo.h'):
- conf.env.Append(CXXFLAGS="-DHAVE_EXECINFO")
pbd = conf.Finish()
pbd.Merge ([ libraries['sigc2'],
diff --git a/libs/pbd/boost-debug/shared_ptr.hpp b/libs/pbd/boost-debug/shared_ptr.hpp
new file mode 100644
index 0000000000..506d11bde5
--- /dev/null
+++ b/libs/pbd/boost-debug/shared_ptr.hpp
@@ -0,0 +1,491 @@
+#define DEBUG_SHARED_PTR
+#ifndef DEBUG_SHARED_PTR
+
+#include <boost/shared_ptr.hpp>
+
+#else
+
+#include <pbd/stacktrace.h>
+
+#ifndef BOOST_SHARED_PTR_HPP_INCLUDED
+#define BOOST_SHARED_PTR_HPP_INCLUDED
+
+//
+// shared_ptr.hpp
+//
+// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
+// Copyright (c) 2001, 2002, 2003 Peter Dimov
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+// See http://www.boost.org/libs/smart_ptr/shared_ptr.htm for documentation.
+//
+
+#include <pbd/stacktrace.h>
+
+#include <boost/config.hpp> // for broken compiler workarounds
+
+#if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES)
+#include <boost/detail/shared_ptr_nmt.hpp>
+#else
+
+#include <boost/assert.hpp>
+#include <boost/checked_delete.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/detail/shared_count.hpp>
+#include <boost/detail/workaround.hpp>
+
+#include <memory> // for std::auto_ptr
+#include <algorithm> // for std::swap
+#include <functional> // for std::less
+#include <typeinfo> // for std::bad_cast
+#include <iosfwd> // for std::basic_ostream
+
+#ifdef BOOST_MSVC // moved here to work around VC++ compiler crash
+# pragma warning(push)
+# pragma warning(disable:4284) // odd return type for operator->
+#endif
+
+namespace boost
+{
+
+template<class T> class weak_ptr;
+template<class T> class enable_shared_from_this;
+
+namespace detail
+{
+
+struct static_cast_tag {};
+struct const_cast_tag {};
+struct dynamic_cast_tag {};
+struct polymorphic_cast_tag {};
+
+template<class T> struct shared_ptr_traits
+{
+ typedef T & reference;
+};
+
+template<> struct shared_ptr_traits<void>
+{
+ typedef void reference;
+};
+
+#if !defined(BOOST_NO_CV_VOID_SPECIALIZATIONS)
+
+template<> struct shared_ptr_traits<void const>
+{
+ typedef void reference;
+};
+
+template<> struct shared_ptr_traits<void volatile>
+{
+ typedef void reference;
+};
+
+template<> struct shared_ptr_traits<void const volatile>
+{
+ typedef void reference;
+};
+
+#endif
+
+// enable_shared_from_this support
+
+template<class T, class Y> void sp_enable_shared_from_this( shared_count const & pn, boost::enable_shared_from_this<T> const * pe, Y const * px )
+{
+ if(pe != 0) pe->_internal_weak_this._internal_assign(const_cast<Y*>(px), pn);
+}
+
+inline void sp_enable_shared_from_this( shared_count const & /*pn*/, ... )
+{
+}
+
+} // namespace detail
+
+
+//
+// shared_ptr
+//
+// An enhanced relative of scoped_ptr with reference counted copy semantics.
+// The object pointed to is deleted when the last shared_ptr pointing to it
+// is destroyed or reset.
+//
+
+template<class T> class shared_ptr
+{
+private:
+
+ // Borland 5.5.1 specific workaround
+ typedef shared_ptr<T> this_type;
+
+public:
+
+ typedef T element_type;
+ typedef T value_type;
+ typedef T * pointer;
+ typedef typename detail::shared_ptr_traits<T>::reference reference;
+
+ shared_ptr(): px(0), pn() // never throws in 1.30+
+ {
+ }
+
+ template<class Y>
+ explicit shared_ptr( Y * p ): px( p ), pn( p ) // Y must be complete
+ {
+ detail::sp_enable_shared_from_this( pn, p, p );
+ }
+
+ //
+ // Requirements: D's copy constructor must not throw
+ //
+ // shared_ptr will release p by calling d(p)
+ //
+
+ template<class Y, class D> shared_ptr(Y * p, D d): px(p), pn(p, d)
+ {
+ detail::sp_enable_shared_from_this( pn, p, p );
+ }
+
+// generated copy constructor, assignment, destructor are fine...
+
+// except that Borland C++ has a bug, and g++ with -Wsynth warns
+#if defined(__BORLANDC__) || defined(__GNUC__)
+
+ shared_ptr & operator=(shared_ptr const & r) // never throws
+ {
+ px = r.px;
+ pn = r.pn; // shared_count::op= doesn't throw
+ return *this;
+ }
+
+#endif
+
+ template<class Y>
+ explicit shared_ptr(weak_ptr<Y> const & r): pn(r.pn) // may throw
+ {
+ // it is now safe to copy r.px, as pn(r.pn) did not throw
+ px = r.px;
+ }
+
+ template<class Y>
+ shared_ptr(shared_ptr<Y> const & r): px(r.px), pn(r.pn) // never throws
+ {
+ }
+
+ template<class Y>
+ shared_ptr(shared_ptr<Y> const & r, detail::static_cast_tag): px(static_cast<element_type *>(r.px)), pn(r.pn)
+ {
+ }
+
+ template<class Y>
+ shared_ptr(shared_ptr<Y> const & r, detail::const_cast_tag): px(const_cast<element_type *>(r.px)), pn(r.pn)
+ {
+ }
+
+ template<class Y>
+ shared_ptr(shared_ptr<Y> const & r, detail::dynamic_cast_tag): px(dynamic_cast<element_type *>(r.px)), pn(r.pn)
+ {
+ if(px == 0) // need to allocate new counter -- the cast failed
+ {
+ pn = detail::shared_count();
+ }
+ }
+
+ template<class Y>
+ shared_ptr(shared_ptr<Y> const & r, detail::polymorphic_cast_tag): px(dynamic_cast<element_type *>(r.px)), pn(r.pn)
+ {
+ if(px == 0)
+ {
+ boost::throw_exception(std::bad_cast());
+ }
+ }
+
+#ifndef BOOST_NO_AUTO_PTR
+
+ template<class Y>
+ explicit shared_ptr(std::auto_ptr<Y> & r): px(r.get()), pn()
+ {
+ Y * tmp = r.get();
+ pn = detail::shared_count(r);
+ detail::sp_enable_shared_from_this( pn, tmp, tmp );
+ }
+
+#endif
+
+#if !defined(BOOST_MSVC) || (BOOST_MSVC > 1200)
+
+ template<class Y>
+ shared_ptr & operator=(shared_ptr<Y> const & r) // never throws
+ {
+ px = r.px;
+ pn = r.pn; // shared_count::op= doesn't throw
+ return *this;
+ }
+
+#endif
+
+#ifndef BOOST_NO_AUTO_PTR
+
+ template<class Y>
+ shared_ptr & operator=(std::auto_ptr<Y> & r)
+ {
+ this_type(r).swap(*this);
+ return *this;
+ }
+
+#endif
+
+ void reset() // never throws in 1.30+
+ {
+ this_type().swap(*this);
+ }
+
+ template<class Y> void reset(Y * p) // Y must be complete
+ {
+ BOOST_ASSERT(p == 0 || p != px); // catch self-reset errors
+ this_type(p).swap(*this);
+ }
+
+ template<class Y, class D> void reset(Y * p, D d)
+ {
+ this_type(p, d).swap(*this);
+ }
+
+ reference operator* () const // never throws
+ {
+ BOOST_ASSERT(px != 0);
+ return *px;
+ }
+
+ T * operator-> () const // never throws
+ {
+ BOOST_ASSERT(px != 0);
+ return px;
+ }
+
+ T * get() const // never throws
+ {
+ return px;
+ }
+
+ // implicit conversion to "bool"
+
+#if defined(__SUNPRO_CC) && BOOST_WORKAROUND(__SUNPRO_CC, <= 0x530)
+
+ operator bool () const
+ {
+ return px != 0;
+ }
+
+#elif \
+ ( defined(__MWERKS__) && BOOST_WORKAROUND(__MWERKS__, < 0x3200) ) || \
+ ( defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 304) )
+
+ typedef T * (this_type::*unspecified_bool_type)() const;
+
+ operator unspecified_bool_type() const // never throws
+ {
+ return px == 0? 0: &this_type::get;
+ }
+
+#else
+
+ typedef T * this_type::*unspecified_bool_type;
+
+ operator unspecified_bool_type() const // never throws
+ {
+ return px == 0? 0: &this_type::px;
+ }
+
+#endif
+
+ // operator! is redundant, but some compilers need it
+
+ bool operator! () const // never throws
+ {
+ return px == 0;
+ }
+
+ bool unique() const // never throws
+ {
+ return pn.unique();
+ }
+
+ long use_count() const // never throws
+ {
+ return pn.use_count();
+ }
+
+ void swap(shared_ptr<T> & other) // never throws
+ {
+ std::swap(px, other.px);
+ pn.swap(other.pn);
+ }
+
+ template<class Y> bool _internal_less(shared_ptr<Y> const & rhs) const
+ {
+ return pn < rhs.pn;
+ }
+
+ void * _internal_get_deleter(std::type_info const & ti) const
+ {
+ return pn.get_deleter(ti);
+ }
+
+// Tasteless as this may seem, making all members public allows member templates
+// to work in the absence of member template friends. (Matthew Langston)
+
+#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
+
+private:
+
+ template<class Y> friend class shared_ptr;
+ template<class Y> friend class weak_ptr;
+
+#endif
+
+ T * px; // contained pointer
+ detail::shared_count pn; // reference counter
+ typename PBD::thing_with_backtrace<T> bt; // backtrace
+
+}; // shared_ptr
+
+template<class T, class U> inline bool operator==(shared_ptr<T> const & a, shared_ptr<U> const & b)
+{
+ return a.get() == b.get();
+}
+
+template<class T, class U> inline bool operator!=(shared_ptr<T> const & a, shared_ptr<U> const & b)
+{
+ return a.get() != b.get();
+}
+
+#if __GNUC__ == 2 && __GNUC_MINOR__ <= 96
+
+// Resolve the ambiguity between our op!= and the one in rel_ops
+
+template<class T> inline bool operator!=(shared_ptr<T> const & a, shared_ptr<T> const & b)
+{
+ return a.get() != b.get();
+}
+
+#endif
+
+template<class T, class U> inline bool operator<(shared_ptr<T> const & a, shared_ptr<U> const & b)
+{
+ return a._internal_less(b);
+}
+
+template<class T> inline void swap(shared_ptr<T> & a, shared_ptr<T> & b)
+{
+ a.swap(b);
+}
+
+template<class T, class U> shared_ptr<T> static_pointer_cast(shared_ptr<U> const & r)
+{
+ return shared_ptr<T>(r, detail::static_cast_tag());
+}
+
+template<class T, class U> shared_ptr<T> const_pointer_cast(shared_ptr<U> const & r)
+{
+ return shared_ptr<T>(r, detail::const_cast_tag());
+}
+
+template<class T, class U> shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> const & r)
+{
+ return shared_ptr<T>(r, detail::dynamic_cast_tag());
+}
+
+// shared_*_cast names are deprecated. Use *_pointer_cast instead.
+
+template<class T, class U> shared_ptr<T> shared_static_cast(shared_ptr<U> const & r)
+{
+ return shared_ptr<T>(r, detail::static_cast_tag());
+}
+
+template<class T, class U> shared_ptr<T> shared_dynamic_cast(shared_ptr<U> const & r)
+{
+ return shared_ptr<T>(r, detail::dynamic_cast_tag());
+}
+
+template<class T, class U> shared_ptr<T> shared_polymorphic_cast(shared_ptr<U> const & r)
+{
+ return shared_ptr<T>(r, detail::polymorphic_cast_tag());
+}
+
+template<class T, class U> shared_ptr<T> shared_polymorphic_downcast(shared_ptr<U> const & r)
+{
+ BOOST_ASSERT(dynamic_cast<T *>(r.get()) == r.get());
+ return shared_static_cast<T>(r);
+}
+
+// get_pointer() enables boost::mem_fn to recognize shared_ptr
+
+template<class T> inline T * get_pointer(shared_ptr<T> const & p)
+{
+ return p.get();
+}
+
+// operator<<
+
+#if defined(__GNUC__) && (__GNUC__ < 3)
+
+template<class Y> std::ostream & operator<< (std::ostream & os, shared_ptr<Y> const & p)
+{
+ os << p.get();
+ return os;
+}
+
+#else
+
+# if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, <= 1200 && __SGI_STL_PORT)
+// MSVC6 has problems finding std::basic_ostream through the using declaration in namespace _STL
+using std::basic_ostream;
+template<class E, class T, class Y> basic_ostream<E, T> & operator<< (basic_ostream<E, T> & os, shared_ptr<Y> const & p)
+# else
+template<class E, class T, class Y> std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, shared_ptr<Y> const & p)
+# endif
+{
+ os << p.get();
+ return os;
+}
+
+#endif
+
+// get_deleter (experimental)
+
+#if ( defined(__GNUC__) && BOOST_WORKAROUND(__GNUC__, < 3) ) || \
+ ( defined(__EDG_VERSION__) && BOOST_WORKAROUND(__EDG_VERSION__, <= 238) ) || \
+ ( defined(__HP_aCC) && BOOST_WORKAROUND(__HP_aCC, <= 33500) )
+
+// g++ 2.9x doesn't allow static_cast<X const *>(void *)
+// apparently EDG 2.38 and HP aCC A.03.35 also don't accept it
+
+template<class D, class T> D * get_deleter(shared_ptr<T> const & p)
+{
+ void const * q = p._internal_get_deleter(typeid(D));
+ return const_cast<D *>(static_cast<D const *>(q));
+}
+
+#else
+
+template<class D, class T> D * get_deleter(shared_ptr<T> const & p)
+{
+ return static_cast<D *>(p._internal_get_deleter(typeid(D)));
+}
+
+#endif
+
+} // namespace boost
+
+#ifdef BOOST_MSVC
+# pragma warning(pop)
+#endif
+
+#endif // #if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES)
+
+#endif // #ifndef BOOST_SHARED_PTR_HPP_INCLUDED
+
+#endif // #ifndef DEBUG_SHARED_PTR
diff --git a/libs/pbd/pbd/stacktrace.h b/libs/pbd/pbd/stacktrace.h
index c6da6ed79d..0a349dcaeb 100644
--- a/libs/pbd/pbd/stacktrace.h
+++ b/libs/pbd/pbd/stacktrace.h
@@ -20,10 +20,95 @@
#ifndef __libpbd_stacktrace_h__
#define __libpbd_stacktrace_h__
+#include <iostream>
#include <ostream>
+#include <glibmm/thread.h>
+#include <list>
namespace PBD {
void stacktrace (std::ostream& out, int levels = 0);
-}
+ void trace_twb();
+
+#ifdef HAVE_EXECINFO
+#include <execinfo.h>
+#include <stdlib.h>
+#endif
+
+template<typename T>
+class thing_with_backtrace
+{
+ public:
+ thing_with_backtrace () {
+ trace_twb();
+#ifdef HAVE_EXECINFO
+ allocation_backtrace = new void*[50];
+ allocation_backtrace_size = backtrace (allocation_backtrace, 50);
+#else
+ allocation_backtrace_size = 0;
+#endif
+ Glib::Mutex::Lock lm (all_mutex);
+ all.push_back (this);
+ }
+
+ thing_with_backtrace (const thing_with_backtrace<T>& other) {
+ trace_twb();
+#ifdef HAVE_EXECINFO
+ allocation_backtrace = new void*[50];
+ allocation_backtrace_size = backtrace (allocation_backtrace, 50);
+#else
+ allocation_backtrace_size = 0;
+#endif
+ Glib::Mutex::Lock lm (all_mutex);
+ all.push_back (this);
+ }
+
+ ~thing_with_backtrace() {
+ if (allocation_backtrace_size) {
+ delete [] allocation_backtrace;
+ }
+ Glib::Mutex::Lock lm (all_mutex);
+ all.remove (this);
+ }
+
+ thing_with_backtrace<T>& operator= (const thing_with_backtrace<T>& other) {
+ /* no copyable members */
+ return *this;
+ }
+
+ static void peek_a_boo (std::ostream& stream) {
+#ifdef HAVE_EXECINFO
+ typename std::list<thing_with_backtrace<T>*>::iterator x;
+ for (x = all.begin(); x != all.end(); ++x) {
+ char **strings;
+ size_t i;
+
+ strings = backtrace_symbols ((*x)->allocation_backtrace, (*x)->allocation_backtrace_size);
+
+ if (strings) {
+ stream << "--- ALLOCATED SHARED_PTR @ " << (*x) << std::endl;
+ for (i = 0; i < (*x)->allocation_backtrace_size && i < 50U; i++) {
+ stream << strings[i] << std::endl;
+ }
+ free (strings);
+ }
+ }
+#else
+ stream << "execinfo not defined for this platform" << std::endl;
+#endif
+ }
+
+private:
+ void** allocation_backtrace;
+ int allocation_backtrace_size;
+ static std::list<thing_with_backtrace<T>* > all;
+ static Glib::StaticMutex all_mutex;
+};
+
+template<typename T> std::list<PBD::thing_with_backtrace<T> *> PBD::thing_with_backtrace<T>::all;
+template<typename T> Glib::StaticMutex PBD::thing_with_backtrace<T>::all_mutex = GLIBMM_STATIC_MUTEX_INIT;
+
+} // namespace PBD
+
+
#endif /* __libpbd_stacktrace_h__ */
diff --git a/libs/pbd/stacktrace.cc b/libs/pbd/stacktrace.cc
index 375fc1eecd..dc9a5e18ab 100644
--- a/libs/pbd/stacktrace.cc
+++ b/libs/pbd/stacktrace.cc
@@ -20,6 +20,11 @@
#include <pbd/stacktrace.h>
#include <iostream>
+void
+PBD::trace_twb ()
+{
+}
+
/* Obtain a backtrace and print it to stdout. */
#ifdef HAVE_EXECINFO