virtualize Port object; clean up automation tracks from track deletion

git-svn-id: svn://localhost/ardour2/trunk@2556 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2007-10-16 21:01:12 +00:00
parent 14dcc3f017
commit f3cf31009a
25 changed files with 1430 additions and 388 deletions

View File

@ -721,6 +721,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

View File

@ -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>

View File

@ -324,3 +324,4 @@ int main (int argc, char *argv[])
#ifdef VST_SUPPORT
} // end of extern C block
#endif

View File

@ -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;

View File

@ -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

View File

@ -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 = [ ]

View File

@ -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

View File

@ -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 ();

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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

View File

@ -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);
}
enum Flags {
IsInput = JackPortIsInput,
IsOutput = JackPortIsOutput,
IsPhysical = JackPortIsPhysical,
IsTerminal = JackPortIsTerminal,
CanMonitor = JackPortCanMonitor
};
virtual DataType type() const = 0;
virtual ~Port() {}
virtual void cycle_start(nframes_t nframes) {}
virtual void cycle_end() {}
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

View File

@ -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();
}

View File

@ -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;
}
}
Port* newport = 0;
jack_port_t *p = jack_port_register (_jack, portname.c_str(), type.to_jack_type(), JackPortIsInput, 0);
if (p) {
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 {
throw PortRegistrationFailure();
}
return 0;
catch (...) {
throw PortRegistrationFailure();
}
}
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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

111
libs/ardour/jack_port.cc Normal file
View File

@ -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
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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'],

View File

@ -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

View File

@ -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__ */

View File

@ -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