libardour added.

git-svn-id: svn://localhost/trunk/ardour2@17 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Taybin Rutkin
2005-09-24 19:13:41 +00:00
parent f9546e5c76
commit 8af0757b61
145 changed files with 58521 additions and 0 deletions

7
libs/ardour/.cvsignore Normal file
View File

@@ -0,0 +1,7 @@
libardour.la
libardour.pc
version.cc
*.lo
*.os
*.mo
*.pot

118
libs/ardour/ChangeLog Normal file
View File

@@ -0,0 +1,118 @@
2002-11-24 gettextize <bug-gnu-gettext@gnu.org>
* configure.ac (AC_OUTPUT): Add intl/Makefile,
2002-11-24 gettextize <bug-gnu-gettext@gnu.org>
* Makefile.am (ACLOCAL_AMFLAGS): New variable.
2001-10-26 Paul Davis <pbd>
* playlist.cc (recover_backup): restored the backup recovery code
for playlists.
* diskstream.cc (do_refill): added state_lock to diskstream, just
to be safe.
* session.cc (butler_thread_work): changed Session ISA thread to
HASA thread.
2001-10-23 Paul Davis <pbd>
merged in marcus' patch for edit/mix group save/restore, and
rationalized both it and the existing code for Route::set_state()
2001-10-20 Paul Davis <pbd>
* session.cc (get_state): in get_state, use the public order for routes.
2001-10-18 Paul Davis <pbd>
* playlist.cc (read): stop a muted region from causing a playlist
read error.
2001-10-17 Paul Davis <pbd>
* region.cc (read_at): remove staccato noise caused by not
shifting target buffer when !opaque.
2001-10-15 Paul Davis <pbd>
* region.cc (set_fade_out_active): made region fade in/out optional.
* configure.in: patches from Ben related to libxml++
2001-10-12 Paul Davis <pbd>
* session.cc (XMLRegionFactory): move most XML-based Region
constructor into region.
2001-10-10 Paul Davis <pbd>
* session.cc (load_sources): add whole-file regions when loading
sources.
2001-10-09 Paul Davis <pbd>
* ardour/session.h: fix an ugly bug with a non-reference return type.
2001-10-04 Paul Davis <pbd>
* playlist.cc (split_region): ensure that left region after split
is in the right place.
* auditioner.cc (play_audition): stop existing audition before
starting a new one.
2001-10-03 Paul Davis <pbd>
* session.cc (process): stop regular process() call from operating
on hidden diskstreams and routes. the butler thread still works on
all diskstreams, every time, which might be a mistake.
2001-10-02 Paul Davis <pbd>
* session.cc (set_auto_play_range): added provisional support
for play ranges using session events. added code to use
auditioner.
* auditioner.cc: new file/object to support auditioning.
* route.cc: remove seek() function (didn't exist).
* session.cc (process): use list<DiskStream *> instead of GList
for diskstreams. add auditioner object.
2001-09-30 Paul Davis <pbd>
* playlist.cc (split_region): fix problem with region splitting
not defining two *smaller* regions of the original.
* region.cc (set_position): remove RegionTemplate object.
* playlist.cc (struct RegionSorter ): fix sorting to use position,
not start - whatever was i thinking ?
2001-09-28 Paul Davis <pbd>
* source.cc: emit source creation signal.
* session.cc (first_stage_init): catch all source creation events.
* sndfilesource.cc (init): fix up an off-by-one substr-length
error when creating a sndfilesource.
2001-09-27 Paul Davis <pbd>
* route.cc (operator): correct loop increment bug that caused a
hang when an Insert is added to a Route as a Redirect.
2001-09-25 Paul Davis <pbd>
* session.cc: make new file sources be partially named for their
initial host diskstream.
peak file construction now carried out en-masse at the
end of capture run.

206
libs/ardour/SConscript Normal file
View File

@@ -0,0 +1,206 @@
# -*- python -*-
import os
import glob
Import('env final_prefix install_prefix final_config_prefix libraries i18n')
ardour = env.Copy()
#
# this defines the version number of libardour
#
domain = 'libardour'
ardour.Append(DOMAIN = domain, MAJOR = 1, MINOR = 0, MICRO = 0)
ardour.Append(CXXFLAGS = "-DPACKAGE=\\\"" + domain + "\\\"")
ardour.Append(CCFLAGS="-DLIBSIGC_DISABLE_DEPRECATED")
ardour.Append(PACKAGE = domain)
ardour.Append(POTFILE = domain + '.pot')
ardour_files=Split("""
audio_library.cc
audio_playlist.cc
audio_track.cc
audioengine.cc
audiofilter.cc
audioregion.cc
auditioner.cc
automation.cc
automation_event.cc
configuration.cc
connection.cc
crossfade.cc
curve.cc
cycle_timer.cc
default_click.cc
diskstream.cc
filesource.cc
gain.cc
gdither.cc
globals.cc
import.cc
insert.cc
io.cc
jack_slave.cc
ladspa_plugin.cc
location.cc
mtc_slave.cc
named_selection.cc
panner.cc
playlist.cc
playlist_factory.cc
plugin.cc
plugin_manager.cc
port.cc
recent_sessions.cc
redirect.cc
region.cc
reverse.cc
route.cc
route_group.cc
send.cc
session.cc
session_butler.cc
session_click.cc
session_events.cc
session_export.cc
session_feedback.cc
session_midi.cc
session_process.cc
session_state.cc
session_time.cc
session_timefx.cc
session_transport.cc
sndfile_helpers.cc
sndfilesource.cc
source.cc
state_manager.cc
stateful.cc
tempo.cc
utils.cc
version.cc
mix.cc
""")
arch_specific_objects = [ ]
vst_files = [ 'vst_plugin.cc', 'session_vst.cc' ]
extra_sources = [ ]
if ardour['VST']:
extra_sources += vst_files
ardour.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE")
ardour.Append(CXXFLAGS="-DDATA_DIR=\\\""+final_prefix+"/share\\\"")
ardour.Append(CXXFLAGS="-DCONFIG_DIR=\\\""+final_config_prefix+"\\\"")
ardour.Append(CXXFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
ardour.Merge ([ libraries['jack'] ])
#
# See if JACK supports jack_client_open()
#
jack_test_source_file = """
#include <jack/jack.h>
int main(int argc, char **argv)
{
jack_client_open ("foo", 0, 0);
return 0;
}
"""
def CheckJackClientOpen(context):
context.Message('Checking for jack_client_open()...')
result = context.TryLink(jack_test_source_file, '.c')
context.Result(result)
return result
#
# See if JACK supports jack_recompute_total_latencies()
#
jack_test_source_file = """
#include <jack/jack.h>
int main(int argc, char **argv)
{
jack_recompute_total_latencies ((jack_client_t*) 0);
return 0;
}
"""
def CheckJackRecomputeLatencies(context):
context.Message('Checking for jack_recompute_total_latencies()...')
result = context.TryLink(jack_test_source_file, '.c')
context.Result(result)
return result
conf = Configure(ardour, custom_tests = {
'CheckJackClientOpen' : CheckJackClientOpen,
'CheckJackRecomputeLatencies' : CheckJackRecomputeLatencies
})
if conf.CheckJackClientOpen():
ardour.Append(CXXFLAGS="-DHAVE_JACK_CLIENT_OPEN")
if conf.CheckJackRecomputeLatencies():
ardour.Append(CXXFLAGS="-DHAVE_JACK_RECOMPUTE_LATENCIES")
#
# Optional header files
#
if conf.CheckCHeader('wordexp.h'):
ardour.Append(CXXFLAGS="-DHAVE_WORDEXP")
if conf.CheckCHeader('sys/vfs.h'):
ardour.Append(CXXFLAGS="-DHAVE_SYS_VFS_H")
ardour = conf.Finish ()
ardour.Merge ([
libraries['core'],
libraries['xml'],
libraries['sndfile'],
libraries['lrdf'],
libraries['samplerate'],
libraries['sigc2'],
libraries['pbd3'],
libraries['soundtouch'],
libraries['midi++2']
])
ardour.VersionBuild(['version.cc', 'ardour/version.h'], 'SConscript')
def SharedAsmObjectEmitter(target, source, env):
for tgt in target:
tgt.attributes.shared = 1
return (target, source)
env['BUILDERS']['SharedAsmObject'] = Builder (action = '$CXX -c -fPIC $SOURCE -o $TARGET',
emitter = SharedAsmObjectEmitter,
suffix = '$SHOBJSUFFIX',
src_suffix = '.s',
single_source = 1)
if env['DEVBUILD'] == 1:
if env['BUILD_SSE_OPTIMIZATIONS'] == 1:
arch_specific_objects = env.SharedAsmObject('sse_functions.os', 'sse_functions.s')
libardour = ardour.SharedLibrary('ardour', ardour_files + extra_sources + arch_specific_objects)
else:
if env['BUILD_SSE_OPTIMIZATIONS'] == 1:
arch_specific_objects = env.StaticObject(target='sse_functions',source='sse_functions.s')
libardour = ardour.StaticLibrary('ardour', ardour_files + extra_sources + arch_specific_objects)
Default(libardour)
if env['NLS']:
i18n (ardour, ardour_files + vst_files, env)
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript', 'i18n.h', 'gettext.h', 'sse_functions.s' ] +
ardour_files + vst_files +
glob.glob('po/*.po') + glob.glob('ardour/*.h')))

View File

@@ -0,0 +1 @@
version.h

View File

@@ -0,0 +1,80 @@
/*
Copyright (C) 1999 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$
*/
#ifndef __ardour_ardour_h__
#define __ardour_ardour_h__
#include <limits.h>
#include <string>
#include <signal.h>
#include <pbd/error.h>
#include <pbd/lockmonitor.h>
#include <pbd/failed_constructor.h>
#include <ardour/configuration.h>
#include <ardour/types.h>
using namespace PBD;
namespace MIDI {
class MachineControl;
class Port;
}
namespace ARDOUR {
class AudioEngine;
static const jack_nframes_t max_frames = JACK_MAX_FRAMES;
int init (AudioEngine&, bool with_vst, bool try_optimization, void (*sighandler)(int,siginfo_t*,void*) = 0);
int cleanup ();
std::string find_config_file (std::string name);
std::string find_data_file (std::string name);
const layer_t max_layer = UCHAR_MAX;
id_t new_id();
Change new_change ();
extern Change StartChanged;
extern Change LengthChanged;
extern Change PositionChanged;
extern Change NameChanged;
extern Change BoundsChanged;
struct LocaleGuard {
LocaleGuard (const char*);
~LocaleGuard ();
const char* old;
};
};
/* how do we make these be within the Ardour namespace? */
extern MIDI::Port* default_mmc_port;
extern MIDI::Port* default_mtc_port;
extern MIDI::Port* default_midi_port;
#endif /* __ardour_ardour_h__ */

View File

@@ -0,0 +1,90 @@
/*
Copyright (C) 2003 Paul Davis
Author: Taybin Rutkin
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$
*/
#ifndef __ardour_audio_library_h__
#define __ardour_audio_library_h__
#include <list>
#include <string>
#include <map>
#include <sigc++/signal.h>
using std::list;
using std::string;
using std::map;
namespace ARDOUR {
class AudioLibrary
{
public:
AudioLibrary ();
~AudioLibrary ();
// add_group returns the URI of the created group
string add_group (string group, string parent_uri = "");
void remove_group (string uri);
void get_groups (list<string>& groups, string parent_uri = "");
// add_member returns the URI of the created group
string add_member (string member, string parent_uri = "");
void remove_member (string uri);
void get_members (list<string>& members, string parent_uri = "");
string get_member_filename (string uri);
void search_members_and (list<string>& results,
const map<string,string>& fields);
void search_members_or (list<string>& results,
const map<string,string>& fields);
void add_field (string field);
void get_fields (list<string>& fields);
void remove_field (string field);
string get_field (string uri, string field);
void set_field (string uri, string field, string literal);
string get_label (string uri);
void set_label (string uri, string label);
sigc::signal<void, string, string> added_group; // group, parent
sigc::signal<void, string, string> added_member;// member, parent
sigc::signal<void, string> removed_group;
sigc::signal<void, string> removed_member;
sigc::signal<void> fields_changed;
private:
void save_changes ();
string field_uri (string name);
bool is_rdf_type (string uri, string type);
void remove_uri (string uri);
string src;
void initialize_db();
};
extern AudioLibrary* Library;
} // ARDOUR namespace
#endif // __ardour_audio_library_h__

View File

@@ -0,0 +1,162 @@
/*
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$
*/
#ifndef __ardour_audio_track_h__
#define __ardour_audio_track_h__
#include <ardour/route.h>
namespace ARDOUR {
class Session;
class DiskStream;
class AudioPlaylist;
class AudioTrack : public Route
{
public:
AudioTrack (Session&, string name, Route::Flag f = Route::Flag (0));
AudioTrack (Session&, const XMLNode&);
~AudioTrack ();
int set_name (string str, void *src);
int roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame,
jack_nframes_t offset, int declick, bool can_record, bool rec_monitors_input);
int no_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame,
jack_nframes_t offset, bool state_changing, bool can_record, bool rec_monitors_input);
int silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame,
jack_nframes_t offset, bool can_record, bool rec_monitors_input);
void toggle_monitor_input ();
bool can_record() const { return true; }
void set_record_enable (bool yn, void *src);
DiskStream& disk_stream() const { return *diskstream; }
int set_diskstream (DiskStream&, void *);
int use_diskstream (string name);
int use_diskstream (id_t id);
jack_nframes_t update_total_latency();
void set_latency_delay (jack_nframes_t);
int export_stuff (vector<Sample*>& buffers, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t end_frame);
sigc::signal<void,void*> diskstream_changed;
enum FreezeState {
NoFreeze,
Frozen,
UnFrozen
};
FreezeState freeze_state() const;
sigc::signal<void> FreezeChange;
void freeze (InterThreadInfo&);
void unfreeze ();
void bounce (InterThreadInfo&);
void bounce_range (jack_nframes_t start, jack_nframes_t end, InterThreadInfo&);
XMLNode& get_state();
int set_state(const XMLNode& node);
MIDI::Controllable& midi_rec_enable_control() {
return _midi_rec_enable_control;
}
void reset_midi_control (MIDI::Port*, bool);
void send_all_midi_feedback ();
bool record_enabled() const;
void set_meter_point (MeterPoint, void* src);
protected:
DiskStream *diskstream;
MeterPoint _saved_meter_point;
void passthru_silence (jack_nframes_t start_frame, jack_nframes_t end_frame,
jack_nframes_t nframes, jack_nframes_t offset, int declick,
bool meter);
uint32_t n_process_buffers ();
private:
struct FreezeRecordInsertInfo {
FreezeRecordInsertInfo(XMLNode& st)
: state (st), insert (0) {}
XMLNode state;
Insert* insert;
id_t id;
UndoAction memento;
};
struct FreezeRecord {
FreezeRecord() {
playlist = 0;
have_mementos = false;
}
~FreezeRecord();
AudioPlaylist* playlist;
vector<FreezeRecordInsertInfo*> insert_info;
bool have_mementos;
FreezeState state;
};
FreezeRecord _freeze_record;
XMLNode* pending_state;
void diskstream_record_enable_changed (void *src);
void diskstream_input_channel_changed (void *src);
void input_change_handler (void *src);
sigc::connection recenable_connection;
sigc::connection ic_connection;
XMLNode& state(bool);
int deprecated_use_diskstream_connections ();
void set_state_part_two ();
void set_state_part_three ();
struct MIDIRecEnableControl : public MIDI::Controllable {
MIDIRecEnableControl (AudioTrack&, MIDI::Port *);
void set_value (float);
void send_feedback (bool);
MIDI::byte* write_feedback (MIDI::byte* buf, int32_t& bufsize, bool val, bool force = false);
AudioTrack& track;
bool setting;
bool last_written;
};
MIDIRecEnableControl _midi_rec_enable_control;
};
}; /* namespace ARDOUR*/
#endif /* __ardour_audio_track_h__ */

View File

@@ -0,0 +1,242 @@
/*
Copyright (C) 2002-2004 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
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$
*/
#ifndef __ardour_audioengine_h__
#define __ardour_audioengine_h__
#include <list>
#include <set>
#include <cmath>
#include <exception>
#include <string>
#include <sigc++/signal.h>
#include <pthread.h>
#include <ardour/ardour.h>
#include <jack/jack.h>
#include <jack/transport.h>
namespace ARDOUR {
class Session;
class Port;
class AudioEngine : public sigc::trackable
{
public:
AudioEngine (std::string client_name);
virtual ~AudioEngine ();
jack_client_t* jack() const { return _jack; }
bool connected() const { return _jack != 0; }
std::string client_name() const { return jack_client_name; }
int reconnect_to_jack ();
int disconnect_from_jack();
bool will_reconnect_at_halt ();
void set_reconnect_at_halt (bool);
int stop ();
int start ();
bool running() const { return _running; }
PBD::NonBlockingLock& process_lock() { return _process_lock; }
jack_nframes_t frame_rate();
jack_nframes_t frames_per_cycle();
int usecs_per_cycle () const { return _usecs_per_cycle; }
jack_nframes_t frames_since_cycle_start () {
if (!_running || !_jack) return 0;
return jack_frames_since_cycle_start (_jack);
}
jack_nframes_t frame_time () {
if (!_running || !_jack) return 0;
return jack_frame_time (_jack);
}
jack_nframes_t transport_frame () const {
if (!_running || !_jack) return 0;
return jack_get_current_transport_frame (_jack);
}
int request_buffer_size (jack_nframes_t);
jack_nframes_t set_monitor_check_interval (jack_nframes_t);
float get_cpu_load() {
if (!_running || !_jack) return 0;
return jack_cpu_load (_jack);
}
void set_session (Session *);
void remove_session ();
class PortRegistrationFailure : public std::exception {
public:
virtual const char *what() const throw() { return "failed port registration"; }
};
class NoBackendAvailable : public std::exception {
public:
virtual const char *what() const throw() { return "could not connect to engine backend"; }
};
Port *register_audio_input_port (const string& portname);
Port *register_audio_output_port (const string& portname);
int unregister_port (Port *);
int connect (const string& source, const string& destination);
int disconnect (const string& source, const string& destination);
int disconnect (Port *);
const char ** get_ports (const string& port_name_pattern, const string& type_name_pattern, uint32_t flags);
uint32_t n_physical_outputs () const;
uint32_t n_physical_inputs () const;
string get_nth_physical_output (uint32_t n) {
return get_nth_physical (n, JackPortIsInput);
}
string get_nth_physical_input (uint32_t n) {
return get_nth_physical (n, JackPortIsOutput);
}
jack_nframes_t get_port_total_latency (const Port&);
void update_total_latencies ();
/* the caller may not delete the object pointed to by
the return value
*/
Port *get_port_by_name (const string& name, bool keep = true);
enum TransportState {
TransportStopped = JackTransportStopped,
TransportRolling = JackTransportRolling,
TransportLooping = JackTransportLooping,
TransportStarting = JackTransportStarting
};
void transport_start ();
void transport_stop ();
void transport_locate (jack_nframes_t);
TransportState transport_state ();
int reset_timebase ();
/* start/stop freewheeling */
int freewheel (bool onoff);
bool freewheeling() const { return _freewheeling; }
/* this signal is sent for every process() cycle while freewheeling.
the regular process() call to session->process() is not made.
*/
sigc::signal<int,jack_nframes_t> Freewheel;
sigc::signal<void> Xrun;
/* this signal is if JACK notifies us of a graph order event */
sigc::signal<void> GraphReordered;
/* this signal is emitted if the sample rate changes */
sigc::signal<void,jack_nframes_t> SampleRateChanged;
/* this signal is sent if JACK ever disconnects us */
sigc::signal<void> Halted;
/* these two are emitted when the engine itself is
started and stopped
*/
sigc::signal<void> Running;
sigc::signal<void> Stopped;
std::string make_port_name_relative (std::string);
std::string make_port_name_non_relative (std::string);
private:
ARDOUR::Session *session;
jack_client_t *_jack;
std::string jack_client_name;
PBD::NonBlockingLock port_lock;
PBD::NonBlockingLock _process_lock;
PBD::Lock session_remove_lock;
pthread_cond_t session_removed;
bool session_remove_pending;
bool _running;
bool _has_run;
jack_nframes_t _buffer_size;
jack_nframes_t _frame_rate;
jack_nframes_t monitor_check_interval;
jack_nframes_t last_monitor_check;
jack_nframes_t _processed_frames;
bool _freewheeling;
bool _freewheel_thread_registered;
sigc::slot<int,jack_nframes_t> freewheel_action;
bool reconnect_on_halt;
int _usecs_per_cycle;
typedef std::set<Port*> Ports;
Ports ports;
int process_callback (jack_nframes_t nframes);
void remove_all_ports ();
typedef std::pair<std::string,std::string> PortConnection;
typedef std::list<PortConnection> PortConnections;
PortConnections port_connections;
void remove_connections_for (Port*);
string get_nth_physical (uint32_t which, int flags);
static int _xrun_callback (void *arg);
static int _graph_order_callback (void *arg);
static int _process_callback (jack_nframes_t nframes, void *arg);
static int _sample_rate_callback (jack_nframes_t nframes, void *arg);
static int _bufsize_callback (jack_nframes_t nframes, void *arg);
static void _jack_timebase_callback (jack_transport_state_t, jack_nframes_t, jack_position_t*, int, void*);
static int _jack_sync_callback (jack_transport_state_t, jack_position_t*, void *arg);
static void _freewheel_callback (int , void *arg);
void jack_timebase_callback (jack_transport_state_t, jack_nframes_t, jack_position_t*, int);
int jack_sync_callback (jack_transport_state_t, jack_position_t*);
int jack_bufsize_callback (jack_nframes_t);
int jack_sample_rate_callback (jack_nframes_t);
static void halted (void *);
static void meter (Port *port, jack_nframes_t nframes);
int connect_to_jack (std::string client_name);
};
}; /* namespace ARDOUR */
#endif /* __ardour_audioengine_h__ */

View File

@@ -0,0 +1,53 @@
/*
Copyright (C) 2004 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
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$
*/
#ifndef __ardour_audiofilter_h__
#define __ardour_audiofilter_h__
#include <vector>
#include <ardour/audioregion.h>
namespace ARDOUR {
class AudioRegion;
class Session;
class FileSource;
class AudioFilter {
public:
AudioFilter (ARDOUR::Session& s)
: session (s){}
virtual ~AudioFilter() {}
virtual int run (ARDOUR::AudioRegion&) = 0;
std::vector<ARDOUR::AudioRegion*> results;
protected:
ARDOUR::Session& session;
int make_new_sources (ARDOUR::AudioRegion&, ARDOUR::AudioRegion::SourceList&);
int finish (ARDOUR::AudioRegion&, ARDOUR::AudioRegion::SourceList&);
};
} /* namespace */
#endif /* __ardour_audiofilter_h__ */

View File

@@ -0,0 +1,121 @@
/*
Copyright (C) 2003 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$
*/
#ifndef __ardour_audio_playlist_h__
#define __ardour_audio_playlist_h__
#include <vector>
#include <list>
#include <ardour/ardour.h>
#include <ardour/playlist.h>
namespace ARDOUR {
class Session;
class Region;
class AudioRegion;
class Source;
class AudioPlaylist : public ARDOUR::Playlist
{
public:
typedef std::list<Crossfade*> Crossfades;
private:
struct State : public ARDOUR::StateManager::State {
RegionList regions;
std::list<UndoAction> region_states;
Crossfades crossfades;
std::list<UndoAction> crossfade_states;
State (std::string why) : ARDOUR::StateManager::State (why) {}
~State ();
};
public:
AudioPlaylist (Session&, const XMLNode&, bool hidden = false);
AudioPlaylist (Session&, string name, bool hidden = false);
AudioPlaylist (const AudioPlaylist&, string name, bool hidden = false);
AudioPlaylist (const AudioPlaylist&, jack_nframes_t start, jack_nframes_t cnt, string name, bool hidden = false);
void clear (bool with_delete = false, bool with_save = true);
jack_nframes_t read (Sample *dst, Sample *mixdown, float *gain_buffer, jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n=0);
int set_state (const XMLNode&);
UndoAction get_memento() const;
sigc::signal<void,Crossfade *> NewCrossfade;
template<class T> void foreach_crossfade (T *t, void (T::*func)(Crossfade *));
void crossfades_at (jack_nframes_t frame, Crossfades&);
template<class T> void apply_to_history (T& obj, void (T::*method)(const ARDOUR::StateManager::StateMap&, state_id_t)) {
RegionLock rlock (this);
(obj.*method) (states, _current_state_id);
}
bool destroy_region (Region*);
void get_equivalent_regions (const AudioRegion&, std::vector<AudioRegion*>&);
void get_region_list_equivalent_regions (const AudioRegion&, std::vector<AudioRegion*>&);
void drop_all_states ();
protected:
/* state management */
StateManager::State* state_factory (std::string) const;
Change restore_state (StateManager::State&);
void send_state_change (Change);
/* playlist "callbacks" */
void notify_crossfade_added (Crossfade *);
void flush_notifications ();
void refresh_dependents (Region& region);
void check_dependents (Region& region, bool norefresh);
void remove_dependents (Region& region);
protected:
~AudioPlaylist (); /* public should use unref() */
private:
Crossfades _crossfades;
Crossfades _pending_xfade_adds;
void crossfade_invalidated (Crossfade*);
XMLNode& state (bool full_state);
void dump () const;
bool region_changed (Change, Region*);
void crossfade_changed (Change);
void add_crossfade (Crossfade&);
};
} /* namespace ARDOUR */
#endif /* __ardour_audio_playlist_h__ */

View File

@@ -0,0 +1,229 @@
/*
Copyright (C) 2000-2001 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$
*/
#ifndef __ardour_audio_region_h__
#define __ardour_audio_region_h__
#include <vector>
#include <pbd/fastlog.h>
#include <pbd/undo.h>
#include <ardour/ardour.h>
#include <ardour/source.h>
#include <ardour/gain.h>
#include <ardour/region.h>
#include <ardour/export.h>
class XMLNode;
namespace ARDOUR {
class Route;
class Playlist;
class Session;
class AudioFilter;
struct AudioRegionState : public RegionState
{
AudioRegionState (std::string why);
Curve _fade_in;
Curve _fade_out;
Curve _envelope;
gain_t _scale_amplitude;
uint32_t _fade_in_disabled;
uint32_t _fade_out_disabled;
};
class AudioRegion : public Region
{
public:
typedef vector<Source *> SourceList;
static Change FadeInChanged;
static Change FadeOutChanged;
static Change FadeInActiveChanged;
static Change FadeOutActiveChanged;
static Change EnvelopeActiveChanged;
static Change ScaleAmplitudeChanged;
static Change EnvelopeChanged;
AudioRegion (Source&, jack_nframes_t start, jack_nframes_t length, bool announce = true);
AudioRegion (Source&, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
AudioRegion (SourceList &, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
AudioRegion (const AudioRegion&, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
AudioRegion (const AudioRegion&);
AudioRegion (Source&, const XMLNode&);
AudioRegion (SourceList &, const XMLNode&);
~AudioRegion();
bool region_list_equivalent (const AudioRegion&);
bool source_equivalent (const AudioRegion&);
bool equivalent (const AudioRegion&);
bool size_equivalent (const AudioRegion&);
void lock_sources ();
void unlock_sources ();
Source& source (uint32_t n=0) const { if (n < sources.size()) return *sources[n]; else return *sources[0]; }
void set_scale_amplitude (gain_t);
gain_t scale_amplitude() const { return _scale_amplitude; }
void normalize_to (float target_in_dB = 0.0f);
uint32_t n_channels() { return sources.size(); }
vector<string> master_source_names();
bool envelope_active () const { return _flags & Region::EnvelopeActive; }
bool fade_in_active () const { return _flags & Region::FadeIn; }
bool fade_out_active () const { return _flags & Region::FadeOut; }
bool captured() const { return !(_flags & (Region::Flag (Region::Import|Region::External))); }
Curve& fade_in() { return _fade_in; }
Curve& fade_out() { return _fade_out; }
Curve& envelope() { return _envelope; }
jack_nframes_t read_peaks (PeakData *buf, jack_nframes_t npeaks, jack_nframes_t offset, jack_nframes_t cnt, uint32_t chan_n=0, double samples_per_unit= 1.0) const;
virtual jack_nframes_t read_at (Sample *buf, Sample *mixdown_buffer,
float *gain_buffer, jack_nframes_t position, jack_nframes_t cnt,
uint32_t chan_n = 0,
jack_nframes_t read_frames = 0,
jack_nframes_t skip_frames = 0) const;
jack_nframes_t master_read_at (Sample *buf, Sample *mixdown_buffer,
float *gain_buffer, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n=0) const;
XMLNode& state (bool);
XMLNode& get_state ();
int set_state (const XMLNode&);
static void set_default_fade (float steepness, jack_nframes_t len);
enum FadeShape {
Linear,
Fast,
Slow,
LogA,
LogB,
};
void set_fade_in_active (bool yn);
void set_fade_in_shape (FadeShape);
void set_fade_in_length (jack_nframes_t);
void set_fade_in (FadeShape, jack_nframes_t);
void set_fade_out_active (bool yn);
void set_fade_out_shape (FadeShape);
void set_fade_out_length (jack_nframes_t);
void set_fade_out (FadeShape, jack_nframes_t);
void set_envelope_active (bool yn);
int separate_by_channel (ARDOUR::Session&, vector<AudioRegion*>&) const;
uint32_t read_data_count() const { return _read_data_count; }
ARDOUR::Playlist* playlist() const { return _playlist; }
UndoAction get_memento() const;
/* filter */
int apply (AudioFilter&);
/* export */
int exportme (ARDOUR::Session&, ARDOUR::AudioExportSpecification&);
Region* get_parent();
/* xfade/fade interactions */
void suspend_fade_in ();
void suspend_fade_out ();
void resume_fade_in ();
void resume_fade_out ();
private:
friend class Playlist;
private:
SourceList sources;
SourceList master_sources; /* used when timefx are applied, so
we can always use the original
source.
*/
mutable Curve _fade_in;
FadeShape _fade_in_shape;
mutable Curve _fade_out;
FadeShape _fade_out_shape;
mutable Curve _envelope;
gain_t _scale_amplitude;
uint32_t _fade_in_disabled;
uint32_t _fade_out_disabled;
void set_default_fades ();
void set_default_fade_in ();
void set_default_fade_out ();
void set_default_envelope ();
StateManager::State* state_factory (std::string why) const;
Change restore_state (StateManager::State&);
void recompute_gain_at_end ();
void recompute_gain_at_start ();
bool copied() const { return _flags & Copied; }
void maybe_uncopy ();
void rename_after_first_edit ();
jack_nframes_t _read_at (const SourceList&, Sample *buf, Sample *mixdown_buffer,
float *gain_buffer, jack_nframes_t position, jack_nframes_t cnt,
uint32_t chan_n = 0,
jack_nframes_t read_frames = 0,
jack_nframes_t skip_frames = 0) const;
bool verify_start (jack_nframes_t position);
bool verify_length (jack_nframes_t position);
bool verify_start_mutable (jack_nframes_t& start);
bool verify_start_and_length (jack_nframes_t start, jack_nframes_t length);
void recompute_at_start ();
void recompute_at_end ();
void envelope_changed (Change);
void source_deleted (Source*);
};
} /* namespace ARDOUR */
/* access from C objects */
extern "C" {
int region_read_peaks_from_c (void *arg, uint32_t npeaks, uint32_t start, uint32_t length, intptr_t data, uint32_t n_chan, double samples_per_unit);
uint32_t region_length_from_c (void *arg);
uint32_t sourcefile_length_from_c (void *arg);
}
#endif /* __ardour_audio_region_h__ */

View File

@@ -0,0 +1,73 @@
/*
Copyright (C) 2001 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$
*/
#ifndef __ardour_auditioner_h__
#define __ardour_auditioner_h__
#include <string>
#include <pthread.h>
#include <pbd/lockmonitor.h>
#include <pbd/atomic.h>
#include <ardour/ardour.h>
#include <ardour/audio_track.h>
namespace ARDOUR {
class Session;
class AudioRegion;
class AudioPlaylist;
class Auditioner : public AudioTrack
{
public:
Auditioner (Session&);
~Auditioner ();
void audition_region (AudioRegion&);
ARDOUR::AudioPlaylist& prepare_playlist ();
void audition_current_playlist ();
int play_audition (jack_nframes_t nframes);
void cancel_audition () {
atomic_set (&_active, 0);
}
bool active() const { return atomic_read (&_active); }
private:
AudioRegion *the_region;
jack_nframes_t current_frame;
atomic_t _active;
PBD::Lock lock;
jack_nframes_t length;
void drop_ports ();
static void *_drop_ports (void *);
void actually_drop_ports ();
void output_changed (IOChange, void*);
};
}; /* namespace ARDOUR */
#endif /* __ardour_auditioner_h__ */

View File

@@ -0,0 +1,247 @@
/*
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$
*/
#ifndef __ardour_automation_event_h__
#define __ardour_automation_event_h__
#include <stdint.h>
#include <list>
#include <cmath>
#include <sigc++/signal.h>
#include <pbd/lockmonitor.h>
#include <pbd/undo.h>
#include <pbd/xml++.h>
#include <ardour/ardour.h>
#include <ardour/state_manager.h>
namespace ARDOUR {
struct ControlEvent {
double when;
double value;
ControlEvent (double w, double v)
: when (w), value (v) { }
ControlEvent (const ControlEvent& other)
: when (other.when), value (other.value) {}
virtual ~ControlEvent() {}
// bool operator==(const ControlEvent& other) {
// return value == other.value && when == other.when;
// }
};
class AutomationList : public StateManager
{
public:
typedef std::list<ControlEvent*> AutomationEventList;
typedef AutomationEventList::iterator iterator;
typedef AutomationEventList::const_iterator const_iterator;
AutomationList(double default_value, bool no_state = false);
~AutomationList();
AutomationList (const AutomationList&);
AutomationList (const AutomationList&, double start, double end);
AutomationList& operator= (const AutomationList&);
bool operator== (const AutomationList&);
void freeze();
void thaw ();
AutomationEventList::size_type size() const { return events.size(); }
bool empty() const { return events.empty(); }
void reset_default (double val) {
default_value = val;
}
void clear ();
void x_scale (double factor);
bool extend_to (double);
void reposition_for_rt_add (double when);
void rt_add (double when, double value);
iterator add (double when, double value, iterator, bool ignore_mode = false);
void add (double when, double value, bool for_loading = false);
void erase_range (double start, double end);
void erase (iterator);
void erase (iterator, iterator);
void move_range (iterator start, iterator end, double, double);
void modify (iterator, double, double);
AutomationList* cut (double, double);
AutomationList* copy (double, double);
void clear (double, double);
AutomationList* cut (iterator, iterator);
AutomationList* copy (iterator, iterator);
void clear (iterator, iterator);
bool paste (AutomationList&, double position, float times);
void set_automation_state (AutoState);
AutoState automation_state() const { return _state; }
sigc::signal<void> automation_style_changed;
void set_automation_style (AutoStyle m);
AutoStyle automation_style() const { return _style; }
sigc::signal<void> automation_state_changed;
bool automation_playback() {
return (_state & Play) || ((_state & Touch) && !_touching);
}
bool automation_write () {
return (_state & Write) || ((_state & Touch) && _touching);
}
void start_touch ();
void stop_touch ();
bool touching() const { return _touching; }
void set_yrange (double min, double max) {
min_yval = min;
max_yval = max;
}
double get_max_y() const { return max_yval; }
double get_min_y() const { return min_yval; }
void truncate_end (double length);
void truncate_start (double length);
iterator begin() { return events.begin(); }
iterator end() { return events.end(); }
ControlEvent* back() { return events.back(); }
ControlEvent* front() { return events.front(); }
const_iterator const_begin() const { return events.begin(); }
const_iterator const_end() const { return events.end(); }
std::pair<AutomationList::iterator,AutomationList::iterator> control_points_adjacent (double when);
template<class T> void apply_to_points (T& obj, void (T::*method)(const AutomationList&)) {
LockMonitor lm (lock, __LINE__, __FILE__);
(obj.*method)(*this);
}
UndoAction get_memento () const;
virtual void store_state (XMLNode& node) const;
virtual void load_state (const XMLNode&);
void set_max_xval (double);
double get_max_xval() const { return max_xval; }
double eval (double where) {
LockMonitor lm (lock, __LINE__, __FILE__);
return unlocked_eval (where);
}
double rt_safe_eval (double where, bool& ok) {
TentativeLockMonitor lm (lock, __LINE__, __FILE__);
if ((ok = lm.locked())) {
return unlocked_eval (where);
} else {
return 0.0;
}
}
struct TimeComparator {
bool operator() (const ControlEvent* a, const ControlEvent* b) {
return a->when < b->when;
}
};
protected:
struct State : public ARDOUR::StateManager::State {
AutomationEventList events;
State (std::string why) : ARDOUR::StateManager::State (why) {}
};
AutomationEventList events;
mutable PBD::NonBlockingLock lock;
bool _frozen;
bool changed_when_thawed;
bool _dirty;
struct LookupCache {
double left; /* leftmost x coordinate used when finding "range" */
std::pair<AutomationList::iterator,AutomationList::iterator> range;
};
LookupCache lookup_cache;
AutoState _state;
AutoStyle _style;
bool _touching;
bool _new_touch;
double max_xval;
double min_yval;
double max_yval;
double default_value;
bool no_state;
iterator rt_insertion_point;
double rt_pos;
void maybe_signal_changed ();
void mark_dirty ();
void _x_scale (double factor);
/* called by type-specific unlocked_eval() to handle
common case of 0, 1 or 2 control points.
*/
double shared_eval (double x);
/* called by shared_eval() to handle any case of
3 or more control points.
*/
virtual double multipoint_eval (double x);
/* called by locked entry point and various private
locations where we already hold the lock.
*/
virtual double unlocked_eval (double where);
Change restore_state (StateManager::State&);
StateManager::State* state_factory (std::string why) const;
virtual ControlEvent* point_factory (double,double) const;
virtual ControlEvent* point_factory (const ControlEvent&) const;
AutomationList* cut_copy_clear (double, double, int op);
};
} // namespace
#endif /* __ardour_automation_event_h__ */

View File

@@ -0,0 +1,46 @@
/*
Copyright (C) 2004 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
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$
*/
#ifndef __ardour_click_h__
#define __ardour_click_h__
#include <ardour/io.h>
namespace ARDOUR {
class ClickIO : public IO
{
public:
ClickIO (Session& s, const string& name,
int input_min = -1, int input_max = -1,
int output_min = -1, int output_max = -1)
: IO (s, name, input_min, input_max, output_min, output_max) {}
~ClickIO() {}
protected:
uint32_t pans_required () const { return 1; }
};
}; /* namespace ARDOUR */
#endif /*__ardour_click_h__ */

View File

@@ -0,0 +1,57 @@
/* config.h. Generated automatically by configure. */
/* config.h.in. Generated automatically from configure.in by autoheader. */
/* Define if you don't have vprintf but do have _doprnt. */
/* #undef HAVE_DOPRNT */
/* Define if you have the vprintf function. */
/* #undef HAVE_VPRINTF */
/* Define if you have the ANSI C header files. */
/* #undef STDC_HEADERS */
/* Define if your <sys/time.h> declares struct tm. */
/* #undef TM_IN_SYS_TIME */
/* Define if you have the regcomp function. */
/* #undef HAVE_REGCOMP */
/* Define if you have the strerror function. */
/* #undef HAVE_STRERROR */
/* Define if you have the <dirent.h> header file. */
#define HAVE_DIRENT_H 1
/* Define if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define if you have the <ladspa.h> header file. */
#define HAVE_LADSPA_H 1
/* Define if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define if you have the <ndir.h> header file. */
/* #undef HAVE_NDIR_H */
/* Define if you have the <sys/dir.h> header file. */
/* #undef HAVE_SYS_DIR_H */
/* Define if you have the <sys/ndir.h> header file. */
/* #undef HAVE_SYS_NDIR_H */
/* Define if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define if you have the gdbm library (-lgdbm). */
#define HAVE_LIBGDBM 1
/* Define if you have the sndfile library (-lsndfile). */
#define HAVE_LIBSNDFILE 1
/* Name of package */
#define PACKAGE "ardour"
/* Version number of package */
#define VERSION "0.107.3"

View File

@@ -0,0 +1,253 @@
/*
Copyright (C) 1999 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$
*/
#ifndef __ardour_configuration_h__
#define __ardour_configuration_h__
#include <map>
#include <sys/types.h>
#include <string>
#include <ardour/types.h>
#include <ardour/stateful.h>
using std::string;
class XMLNode;
namespace ARDOUR {
class Configuration : public Stateful
{
public:
Configuration();
virtual ~Configuration();
struct MidiPortDescriptor {
string tag;
string device;
string type;
string mode;
MidiPortDescriptor (const XMLNode&);
XMLNode& get_state();
};
std::map<string,MidiPortDescriptor *> midi_ports;
int load_state ();
int save_state ();
XMLNode& option_node (const string &, const string &);
int set_state (const XMLNode&);
XMLNode& get_state (void);
XMLNode * get_keys() const;
void set_keys(XMLNode *);
void set_use_vst (bool yn);
bool get_use_vst();
bool get_trace_midi_input ();
void set_trace_midi_input (bool);
bool get_trace_midi_output ();
void set_trace_midi_output (bool);
string get_raid_path();
void set_raid_path(string);
uint32_t get_minimum_disk_io();
void set_minimum_disk_io(uint32_t);
float get_track_buffer();
void set_track_buffer(float);
bool does_hiding_groups_deactivates_groups();
void set_hiding_groups_deactivates_groups(bool);
string get_auditioner_output_left();
void set_auditioner_output_left(string);
string get_auditioner_output_right();
void set_auditioner_output_right(string);
bool get_mute_affects_pre_fader();
void set_mute_affects_pre_fader (bool);
bool get_mute_affects_post_fader();
void set_mute_affects_post_fader (bool);
bool get_mute_affects_control_outs ();
void set_mute_affects_control_outs (bool);
bool get_mute_affects_main_outs ();
void set_mute_affects_main_outs (bool);
bool get_solo_latch ();
void set_solo_latch (bool);
uint32_t get_disk_choice_space_threshold();
void set_disk_choice_space_threshold (uint32_t);
string get_mmc_port_name();
void set_mmc_port_name(string);
string get_mtc_port_name();
void set_mtc_port_name(string);
string get_midi_port_name();
void set_midi_port_name(string);
bool get_use_hardware_monitoring();
void set_use_hardware_monitoring(bool);
bool get_jack_time_master();
void set_jack_time_master(bool);
bool get_native_format_is_bwf();
void set_native_format_is_bwf(bool);
bool get_plugins_stop_with_transport();
void set_plugins_stop_with_transport(bool);
bool get_no_sw_monitoring();
void set_no_sw_monitoring(bool);
bool get_stop_recording_on_xrun();
void set_stop_recording_on_xrun(bool);
bool get_verify_remove_last_capture();
void set_verify_remove_last_capture(bool);
bool get_stop_at_session_end();
void set_stop_at_session_end(bool);
bool get_seamless_looping();
void set_seamless_looping(bool);
bool get_auto_xfade();
void set_auto_xfade (bool);
bool get_no_new_session_dialog();
void set_no_new_session_dialog(bool);
uint32_t get_timecode_skip_limit ();
void set_timecode_skip_limit (uint32_t);
bool get_timecode_source_is_synced ();
void set_timecode_source_is_synced (bool);
string get_user_ardour_path ();
string get_system_ardour_path ();
gain_t get_quieten_at_speed ();
void set_quieten_at_speed (gain_t);
private:
void set_defaults ();
string get_system_path();
string get_user_path();
/* this is subject to wordexp, so we need
to keep the original (user-entered) form
around. e.g. ~/blah-> /home/foo/blah
*/
string raid_path;
bool raid_path_is_user;
string orig_raid_path;
uint32_t minimum_disk_io_bytes;
bool minimum_disk_io_bytes_is_user;
float track_buffer_seconds;
bool track_buffer_seconds_is_user;
bool hiding_groups_deactivates_groups;
bool hiding_groups_deactivates_groups_is_user;
string auditioner_output_left;
bool auditioner_output_left_is_user;
string auditioner_output_right;
bool auditioner_output_right_is_user;
bool mute_affects_pre_fader;
bool mute_affects_pre_fader_is_user;
bool mute_affects_post_fader;
bool mute_affects_post_fader_is_user;
bool mute_affects_control_outs;
bool mute_affects_control_outs_is_user;
bool mute_affects_main_outs;
bool mute_affects_main_outs_is_user;
bool solo_latch;
bool solo_latch_is_user;
uint32_t disk_choice_space_threshold;
bool disk_choice_space_threshold_is_user;
string mtc_port_name;
bool mtc_port_name_is_user;
string mmc_port_name;
bool mmc_port_name_is_user;
string midi_port_name;
bool midi_port_name_is_user;
bool use_hardware_monitoring;
bool use_hardware_monitoring_is_user;
bool be_jack_time_master;
bool be_jack_time_master_is_user;
bool native_format_is_bwf;
bool native_format_is_bwf_is_user;
bool trace_midi_input;
bool trace_midi_input_is_user;
bool trace_midi_output;
bool trace_midi_output_is_user;
bool plugins_stop_with_transport;
bool plugins_stop_with_transport_is_user;
bool no_sw_monitoring;
bool no_sw_monitoring_is_user;
bool stop_recording_on_xrun;
bool stop_recording_on_xrun_is_user;
bool verify_remove_last_capture;
bool verify_remove_last_capture_is_user;
bool stop_at_session_end;
bool stop_at_session_end_is_user;
bool seamless_looping;
bool seamless_looping_is_user;
bool auto_xfade;
bool auto_xfade_is_user;
bool no_new_session_dialog;
bool no_new_session_dialog_is_user;
uint32_t timecode_skip_limit;
bool timecode_skip_limit_is_user;
bool timecode_source_is_synced;
bool timecode_source_is_synced_is_user;
bool use_vst; /* always per-user */
bool quieten_at_speed;
bool quieten_at_speed_is_user;
XMLNode *key_node;
bool user_configuration;
XMLNode& state (bool user_only);
};
extern Configuration *Config;
extern gain_t speed_quietning; /* see comment in configuration.cc */
}; /* namespace ARDOUR */
#endif /* __ardour_configuration_h__ */

View File

@@ -0,0 +1,94 @@
/*
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$
*/
#ifndef __ardour_connection_h__
#define __ardour_connection_h__
#include <vector>
#include <string>
#include <sigc++/signal.h>
#include <pbd/lockmonitor.h>
#include <ardour/stateful.h>
using std::vector;
using std::string;
namespace ARDOUR {
class Connection : public Stateful, public sigc::trackable {
public:
Connection (string name, bool sdep = false) : _name (name), _sysdep(sdep) {}
~Connection() {}
typedef vector<string> PortList;
void set_name (string name, void *src);
string name() const { return _name; }
bool system_dependent() const { return _sysdep; }
uint32_t nports () const { return _ports.size(); }
const PortList& port_connections (int port) const;
void add_connection (int port, string portname);
void remove_connection (int port, string portname);
void add_port ();
void remove_port (int port);
void clear ();
sigc::signal<void,void*> NameChanged;
sigc::signal<void> ConfigurationChanged;
sigc::signal<void,int> ConnectionsChanged;
bool operator==(const Connection& other) const;
XMLNode& get_state (void);
int set_state (const XMLNode&);
protected:
Connection (const XMLNode&);
private:
mutable PBD::Lock port_lock;
vector<PortList> _ports;
string _name;
bool _sysdep;
int set_connections (const string& str);
int parse_io_string (const string& str, vector<string>& ports);
};
class InputConnection : public Connection {
public:
InputConnection (string name, bool sdep = false) : Connection (name, sdep) {}
InputConnection (const XMLNode&);
};
class OutputConnection : public Connection {
public:
OutputConnection (string name, bool sdep = false) : Connection (name, sdep) {}
OutputConnection (const XMLNode&);
};
}
#endif /* __ardour_connection_h__ */

View File

@@ -0,0 +1,60 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __playlist_const_buffer_h__
#define __playlist_const_buffer_h__
#include <string>
#include <cstdlib>
#include "edl.h"
namespace EDL {
class ConstSource : public Source {
public:
ConstSource (const gchar *id) {
_type = Source::Const;
value = strtod (id, 0);
strncpy (idstr, id, 15);
idstr[15] = '\0';
}
const gchar * const id() { return idstr; }
uint32_t length() { return ~0U; }
uint32_t read (Source::Data *dst, uint32_t start, uint32_t cnt) {
uint32_t n = cnt;
while (n--) *dst++ = value;
return cnt;
}
void peak (guint8 *max, guint8 *min, uint32_t start, uint32_t cnt) {
*max = *min = (guint8) value;
}
private:
Source::Data value;
gchar idstr[16];
};
}; /* namespace EDL */
#endif /* __playlist_const_buffer_h__ */

View File

@@ -0,0 +1,182 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __ardour_overlap_h__
#define __ardour_overlap_h__
#include <vector>
#include <algorithm>
#include <sigc++/signal.h>
#include <pbd/undo.h>
#include <ardour/ardour.h>
#include <ardour/curve.h>
#include <ardour/audioregion.h>
#include <ardour/state_manager.h>
#include <ardour/crossfade_compare.h>
namespace ARDOUR {
class AudioRegion;
class Playlist;
struct CrossfadeState : public StateManager::State {
CrossfadeState (std::string reason) : StateManager::State (reason) {}
UndoAction fade_in_memento;
UndoAction fade_out_memento;
jack_nframes_t position;
jack_nframes_t length;
AnchorPoint anchor_point;
bool follow_overlap;
bool active;
};
class Crossfade : public Stateful, public StateManager
{
public:
class NoCrossfadeHere: std::exception {
public:
virtual const char *what() const throw() { return "no crossfade should be constructed here"; }
};
/* constructor for "fixed" xfades at each end of an internal overlap */
Crossfade (ARDOUR::AudioRegion& in, ARDOUR::AudioRegion& out,
jack_nframes_t position,
jack_nframes_t initial_length,
AnchorPoint);
/* constructor for xfade between two regions that are overlapped in any way
except the "internal" case.
*/
Crossfade (ARDOUR::AudioRegion& in, ARDOUR::AudioRegion& out, CrossfadeModel, bool active);
/* the usual XML constructor */
Crossfade (const ARDOUR::Playlist&, XMLNode&);
virtual ~Crossfade();
bool operator== (const ARDOUR::Crossfade&);
XMLNode& get_state (void);
int set_state (const XMLNode&);
ARDOUR::AudioRegion& in() const { return *_in; }
ARDOUR::AudioRegion& out() const { return *_out; }
jack_nframes_t read_at (Sample *buf, Sample *mixdown_buffer,
float *gain_buffer, jack_nframes_t position, jack_nframes_t cnt,
uint32_t chan_n,
jack_nframes_t read_frames = 0,
jack_nframes_t skip_frames = 0);
bool refresh ();
uint32_t upper_layer () const {
return std::max (_in->layer(), _out->layer());
}
uint32_t lower_layer () const {
return std::min (_in->layer(), _out->layer());
}
bool involves (ARDOUR::AudioRegion& region) const {
return _in == &region || _out == &region;
}
bool involves (ARDOUR::AudioRegion& a, ARDOUR::AudioRegion& b) const {
return (_in == &a && _out == &b) || (_in == &b && _out == &a);
}
jack_nframes_t length() const { return _length; }
jack_nframes_t overlap_length() const;
jack_nframes_t position() const { return _position; }
sigc::signal<void,Crossfade*> Invalidated;
sigc::signal<void> GoingAway;
bool covers (jack_nframes_t frame) const {
return _position <= frame && frame < _position + _length;
}
OverlapType coverage (jack_nframes_t start, jack_nframes_t end) const;
UndoAction get_memento() const;
static void set_buffer_size (jack_nframes_t);
bool active () const { return _active; }
void set_active (bool yn);
bool following_overlap() const { return _follow_overlap; }
bool can_follow_overlap() const;
void set_follow_overlap (bool yn);
Curve& fade_in() { return _fade_in; }
Curve& fade_out() { return _fade_out; }
jack_nframes_t set_length (jack_nframes_t);
static jack_nframes_t short_xfade_length() { return _short_xfade_length; }
static void set_short_xfade_length (jack_nframes_t n);
static Change ActiveChanged;
private:
friend struct CrossfadeComparePtr;
static jack_nframes_t _short_xfade_length;
ARDOUR::AudioRegion* _in;
ARDOUR::AudioRegion* _out;
bool _active;
bool _in_update;
OverlapType overlap_type;
jack_nframes_t _length;
jack_nframes_t _position;
AnchorPoint _anchor_point;
bool _follow_overlap;
bool _fixed;
Curve _fade_in;
Curve _fade_out;
static Sample* crossfade_buffer_out;
static Sample* crossfade_buffer_in;
void initialize ();
int compute (ARDOUR::AudioRegion&, ARDOUR::AudioRegion&, CrossfadeModel);
bool update (bool force);
StateManager::State* state_factory (std::string why) const;
Change restore_state (StateManager::State&);
void member_changed (ARDOUR::Change);
};
} // namespace ARDOUR
#endif /* __ardour_overlap_h__ */

View File

@@ -0,0 +1,43 @@
/*
Copyright (C) 2003 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$
*/
#ifndef __ardour_crossfade_compare_h__
#define __ardour_crossfade_compare_h__
/* this exists so that playlist.h doesn't have to include crossfade.h
*/
namespace ARDOUR {
class Crossfade;
struct CrossfadeComparePtr {
bool operator() (const Crossfade *a, const Crossfade *b) const;
};
enum AnchorPoint {
StartOfIn,
EndOfIn,
EndOfOut
};
}
#endif /* __ardour_crossfade_compare_h__ */

View File

@@ -0,0 +1,86 @@
/*
Copyright (C) 2001-2003 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$
*/
#ifndef __ardour_curve_h__
#define __ardour_curve_h__
#include <sys/types.h>
#include <sigc++/signal.h>
#include <pbd/lockmonitor.h>
#include <pbd/undo.h>
#include <list>
#include <algorithm>
#include <pthread.h>
#include <ardour/automation_event.h>
namespace ARDOUR {
struct CurvePoint : public ControlEvent
{
double coeff[4];
CurvePoint (double w, double v)
: ControlEvent (w, v) {
coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0.0;
}
~CurvePoint() {}
};
class Curve : public AutomationList
{
public:
Curve (double min_yval, double max_yval, double defaultvalue, bool nostate = false);
~Curve ();
Curve (const Curve& other);
Curve (const Curve& other, double start, double end);
bool rt_safe_get_vector (double x0, double x1, float *arg, int32_t veclen);
void get_vector (double x0, double x1, float *arg, int32_t veclen);
AutomationEventList::iterator closest_control_point_before (double xval);
AutomationEventList::iterator closest_control_point_after (double xval);
void solve ();
protected:
ControlEvent* point_factory (double,double) const;
ControlEvent* point_factory (const ControlEvent&) const;
Change restore_state (StateManager::State&);
private:
AutomationList::iterator last_bound;
double unlocked_eval (double where);
double multipoint_eval (double x);
void _get_vector (double x0, double x1, float *arg, int32_t veclen);
};
}; /* namespace ARDOUR */
extern "C" {
void curve_get_vector_from_c (void *arg, double, double, float*, int32_t);
}
#endif /* __ardour_curve_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$
*/
#ifndef __ardour_cycle_timer_h__
#define __ardour_cycle_timer_h__
#include <string>
#include <cstdio>
#include <ardour/cycles.h>
using std::string;
class CycleTimer {
private:
static float cycles_per_usec;
uint32_t long entry;
uint32_t long exit;
string _name;
public:
CycleTimer(string name) : _name (name){
if (cycles_per_usec == 0) {
cycles_per_usec = get_mhz ();
}
entry = get_cycles();
}
~CycleTimer() {
exit = get_cycles();
printf ("%s: %.9f usecs (%lu-%lu)\n", _name.c_str(), (float) (exit - entry) / cycles_per_usec, entry, exit);
}
static float get_mhz ();
};
#endif /* __ardour_cycle_timer_h__ */

221
libs/ardour/ardour/cycles.h Normal file
View File

@@ -0,0 +1,221 @@
/*
Copyright (C) 2001 Paul Davis
Code derived from various headers from the Linux kernel
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$
*/
#ifndef __ardour_cycles_h__
#define __ardour_cycles_h__
#include <stdint.h>
#if defined(__i386__) || defined(__x86_64__)
/*
* Standard way to access the cycle counter on i586+ CPUs.
* Currently only used on SMP.
*
* If you really have a SMP machine with i486 chips or older,
* compile for that, and this will just always return zero.
* That's ok, it just means that the nicer scheduling heuristics
* won't work for you.
*
* We only use the low 32 bits, and we'd simply better make sure
* that we reschedule before that wraps. Scheduling at least every
* four billion cycles just basically sounds like a good idea,
* regardless of how fast the machine is.
*/
typedef uint64_t cycles_t;
extern cycles_t cacheflush_time;
#define rdtscll(val) \
__asm__ __volatile__("rdtsc" : "=A" (val))
static inline cycles_t get_cycles (void)
{
uint32_t long ret;
rdtscll(ret);
return ret;
}
#elif defined(__powerpc__)
#define CPU_FTR_601 0x00000100
typedef uint32_t cycles_t;
/*
* For the "cycle" counter we use the timebase lower half.
* Currently only used on SMP.
*/
extern cycles_t cacheflush_time;
static inline cycles_t get_cycles(void)
{
cycles_t ret = 0;
__asm__ __volatile__(
"98: mftb %0\n"
"99:\n"
".section __ftr_fixup,\"a\"\n"
" .long %1\n"
" .long 0\n"
" .long 98b\n"
" .long 99b\n"
".previous"
: "=r" (ret) : "i" (CPU_FTR_601));
return ret;
}
#elif defined(__ia64__)
/* ia64 */
typedef uint32_t cycles_t;
static inline cycles_t
get_cycles (void)
{
cycles_t ret;
__asm__ __volatile__ ("mov %0=ar.itc" : "=r"(ret));
return ret;
}
#elif defined(__alpha__)
/* alpha */
/*
* Standard way to access the cycle counter.
* Currently only used on SMP for scheduling.
*
* Only the low 32 bits are available as a continuously counting entity.
* But this only means we'll force a reschedule every 8 seconds or so,
* which isn't an evil thing.
*/
typedef uint32_t cycles_t;
static inline cycles_t get_cycles (void)
{
cycles_t ret;
__asm__ __volatile__ ("rpcc %0" : "=r"(ret));
return ret;
}
#elif defined(__s390__)
/* s390 */
typedef uint32_t long cycles_t;
static inline cycles_t get_cycles(void)
{
cycles_t cycles;
__asm__("stck 0(%0)" : : "a" (&(cycles)) : "memory", "cc");
return cycles >> 2;
}
#elif defined(__hppa__)
/* hppa/parisc */
#define mfctl(reg) ({ \
uint32_t cr; \
__asm__ __volatile__( \
"mfctl " #reg ",%0" : \
"=r" (cr) \
); \
cr; \
})
typedef uint32_t cycles_t;
static inline cycles_t get_cycles (void)
{
return mfctl(16);
}
#elif defined(__mips__)
/* mips/mipsel */
/*
* Standard way to access the cycle counter.
* Currently only used on SMP for scheduling.
*
* Only the low 32 bits are available as a continuously counting entity.
* But this only means we'll force a reschedule every 8 seconds or so,
* which isn't an evil thing.
*
* We know that all SMP capable CPUs have cycle counters.
*/
#define __read_32bit_c0_register(source, sel) \
({ int __res; \
if (sel == 0) \
__asm__ __volatile__( \
"mfc0\t%0, " #source "\n\t" \
: "=r" (__res)); \
else \
__asm__ __volatile__( \
".set\tmips32\n\t" \
"mfc0\t%0, " #source ", " #sel "\n\t" \
".set\tmips0\n\t" \
: "=r" (__res)); \
__res; \
})
/* #define CP0_COUNT $9 */
#define read_c0_count() __read_32bit_c0_register($9, 0)
typedef uint32_t cycles_t;
static inline cycles_t get_cycles (void)
{
return read_c0_count();
}
/* begin mach */
#elif defined(__APPLE__)
#include <CoreAudio/CoreAudioTypes.h>
#include <CoreAudio/HostTime.h>
typedef UInt64 cycles_t;
static inline cycles_t get_cycles (void)
{
UInt64 time = AudioGetCurrentHostTime();
return AudioConvertHostTimeToNanos(time);
}
/* end mach */
#else
/* debian: sparc, arm, m68k */
#warning You are compiling libardour on a platform for which ardour/cycles.h needs work
#include <sys/time.h>
typedef long cycles_t;
extern cycles_t cacheflush_time;
static inline cycles_t get_cycles(void)
{
struct timeval tv;
gettimeofday (&tv, NULL);
return tv.tv_usec;
}
#endif
#endif /* __ardour_cycles_h__ */

34
libs/ardour/ardour/dB.h Normal file
View File

@@ -0,0 +1,34 @@
/*
Copyright (C) 2001 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$
*/
#ifndef __ardour_dB_h__
#define __ardour_dB_h__
#include <pbd/fastlog.h>
static inline float dB_to_coefficient (float dB) {
return dB > -318.8f ? pow (10.0f, dB * 0.05f) : 0.0f;
}
static inline float coefficient_to_dB (float coeff) {
return 20.0f * fast_log10 (coeff);
}
#endif /* __ardour_dB_h__ */

View File

@@ -0,0 +1,433 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __ardour_diskstream_h__
#define __ardour_diskstream_h__
#include <sigc++/signal.h>
#include <cmath>
#include <string>
#include <queue>
#include <map>
#include <vector>
#include <time.h>
#include <pbd/fastlog.h>
#include <pbd/ringbufferNPT.h>
#include <pbd/atomic.h>
#include <ardour/ardour.h>
#include <ardour/configuration.h>
#include <ardour/session.h>
#include <ardour/route_group.h>
#include <ardour/route.h>
#include <ardour/port.h>
#include <ardour/utils.h>
#include <ardour/stateful.h>
struct tm;
namespace ARDOUR {
class AudioEngine;
class Send;
class Session;
class AudioPlaylist;
class FileSource;
class IO;
class DiskStream : public Stateful, public sigc::trackable
{
public:
enum Flag {
Recordable = 0x1,
Hidden = 0x2
};
DiskStream (Session &, const string& name, Flag f = Recordable);
DiskStream (Session &, const XMLNode&);
string name() const { return _name; }
ARDOUR::IO* io() const { return _io; }
void set_io (ARDOUR::IO& io);
DiskStream& ref() { _refcnt++; return *this; }
void unref() { if (_refcnt) _refcnt--; if (_refcnt == 0) delete this; }
uint32_t refcnt() const { return _refcnt; }
float playback_buffer_load() const;
float capture_buffer_load() const;
void set_flag (Flag f) {
_flags |= f;
}
void unset_flag (Flag f) {
_flags &= ~f;
}
AlignStyle alignment_style() const { return _alignment_style; }
void set_align_style (AlignStyle);
void set_persistent_align_style (AlignStyle);
bool hidden() const { return _flags & Hidden; }
bool recordable() const { return _flags & Recordable; }
jack_nframes_t roll_delay() const { return _roll_delay; }
void set_roll_delay (jack_nframes_t);
void set_name (string str, void* src);
string input_source (uint32_t n=0) const {
if (n < channels.size()) {
return channels[n].source ? channels[n].source->name() : "";
} else {
return "";
}
}
Port *input_source_port (uint32_t n=0) const {
if (n < channels.size()) return channels[n].source; return 0;
}
void set_record_enabled (bool yn, void *src);
bool record_enabled() const { return atomic_read (&_record_enabled); }
void punch_in ();
void punch_out ();
bool reversed() const { return _actual_speed < 0.0f; }
float speed() const { return _visible_speed; }
void set_speed (float);
float peak_power(uint32_t n=0) {
float x = channels[n].peak_power;
channels[n].peak_power = 0.0f;
if (x > 0.0f) {
return 20.0f * fast_log10(x);
} else {
return minus_infinity();
}
}
int use_playlist (AudioPlaylist *);
int use_new_playlist ();
int use_copy_playlist ();
void start_scrub (jack_nframes_t where);
void end_scrub ();
Sample *playback_buffer (uint32_t n=0) {
if (n < channels.size())
return channels[n].current_playback_buffer;
return 0;
}
Sample *capture_buffer (uint32_t n=0) {
if (n < channels.size())
return channels[n].current_capture_buffer;
return 0;
}
AudioPlaylist *playlist () { return _playlist; }
FileSource *fades_source (uint32_t n=0) {
if (n < channels.size())
return channels[n].fades_source;
return 0;
}
FileSource *write_source (uint32_t n=0) {
if (n < channels.size())
return channels[n].write_source;
return 0;
}
jack_nframes_t current_capture_start() const { return capture_start_frame; }
jack_nframes_t current_capture_end() const { return capture_start_frame + capture_captured; }
jack_nframes_t get_capture_start_frame (uint32_t n=0);
jack_nframes_t get_captured_frames (uint32_t n=0);
uint32_t n_channels() { return _n_channels; }
int add_channel ();
int remove_channel ();
static void set_disk_io_chunk_frames (uint32_t n) {
disk_io_chunk_frames = n;
}
static jack_nframes_t disk_io_frames() { return disk_io_chunk_frames; }
sigc::signal<void,void*> record_enable_changed;
sigc::signal<void> speed_changed;
sigc::signal<void,void*> reverse_changed;
sigc::signal<void> PlaylistChanged;
sigc::signal<void> AlignmentStyleChanged;
static sigc::signal<void> DiskOverrun;
static sigc::signal<void> DiskUnderrun;
static sigc::signal<void,DiskStream*> DiskStreamCreated; // XXX use a ref with sigc2
static sigc::signal<void,DiskStream*> CannotRecordNoInput; // XXX use a ref with sigc2
static sigc::signal<void,list<Source*>*> DeleteSources;
/* stateful */
XMLNode& get_state(void);
int set_state(const XMLNode& node);
void monitor_input (bool);
jack_nframes_t capture_offset() const { return _capture_offset; }
void set_capture_offset ();
static void swap_by_ptr (Sample *first, Sample *last) {
while (first < last) {
Sample tmp = *first;
*first++ = *last;
*last-- = tmp;
}
}
static void swap_by_ptr (Sample *first, Sample *last, jack_nframes_t n) {
while (n--) {
Sample tmp = *first;
*first++ = *last;
*last-- = tmp;
}
}
bool slaved() const { return _slaved; }
void set_slaved(bool yn) { _slaved = yn; }
int set_loop (Location *loc);
sigc::signal<void,Location *> LoopSet;
std::list<Region*>& last_capture_regions () {
return _last_capture_regions;
}
void handle_input_change (IOChange, void *src);
id_t id() const { return _id; }
XMLNode* deprecated_io_node;
protected:
friend class Session;
/* the Session is the only point of access for these
because they require that the Session is "inactive"
while they are called.
*/
void set_pending_overwrite (bool);
int overwrite_existing_buffers ();
void reverse_scrub_buffer (bool to_forward);
void set_block_size (jack_nframes_t);
int internal_playback_seek (jack_nframes_t distance);
int can_internal_playback_seek (jack_nframes_t distance);
void reset_write_sources (bool);
void non_realtime_input_change ();
uint32_t read_data_count() const { return _read_data_count; }
uint32_t write_data_count() const { return _write_data_count; }
protected:
friend class Auditioner;
int seek (jack_nframes_t which_sample, bool complete_refill = false);
protected:
friend class AudioTrack;
void prepare ();
int process (jack_nframes_t transport_frame, jack_nframes_t nframes, jack_nframes_t offset, bool can_record, bool rec_monitors_input);
bool commit (jack_nframes_t nframes);
void recover (); /* called if commit will not be called, but process was */
private:
/* use unref() to destroy a diskstream */
~DiskStream();
struct ChannelInfo {
Sample *playback_wrap_buffer;
Sample *capture_wrap_buffer;
Sample *speed_buffer;
float peak_power;
FileSource *fades_source;
FileSource *write_source;
Port *source;
Sample *current_capture_buffer;
Sample *current_playback_buffer;
RingBufferNPT<Sample> *playback_buf;
RingBufferNPT<Sample> *capture_buf;
Sample* scrub_buffer;
Sample* scrub_forward_buffer;
Sample* scrub_reverse_buffer;
RingBufferNPT<Sample>::rw_vector playback_vector;
RingBufferNPT<Sample>::rw_vector capture_vector;
};
typedef vector<ChannelInfo> ChannelList;
string _name;
ARDOUR::Session& _session;
ARDOUR::IO* _io;
ChannelList channels;
uint32_t _n_channels;
id_t _id;
atomic_t _record_enabled;
bool rec_monitoring_off_for_roll;
AudioPlaylist* _playlist;
float _visible_speed;
float _actual_speed;
/* items needed for speed change logic */
bool _buffer_reallocation_required;
bool _seek_required;
bool force_refill;
jack_nframes_t capture_start_frame;
jack_nframes_t capture_captured;
bool was_recording;
jack_nframes_t adjust_capture_position;
jack_nframes_t _capture_offset;
jack_nframes_t _roll_delay;
jack_nframes_t first_recordable_frame;
jack_nframes_t last_recordable_frame;
int last_possibly_recording;
AlignStyle _alignment_style;
bool _scrubbing;
bool _slaved;
bool _processed;
Location* loop_location;
jack_nframes_t overwrite_frame;
off_t overwrite_offset;
bool pending_overwrite;
bool overwrite_queued;
IOChange input_change_pending;
jack_nframes_t wrap_buffer_size;
jack_nframes_t speed_buffer_size;
uint64_t last_phase;
uint64_t phi;
jack_nframes_t file_frame;
jack_nframes_t playback_sample;
jack_nframes_t playback_distance;
uint32_t _read_data_count;
uint32_t _write_data_count;
bool in_set_state;
AlignStyle _persistent_alignment_style;
bool first_input_change;
PBD::NonBlockingLock state_lock;
jack_nframes_t scrub_start;
jack_nframes_t scrub_buffer_size;
jack_nframes_t scrub_offset;
uint32_t _refcnt;
sigc::connection ports_created_c;
sigc::connection plmod_connection;
sigc::connection plstate_connection;
sigc::connection plgone_connection;
/* the two central butler operations */
int do_flush (bool force = false);
int do_refill (Sample *mixdown_buffer, float *gain_buffer);
int read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, jack_nframes_t& start, jack_nframes_t cnt,
ChannelInfo& channel_info, int channel, bool reversed);
uint32_t i_am_the_modifier;
/* XXX fix this redundancy ... */
void playlist_changed (Change);
void playlist_modified ();
void playlist_deleted (Playlist*);
void session_controls_changed (Session::ControlType);
void finish_capture (bool rec_monitors_input);
void clean_up_capture (struct tm&, time_t, bool abort);
void transport_stopped (struct tm&, time_t, bool abort);
struct CaptureInfo {
uint32_t start;
uint32_t frames;
};
vector<CaptureInfo*> capture_info;
PBD::Lock capture_info_lock;
void init (Flag);
void init_channel (ChannelInfo &chan);
void destroy_channel (ChannelInfo &chan);
static jack_nframes_t disk_io_chunk_frames;
int use_new_write_source (uint32_t n=0);
int use_new_fade_source (uint32_t n=0);
int find_and_use_playlist (const string&);
void allocate_temporary_buffers ();
unsigned char _flags;
int create_input_port ();
int connect_input_port ();
int seek_unlocked (jack_nframes_t which_sample);
int ports_created ();
bool realtime_set_speed (float, bool global_change);
void non_realtime_set_speed ();
std::list<Region*> _last_capture_regions;
std::vector<FileSource*> capturing_sources;
int use_pending_capture_data (XMLNode& node);
void get_input_sources ();
void check_record_status (jack_nframes_t transport_frame, jack_nframes_t nframes, bool can_record);
void set_align_style_from_io();
};
}; /* namespace ARDOUR */
#endif /* __ardour_diskstream_h__ */

View File

@@ -0,0 +1,88 @@
#ifndef __ardour_export_h__
#define __ardour_export_h__
#include <map>
#include <vector>
#include <string>
#include <sigc++/signal.h>
#include <sndfile.h>
#include <samplerate.h>
#include <ardour/ardour.h>
#include <ardour/gdither.h>
using std::map;
using std::vector;
using std::string;
using std::pair;
namespace ARDOUR
{
class Port;
typedef pair<Port *, uint32_t> PortChannelPair;
typedef map<uint32_t, vector<PortChannelPair> > AudioExportPortMap;
struct AudioExportSpecification : public SF_INFO, public sigc::trackable {
AudioExportSpecification();
~AudioExportSpecification ();
void init ();
void clear ();
int prepare (jack_nframes_t blocksize, jack_nframes_t frame_rate);
int process (jack_nframes_t nframes);
/* set by the user */
string path;
jack_nframes_t sample_rate;
int src_quality;
SNDFILE* out;
uint32_t channels;
AudioExportPortMap port_map;
jack_nframes_t start_frame;
jack_nframes_t end_frame;
GDitherType dither_type;
bool do_freewheel;
/* used exclusively during export */
jack_nframes_t frame_rate;
GDither dither;
float* dataF;
float* dataF2;
float* leftoverF;
jack_nframes_t leftover_frames;
jack_nframes_t max_leftover_frames;
void* output_data;
jack_nframes_t out_samples_max;
uint32_t sample_bytes;
uint32_t data_width;
jack_nframes_t total_frames;
SF_INFO sfinfo;
SRC_DATA src_data;
SRC_STATE* src_state;
jack_nframes_t pos;
sigc::connection freewheel_connection;
/* shared between UI thread and audio thread */
float progress; /* audio thread sets this */
bool stop; /* UI sets this */
bool running; /* audio thread sets to false when export is done */
int status;
};
};
#endif /* __ardour_export_h__ */

View File

@@ -0,0 +1,163 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __playlist_file_buffer_h__
#define __playlist_file_buffer_h__
// darwin supports 64 by default and doesn't provide wrapper functions.
#if defined (__APPLE__)
typedef off_t off64_t;
#define open64 open
#define close64 close
#define lseek64 lseek
#define pread64 pread
#define pwrite64 pwrite
#endif
#include <vector>
#include <string>
#include <ardour/source.h>
struct tm;
using std::string;
namespace ARDOUR {
class FileSource : public Source {
public:
FileSource (string path, jack_nframes_t rate, bool repair_first = false);
FileSource (const XMLNode&, jack_nframes_t rate);
~FileSource ();
jack_nframes_t length() const { return _length; }
jack_nframes_t read (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const;
jack_nframes_t write (Sample *src, jack_nframes_t cnt);
void mark_for_remove();
string peak_path(string audio_path);
string old_peak_path(string audio_path);
string path() const { return _path; }
int update_header (jack_nframes_t when, struct tm&, time_t);
int move_to_trash (const string trash_dir_name);
static bool is_empty (string path);
void mark_streaming_write_completed ();
void mark_take (string);
string take_id() const { return _take_id; }
static void set_bwf_country_code (string x);
static void set_bwf_organization_code (string x);
static void set_bwf_serial_number (int);
static void set_search_path (string);
private:
int fd;
string _path;
bool remove_at_unref;
bool is_bwf;
off64_t data_offset;
string _take_id;
static char bwf_country_code[3];
static char bwf_organization_code[4];
static char bwf_serial_number[13];
struct GenericChunk {
char id[4];
int32_t size;
};
struct WAVEChunk : public GenericChunk {
char text[4]; /* wave pseudo-chunk id "WAVE" */
};
struct FMTChunk : public GenericChunk {
int16_t formatTag; /* format tag; currently pcm */
int16_t nChannels; /* number of channels */
uint32_t nSamplesPerSec; /* sample rate in hz */
int32_t nAvgBytesPerSec; /* average bytes per second */
int16_t nBlockAlign; /* number of bytes per sample */
int16_t nBitsPerSample; /* number of bits in a sample */
};
struct BroadcastChunk : public GenericChunk {
char description[256];
char originator[32];
char originator_reference[32];
char origination_date[10];
char origination_time[8];
int32_t time_reference_low;
int32_t time_reference_high;
int16_t version; /* 1.0 because we have umid and 190 bytes of "reserved" */
char umid[64];
char reserved[190];
/* we don't treat coding history as part of the struct */
};
struct ChunkInfo {
string name;
uint32_t size;
off64_t offset;
ChunkInfo (string s, uint32_t sz, off64_t o)
: name (s), size (sz), offset (o) {}
};
vector<ChunkInfo> chunk_info;
struct {
WAVEChunk wave;
FMTChunk format;
GenericChunk data;
BroadcastChunk bext;
vector<string> coding_history;
} header;
int init (string, bool must_exist, jack_nframes_t);
jack_nframes_t read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const;
int discover_chunks (bool silent);
ChunkInfo* lookup_chunk (string name);
int write_header ();
int read_header (bool silent);
int check_header (jack_nframes_t rate, bool silent);
int fill_header (jack_nframes_t rate);
int read_broadcast_data (ChunkInfo&);
void compute_header_size ();
static const int32_t wave_header_size = sizeof (WAVEChunk) + sizeof (FMTChunk) + sizeof (GenericChunk);
static const int32_t bwf_header_size = wave_header_size + sizeof (BroadcastChunk);
static string search_path;
int repair (string, jack_nframes_t);
};
}
#endif /* __playlist_file_buffer_h__ */

44
libs/ardour/ardour/gain.h Normal file
View File

@@ -0,0 +1,44 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __ardour_gain_h__
#define __ardour_gain_h__
#include "ardour.h"
#include "curve.h"
namespace ARDOUR {
struct Gain : public Curve {
Gain();
Gain (const Gain&);
Gain& operator= (const Gain&);
static void fill_linear_fade_in (Gain& curve, jack_nframes_t frames);
static void fill_linear_volume_fade_in (Gain& curve, jack_nframes_t frames);
static void fill_linear_fade_out (Gain& curve, jack_nframes_t frames);
static void fill_linear_volume_fade_out (Gain& curve, jack_nframes_t frames);
};
} /* namespace ARDOUR */
#endif /* __ardour_gain_h__ */

View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2002 Steve Harris <steve@plugin.org.uk>
*
* 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$
*/
#ifndef GDITHER_H
#define GDITHER_H
#ifdef __cplusplus
extern "C" {
#endif
#include "gdither_types.h"
/* Create and initialise a state structure, takes a dither type, a number of
* channels and a bit depth as input
*
* The Dither type is one of
*
* GDitherNone - straight nearest neighbour rounding. Theres no pressing
* reason to do this at 8 or 16 bit, but you might want to at 24, for some
* reason. At the lest it will save you writing int->float conversion code,
* which is arder than it sounds.
*
* GDitherRect - mathematically most accurate, lowest noise floor, but not
* that good for audio. It is the fastest though.
*
* GDitherTri - a happy medium between Rectangular and Shaped, reasonable
* noise floor, not too obvious, quite fast.
*
* GDitherShaped - should have the least audible impact, but has the highest
* noise floor, fairly CPU intensive. Not advisible if your going to apply
* any frequency manipulation afterwards.
*
* channels, sets the number of channels in the output data, output data will
* be written interleaved into the area given to gdither_run(). Set to 1
* if you are not working with interleaved buffers.
*
* bit depth, sets the bit width of the output sample data, it can be one of:
*
* GDither8bit - 8 bit unsiged
* GDither16bit - 16 bit signed
* GDither32bit - 24+bits in upper bits of a 32 bit word
* GDitherFloat - IEEE floating point (32bits)
* GDitherDouble - Double precision IEEE floating point (64bits)
*
* dither_depth, set the number of bits before the signal will be truncated to,
* eg. 16 will produce an output stream with 16bits-worth of signal. Setting to
* zero or greater than the width of the output format will dither to the
* maximum precision allowed by the output format.
*/
GDither gdither_new(GDitherType type, uint32_t channels,
GDitherSize bit_depth, int dither_depth);
/* Frees memory used by gdither_new.
*/
void gdither_free(GDither s);
/* Applies dithering to the supplied signal.
*
* channel is the channel number you are processing (0 - channles-1), length is
* the length of the input, in samples, x is the input samples (float), y is
* where the output samples will be written, it should have the approaprate
* type for the chosen bit depth
*/
void gdither_runf(GDither s, uint32_t channel, uint32_t length,
float *x, void *y);
/* see gdither_runf, vut input argument is double format */
void gdither_run(GDither s, uint32_t channel, uint32_t length,
double *x, void *y);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2002 Steve Harris <steve@plugin.org.uk>
*
* 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$
*/
#ifndef GDITHER_TYPES_H
#define GDITHER_TYPES_H
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
GDitherNone = 0,
GDitherRect,
GDitherTri,
GDitherShaped
} GDitherType;
typedef enum {
GDither8bit = 8,
GDither16bit = 16,
GDither32bit = 32,
GDitherFloat = 25,
GDitherDouble = 54
} GDitherSize;
typedef void *GDither;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2002 Steve Harris <steve@plugin.org.uk>
*
* 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$
*/
#ifndef GDITHER_TYPES_H
#define GDITHER_TYPES_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define GDITHER_SH_BUF_SIZE 8
#define GDITHER_SH_BUF_MASK 7
/* this must agree with whats in gdither_types.h */
typedef enum {
GDitherNone = 0,
GDitherRect,
GDitherTri,
GDitherShaped
} GDitherType;
typedef enum {
GDither8bit = 8,
GDither16bit = 16,
GDither32bit = 32,
GDitherFloat = 25,
GDitherDouble = 54
} GDitherSize;
typedef struct {
uint32_t phase;
float buffer[GDITHER_SH_BUF_SIZE];
} GDitherShapedState;
typedef struct GDither_s {
GDitherType type;
uint32_t channels;
uint32_t bit_depth;
uint32_t dither_depth;
float scale;
uint32_t post_scale;
float post_scale_fp;
float bias;
int clamp_u;
int clamp_l;
float *tri_state;
GDitherShapedState *shaped_state;
} *GDither;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,153 @@
/*
Copyright (C) 2001 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$
*/
#ifndef __ardour_history_h__
#define __ardour_history_h__
#include <list>
#include <sigc++/signal.h>
template<class T>
//struct History : public SigC::Object
struct History : public sigc::trackable
{
typedef list<T *> StateList;
StateList states;
StateList::iterator current;
History() { current = states.end(); }
~History() { states.erase (states.begin(), states.end()); }
sigc::signal<void> CurrentChanged;
void clear () {
for (StateList::iterator i = states.begin(); i != states.end(); i++) {
delete *i;
}
states.clear ();
current = states.end();
CurrentChanged();
}
void push (T *state) {
/* remove any "undone" history above the current location
in the history, before pushing new state.
*/
if (current != states.begin() && current != states.end()) {
states.erase (states.begin(), current);
}
current = states.insert (states.begin(), state);
CurrentChanged ();
}
T *top() {
if (current != states.end()) {
return *current;
} else {
return 0;
}
}
T *pop (bool remove) {
if (current == states.end()) {
return 0;
}
if (current == states.begin()) {
return *current;
}
current--;
T *state = *current;
if (remove) {
states.erase (current);
}
CurrentChanged ();
return state;
}
T *earlier (uint32_t n) {
StateList::iterator i;
if (current == states.end()) {
return 0;
}
if (n == 0) {
return *current;
}
/* the list is in LIFO order, so move toward the end to go "earlier" */
for (i = current; n && i != states.end(); i++, n--);
if (i == states.end()) {
return 0;
} else {
current = i;
CurrentChanged ();
return *i;
}
}
T *later (uint32_t n) {
StateList::iterator i;
if (current == states.end()) {
return 0;
}
if (n == 0) {
return *current;
}
/* the list is in LIFO order, so move toward the beginning to go "later" */
for (i = current; n && i != states.begin(); i--, n--);
if (i != current) {
current = i;
CurrentChanged();
}
return *i;
}
T *nth (uint32_t n) {
StateList::iterator i;
for (i = states.begin(); n && i != states.end(); n--, i++);
if (i != states.end()) {
if (i != current) {
current = i;
CurrentChanged ();
}
return *i;
} else {
return 0;
}
}
};
#endif /* __ardour_history_h__ */

183
libs/ardour/ardour/insert.h Normal file
View File

@@ -0,0 +1,183 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __ardour_insert_h__
#define __ardour_insert_h__
#include <vector>
#include <string>
#include <exception>
#include <sigc++/signal.h>
#include <ardour/ardour.h>
#include <ardour/redirect.h>
#include <ardour/plugin_state.h>
class XMLNode;
namespace MIDI {
class Port;
}
namespace ARDOUR {
class Session;
class Plugin;
class Route;
class Insert : public Redirect
{
public:
Insert(Session& s, Placement p);
Insert(Session& s, string name, Placement p);
Insert(Session& s, Placement p, int imin, int imax, int omin, int omax);
virtual ~Insert() { }
virtual void run (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset) = 0;
virtual void activate () {}
virtual void deactivate () {}
virtual int32_t can_support_input_configuration (int32_t in) const = 0;
virtual int32_t configure_io (int32_t magic, int32_t in, int32_t out) = 0;
virtual int32_t compute_output_streams (int32_t cnt) const = 0;
};
class PortInsert : public Insert
{
public:
PortInsert (Session&, Placement);
PortInsert (Session&, const XMLNode&);
PortInsert (const PortInsert&);
~PortInsert ();
XMLNode& state(bool full);
XMLNode& get_state(void);
int set_state(const XMLNode&);
void init ();
void run (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset);
jack_nframes_t latency();
uint32_t output_streams() const;
uint32_t input_streams() const;
int32_t can_support_input_configuration (int32_t) const;
int32_t configure_io (int32_t magic, int32_t in, int32_t out);
int32_t compute_output_streams (int32_t cnt) const;
};
struct PluginInsertState : public RedirectState
{
PluginInsertState (std::string why)
: RedirectState (why) {}
~PluginInsertState() {}
PluginState plugin_state;
};
class PluginInsert : public Insert
{
public:
PluginInsert (Session&, Plugin&, Placement);
PluginInsert (Session&, const XMLNode&);
PluginInsert (const PluginInsert&);
~PluginInsert ();
static const string port_automation_node_name;
XMLNode& state(bool);
XMLNode& get_state(void);
int set_state(const XMLNode&);
StateManager::State* state_factory (std::string why) const;
Change restore_state (StateManager::State&);
void run (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset);
void silence (jack_nframes_t nframes, jack_nframes_t offset);
void activate ();
void deactivate ();
void set_block_size (jack_nframes_t nframes);
uint32_t output_streams() const;
uint32_t input_streams() const;
uint32_t natural_output_streams() const;
uint32_t natural_input_streams() const;
int set_count (uint32_t num);
uint32_t get_count () const { return _plugins.size(); }
int32_t can_support_input_configuration (int32_t) const;
int32_t configure_io (int32_t magic, int32_t in, int32_t out);
int32_t compute_output_streams (int32_t cnt) const;
bool is_generator() const;
void reset_midi_control (MIDI::Port*, bool);
void send_all_midi_feedback ();
void set_parameter (uint32_t port, float val);
AutoState get_port_automation_state (uint32_t port);
void set_port_automation_state (uint32_t port, AutoState);
void protect_automation ();
float default_parameter_value (uint32_t which);
Plugin& plugin(uint32_t num=0) const {
if (num < _plugins.size()) {
return *_plugins[num];
} else {
return *_plugins[0]; // we always have one
}
}
string describe_parameter (uint32_t);
jack_nframes_t latency();
void transport_stopped (jack_nframes_t now);
void automation_snapshot (jack_nframes_t now);
protected:
void store_state (PluginInsertState&) const;
private:
void parameter_changed (uint32_t, float);
vector<Plugin*> _plugins;
void automation_run (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset);
void connect_and_run (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset, bool with_auto, jack_nframes_t now = 0);
void init ();
void set_automatable ();
void auto_state_changed (uint32_t which);
void automation_list_creation_callback (uint32_t, AutomationList&);
Plugin* plugin_factory (Plugin&);
};
}; /* namespace ARDOUR */
#endif /* __ardour_insert_h__ */

408
libs/ardour/ardour/io.h Normal file
View File

@@ -0,0 +1,408 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __ardour_io_h__
#define __ardour_io_h__
#include <string>
#include <vector>
#include <cmath>
#include <sigc++/signal.h>
#include <jack/jack.h>
#include <pbd/lockmonitor.h>
#include <pbd/fastlog.h>
#include <pbd/undo.h>
#include <pbd/atomic.h>
#include <midi++/controllable.h>
#include <ardour/ardour.h>
#include <ardour/stateful.h>
#include <ardour/utils.h>
#include <ardour/state_manager.h>
#include <ardour/curve.h>
using std::string;
using std::vector;
class XMLNode;
namespace ARDOUR {
class Session;
class AudioEngine;
class Port;
class Connection;
class Panner;
class IO : public Stateful, public ARDOUR::StateManager
{
public:
static const string state_node_name;
IO (Session&, string name,
int input_min = -1, int input_max = -1,
int output_min = -1, int output_max = -1);
virtual ~IO();
int input_minimum() const { return _input_minimum; }
int input_maximum() const { return _input_maximum; }
int output_minimum() const { return _output_minimum; }
int output_maximum() const { return _output_maximum; }
void set_input_minimum (int n);
void set_input_maximum (int n);
void set_output_minimum (int n);
void set_output_maximum (int n);
const string& name() const { return _name; }
virtual int set_name (string str, void *src);
virtual void silence (jack_nframes_t, jack_nframes_t offset);
void pan (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset, gain_t gain_coeff);
void pan_automated (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t start_frame, jack_nframes_t end_frame,
jack_nframes_t nframes, jack_nframes_t offset);
void collect_input (vector<Sample*>&, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset);
void deliver_output (vector<Sample *>&, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset);
void deliver_output_no_pan (vector<Sample *>&, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset);
void just_meter_input (jack_nframes_t start_frame, jack_nframes_t end_frame,
jack_nframes_t nframes, jack_nframes_t offset);
virtual uint32_t n_process_buffers () { return 0; }
virtual void set_gain (gain_t g, void *src);
void inc_gain (gain_t delta, void *src);
gain_t gain () const { return _desired_gain; }
virtual gain_t effective_gain () const;
Panner& panner() { return *_panner; }
int ensure_io (uint32_t, uint32_t, bool clear, void *src);
int use_input_connection (Connection&, void *src);
int use_output_connection (Connection&, void *src);
Connection *input_connection() const { return _input_connection; }
Connection *output_connection() const { return _output_connection; }
int add_input_port (string source, void *src);
int add_output_port (string destination, void *src);
int remove_input_port (Port *, void *src);
int remove_output_port (Port *, void *src);
int set_input (Port *, void *src);
int connect_input (Port *our_port, string other_port, void *src);
int connect_output (Port *our_port, string other_port, void *src);
int disconnect_input (Port *our_port, string other_port, void *src);
int disconnect_output (Port *our_port, string other_port, void *src);
int disconnect_inputs (void *src);
int disconnect_outputs (void *src);
jack_nframes_t output_latency() const;
jack_nframes_t input_latency() const;
void set_port_latency (jack_nframes_t);
Port *output (uint32_t n) const {
if (n < _noutputs) {
return _outputs[n];
} else {
return 0;
}
}
Port *input (uint32_t n) const {
if (n < _ninputs) {
return _inputs[n];
} else {
return 0;
}
}
uint32_t n_inputs () const { return _ninputs; }
uint32_t n_outputs () const { return _noutputs; }
sigc::signal<void,IOChange,void*> input_changed;
sigc::signal<void,IOChange,void*> output_changed;
sigc::signal<void,void*> gain_changed;
sigc::signal<void,void*> name_changed;
virtual XMLNode& state (bool full);
XMLNode& get_state (void);
int set_state (const XMLNode&);
virtual UndoAction get_memento() const;
static int disable_connecting (void);
static int enable_connecting (void);
static int disable_ports (void);
static int enable_ports (void);
static int disable_panners (void);
static int reset_panners (void);
static sigc::signal<int> PortsLegal;
static sigc::signal<int> PannersLegal;
static sigc::signal<int> ConnectingLegal;
static sigc::signal<void,uint32_t> MoreOutputs;
static sigc::signal<int> PortsCreated;
/* MIDI control */
void set_midi_to_gain_function (gain_t (*function)(double val)) {
_midi_gain_control.midi_to_gain = function;
}
void set_gain_to_midi_function (double (*function)(gain_t gain)) {
_midi_gain_control.gain_to_midi = function;
}
MIDI::Controllable& midi_gain_control() {
return _midi_gain_control;
}
virtual void reset_midi_control (MIDI::Port*, bool on);
virtual void send_all_midi_feedback ();
virtual MIDI::byte* write_midi_feedback (MIDI::byte*, int32_t& bufsize);
/* Peak metering */
float peak_input_power (uint32_t n) {
if (n < std::max(_ninputs, _noutputs)) {
float x = _stored_peak_power[n];
if(x > 0.0) {
return 20 * fast_log10(x);
} else {
return minus_infinity();
}
} else {
return minus_infinity();
}
}
static sigc::signal<void> GrabPeakPower;
/* automation */
void clear_automation ();
bool gain_automation_recording() const {
return (_gain_automation_curve.automation_state() & (Write|Touch));
}
bool gain_automation_playback() const {
return (_gain_automation_curve.automation_state() & Play) ||
((_gain_automation_curve.automation_state() & Touch) &&
!_gain_automation_curve.touching());
}
virtual void set_gain_automation_state (AutoState);
AutoState gain_automation_state() const { return _gain_automation_curve.automation_state(); }
sigc::signal<void> gain_automation_state_changed;
virtual void set_gain_automation_style (AutoStyle);
AutoStyle gain_automation_style () const { return _gain_automation_curve.automation_style(); }
sigc::signal<void> gain_automation_style_changed;
static void set_automation_interval (jack_nframes_t frames) {
_automation_interval = frames;
}
static jack_nframes_t automation_interval() {
return _automation_interval;
}
virtual void transport_stopped (jack_nframes_t now);
virtual void automation_snapshot (jack_nframes_t now);
ARDOUR::Curve& gain_automation_curve () { return _gain_automation_curve; }
void start_gain_touch ();
void end_gain_touch ();
void start_pan_touch (uint32_t which);
void end_pan_touch (uint32_t which);
id_t id() const { return _id; }
void defer_pan_reset ();
void allow_pan_reset ();
/* the session calls this for master outs before
anyone else. controls outs too, at some point.
*/
XMLNode *pending_state_node;
int ports_became_legal ();
private:
mutable PBD::Lock io_lock;
protected:
Session& _session;
Panner* _panner;
gain_t _gain;
gain_t _effective_gain;
gain_t _desired_gain;
PBD::NonBlockingLock declick_lock;
vector<Port*> _outputs;
vector<Port*> _inputs;
vector<float> _peak_power;
vector<float> _stored_peak_power;
string _name;
Connection* _input_connection;
Connection* _output_connection;
id_t _id;
bool no_panner_reset;
XMLNode* deferred_state;
virtual void set_deferred_state() {}
void reset_peak_meters();
void reset_panner ();
virtual uint32_t pans_required() const { return _ninputs; }
static void apply_declick (vector<Sample*>&, uint32_t nbufs, jack_nframes_t nframes,
gain_t initial, gain_t target, bool invert_polarity);
struct MIDIGainControl : public MIDI::Controllable {
MIDIGainControl (IO&, MIDI::Port *);
void set_value (float);
void send_feedback (gain_t);
MIDI::byte* write_feedback (MIDI::byte* buf, int32_t& bufsize, gain_t val, bool force = false);
IO& io;
bool setting;
MIDI::byte last_written;
gain_t (*midi_to_gain) (double val);
double (*gain_to_midi) (gain_t gain);
};
MIDIGainControl _midi_gain_control;
/* state management */
Change restore_state (State&);
StateManager::State* state_factory (std::string why) const;
void send_state_changed();
bool get_midi_node_info (XMLNode * node, MIDI::eventType & ev, MIDI::channel_t & chan, MIDI::byte & additional);
bool set_midi_node_info (XMLNode * node, MIDI::eventType ev, MIDI::channel_t chan, MIDI::byte additional);
/* automation */
jack_nframes_t last_automation_snapshot;
static jack_nframes_t _automation_interval;
AutoState _gain_automation_state;
AutoStyle _gain_automation_style;
bool apply_gain_automation;
Curve _gain_automation_curve;
int save_automation (const string&);
int load_automation (const string&);
PBD::NonBlockingLock automation_lock;
/* AudioTrack::deprecated_use_diskstream_connections() needs these */
int set_inputs (const string& str);
int set_outputs (const string& str);
static bool connecting_legal;
static bool ports_legal;
private:
uint32_t _ninputs;
uint32_t _noutputs;
/* are these the best variable names ever, or what? */
sigc::connection input_connection_configuration_connection;
sigc::connection output_connection_configuration_connection;
sigc::connection input_connection_connection_connection;
sigc::connection output_connection_connection_connection;
static bool panners_legal;
int connecting_became_legal ();
int panners_became_legal ();
sigc::connection connection_legal_c;
sigc::connection port_legal_c;
sigc::connection panner_legal_c;
int _input_minimum;
int _input_maximum;
int _output_minimum;
int _output_maximum;
static int parse_io_string (const string&, vector<string>& chns);
static int parse_gain_string (const string&, vector<string>& chns);
int set_sources (vector<string>&, void *src, bool add);
int set_destinations (vector<string>&, void *src, bool add);
int ensure_inputs (uint32_t, bool clear, bool lockit, void *src);
int ensure_outputs (uint32_t, bool clear, bool lockit, void *src);
void drop_input_connection ();
void drop_output_connection ();
void input_connection_configuration_changed ();
void input_connection_connection_changed (int);
void output_connection_configuration_changed ();
void output_connection_connection_changed (int);
int create_ports (const XMLNode&);
int make_connections (const XMLNode&);
void setup_peak_meters ();
void grab_peak_power ();
bool ensure_inputs_locked (uint32_t, bool clear, void *src);
bool ensure_outputs_locked (uint32_t, bool clear, void *src);
int32_t find_input_port_hole ();
int32_t find_output_port_hole ();
};
}; /* namespace ARDOUR */
#endif /*__ardour_io_h__ */

606
libs/ardour/ardour/ladspa.h Normal file
View File

@@ -0,0 +1,606 @@
/* ladspa.h
Linux Audio Developer's Simple Plugin API Version 1.1[LGPL].
Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis,
Stefan Westerfeld.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation; either version 2.1 of
the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA. */
#ifndef LADSPA_INCLUDED
#define LADSPA_INCLUDED
#define LADSPA_VERSION "1.1"
#define LADSPA_VERSION_MAJOR 1
#define LADSPA_VERSION_MINOR 1
#ifdef __cplusplus
extern "C" {
#endif
/*****************************************************************************/
/* Overview:
There is a large number of synthesis packages in use or development
on the Linux platform at this time. This API (`The Linux Audio
Developer's Simple Plugin API') attempts to give programmers the
ability to write simple `plugin' audio processors in C/C++ and link
them dynamically (`plug') into a range of these packages (`hosts').
It should be possible for any host and any plugin to communicate
completely through this interface.
This API is deliberately short and simple. To achieve compatibility
with a range of promising Linux sound synthesis packages it
attempts to find the `greatest common divisor' in their logical
behaviour. Having said this, certain limiting decisions are
implicit, notably the use of a fixed type (LADSPA_Data) for all
data transfer and absence of a parameterised `initialisation'
phase. See below for the LADSPA_Data typedef.
Plugins are expected to distinguish between control and audio
data. Plugins have `ports' that are inputs or outputs for audio or
control data and each plugin is `run' for a `block' corresponding
to a short time interval measured in samples. Audio data is
communicated using arrays of LADSPA_Data, allowing a block of audio
to be processed by the plugin in a single pass. Control data is
communicated using single LADSPA_Data values. Control data has a
single value at the start of a call to the `run()' or `run_adding()'
function, and may be considered to remain this value for its
duration. The plugin may assume that all its input and output ports
have been connected to the relevant data location (see the
`connect_port()' function below) before it is asked to run.
Plugins will reside in shared object files suitable for dynamic
linking by dlopen() and family. The file will provide a number of
`plugin types' that can be used to instantiate actual plugins
(sometimes known as `plugin instances') that can be connected
together to perform tasks.
This API contains very limited error-handling. */
/*****************************************************************************/
/* Fundamental data type passed in and out of plugin. This data type
is used to communicate audio samples and control values. It is
assumed that the plugin will work sensibly given any numeric input
value although it may have a preferred range (see hints below).
For audio it is generally assumed that 1.0f is the `0dB' reference
amplitude and is a `normal' signal level. */
typedef float LADSPA_Data;
/*****************************************************************************/
/* Special Plugin Properties:
Optional features of the plugin type are encapsulated in the
LADSPA_Properties type. This is assembled by ORing individual
properties together. */
typedef int LADSPA_Properties;
/* Property LADSPA_PROPERTY_REALTIME indicates that the plugin has a
real-time dependency (e.g. listens to a MIDI device) and so its
output must not be cached or subject to significant latency. */
#define LADSPA_PROPERTY_REALTIME 0x1
/* Property LADSPA_PROPERTY_INPLACE_BROKEN indicates that the plugin
may cease to work correctly if the host elects to use the same data
location for both input and output (see connect_port()). This
should be avoided as enabling this flag makes it impossible for
hosts to use the plugin to process audio `in-place.' */
#define LADSPA_PROPERTY_INPLACE_BROKEN 0x2
/* Property LADSPA_PROPERTY_HARD_RT_CAPABLE indicates that the plugin
is capable of running not only in a conventional host but also in a
`hard real-time' environment. To qualify for this the plugin must
satisfy all of the following:
(1) The plugin must not use malloc(), free() or other heap memory
management within its run() or run_adding() functions. All new
memory used in run() must be managed via the stack. These
restrictions only apply to the run() function.
(2) The plugin will not attempt to make use of any library
functions with the exceptions of functions in the ANSI standard C
and C maths libraries, which the host is expected to provide.
(3) The plugin will not access files, devices, pipes, sockets, IPC
or any other mechanism that might result in process or thread
blocking.
(4) The plugin will take an amount of time to execute a run() or
run_adding() call approximately of form (A+B*SampleCount) where A
and B depend on the machine and host in use. This amount of time
may not depend on input signals or plugin state. The host is left
the responsibility to perform timings to estimate upper bounds for
A and B. */
#define LADSPA_PROPERTY_HARD_RT_CAPABLE 0x4
#define LADSPA_IS_REALTIME(x) ((x) & LADSPA_PROPERTY_REALTIME)
#define LADSPA_IS_INPLACE_BROKEN(x) ((x) & LADSPA_PROPERTY_INPLACE_BROKEN)
#define LADSPA_IS_HARD_RT_CAPABLE(x) ((x) & LADSPA_PROPERTY_HARD_RT_CAPABLE)
/*****************************************************************************/
/* Plugin Ports:
Plugins have `ports' that are inputs or outputs for audio or
data. Ports can communicate arrays of LADSPA_Data (for audio
inputs/outputs) or single LADSPA_Data values (for control
input/outputs). This information is encapsulated in the
LADSPA_PortDescriptor type which is assembled by ORing individual
properties together.
Note that a port must be an input or an output port but not both
and that a port must be a control or audio port but not both. */
typedef int LADSPA_PortDescriptor;
/* Property LADSPA_PORT_INPUT indicates that the port is an input. */
#define LADSPA_PORT_INPUT 0x1
/* Property LADSPA_PORT_OUTPUT indicates that the port is an output. */
#define LADSPA_PORT_OUTPUT 0x2
/* Property LADSPA_PORT_CONTROL indicates that the port is a control
port. */
#define LADSPA_PORT_CONTROL 0x4
/* Property LADSPA_PORT_AUDIO indicates that the port is a audio
port. */
#define LADSPA_PORT_AUDIO 0x8
#define LADSPA_IS_PORT_INPUT(x) ((x) & LADSPA_PORT_INPUT)
#define LADSPA_IS_PORT_OUTPUT(x) ((x) & LADSPA_PORT_OUTPUT)
#define LADSPA_IS_PORT_CONTROL(x) ((x) & LADSPA_PORT_CONTROL)
#define LADSPA_IS_PORT_AUDIO(x) ((x) & LADSPA_PORT_AUDIO)
/*****************************************************************************/
/* Plugin Port Range Hints:
The host may wish to provide a representation of data entering or
leaving a plugin (e.g. to generate a GUI automatically). To make
this more meaningful, the plugin should provide `hints' to the host
describing the usual values taken by the data.
Note that these are only hints. The host may ignore them and the
plugin must not assume that data supplied to it is meaningful. If
the plugin receives invalid input data it is expected to continue
to run without failure and, where possible, produce a sensible
output (e.g. a high-pass filter given a negative cutoff frequency
might switch to an all-pass mode).
Hints are meaningful for all input and output ports but hints for
input control ports are expected to be particularly useful.
More hint information is encapsulated in the
LADSPA_PortRangeHintDescriptor type which is assembled by ORing
individual hint types together. Hints may require further
LowerBound and UpperBound information.
All the hint information for a particular port is aggregated in the
LADSPA_PortRangeHint structure. */
typedef int LADSPA_PortRangeHintDescriptor;
/* Hint LADSPA_HINT_BOUNDED_BELOW indicates that the LowerBound field
of the LADSPA_PortRangeHint should be considered meaningful. The
value in this field should be considered the (inclusive) lower
bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also
specified then the value of LowerBound should be multiplied by the
sample rate. */
#define LADSPA_HINT_BOUNDED_BELOW 0x1
/* Hint LADSPA_HINT_BOUNDED_ABOVE indicates that the UpperBound field
of the LADSPA_PortRangeHint should be considered meaningful. The
value in this field should be considered the (inclusive) upper
bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also
specified then the value of UpperBound should be multiplied by the
sample rate. */
#define LADSPA_HINT_BOUNDED_ABOVE 0x2
/* Hint LADSPA_HINT_TOGGLED indicates that the data item should be
considered a Boolean toggle. Data less than or equal to zero should
be considered `off' or `false,' and data above zero should be
considered `on' or `true.' LADSPA_HINT_TOGGLED may not be used in
conjunction with any other hint except LADSPA_HINT_DEFAULT_0 or
LADSPA_HINT_DEFAULT_1. */
#define LADSPA_HINT_TOGGLED 0x4
/* Hint LADSPA_HINT_SAMPLE_RATE indicates that any bounds specified
should be interpreted as multiples of the sample rate. For
instance, a frequency range from 0Hz to the Nyquist frequency (half
the sample rate) could be requested by this hint in conjunction
with LowerBound = 0 and UpperBound = 0.5. Hosts that support bounds
at all must support this hint to retain meaning. */
#define LADSPA_HINT_SAMPLE_RATE 0x8
/* Hint LADSPA_HINT_LOGARITHMIC indicates that it is likely that the
user will find it more intuitive to view values using a logarithmic
scale. This is particularly useful for frequencies and gains. */
#define LADSPA_HINT_LOGARITHMIC 0x10
/* Hint LADSPA_HINT_INTEGER indicates that a user interface would
probably wish to provide a stepped control taking only integer
values. Any bounds set should be slightly wider than the actual
integer range required to avoid floating point rounding errors. For
instance, the integer set {0,1,2,3} might be described as [-0.1,
3.1]. */
#define LADSPA_HINT_INTEGER 0x20
/* The various LADSPA_HINT_HAS_DEFAULT_* hints indicate a `normal'
value for the port that is sensible as a default. For instance,
this value is suitable for use as an initial value in a user
interface or as a value the host might assign to a control port
when the user has not provided one. Defaults are encoded using a
mask so only one default may be specified for a port. Some of the
hints make use of lower and upper bounds, in which case the
relevant bound or bounds must be available and
LADSPA_HINT_SAMPLE_RATE must be applied as usual. The resulting
default must be rounded if LADSPA_HINT_INTEGER is present. Default
values were introduced in LADSPA v1.1. */
#define LADSPA_HINT_DEFAULT_MASK 0x3C0
/* This default values indicates that no default is provided. */
#define LADSPA_HINT_DEFAULT_NONE 0x0
/* This default hint indicates that the suggested lower bound for the
port should be used. */
#define LADSPA_HINT_DEFAULT_MINIMUM 0x40
/* This default hint indicates that a low value between the suggested
lower and upper bounds should be chosen. For ports with
LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.75 +
log(upper) * 0.25). Otherwise, this should be (lower * 0.75 + upper
* 0.25). */
#define LADSPA_HINT_DEFAULT_LOW 0x80
/* This default hint indicates that a middle value between the
suggested lower and upper bounds should be chosen. For ports with
LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.5 +
log(upper) * 0.5). Otherwise, this should be (lower * 0.5 + upper *
0.5). */
#define LADSPA_HINT_DEFAULT_MIDDLE 0xC0
/* This default hint indicates that a high value between the suggested
lower and upper bounds should be chosen. For ports with
LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.25 +
log(upper) * 0.75). Otherwise, this should be (lower * 0.25 + upper
* 0.75). */
#define LADSPA_HINT_DEFAULT_HIGH 0x100
/* This default hint indicates that the suggested upper bound for the
port should be used. */
#define LADSPA_HINT_DEFAULT_MAXIMUM 0x140
/* This default hint indicates that the number 0 should be used. Note
that this default may be used in conjunction with
LADSPA_HINT_TOGGLED. */
#define LADSPA_HINT_DEFAULT_0 0x200
/* This default hint indicates that the number 1 should be used. Note
that this default may be used in conjunction with
LADSPA_HINT_TOGGLED. */
#define LADSPA_HINT_DEFAULT_1 0x240
/* This default hint indicates that the number 100 should be used. */
#define LADSPA_HINT_DEFAULT_100 0x280
/* This default hint indicates that the Hz frequency of `concert A'
should be used. This will be 440 unless the host uses an unusual
tuning convention, in which case it may be within a few Hz. */
#define LADSPA_HINT_DEFAULT_440 0x2C0
#define LADSPA_IS_HINT_BOUNDED_BELOW(x) ((x) & LADSPA_HINT_BOUNDED_BELOW)
#define LADSPA_IS_HINT_BOUNDED_ABOVE(x) ((x) & LADSPA_HINT_BOUNDED_ABOVE)
#define LADSPA_IS_HINT_TOGGLED(x) ((x) & LADSPA_HINT_TOGGLED)
#define LADSPA_IS_HINT_SAMPLE_RATE(x) ((x) & LADSPA_HINT_SAMPLE_RATE)
#define LADSPA_IS_HINT_LOGARITHMIC(x) ((x) & LADSPA_HINT_LOGARITHMIC)
#define LADSPA_IS_HINT_INTEGER(x) ((x) & LADSPA_HINT_INTEGER)
#define LADSPA_IS_HINT_HAS_DEFAULT(x) ((x) & LADSPA_HINT_DEFAULT_MASK)
#define LADSPA_IS_HINT_DEFAULT_MINIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
== LADSPA_HINT_DEFAULT_MINIMUM)
#define LADSPA_IS_HINT_DEFAULT_LOW(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
== LADSPA_HINT_DEFAULT_LOW)
#define LADSPA_IS_HINT_DEFAULT_MIDDLE(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
== LADSPA_HINT_DEFAULT_MIDDLE)
#define LADSPA_IS_HINT_DEFAULT_HIGH(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
== LADSPA_HINT_DEFAULT_HIGH)
#define LADSPA_IS_HINT_DEFAULT_MAXIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
== LADSPA_HINT_DEFAULT_MAXIMUM)
#define LADSPA_IS_HINT_DEFAULT_0(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
== LADSPA_HINT_DEFAULT_0)
#define LADSPA_IS_HINT_DEFAULT_1(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
== LADSPA_HINT_DEFAULT_1)
#define LADSPA_IS_HINT_DEFAULT_100(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
== LADSPA_HINT_DEFAULT_100)
#define LADSPA_IS_HINT_DEFAULT_440(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
== LADSPA_HINT_DEFAULT_440)
typedef struct _LADSPA_PortRangeHint {
/* Hints about the port. */
LADSPA_PortRangeHintDescriptor HintDescriptor;
/* Meaningful when hint LADSPA_HINT_BOUNDED_BELOW is active. When
LADSPA_HINT_SAMPLE_RATE is also active then this value should be
multiplied by the relevant sample rate. */
LADSPA_Data LowerBound;
/* Meaningful when hint LADSPA_HINT_BOUNDED_ABOVE is active. When
LADSPA_HINT_SAMPLE_RATE is also active then this value should be
multiplied by the relevant sample rate. */
LADSPA_Data UpperBound;
} LADSPA_PortRangeHint;
/*****************************************************************************/
/* Plugin Handles:
This plugin handle indicates a particular instance of the plugin
concerned. It is valid to compare this to NULL (0 for C++) but
otherwise the host should not attempt to interpret it. The plugin
may use it to reference internal instance data. */
typedef void * LADSPA_Handle;
/*****************************************************************************/
/* Descriptor for a Type of Plugin:
This structure is used to describe a plugin type. It provides a
number of functions to examine the type, instantiate it, link it to
buffers and workspaces and to run it. */
typedef struct _LADSPA_Descriptor {
/* This numeric identifier indicates the plugin type
uniquely. Plugin programmers may reserve ranges of IDs from a
central body to avoid clashes. Hosts may assume that IDs are
below 0x1000000. */
unsigned long UniqueID;
/* This identifier can be used as a unique, case-sensitive
identifier for the plugin type within the plugin file. Plugin
types should be identified by file and label rather than by index
or plugin name, which may be changed in new plugin
versions. Labels must not contain white-space characters. */
const char * Label;
/* This indicates a number of properties of the plugin. */
LADSPA_Properties Properties;
/* This member points to the null-terminated name of the plugin
(e.g. "Sine Oscillator"). */
const char * Name;
/* This member points to the null-terminated string indicating the
maker of the plugin. This can be an empty string but not NULL. */
const char * Maker;
/* This member points to the null-terminated string indicating any
copyright applying to the plugin. If no Copyright applies the
string "None" should be used. */
const char * Copyright;
/* This indicates the number of ports (input AND output) present on
the plugin. */
unsigned long PortCount;
/* This member indicates an array of port descriptors. Valid indices
vary from 0 to PortCount-1. */
const LADSPA_PortDescriptor * PortDescriptors;
/* This member indicates an array of null-terminated strings
describing ports (e.g. "Frequency (Hz)"). Valid indices vary from
0 to PortCount-1. */
const char * const * PortNames;
/* This member indicates an array of range hints for each port (see
above). Valid indices vary from 0 to PortCount-1. */
const LADSPA_PortRangeHint * PortRangeHints;
/* This may be used by the plugin developer to pass any custom
implementation data into an instantiate call. It must not be used
or interpreted by the host. It is expected that most plugin
writers will not use this facility as LADSPA_Handle should be
used to hold instance data. */
void * ImplementationData;
/* This member is a function pointer that instantiates a plugin. A
handle is returned indicating the new plugin instance. The
instantiation function accepts a sample rate as a parameter. The
plugin descriptor from which this instantiate function was found
must also be passed. This function must return NULL if
instantiation fails.
Note that instance initialisation should generally occur in
activate() rather than here. */
LADSPA_Handle (*instantiate)(const struct _LADSPA_Descriptor * Descriptor,
unsigned long SampleRate);
/* This member is a function pointer that connects a port on an
instantiated plugin to a memory location at which a block of data
for the port will be read/written. The data location is expected
to be an array of LADSPA_Data for audio ports or a single
LADSPA_Data value for control ports. Memory issues will be
managed by the host. The plugin must read/write the data at these
locations every time run() or run_adding() is called and the data
present at the time of this connection call should not be
considered meaningful.
connect_port() may be called more than once for a plugin instance
to allow the host to change the buffers that the plugin is
reading or writing. These calls may be made before or after
activate() or deactivate() calls.
connect_port() must be called at least once for each port before
run() or run_adding() is called. When working with blocks of
LADSPA_Data the plugin should pay careful attention to the block
size passed to the run function as the block allocated may only
just be large enough to contain the block of samples.
Plugin writers should be aware that the host may elect to use the
same buffer for more than one port and even use the same buffer
for both input and output (see LADSPA_PROPERTY_INPLACE_BROKEN).
However, overlapped buffers or use of a single buffer for both
audio and control data may result in unexpected behaviour. */
void (*connect_port)(LADSPA_Handle Instance,
unsigned long Port,
LADSPA_Data * DataLocation);
/* This member is a function pointer that initialises a plugin
instance and activates it for use. This is separated from
instantiate() to aid real-time support and so that hosts can
reinitialise a plugin instance by calling deactivate() and then
activate(). In this case the plugin instance must reset all state
information dependent on the history of the plugin instance
except for any data locations provided by connect_port() and any
gain set by set_run_adding_gain(). If there is nothing for
activate() to do then the plugin writer may provide a NULL rather
than an empty function.
When present, hosts must call this function once before run() (or
run_adding()) is called for the first time. This call should be
made as close to the run() call as possible and indicates to
real-time plugins that they are now live. Plugins should not rely
on a prompt call to run() after activate(). activate() may not be
called again unless deactivate() is called first. Note that
connect_port() may be called before or after a call to
activate(). */
void (*activate)(LADSPA_Handle Instance);
/* This method is a function pointer that runs an instance of a
plugin for a block. Two parameters are required: the first is a
handle to the particular instance to be run and the second
indicates the block size (in samples) for which the plugin
instance may run.
Note that if an activate() function exists then it must be called
before run() or run_adding(). If deactivate() is called for a
plugin instance then the plugin instance may not be reused until
activate() has been called again.
If the plugin has the property LADSPA_PROPERTY_HARD_RT_CAPABLE
then there are various things that the plugin should not do
within the run() or run_adding() functions (see above). */
void (*run)(LADSPA_Handle Instance,
unsigned long SampleCount);
/* This method is a function pointer that runs an instance of a
plugin for a block. This has identical behaviour to run() except
in the way data is output from the plugin. When run() is used,
values are written directly to the memory areas associated with
the output ports. However when run_adding() is called, values
must be added to the values already present in the memory
areas. Furthermore, output values written must be scaled by the
current gain set by set_run_adding_gain() (see below) before
addition.
run_adding() is optional. When it is not provided by a plugin,
this function pointer must be set to NULL. When it is provided,
the function set_run_adding_gain() must be provided also. */
void (*run_adding)(LADSPA_Handle Instance,
unsigned long SampleCount);
/* This method is a function pointer that sets the output gain for
use when run_adding() is called (see above). If this function is
never called the gain is assumed to default to 1. Gain
information should be retained when activate() or deactivate()
are called.
This function should be provided by the plugin if and only if the
run_adding() function is provided. When it is absent this
function pointer must be set to NULL. */
void (*set_run_adding_gain)(LADSPA_Handle Instance,
LADSPA_Data Gain);
/* This is the counterpart to activate() (see above). If there is
nothing for deactivate() to do then the plugin writer may provide
a NULL rather than an empty function.
Hosts must deactivate all activated units after they have been
run() (or run_adding()) for the last time. This call should be
made as close to the last run() call as possible and indicates to
real-time plugins that they are no longer live. Plugins should
not rely on prompt deactivation. Note that connect_port() may be
called before or after a call to deactivate().
Deactivation is not similar to pausing as the plugin instance
will be reinitialised when activate() is called to reuse it. */
void (*deactivate)(LADSPA_Handle Instance);
/* Once an instance of a plugin has been finished with it can be
deleted using the following function. The instance handle passed
ceases to be valid after this call.
If activate() was called for a plugin instance then a
corresponding call to deactivate() must be made before cleanup()
is called. */
void (*cleanup)(LADSPA_Handle Instance);
} LADSPA_Descriptor;
/**********************************************************************/
/* Accessing a Plugin: */
/* The exact mechanism by which plugins are loaded is host-dependent,
however all most hosts will need to know is the name of shared
object file containing the plugin types. To allow multiple hosts to
share plugin types, hosts may wish to check for environment
variable LADSPA_PATH. If present, this should contain a
colon-separated path indicating directories that should be searched
(in order) when loading plugin types.
A plugin programmer must include a function called
"ladspa_descriptor" with the following function prototype within
the shared object file. This function will have C-style linkage (if
you are using C++ this is taken care of by the `extern "C"' clause
at the top of the file).
A host will find the plugin shared object file by one means or
another, find the ladspa_descriptor() function, call it, and
proceed from there.
Plugin types are accessed by index (not ID) using values from 0
upwards. Out of range indexes must result in this function
returning NULL, so the plugin count can be determined by checking
for the least index that results in NULL being returned. */
const LADSPA_Descriptor * ladspa_descriptor(unsigned long Index);
/* Datatype corresponding to the ladspa_descriptor() function. */
typedef const LADSPA_Descriptor *
(*LADSPA_Descriptor_Function)(unsigned long Index);
/**********************************************************************/
#ifdef __cplusplus
}
#endif
#endif /* LADSPA_INCLUDED */
/* EOF */

View File

@@ -0,0 +1,142 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __ardour_ladspa_plugin_h__
#define __ardour_ladspa_plugin_h__
#include <list>
#include <set>
#include <vector>
#include <string>
#include <dlfcn.h>
#include <midi++/controllable.h>
#include <sigc++/signal.h>
#include <jack/types.h>
#include <ardour/ladspa.h>
#include <ardour/stateful.h>
#include <ardour/plugin_state.h>
#include <ardour/plugin.h>
#include <ardour/ladspa_plugin.h>
using std::string;
using std::vector;
using std::list;
namespace ARDOUR {
class AudioEngine;
class Session;
class LadspaPlugin : public ARDOUR::Plugin
{
public:
LadspaPlugin (void *module, ARDOUR::AudioEngine&, ARDOUR::Session&, uint32_t index, jack_nframes_t sample_rate);
LadspaPlugin (const LadspaPlugin &);
~LadspaPlugin ();
/* Plugin interface */
uint32_t unique_id() const { return descriptor->UniqueID; }
const char * label() const { return descriptor->Label; }
const char * name() const { return descriptor->Name; }
const char * maker() const { return descriptor->Maker; }
uint32_t parameter_count() const { return descriptor->PortCount; }
float default_value (uint32_t port);
jack_nframes_t latency() const;
void set_parameter (uint32_t port, float val);
float get_parameter (uint32_t port) const;
int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const;
std::set<uint32_t> automatable() const;
uint32_t nth_parameter (uint32_t port, bool& ok) const;
void activate () {
if (descriptor->activate) {
descriptor->activate (handle);
}
was_activated = true;
}
void deactivate () {
if (descriptor->deactivate)
descriptor->deactivate (handle);
}
void cleanup () {
if (was_activated && descriptor->cleanup) {
descriptor->cleanup (handle);
}
}
void set_block_size (jack_nframes_t nframes) {}
int connect_and_run (vector<Sample*>& bufs, uint32_t maxbuf, int32_t& in, int32_t& out, jack_nframes_t nframes, jack_nframes_t offset);
void store_state (ARDOUR::PluginState&);
void restore_state (ARDOUR::PluginState&);
string describe_parameter (uint32_t);
string state_node_name() const { return "ladspa"; }
void print_parameter (uint32_t, char*, uint32_t len) const;
bool parameter_is_audio(uint32_t) const;
bool parameter_is_control(uint32_t) const;
bool parameter_is_input(uint32_t) const;
bool parameter_is_output(uint32_t) const;
bool parameter_is_toggled(uint32_t) const;
XMLNode& get_state();
int set_state(const XMLNode& node);
bool save_preset(string name);
bool has_editor() const { return false; }
int require_output_streams (uint32_t);
/* LADSPA extras */
LADSPA_Properties properties() const { return descriptor->Properties; }
uint32_t index() const { return _index; }
const char * copyright() const { return descriptor->Copyright; }
LADSPA_PortDescriptor port_descriptor(uint32_t i) const { return descriptor->PortDescriptors[i]; }
const LADSPA_PortRangeHint * port_range_hints() const { return descriptor->PortRangeHints; }
const char * const * port_names() const { return descriptor->PortNames; }
void set_gain (float gain) {
descriptor->set_run_adding_gain (handle, gain);
}
void run_adding (uint32_t nsamples) {
descriptor->run_adding (handle, nsamples);
}
void connect_port (uint32_t port, float *ptr) {
descriptor->connect_port (handle, port, ptr);
}
private:
void *module;
const LADSPA_Descriptor *descriptor;
LADSPA_Handle handle;
jack_nframes_t sample_rate;
LADSPA_Data *control_data;
LADSPA_Data *shadow_data;
LADSPA_Data *latency_control_port;
uint32_t _index;
bool was_activated;
void init (void *mod, uint32_t index, jack_nframes_t rate);
void run (jack_nframes_t nsamples);
void latency_compute_run ();
};
}
#endif /* __ardour_ladspa_plugin_h__ */

View File

@@ -0,0 +1,193 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __ardour_location_h__
#define __ardour_location_h__
#include <string>
#include <list>
#include <iostream>
#include <map>
#include <sys/types.h>
#include <pthread.h>
#include <sigc++/signal.h>
#include <pbd/lockmonitor.h>
#include <pbd/undo.h>
#include "ardour.h"
#include "stateful.h"
#include "state_manager.h"
using std::string;
namespace ARDOUR {
class Location : public Stateful, public sigc::trackable
{
public:
enum Flags {
IsMark = 0x1,
IsAutoPunch = 0x2,
IsAutoLoop = 0x4,
IsHidden = 0x8,
IsCDMarker = 0x10,
IsEnd = 0x20
};
Location (jack_nframes_t sample_start,
jack_nframes_t sample_end,
const string &name,
Flags bits = Flags(0))
: _name (name),
_start (sample_start),
_end (sample_end),
_flags (bits) { }
Location () {
_start = 0;
_end = 0;
_flags = 0;
}
Location (const Location& other);
Location* operator= (const Location& other);
jack_nframes_t start() { return _start; }
jack_nframes_t end() { return _end; }
jack_nframes_t length() { return _end - _start; }
int set_start (jack_nframes_t s);
int set_end (jack_nframes_t e);
int set (jack_nframes_t start, jack_nframes_t end);
const string& name() { return _name; }
void set_name (const string &str) { _name = str; name_changed(this); }
void set_auto_punch (bool yn, void *src);
void set_auto_loop (bool yn, void *src);
void set_hidden (bool yn, void *src);
void set_cd (bool yn, void *src);
void set_is_end (bool yn, void* src);
bool is_auto_punch () { return _flags & IsAutoPunch; }
bool is_auto_loop () { return _flags & IsAutoLoop; }
bool is_mark () { return _flags & IsMark; }
bool is_hidden () { return _flags & IsHidden; }
bool is_cd_marker () { return _flags & IsCDMarker; }
bool is_end() { return _flags & IsEnd; }
sigc::signal<void,Location*> name_changed;
sigc::signal<void,Location*> end_changed;
sigc::signal<void,Location*> start_changed;
sigc::signal<void,Location*,void*> FlagsChanged;
/* this is sent only when both start&end change at the same time */
sigc::signal<void,Location*> changed;
/* CD Track / CD-Text info */
std::map<string, string> cd_info;
XMLNode& cd_info_node (const string &, const string &);
XMLNode& get_state (void);
int set_state (const XMLNode&);
private:
string _name;
jack_nframes_t _start;
jack_nframes_t _end;
uint32_t _flags;
void set_mark (bool yn);
bool set_flag_internal (bool yn, Flags flag);
};
class Locations : public Stateful, public StateManager
{
public:
typedef std::list<Location *> LocationList;
Locations ();
~Locations ();
void add (Location *, bool make_current = false);
void remove (Location *);
void clear ();
void clear_markers ();
void clear_ranges ();
XMLNode& get_state (void);
int set_state (const XMLNode&);
Location* auto_loop_location () const;
Location* auto_punch_location () const;
Location* end_location() const;
int set_current (Location *, bool want_lock = true);
Location *current () const { return current_location; }
Location *first_location_before (jack_nframes_t);
Location *first_location_after (jack_nframes_t);
sigc::signal<void,Location*> current_changed;
sigc::signal<void> changed;
sigc::signal<void,Location*> added;
sigc::signal<void,Location*> removed;
template<class T> void apply (T& obj, void (T::*method)(LocationList&)) {
LockMonitor lm (lock, __LINE__, __FILE__);
(obj.*method)(locations);
}
template<class T1, class T2> void apply (T1& obj, void (T1::*method)(LocationList&, T2& arg), T2& arg) {
LockMonitor lm (lock, __LINE__, __FILE__);
(obj.*method)(locations, arg);
}
UndoAction get_memento () const;
private:
struct State : public ARDOUR::StateManager::State {
LocationList locations;
LocationList states;
State (std::string why) : ARDOUR::StateManager::State (why) {}
};
LocationList locations;
Location *current_location;
PBD::Lock lock;
int set_current_unlocked (Location *);
void location_changed (Location*);
Change restore_state (StateManager::State&);
StateManager::State* state_factory (std::string why) const;
};
}; /* namespace ARDOUR */
#endif /* __ardour_location_h__ */

View File

@@ -0,0 +1,133 @@
/*
Copyright (C) 2001 Steve Harris & 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$
*/
#ifndef __ardour_logcurve_h__
#define __ardour_logcurve_h__
#include <pbd/fastlog.h>
#include <pbd/lockmonitor.h>
namespace ARDOUR {
class LogCurve {
public:
LogCurve (float steepness = 0.2, uint32_t len = 0) {
l = len;
S = steepness;
a = log(S);
b = 1.0f / log(1.0f + (1.0f / S));
}
bool operator== (const LogCurve& other) const {
return S == other.S && l == other.l;
}
bool operator!= (const LogCurve& other) const {
return S != other.S || l != other.l;
}
float value (float frac) const {
return (fast_log(frac + S) - a) * b;
}
float value (uint32_t pos) const {
return (fast_log(((float) pos/l) + S) - a) * b;
}
float invert_value (float frac) const {
return (a - fast_log(frac + S)) * b;
}
float invert_value (uint32_t pos) const {
return (a - fast_log(((float) pos/l) + S)) * b;
}
void fill (float *vec, uint32_t veclen, bool invert) const {
float dx = 1.0f/veclen;
float x;
uint32_t i;
if (!invert) {
vec[0] = 0.0;
vec[veclen-1] = 1.0;
for (i = 1, x = 0; i < veclen - 1; x += dx, i++) {
vec[i] = value (x);
}
} else {
vec[0] = 1.0;
vec[veclen-1] = 0.0;
for (i = veclen-2, x = 0.0f; i > 0; x += dx, i--) {
vec[i] = value (x);
}
}
}
float steepness() const { return S; }
uint32_t length() const { return l; }
void set_steepness (float steepness) {
S = steepness;
a = log(S);
b = 1.0f / log(1.0f + (1.0f / S));
}
void set_length (uint32_t len) { l = len; }
mutable PBD::NonBlockingLock lock;
protected:
float a;
float b;
float S;
uint32_t l;
};
class LogCurveIn : public LogCurve
{
public:
LogCurveIn (float steepness = 0.2, uint32_t len = 0)
: LogCurve (steepness, len) {}
float value (float frac) const {
return (fast_log(frac + S) - a) * b;
}
float value (uint32_t pos) const {
return (fast_log(((float) pos/l) + S) - a) * b;
}
};
class LogCurveOut : public LogCurve
{
public:
LogCurveOut (float steepness = 0.2, uint32_t len = 0)
: LogCurve (steepness, len) {}
};
}; /* namespace ARDOUR */
#endif /* __ardour_logcurve_h__ */

74
libs/ardour/ardour/mix.h Normal file
View File

@@ -0,0 +1,74 @@
/*
Copyright (C) 2005 Sampo Savolainen
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$
*/
#ifndef __ardour_mix_h__
#define __ardour_mix_h__
#include <ardour/types.h>
#include <ardour/utils.h>
#include <ardour/io.h>
#if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
extern "C" {
/* SSE functions */
float x86_sse_compute_peak (ARDOUR::Sample *buf, jack_nframes_t nsamples, float current);
void x86_sse_apply_gain_to_buffer (ARDOUR::Sample *buf, jack_nframes_t nframes, float gain);
void x86_sse_mix_buffers_with_gain (ARDOUR::Sample *dst, ARDOUR::Sample *src, jack_nframes_t nframes, float gain);
void x86_sse_mix_buffers_no_gain (ARDOUR::Sample *dst, ARDOUR::Sample *src, jack_nframes_t nframes);
}
/* debug wrappers for SSE functions */
float debug_compute_peak (ARDOUR::Sample *buf, jack_nframes_t nsamples, float current);
void debug_apply_gain_to_buffer (ARDOUR::Sample *buf, jack_nframes_t nframes, float gain);
void debug_mix_buffers_with_gain (ARDOUR::Sample *dst, ARDOUR::Sample *src, jack_nframes_t nframes, float gain);
void debug_mix_buffers_no_gain (ARDOUR::Sample *dst, ARDOUR::Sample *src, jack_nframes_t nframes);
#endif
#if defined (__APPLE__)
float veclib_compute_peak (ARDOUR::Sample *buf, jack_nframes_t nsamples, float current);
void veclib_apply_gain_to_buffer (ARDOUR::Sample *buf, jack_nframes_t nframes, float gain);
void veclib_mix_buffers_with_gain (ARDOUR::Sample *dst, ARDOUR::Sample *src, jack_nframes_t nframes, float gain);
void veclib_mix_buffers_no_gain (ARDOUR::Sample *dst, ARDOUR::Sample *src, jack_nframes_t nframes);
#endif
/* non-optimized functions */
float compute_peak (ARDOUR::Sample *buf, jack_nframes_t nsamples, float current);
void apply_gain_to_buffer (ARDOUR::Sample *buf, jack_nframes_t nframes, float gain);
void mix_buffers_with_gain (ARDOUR::Sample *dst, ARDOUR::Sample *src, jack_nframes_t nframes, float gain);
void mix_buffers_no_gain (ARDOUR::Sample *dst, ARDOUR::Sample *src, jack_nframes_t nframes);
#endif /* __ardour_mix_h__ */

View File

@@ -0,0 +1,55 @@
/*
Copyright (C) 2003 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$
*/
#ifndef __ardour_named_selection_h__
#define __ardour_named_selection_h__
#include <string>
#include <list>
#include <ardour/stateful.h>
class XMLNode;
namespace ARDOUR
{
class Session;
class Playlist;
struct NamedSelection : public Stateful
{
NamedSelection (std::string, std::list<Playlist*>&);
NamedSelection (Session&, const XMLNode&);
virtual ~NamedSelection ();
std::string name;
std::list<Playlist*> playlists;
XMLNode& get_state (void);
int set_state (const XMLNode&);
static sigc::signal<void,NamedSelection*> NamedSelectionCreated;
};
}/* namespace ARDOUR */
#endif /* __ardour_named_selection_h__ */

View File

@@ -0,0 +1,19 @@
#ifndef NOISE_H
#define NOISE_H
/* Can be overrriden with any code that produces whitenoise between 0.0f and
* 1.0f, eg (random() / (float)RAND_MAX) should be a good source of noise, but
* its expensive */
#ifndef GDITHER_NOISE
#define GDITHER_NOISE gdither_noise()
#endif
inline static float gdither_noise()
{
static uint32_t rnd = 23232323;
rnd = (rnd * 196314165) + 907633515;
return rnd * 2.3283064365387e-10f;
}
#endif

331
libs/ardour/ardour/panner.h Normal file
View File

@@ -0,0 +1,331 @@
/*
Copyright (C) 2004 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
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$
*/
#ifndef __ardour_panner_h__
#define __ardour_panner_h__
#include <cmath>
#include <vector>
#include <string>
#include <iostream>
#include <sigc++/signal.h>
#include <midi++/controllable.h>
#include <ardour/types.h>
#include <ardour/stateful.h>
#include <ardour/curve.h>
using std::istream;
using std::ostream;
namespace ARDOUR {
class Session;
class Panner;
class StreamPanner : public sigc::trackable, public Stateful
{
public:
StreamPanner (Panner& p);
~StreamPanner ();
void set_muted (bool yn);
bool muted() const { return _muted; }
void set_position (float x, bool link_call = false);
void set_position (float x, float y, bool link_call = false);
void set_position (float x, float y, float z, bool link_call = false);
void get_position (float& xpos) const { xpos = x; }
void get_position (float& xpos, float& ypos) const { xpos = x; ypos = y; }
void get_position (float& xpos, float& ypos, float& zpos) const { xpos = x; ypos = y; zpos = z; }
void get_effective_position (float& xpos) const { xpos = effective_x; }
void get_effective_position (float& xpos, float& ypos) const { xpos = effective_x; ypos = effective_y; }
void get_effective_position (float& xpos, float& ypos, float& zpos) const { xpos = effective_x; ypos = effective_y; zpos = effective_z; }
/* the basic panner API */
virtual void distribute (Sample* src, Sample** obufs, gain_t gain_coeff, jack_nframes_t nframes) = 0;
virtual void distribute_automated (Sample* src, Sample** obufs,
jack_nframes_t start, jack_nframes_t end, jack_nframes_t nframes, pan_t** buffers) = 0;
/* automation */
virtual void snapshot (jack_nframes_t now) = 0;
virtual void transport_stopped (jack_nframes_t frame) = 0;
virtual void set_automation_state (AutoState) = 0;
virtual void set_automation_style (AutoStyle) = 0;
/* MIDI control */
struct MIDIControl : public MIDI::Controllable {
MIDIControl (StreamPanner&, MIDI::Port *);
void set_value (float);
void send_feedback (gain_t);
MIDI::byte* write_feedback (MIDI::byte* buf, int32_t& bufsize, gain_t val, bool force = false);
pan_t (*midi_to_pan)(double val);
double (*pan_to_midi)(pan_t p);
StreamPanner& sp;
bool setting;
gain_t last_written;
};
MIDIControl& midi_control() { return _midi_control; }
void reset_midi_control (MIDI::Port *, bool);
/* XXX this is wrong. for multi-dimensional panners, there
must surely be more than 1 automation curve.
*/
virtual Curve& automation() = 0;
virtual int load (istream&, string path, uint32_t&) = 0;
virtual int save (ostream&) const = 0;
sigc::signal<void> Changed; /* for position */
sigc::signal<void> StateChanged; /* for mute */
int set_state (const XMLNode&);
virtual XMLNode& state (bool full_state) = 0;
Panner & get_parent() { return parent; }
protected:
friend class Panner;
Panner& parent;
float x;
float y;
float z;
/* these are for automation. they store the last value
used by the most recent process() cycle.
*/
float effective_x;
float effective_y;
float effective_z;
bool _muted;
MIDIControl _midi_control;
void add_state (XMLNode&);
bool get_midi_node_info (XMLNode * node, MIDI::eventType & ev, MIDI::channel_t & chan, MIDI::byte & additional);
bool set_midi_node_info (XMLNode * node, MIDI::eventType ev, MIDI::channel_t chan, MIDI::byte additional);
virtual void update () = 0;
};
class BaseStereoPanner : public StreamPanner
{
public:
BaseStereoPanner (Panner&);
~BaseStereoPanner ();
/* this class just leaves the pan law itself to be defined
by the update(), distribute_automated()
methods. derived classes also need a factory method
and a type name. See EqualPowerStereoPanner as an example.
*/
void distribute (Sample* src, Sample** obufs, gain_t gain_coeff, jack_nframes_t nframes);
int load (istream&, string path, uint32_t&);
int save (ostream&) const;
void snapshot (jack_nframes_t now);
void transport_stopped (jack_nframes_t frame);
void set_automation_state (AutoState);
void set_automation_style (AutoStyle);
Curve& automation() { return _automation; }
protected:
float left;
float right;
float desired_left;
float desired_right;
float left_interp;
float right_interp;
Curve _automation;
};
class EqualPowerStereoPanner : public BaseStereoPanner
{
public:
EqualPowerStereoPanner (Panner&);
~EqualPowerStereoPanner ();
void distribute_automated (Sample* src, Sample** obufs,
jack_nframes_t start, jack_nframes_t end, jack_nframes_t nframes, pan_t** buffers);
void get_current_coefficients (pan_t*) const;
void get_desired_coefficients (pan_t*) const;
static StreamPanner* factory (Panner&);
static string name;
XMLNode& state (bool full_state);
XMLNode& get_state (void);
int set_state (const XMLNode&);
private:
void update ();
};
class Multi2dPanner : public StreamPanner
{
public:
Multi2dPanner (Panner& parent);
~Multi2dPanner ();
void snapshot (jack_nframes_t now);
void transport_stopped (jack_nframes_t frame);
void set_automation_state (AutoState);
void set_automation_style (AutoStyle);
/* XXX this is wrong. for multi-dimensional panners, there
must surely be more than 1 automation curve.
*/
Curve& automation() { return _automation; }
void distribute (Sample* src, Sample** obufs, gain_t gain_coeff, jack_nframes_t nframes);
void distribute_automated (Sample* src, Sample** obufs,
jack_nframes_t start, jack_nframes_t end, jack_nframes_t nframes, pan_t** buffers);
int load (istream&, string path, uint32_t&);
int save (ostream&) const;
static StreamPanner* factory (Panner&);
static string name;
XMLNode& state (bool full_state);
XMLNode& get_state (void);
int set_state (const XMLNode&);
private:
Curve _automation;
void update ();
};
class Panner : public std::vector<StreamPanner*>, public Stateful, public sigc::trackable
{
public:
struct Output {
float x;
float y;
pan_t current_pan;
pan_t desired_pan;
Output (float xp, float yp)
: x (xp), y (yp), current_pan (0.0f), desired_pan (0.f) {}
};
Panner (string name, Session&);
virtual ~Panner ();
void set_name (string);
bool bypassed() const { return _bypassed; }
void set_bypassed (bool yn);
StreamPanner* add ();
void remove (uint32_t which);
void clear ();
void reset (uint32_t noutputs, uint32_t npans);
void snapshot (jack_nframes_t now);
void transport_stopped (jack_nframes_t frame);
void clear_automation ();
void set_automation_state (AutoState);
AutoState automation_state() const;
void set_automation_style (AutoStyle);
AutoStyle automation_style() const;
bool touching() const;
int load ();
int save () const;
XMLNode& get_state (void);
XMLNode& state (bool full);
int set_state (const XMLNode&);
sigc::signal<void> Changed;
static bool equivalent (pan_t a, pan_t b) {
return fabsf (a - b) < 0.002; // about 1 degree of arc for a stereo panner
}
void move_output (uint32_t, float x, float y);
uint32_t nouts() const { return outputs.size(); }
Output& output (uint32_t n) { return outputs[n]; }
std::vector<Output> outputs;
Session& session() const { return _session; }
void reset_midi_control (MIDI::Port *, bool);
void send_all_midi_feedback ();
MIDI::byte* write_midi_feedback (MIDI::byte*, int32_t& bufsize);
enum LinkDirection {
SameDirection,
OppositeDirection
};
LinkDirection link_direction() const { return _link_direction; }
void set_link_direction (LinkDirection);
bool linked() const { return _linked; }
void set_linked (bool yn);
sigc::signal<void> LinkStateChanged;
sigc::signal<void> StateChanged; /* for bypass */
/* only StreamPanner should call these */
void set_position (float x, StreamPanner& orig);
void set_position (float x, float y, StreamPanner& orig);
void set_position (float x, float y, float z, StreamPanner& orig);
private:
string automation_path;
Session& _session;
uint32_t current_outs;
bool _linked;
bool _bypassed;
LinkDirection _link_direction;
static float current_automation_version_number;
};
}; /* namespace ARDOUR */
#endif /*__ardour_panner_h__ */

17
libs/ardour/ardour/peak.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef __ardour_peak_h__
#define __ardour_peak_h__
#include <cmath>
#include <ardour/types.h>
#include <ardour/utils.h>
static inline float
compute_peak (ARDOUR::Sample *buf, jack_nframes_t nsamples, float current)
{
for (jack_nframes_t i = 0; i < nsamples; ++i) {
current = f_max (current, fabsf (buf[i]));
}
return current;
}
#endif /* __ardour_peak_h__ */

View File

@@ -0,0 +1,278 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __ardour_playlist_h__
#define __ardour_playlist_h__
#include <string>
#include <set>
#include <map>
#include <list>
#include <sys/stat.h>
#include <sigc++/signal.h>
#include <pbd/atomic.h>
#include <pbd/undo.h>
#include <ardour/ardour.h>
#include <ardour/crossfade_compare.h>
#include <ardour/location.h>
#include <ardour/stateful.h>
#include <ardour/source.h>
#include <ardour/state_manager.h>
namespace ARDOUR {
class Session;
class Region;
class Playlist : public Stateful, public StateManager {
public:
typedef list<Region*> RegionList;
Playlist (Session&, const XMLNode&, bool hidden = false);
Playlist (Session&, string name, bool hidden = false);
Playlist (const Playlist&, string name, bool hidden = false);
Playlist (const Playlist&, jack_nframes_t start, jack_nframes_t cnt, string name, bool hidden = false);
virtual jack_nframes_t read (Sample *dst, Sample *mixdown, float *gain_buffer, jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n=0) = 0;
virtual void clear (bool with_delete = false, bool with_save = true);
virtual void dump () const;
virtual UndoAction get_memento() const = 0;
void ref();
void unref();
uint32_t refcnt() const { return _refcnt; }
const string& name() const { return _name; }
void set_name (const string& str);
bool frozen() const { return _frozen; }
void set_frozen (bool yn);
bool hidden() const { return _hidden; }
bool empty() const;
jack_nframes_t get_maximum_extent () const;
layer_t top_layer() const;
EditMode get_edit_mode() const { return _edit_mode; }
void set_edit_mode (EditMode);
/* Editing operations */
void add_region (const Region&, jack_nframes_t position, float times = 1, bool with_save = true);
void remove_region (Region *);
void replace_region (Region& old, Region& newr, jack_nframes_t pos);
void split_region (Region&, jack_nframes_t position);
void partition (jack_nframes_t start, jack_nframes_t end, bool just_top_level);
void duplicate (Region&, jack_nframes_t position, float times);
void nudge_after (jack_nframes_t start, jack_nframes_t distance, bool forwards);
Region* find_region (id_t) const;
Playlist* cut (list<AudioRange>&, bool result_is_hidden = true);
Playlist* copy (list<AudioRange>&, bool result_is_hidden = true);
int paste (Playlist&, jack_nframes_t position, float times);
uint32_t read_data_count() { return _read_data_count; }
RegionList* regions_at (jack_nframes_t frame);
RegionList* regions_touched (jack_nframes_t start, jack_nframes_t end);
Region* top_region_at (jack_nframes_t frame);
Region* find_next_region (jack_nframes_t frame, RegionPoint point, int dir);
template<class T> void foreach_region (T *t, void (T::*func)(Region *, void *), void *arg);
template<class T> void foreach_region (T *t, void (T::*func)(Region *));
XMLNode& get_state ();
int set_state (const XMLNode&);
XMLNode& get_template ();
sigc::signal<void,Region *> RegionAdded;
sigc::signal<void,Region *> RegionRemoved;
sigc::signal<void,Playlist*,bool> InUse;
sigc::signal<void> Modified;
sigc::signal<void> NameChanged;
sigc::signal<void> LengthChanged;
sigc::signal<void> LayeringChanged;
sigc::signal<void,Playlist *> GoingAway;
sigc::signal<void> StatePushed;
static sigc::signal<void,Playlist*> PlaylistCreated;
static string bump_name (string old_name, Session&);
static string bump_name_once (string old_name);
void freeze ();
void thaw ();
void raise_region (Region&);
void lower_region (Region&);
void raise_region_to_top (Region&);
void lower_region_to_bottom (Region&);
uint32_t read_data_count() const { return _read_data_count; }
Session& session() { return _session; }
id_t get_orig_diskstream_id () const { return _orig_diskstream_id; }
void set_orig_diskstream_id (id_t did) { _orig_diskstream_id = did; }
/* destructive editing */
virtual bool destroy_region (Region *) = 0;
protected:
friend class Session;
virtual ~Playlist (); /* members of the public use unref() */
protected:
struct RegionLock {
RegionLock (Playlist *pl, bool do_block_notify = true) : playlist (pl), block_notify (do_block_notify) {
playlist->region_lock.lock();
if (block_notify) {
playlist->delay_notifications();
}
}
~RegionLock() {
playlist->region_lock.unlock();
if (block_notify) {
playlist->release_notifications ();
}
}
Playlist *playlist;
bool block_notify;
};
friend class RegionLock;
RegionList regions;
string _name;
Session& _session;
atomic_t block_notifications;
atomic_t ignore_state_changes;
mutable PBD::NonBlockingLock region_lock;
RegionList pending_removals;
RegionList pending_adds;
RegionList pending_bounds;
bool pending_modified;
bool pending_length;
bool save_on_thaw;
string last_save_reason;
bool in_set_state;
bool _hidden;
bool _splicing;
bool _nudging;
uint32_t _refcnt;
EditMode _edit_mode;
bool in_flush;
bool in_partition;
bool _frozen;
uint32_t subcnt;
uint32_t _read_data_count;
id_t _orig_diskstream_id;
uint64_t layer_op_counter;
jack_nframes_t freeze_length;
void init (bool hide);
bool holding_state () const {
return atomic_read (&block_notifications) != 0 ||
atomic_read (&ignore_state_changes) != 0;
}
/* prevent the compiler from ever generating these */
Playlist (const Playlist&);
Playlist (Playlist&);
void delay_notifications ();
void release_notifications ();
virtual void flush_notifications ();
void notify_region_removed (Region *);
void notify_region_added (Region *);
void notify_length_changed ();
void notify_layering_changed ();
void notify_modified ();
void notify_state_changed (Change);
void mark_session_dirty();
void region_changed_proxy (Change, Region*);
virtual bool region_changed (Change, Region*);
void region_bounds_changed (Change, Region *);
void region_deleted (Region *);
void sort_regions ();
void possibly_splice ();
void possibly_splice_unlocked();
void core_splice ();
void splice_locked ();
void splice_unlocked ();
virtual void check_dependents (Region& region, bool norefresh) {}
virtual void refresh_dependents (Region& region) {}
virtual void remove_dependents (Region& region) {}
virtual XMLNode& state (bool);
/* override state_manager::save_state so we can check in_set_state() */
void save_state (std::string why);
void maybe_save_state (std::string why);
void add_region_internal (Region *, jack_nframes_t position, bool delay_sort = false);
int remove_region_internal (Region *, bool delay_sort = false);
RegionList *find_regions_at (jack_nframes_t frame);
void copy_regions (RegionList&) const;
void partition_internal (jack_nframes_t start, jack_nframes_t end, bool cutting, RegionList& thawlist);
jack_nframes_t _get_maximum_extent() const;
Playlist* cut_copy (Playlist* (Playlist::*pmf)(jack_nframes_t, jack_nframes_t, bool),
list<AudioRange>& ranges, bool result_is_hidden);
Playlist *cut (jack_nframes_t start, jack_nframes_t cnt, bool result_is_hidden);
Playlist *copy (jack_nframes_t start, jack_nframes_t cnt, bool result_is_hidden);
int move_region_to_layer (layer_t, Region& r, int dir);
void relayer ();
static Playlist* copyPlaylist (const Playlist&, jack_nframes_t start, jack_nframes_t length,
string name, bool result_is_hidden);
void unset_freeze_parent (Playlist*);
void unset_freeze_child (Playlist*);
void timestamp_layer_op (Region&);
};
} /* namespace ARDOUR */
#endif /* __ardour_playlist_h__ */

View File

@@ -0,0 +1,49 @@
/*
Copyright (C) 2003 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$
*/
#ifndef __ardour_playlist_templates_h__
#define __ardour_playlist_templates_h__
namespace ARDOUR {
template<class T> void AudioPlaylist::foreach_crossfade (T *t, void (T::*func)(Crossfade *)) {
RegionLock rlock (this, false);
for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); i++) {
(t->*func) (*i);
}
}
template<class T> void Playlist::foreach_region (T *t, void (T::*func)(Region *, void *), void *arg) {
RegionLock rlock (this, false);
for (RegionList::iterator i = regions.begin(); i != regions.end(); i++) {
(t->*func) ((*i), arg);
}
}
template<class T> void Playlist::foreach_region (T *t, void (T::*func)(Region *)) {
RegionLock rlock (this, false);
for (RegionList::const_iterator i = regions.begin(); i != regions.end(); i++) {
(t->*func) (*i);
}
}
}
#endif /* __ardour_playlist_templates_h__ */

194
libs/ardour/ardour/plugin.h Normal file
View File

@@ -0,0 +1,194 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __ardour_ladspa_h__
#define __ardour_ladspa_h__
#include <midi++/controllable.h>
#include <sigc++/signal.h>
#include <jack/types.h>
#include <ardour/types.h>
#include <ardour/stateful.h>
#include <ardour/plugin_state.h>
#include <ardour/cycles.h>
#include <list>
#include <vector>
#include <set>
#include <map>
using std::string;
using std::vector;
using std::list;
using std::set;
using std::map;
namespace ARDOUR {
class AudioEngine;
class Session;
class PluginInfo {
public:
enum Type {
LADSPA,
VST
};
PluginInfo () { };
PluginInfo (const PluginInfo &o)
: name(o.name), n_inputs(o.n_inputs), n_outputs(o.n_outputs),
path (o.path), index(o.index) {}
~PluginInfo () { };
string name;
string category;
uint32_t n_inputs;
uint32_t n_outputs;
Type type;
private:
friend class PluginManager;
string path;
uint32_t index;
};
class Plugin : public Stateful, public sigc::trackable
{
public:
Plugin (ARDOUR::AudioEngine&, ARDOUR::Session&);
Plugin (const Plugin&);
~Plugin ();
struct ParameterDescriptor {
/* essentially a union of LADSPA and VST info */
bool integer_step;
bool toggled;
bool logarithmic;
bool sr_dependent;
string label;
float lower;
float upper;
float step;
float smallstep;
float largestep;
bool min_unbound;
bool max_unbound;
};
virtual uint32_t unique_id() const = 0;
virtual const char * label() const = 0;
virtual const char * name() const = 0;
virtual const char * maker() const = 0;
virtual uint32_t parameter_count () const = 0;
virtual float default_value (uint32_t port) = 0;
virtual jack_nframes_t latency() const = 0;
virtual void set_parameter (uint32_t which, float val) = 0;
virtual float get_parameter(uint32_t which) const = 0;
virtual int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const = 0;
virtual uint32_t nth_parameter (uint32_t which, bool& ok) const = 0;
virtual void activate () = 0;
virtual void deactivate () = 0;
virtual void set_block_size (jack_nframes_t nframes) = 0;
virtual int connect_and_run (vector<Sample*>& bufs, uint32_t maxbuf, int32_t& in, int32_t& out, jack_nframes_t nframes, jack_nframes_t offset) = 0;
virtual std::set<uint32_t> automatable() const = 0;
virtual void store_state (ARDOUR::PluginState&) = 0;
virtual void restore_state (ARDOUR::PluginState&) = 0;
virtual string describe_parameter (uint32_t) = 0;
virtual string state_node_name() const = 0;
virtual void print_parameter (uint32_t, char*, uint32_t len) const = 0;
virtual bool parameter_is_audio(uint32_t) const = 0;
virtual bool parameter_is_control(uint32_t) const = 0;
virtual bool parameter_is_input(uint32_t) const = 0;
virtual bool parameter_is_output(uint32_t) const = 0;
virtual bool save_preset(string name) = 0;
virtual bool load_preset (const string preset_label);
virtual list<string> get_presets();
virtual bool has_editor() const = 0;
sigc::signal<void,uint32_t,float> ParameterChanged;
sigc::signal<void,Plugin *> GoingAway;
void reset_midi_control (MIDI::Port*, bool);
void send_all_midi_feedback ();
MIDI::byte* write_midi_feedback (MIDI::byte*, int32_t& bufsize);
MIDI::Controllable *get_nth_midi_control (uint32_t);
PluginInfo & get_info() { return _info; }
void set_info (const PluginInfo &inf) { _info = inf; }
ARDOUR::AudioEngine& engine() const { return _engine; }
ARDOUR::Session& session() const { return _session; }
void set_cycles (uint32_t c) { _cycles = c; }
cycles_t cycles() const { return _cycles; }
protected:
ARDOUR::AudioEngine& _engine;
ARDOUR::Session& _session;
PluginInfo _info;
uint32_t _cycles;
map<string,string> presets;
bool save_preset(string name, string domain /* vst, ladspa etc. */);
void setup_midi_controls ();
struct MIDIPortControl : public MIDI::Controllable {
MIDIPortControl (Plugin&, uint32_t abs_port_id, MIDI::Port *,
float lower, float upper, bool toggled, bool logarithmic);
void set_value (float);
void send_feedback (float);
MIDI::byte* write_feedback (MIDI::byte* buf, int32_t& bufsize, float val, bool force = false);
Plugin& plugin;
uint32_t absolute_port;
float upper;
float lower;
float range;
bool toggled;
bool logarithmic;
bool setting;
float last_written;
};
vector<MIDIPortControl*> midi_controls;
};
/* this is actually defined in plugin_manager.cc */
Plugin * find_plugin(ARDOUR::Session&, string name, PluginInfo::Type);
} // namespace ARDOUR
#endif /* __ardour_plugin_h__ */

View File

@@ -0,0 +1,63 @@
#ifndef __ardour_plugin_manager_h__
#define __ardour_plugin_manager_h__
#include <list>
#include <map>
#include <string>
#include <ardour/types.h>
namespace ARDOUR {
class PluginInfo;
class Plugin;
class Session;
class AudioEngine;
class PluginManager {
public:
PluginManager (ARDOUR::AudioEngine&);
~PluginManager ();
std::list<PluginInfo*> &vst_plugin_info () { return _vst_plugin_info; }
std::list<PluginInfo*> &ladspa_plugin_info () { return _ladspa_plugin_info; }
void refresh ();
int add_ladspa_directory (std::string dirpath);
int add_vst_directory (std::string dirpath);
Plugin *load (ARDOUR::Session& s, PluginInfo* info);
static PluginManager* the_manager() { return _manager; }
private:
ARDOUR::AudioEngine& _engine;
std::list<PluginInfo*> _vst_plugin_info;
std::list<PluginInfo*> _ladspa_plugin_info;
std::map<uint32_t, std::string> rdf_type;
std::string ladspa_path;
std::string vst_path;
void ladspa_refresh ();
void vst_refresh ();
void add_lrdf_data (const std::string &path);
void add_ladspa_presets ();
void add_vst_presets ();
void add_presets (std::string domain);
int vst_discover_from_path (std::string path);
int vst_discover (std::string path);
int ladspa_discover_from_path (std::string path);
int ladspa_discover (std::string path);
std::string get_ladspa_category (uint32_t id);
static PluginManager* _manager; // singleton
};
} /* namespace ARDOUR */
#endif /* __ardour_plugin_manager_h__ */

View File

@@ -0,0 +1,14 @@
#ifndef __ardour_plugin_state_h__
#define __ardour_plugin_state_h__
#include <map>
namespace ARDOUR {
struct PluginState {
std::map<uint32_t,float> parameters;
};
}
#endif /* __ardour_plugin_state_h__ */

213
libs/ardour/ardour/port.h Normal file
View File

@@ -0,0 +1,213 @@
/*
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$
*/
#ifndef __ardour_port_h__
#define __ardour_port_h__
#include <sigc++/signal.h>
#include <pbd/failed_constructor.h>
#include <ardour/ardour.h>
#include <jack/jack.h>
namespace ARDOUR {
class AudioEngine;
class Port : public sigc::trackable {
public:
virtual ~Port() {
free (port);
}
Sample *get_buffer (jack_nframes_t nframes) {
if (_flags & JackPortIsOutput) {
return _buffer;
} else {
return (Sample *) jack_port_get_buffer (port, nframes);
}
}
void reset_buffer () {
if (_flags & JackPortIsOutput) {
_buffer = (Sample *) jack_port_get_buffer (port, 0);
} else {
_buffer = 0; /* catch illegal attempts to use it */
}
silent = false;
}
string name() {
return _name;
}
string short_name() {
return jack_port_short_name (port);
}
int set_name (string str);
JackPortFlags flags() const {
return _flags;
}
bool is_mine (jack_client_t *client) {
return jack_port_is_mine (client, port);
}
const char* type() const {
return _type.c_str();
}
int connected () const {
return jack_port_connected (port);
}
bool connected_to (const string& portname) const {
return jack_port_connected_to (port, portname.c_str());
}
const char ** get_connections () const {
return jack_port_get_connections (port);
}
void reset_overs () {
_short_overs = 0;
_long_overs = 0;
overlen = 0;
}
void reset_peak_meter () {
_peak = 0;
}
void reset_meters () {
reset_peak_meter ();
reset_overs ();
}
void enable_metering() {
metering++;
}
void disable_metering () {
if (metering) { metering--; }
}
float peak_db() const { return _peak_db; }
jack_default_audio_sample_t peak() const { return _peak; }
uint32_t short_overs () const { return _short_overs; }
uint32_t long_overs () const { return _long_overs; }
static void set_short_over_length (jack_nframes_t);
static void set_long_over_length (jack_nframes_t);
bool receives_input() const {
return _flags & JackPortIsInput;
}
bool sends_output () const {
return _flags & JackPortIsOutput;
}
bool monitoring_input () const {
return jack_port_monitoring_input (port);
}
bool can_monitor () const {
return _flags & JackPortCanMonitor;
}
void ensure_monitor_input (bool yn) {
jack_port_request_monitor (port, yn);
}
void request_monitor_input (bool yn) {
jack_port_request_monitor (port, yn);
}
jack_nframes_t latency () const {
return jack_port_get_latency (port);
}
void set_latency (jack_nframes_t nframes) {
jack_port_set_latency (port, nframes);
}
sigc::signal<void,bool> MonitorInputChanged;
sigc::signal<void,bool> ClockSyncChanged;
bool is_silent() const { return silent; }
void silence (jack_nframes_t nframes, jack_nframes_t offset) {
/* assumes that the port is an output port */
if (!silent) {
memset (_buffer + offset, 0, sizeof (Sample) * nframes);
if (offset == 0) {
/* XXX this isn't really true, but i am not sure
how to set this correctly. we really just
want to set it true when the entire port
buffer has been overrwritten.
*/
silent = true;
}
}
}
void mark_silence (bool yn) {
silent = yn;
}
private:
friend class AudioEngine;
Port (jack_port_t *port);
void reset ();
/* engine isn't supposed to below here */
Sample *_buffer;
/* cache these 3 from JACK so that we can
access them for reconnecting.
*/
JackPortFlags _flags;
string _type;
string _name;
bool last_monitor : 1;
bool silent : 1;
jack_port_t *port;
jack_nframes_t overlen;
jack_default_audio_sample_t _peak;
float _peak_db;
uint32_t _short_overs;
uint32_t _long_overs;
unsigned short metering;
static jack_nframes_t long_over_length;
static jack_nframes_t short_over_length;
};
}; /* namespace ARDOUR */
#endif /* __ardour_port_h__ */

View File

@@ -0,0 +1,39 @@
/*
Copyright (C) 2004 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
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.
*/
#ifndef __ardour_recent_sessions_h__
#define __ardour_recent_sessions__h__
#include <deque>
#include <utility>
#include <string>
using std::deque;
using std::pair;
using std::string;
namespace ARDOUR {
typedef deque<pair<string,string> > RecentSessions;
int read_recent_sessions (RecentSessions& rs);
int store_recent_sessions (string name, string path);
int write_recent_sessions (RecentSessions& rs);
}; // namespace ARDOUR
#endif // __ardour_recent_sessions_h__

View File

@@ -0,0 +1,153 @@
/*
Copyright (C) 2001 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$
*/
#ifndef __ardour_redirect_h__
#define __ardour_redirect_h__
#include <string>
#include <vector>
#include <set>
#include <map>
#include <sigc++/signal.h>
#include <pbd/lockmonitor.h>
#include <pbd/undo.h>
#include <ardour/ardour.h>
#include <ardour/io.h>
#include <ardour/automation_event.h>
using std::map;
using std::set;
using std::string;
using std::vector;
class XMLNode;
namespace ARDOUR {
class Session;
struct RedirectState : public StateManager::State {
RedirectState (string why)
: StateManager::State (why) {}
~RedirectState () {}
bool active;
};
class Redirect : public IO
{
public:
static const string state_node_name;
Redirect (Session&, const string& name, Placement,
int input_min = -1, int input_max = -1, int output_min = -1, int output_max = -1);
Redirect (const Redirect&);
virtual ~Redirect ();
static Redirect *clone (const Redirect&);
bool active () const { return _active; }
void set_active (bool yn, void *src);
virtual uint32_t output_streams() const { return n_outputs(); }
virtual uint32_t input_streams () const { return n_inputs(); }
virtual uint32_t natural_output_streams() const { return n_outputs(); }
virtual uint32_t natural_input_streams () const { return n_inputs(); }
uint32_t sort_key() const { return _sort_key; }
void set_sort_key (uint32_t sk,void *src) { _sort_key = sk; sort_key_changed (this, src); }
Placement placement() const { return _placement; }
void set_placement (Placement, void *src);
virtual void run (vector<Sample *>& ibufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset) = 0;
virtual void activate () = 0;
virtual void deactivate () = 0;
virtual jack_nframes_t latency() { return 0; }
virtual void set_block_size (jack_nframes_t nframes) {}
sigc::signal<void,Redirect*,void*> active_changed;
sigc::signal<void,Redirect*,void*> sort_key_changed;
sigc::signal<void,Redirect*,void*> placement_changed;
sigc::signal<void,Redirect*,bool> AutomationPlaybackChanged;
sigc::signal<void,Redirect*,uint32_t> AutomationChanged;
sigc::signal<void,Redirect*> GoingAway;
static sigc::signal<void,Redirect*> RedirectCreated;
XMLNode& state (bool full);
XMLNode& get_state (void);
int set_state (const XMLNode&);
StateManager::State* state_factory (string why) const;
Change restore_state (StateManager::State&);
void *get_gui () const { return _gui; }
void set_gui (void *p) { _gui = p; }
virtual string describe_parameter (uint32_t which);
virtual float default_parameter_value (uint32_t which) {
return 1.0f;
}
int load_automation (string path);
int save_automation (string path);
void what_has_automation (set<uint32_t>&) const;
void what_has_visible_automation (set<uint32_t>&) const;
const set<uint32_t>& what_can_be_automated () const { return can_automate_list; }
void mark_automation_visible (uint32_t, bool);
AutomationList& automation_list (uint32_t);
bool find_next_event (jack_nframes_t, jack_nframes_t, ControlEvent&) const;
virtual void transport_stopped (jack_nframes_t frame) {};
protected:
void set_placement (const string&, void *src);
/* children may use this stuff as they see fit */
map<uint32_t,AutomationList*> parameter_automation;
set<uint32_t> visible_parameter_automation;
mutable PBD::NonBlockingLock _automation_lock;
void can_automate (uint32_t);
set<uint32_t> can_automate_list;
void store_state (RedirectState&) const;
virtual void automation_list_creation_callback (uint32_t, AutomationList&) {}
private:
bool _active;
Placement _placement;
uint32_t _sort_key;
void* _gui; /* generic, we don't know or care what this is */
};
}; /* namespace ARDOUR */
#endif /* __ardour_redirect_h__ */

259
libs/ardour/ardour/region.h Normal file
View File

@@ -0,0 +1,259 @@
/*
Copyright (C) 2000-2001 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$
*/
#ifndef __ardour_region_h__
#define __ardour_region_h__
#include <pbd/undo.h>
#include <ardour/ardour.h>
#include <ardour/logcurve.h>
#include <ardour/state_manager.h>
class XMLNode;
namespace ARDOUR {
class Playlist;
class Source;
enum RegionEditState {
EditChangesNothing = 0,
EditChangesName = 1,
EditChangesID = 2
};
struct RegionState : public StateManager::State {
RegionState (std::string why) : StateManager::State (why) {}
jack_nframes_t _start;
jack_nframes_t _length;
jack_nframes_t _position;
uint32_t _flags;
jack_nframes_t _sync_position;
layer_t _layer;
string _name;
mutable RegionEditState _first_edit;
};
class Region : public Stateful, public StateManager
{
public:
enum Flag {
Muted = 0x1,
Opaque = 0x2,
EnvelopeActive = 0x4,
DefaultFadeIn = 0x8,
DefaultFadeOut = 0x10,
Locked = 0x20,
Automatic = 0x40,
WholeFile = 0x80,
FadeIn = 0x100,
FadeOut = 0x200,
Copied = 0x400,
Import = 0x800,
External = 0x1000,
SyncMarked = 0x2000,
LeftOfSplit = 0x4000,
RightOfSplit = 0x8000,
Hidden = 0x10000,
DoNotSaveState = 0x20000,
//
range_guarantoor = USHRT_MAX
};
static const Flag DefaultFlags = Flag (Opaque|DefaultFadeIn|DefaultFadeOut|FadeIn|FadeOut);
static Change FadeChanged;
static Change SyncOffsetChanged;
static Change MuteChanged;
static Change OpacityChanged;
static Change LockChanged;
static Change LayerChanged;
static Change HiddenChanged;
Region (jack_nframes_t start, jack_nframes_t length,
const string& name, layer_t = 0, Flag flags = DefaultFlags);
Region (const Region&, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t = 0, Flag flags = DefaultFlags);
Region (const Region&);
Region (const XMLNode&);
~Region();
ARDOUR::id_t id() const { return _id; }
/* Note: changing the name of a Region does not constitute an edit */
string name() const { return _name; }
void set_name (string str);
jack_nframes_t position () const { return _position; }
jack_nframes_t start () const { return _start; }
jack_nframes_t length() const { return _length; }
layer_t layer () const { return _layer; }
jack_nframes_t sync_offset(int& dir) const;
jack_nframes_t sync_position() const;
jack_nframes_t adjust_to_sync (jack_nframes_t);
/* first_frame() is an alias; last_frame() just hides some math */
jack_nframes_t first_frame() const { return _position; }
jack_nframes_t last_frame() const { return _position + _length - 1; }
bool hidden() const { return _flags & Hidden; }
bool muted() const { return _flags & Muted; }
bool opaque () const { return _flags & Opaque; }
bool envelope_active () const { return _flags & EnvelopeActive; }
bool locked() const { return _flags & Locked; }
bool automatic() const { return _flags & Automatic; }
bool whole_file() const { return _flags & WholeFile ; }
Flag flags() const { return _flags; }
virtual bool should_save_state () const { return !(_flags & DoNotSaveState); };
void freeze ();
void thaw (const string& why);
bool covers (jack_nframes_t frame) const {
return _position <= frame && frame < _position + _length;
}
OverlapType coverage (jack_nframes_t start, jack_nframes_t end) const {
return ARDOUR::coverage (_position, _position + _length - 1, start, end);
}
virtual jack_nframes_t read_at (Sample *buf, Sample *mixdown_buffer,
float *gain_buffer, jack_nframes_t position, jack_nframes_t cnt,
uint32_t chan_n = 0,
jack_nframes_t read_frames = 0,
jack_nframes_t skip_frames = 0) const = 0;
/* EDITING OPERATIONS */
void set_length (jack_nframes_t, void *src);
void set_start (jack_nframes_t, void *src);
void set_position (jack_nframes_t, void *src);
void set_position_on_top (jack_nframes_t, void *src);
void special_set_position (jack_nframes_t);
void nudge_position (long, void *src);
void move_to_natural_position (void *src);
void trim_start (jack_nframes_t new_position, void *src);
void trim_front (jack_nframes_t new_position, void *src);
void trim_end (jack_nframes_t new_position, void *src);
void trim_to (jack_nframes_t position, jack_nframes_t length, void *src);
void set_layer (layer_t l); /* ONLY Playlist can call this */
void raise ();
void lower ();
void raise_to_top ();
void lower_to_bottom ();
void set_sync_position (jack_nframes_t n);
void clear_sync_position ();
void set_hidden (bool yn);
void set_muted (bool yn);
void set_opaque (bool yn);
void set_envelope_active (bool yn);
void set_locked (bool yn);
virtual uint32_t read_data_count() const { return _read_data_count; }
ARDOUR::Playlist* playlist() const { return _playlist; }
virtual UndoAction get_memento() const = 0;
void set_playlist (ARDOUR::Playlist*);
virtual void lock_sources () {}
virtual void unlock_sources () {}
/* serialization */
virtual XMLNode& state (bool);
XMLNode& get_state ();
int set_state (const XMLNode&);
sigc::signal<void,Region*> GoingAway;
/* This is emitted only when a new id is assigned. Therefore,
in a pure Region copy, it will not be emitted.
It must be emitted by derived classes, not Region
itself, to permit dynamic_cast<> to be used to
infer the type of Region.
*/
static sigc::signal<void,Region*> CheckNewRegion;
virtual Region* get_parent() = 0;
uint64_t last_layer_op() const { return _last_layer_op; }
void set_last_layer_op (uint64_t when);
protected:
jack_nframes_t _start;
jack_nframes_t _length;
jack_nframes_t _position;
Flag _flags;
jack_nframes_t _sync_position;
layer_t _layer;
string _name;
mutable RegionEditState _first_edit;
int _frozen;
PBD::Lock lock;
ARDOUR::id_t _id;
ARDOUR::Playlist* _playlist;
mutable uint32_t _read_data_count; // modified in read()
Change pending_changed;
uint64_t _last_layer_op; // timestamp
XMLNode& get_short_state (); /* used only by Session */
/* state management */
void send_change (Change);
void send_state_changed ();
/* derived classes need these during their own state management calls */
void store_state (RegionState&) const;
Change restore_and_return_flags (RegionState&);
void trim_to_internal (jack_nframes_t position, jack_nframes_t length, void *src);
bool copied() const { return _flags & Copied; }
void maybe_uncopy ();
void first_edit ();
virtual bool verify_start (jack_nframes_t) = 0;
virtual bool verify_start_and_length (jack_nframes_t, jack_nframes_t) = 0;
virtual bool verify_start_mutable (jack_nframes_t&_start) = 0;
virtual bool verify_length (jack_nframes_t) = 0;
virtual void recompute_at_start () = 0;
virtual void recompute_at_end () = 0;
};
} /* namespace ARDOUR */
#endif /* __ardour_region_h__ */

View File

@@ -0,0 +1,22 @@
#ifndef __ardour_region_factory_h__
#define __ardour_region_factory_h__
#include <ardour/types.h>
#include <ardour/region.h>
class XMLNode;
namespace ARDOUR {
class Session;
Region* createRegion (const Region&, jack_nframes_t start,
jack_nframes_t length, std::string name,
layer_t = 0, Region::Flag flags = Region::DefaultFlags);
// Region* createRegion (const Region&, std::string name);
Region* createRegion (const Region&);
Region* createRegion (Session&, XMLNode&, bool);
}
#endif /* __ardour_region_factory_h__ */

View File

@@ -0,0 +1,38 @@
/*
Copyright (C) 2004 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
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$
*/
#ifndef __ardour_reverse_h__
#define __ardour_reverse_h__
#include <ardour/audiofilter.h>
namespace ARDOUR {
class Reverse : public AudioFilter {
public:
Reverse (ARDOUR::Session&);
~Reverse ();
int run (ARDOUR::AudioRegion&);
};
} /* namespace */
#endif /* __ardour_reverse_h__ */

359
libs/ardour/ardour/route.h Normal file
View File

@@ -0,0 +1,359 @@
/*
Copyright (C) 2000-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$
*/
#ifndef __ardour_route_h__
#define __ardour_route_h__
#include <cmath>
#include <list>
#include <set>
#include <map>
#include <string>
#include <pthread.h>
#include <pbd/atomic.h>
#include <pbd/fastlog.h>
#include <pbd/lockmonitor.h>
#include <pbd/xml++.h>
#include <pbd/undo.h>
#include <midi++/controllable.h>
#include <ardour/ardour.h>
#include <ardour/stateful.h>
#include <ardour/io.h>
#include <ardour/session.h>
#include <ardour/redirect.h>
namespace ARDOUR {
class Insert;
class Send;
class RouteGroup;
enum mute_type {
PRE_FADER = 0x1,
POST_FADER = 0x2,
CONTROL_OUTS = 0x4,
MAIN_OUTS = 0x8
};
class Route : public IO
{
private:
typedef list<Redirect *> RedirectList;
public:
enum Flag {
Hidden = 0x1,
MasterOut = 0x2,
ControlOut = 0x4,
};
Route (Session&, std::string name, int input_min, int input_max, int output_min, int output_max, Flag flags = Flag(0));
Route (Session&, const XMLNode&);
virtual ~Route();
std::string comment() { return _comment; }
void set_comment (std::string str, void *src);
long order_key(std::string name) const;
void set_order_key (std::string name, long n);
bool hidden() const { return _flags & Hidden; }
bool master() const { return _flags & MasterOut; }
bool control() const { return _flags & ControlOut; }
/* these are the core of the API of a Route. see the protected sections as well */
virtual int roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame,
jack_nframes_t offset, int declick, bool can_record, bool rec_monitors_input);
virtual int no_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame,
jack_nframes_t offset, bool state_changing, bool can_record, bool rec_monitors_input);
virtual int silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame,
jack_nframes_t offset, bool can_record, bool rec_monitors_input);
virtual void toggle_monitor_input ();
virtual bool can_record() const { return false; }
virtual void set_record_enable (bool yn, void *src) {}
virtual bool record_enabled() const { return false; }
virtual void transport_stopped (bool abort, bool did_locate, bool flush_redirects);
virtual void set_pending_declick (int);
/* end of vfunc-based API */
/* override IO::set_gain() to provide group control */
void set_gain (gain_t val, void *src);
void inc_gain (gain_t delta, void *src);
bool active() const { return _active; }
void set_active (bool yn);
void set_solo (bool yn, void *src);
bool soloed() const { return _soloed; }
void set_solo_safe (bool yn, void *src);
bool solo_safe() const { return _solo_safe; }
void set_mute (bool yn, void *src);
bool muted() const { return _muted; }
void set_mute_config (mute_type, bool, void *src);
bool get_mute_config (mute_type);
void set_phase_invert (bool yn, void *src);
bool phase_invert() const { return _phase_invert; }
void set_edit_group (RouteGroup *, void *);
RouteGroup *edit_group () { return _edit_group; }
void set_mix_group (RouteGroup *, void *);
RouteGroup *mix_group () { return _mix_group; }
virtual void set_meter_point (MeterPoint, void *src);
MeterPoint meter_point() const { return _meter_point; }
/* Redirects */
void flush_redirects ();
template<class T> void foreach_redirect (T *obj, void (T::*func)(Redirect *)) {
LockMonitor lm (redirect_lock, __LINE__, __FILE__);
for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
(obj->*func) (*i);
}
}
Redirect *nth_redirect (uint32_t n) {
LockMonitor lm (redirect_lock, __LINE__, __FILE__);
RedirectList::iterator i;
for (i = _redirects.begin(); i != _redirects.end() && n; ++i, --n);
if (i == _redirects.end()) {
return 0;
} else {
return *i;
}
}
uint32_t max_redirect_outs () const { return redirect_max_outs; }
int add_redirect (Redirect *, void *src, uint32_t* err_streams = 0);
int add_redirects (const RedirectList&, void *src, uint32_t* err_streams = 0);
int remove_redirect (Redirect *, void *src, uint32_t* err_streams = 0);
int copy_redirects (const Route&, Placement, uint32_t* err_streams = 0);
int sort_redirects (uint32_t* err_streams = 0);
void clear_redirects (void *src);
void all_redirects_flip();
void all_redirects_active (bool state);
virtual jack_nframes_t update_total_latency();
jack_nframes_t signal_latency() const { return _own_latency; }
virtual void set_latency_delay (jack_nframes_t);
sigc::signal<void,void*> solo_changed;
sigc::signal<void,void*> solo_safe_changed;
sigc::signal<void,void*> comment_changed;
sigc::signal<void,void*> mute_changed;
sigc::signal<void,void*> pre_fader_changed;
sigc::signal<void,void*> post_fader_changed;
sigc::signal<void,void*> control_outs_changed;
sigc::signal<void,void*> main_outs_changed;
sigc::signal<void,void*> redirects_changed;
sigc::signal<void,void*> record_enable_changed;
sigc::signal<void,void*> edit_group_changed;
sigc::signal<void,void*> mix_group_changed;
sigc::signal<void> active_changed;
sigc::signal<void,void*> meter_change;
sigc::signal<void> GoingAway;
/* gui's call this for their own purposes. */
sigc::signal<void,std::string,void*> gui_changed;
/* stateful */
XMLNode& get_state();
int set_state(const XMLNode& node);
XMLNode& get_template();
sigc::signal<void,void*> SelectedChanged;
/* undo */
UndoAction get_memento() const;
void set_state (state_id_t);
int set_control_outs (const vector<std::string>& ports);
IO* control_outs() { return _control_outs; }
bool feeds (Route *);
set<Route *> fed_by;
struct MIDIToggleControl : public MIDI::Controllable {
enum ToggleType {
MuteControl = 0,
SoloControl
};
MIDIToggleControl (Route&, ToggleType, MIDI::Port *);
void set_value (float);
void send_feedback (bool);
MIDI::byte* write_feedback (MIDI::byte* buf, int32_t& bufsize, bool val, bool force = false);
Route& route;
ToggleType type;
bool setting;
bool last_written;
};
MIDI::Controllable& midi_solo_control() {
return _midi_solo_control;
}
MIDI::Controllable& midi_mute_control() {
return _midi_mute_control;
}
virtual void reset_midi_control (MIDI::Port*, bool);
virtual void send_all_midi_feedback ();
virtual MIDI::byte* write_midi_feedback (MIDI::byte*, int32_t& bufsize);
void automation_snapshot (jack_nframes_t now);
void protect_automation ();
protected:
friend class Session;
void set_solo_mute (bool yn);
void set_block_size (jack_nframes_t nframes);
bool has_external_redirects() const;
void curve_reallocate ();
protected:
unsigned char _flags;
/* tight cache-line access here is more important than sheer speed of
access.
*/
bool _muted : 1;
bool _soloed : 1;
bool _solo_muted : 1;
bool _solo_safe : 1;
bool _phase_invert : 1;
bool _recordable : 1;
bool _active : 1;
bool _mute_affects_pre_fader : 1;
bool _mute_affects_post_fader : 1;
bool _mute_affects_control_outs : 1;
bool _mute_affects_main_outs : 1;
bool _silent : 1;
bool _declickable : 1;
int _pending_declick;
MeterPoint _meter_point;
gain_t solo_gain;
gain_t mute_gain;
gain_t desired_solo_gain;
gain_t desired_mute_gain;
jack_nframes_t check_initial_delay (jack_nframes_t, jack_nframes_t&, jack_nframes_t&);
jack_nframes_t _initial_delay;
jack_nframes_t _roll_delay;
jack_nframes_t _own_latency;
RedirectList _redirects;
PBD::NonBlockingLock redirect_lock;
IO *_control_outs;
PBD::NonBlockingLock control_outs_lock;
RouteGroup *_edit_group;
RouteGroup *_mix_group;
std::string _comment;
bool _have_internal_generator;
MIDIToggleControl _midi_solo_control;
MIDIToggleControl _midi_mute_control;
void passthru (jack_nframes_t start_frame, jack_nframes_t end_frame,
jack_nframes_t nframes, jack_nframes_t offset, int declick, bool meter_inputs);
void process_output_buffers (vector<Sample*>& bufs, uint32_t nbufs,
jack_nframes_t start_frame, jack_nframes_t end_frame,
jack_nframes_t nframes, jack_nframes_t offset, bool with_redirects, int declick,
bool meter);
protected:
/* for derived classes */
virtual XMLNode& state(bool);
void silence (jack_nframes_t nframes, jack_nframes_t offset);
sigc::connection input_signal_connection;
state_id_t _current_state_id;
uint32_t redirect_max_outs;
uint32_t pans_required() const;
uint32_t n_process_buffers ();
private:
void init ();
static uint32_t order_key_cnt;
typedef std::map<std::string,long> OrderKeys;
OrderKeys order_keys;
void input_change_handler (IOChange, void *src);
void output_change_handler (IOChange, void *src);
bool legal_redirect (Redirect&);
int reset_plugin_counts (uint32_t*); /* locked */
int _reset_plugin_counts (uint32_t*); /* unlocked */
/* plugin count handling */
struct InsertCount {
ARDOUR::Insert& insert;
int32_t cnt;
int32_t in;
int32_t out;
InsertCount (ARDOUR::Insert& ins) : insert (ins), cnt (-1) {}
};
int32_t apply_some_plugin_counts (std::list<InsertCount>& iclist);
int32_t check_some_plugin_counts (std::list<InsertCount>& iclist, int32_t required_inputs, uint32_t* err_streams);
void set_deferred_state ();
void add_redirect_from_xml (const XMLNode&);
void redirect_active_proxy (Redirect*, void*);
};
}; /* namespace ARDOUR*/
#endif /* __ardour_route_h__ */

View File

@@ -0,0 +1,111 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __ardour_route_group_h__
#define __ardour_route_group_h__
#include <list>
#include <string>
#include <stdint.h>
#include <sigc++/signal.h>
#include <ardour/stateful.h>
#include <ardour/types.h>
using std::string;
using std::list;
namespace ARDOUR {
class Route;
class AudioTrack;
class RouteGroup : public Stateful, public sigc::trackable {
public:
enum Flag {
Relative = 0x1,
Active = 0x2,
Hidden = 0x4,
};
RouteGroup(const string &n, Flag f = Flag(0)) : _name (n), _flags (f) {}
const string& name() { return _name; }
bool is_active () const { return _flags & Active; }
bool is_relative () const { return _flags & Relative; }
bool is_hidden () const { return _flags & Hidden; }
bool empty() const {return routes.empty();}
gain_t get_max_factor(gain_t factor);
gain_t get_min_factor(gain_t factor);
int size() { return routes.size();}
ARDOUR::Route * first () const { return *routes.begin();}
void set_active (bool yn, void *src);
void set_relative (bool yn, void *src);
void set_hidden (bool yn, void *src);
int add (Route *);
int remove (Route *);
template<class T> void apply (void (Route::*func)(T, void *), T val, void *src) {
for (list<Route *>::iterator i = routes.begin(); i != routes.end(); i++) {
((*i)->*func)(val, this);
}
}
template<class T> void foreach_route (T *obj, void (T::*func)(Route&)) {
for (list<Route *>::iterator i = routes.begin(); i != routes.end(); i++) {
(obj->*func)(**i);
}
}
/* to use these, #include <ardour/route_group_specialized.h> */
template<class T> void apply (void (AudioTrack::*func)(T, void *), T val, void *src);
void clear () {
routes.clear ();
changed();
}
const list<Route*>& route_list() { return routes; }
sigc::signal<void> changed;
sigc::signal<void,void*> FlagsChanged;
XMLNode& get_state (void);
int set_state (const XMLNode&);
private:
list<Route *> routes;
string _name;
uint32_t _flags;
void remove_when_going_away (Route*);
};
} /* namespace */
#endif /* __ardour_route_group_h__ */

View File

@@ -0,0 +1,22 @@
#ifndef __ardour_route_group_specialized_h__
#define __ardour_route_group_specialized_h__
#include <ardour/route_group.h>
#include <ardour/audio_track.h>
namespace ARDOUR {
template<class T> void
RouteGroup::apply (void (AudioTrack::*func)(T, void *), T val, void *src)
{
for (list<Route *>::iterator i = routes.begin(); i != routes.end(); i++) {
AudioTrack *at;
if ((at = dynamic_cast<AudioTrack*>(*i)) != 0) {
(at->*func)(val, this);
}
}
}
} /* namespace ARDOUR */
#endif /* __ardour_route_group_specialized_h__ */

63
libs/ardour/ardour/send.h Normal file
View File

@@ -0,0 +1,63 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __ardour_send_h__
#define __ardour_send_h__
#include <sigc++/signal.h>
#include <string>
#include <ardour/ardour.h>
#include <ardour/audioengine.h>
#include "io.h"
#include "stateful.h"
#include "redirect.h"
namespace ARDOUR {
class Send : public Redirect {
public:
Send (Session&, Placement);
Send (Session&, const XMLNode&);
Send (const Send&);
~Send ();
void run (vector<Sample *> &bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset);
void activate() {}
void deactivate () {}
void set_metering (bool yn);
XMLNode& state(bool full);
XMLNode& get_state(void);
int set_state(const XMLNode& node);
uint32_t pans_required() const { return expected_inputs; }
void expect_inputs (uint32_t);
private:
bool _metering;
uint32_t expected_inputs;
};
}; /* namespace ARDOUR */
#endif /* __ardour_send_h__ */

View File

@@ -0,0 +1,55 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __playlist_seqsource_h__
#define __playlist_seqsource_h__
#include <string>
#include "edl.h"
namespace EDL {
class PlaylistSource : public Source {
public:
PlaylistSource (Playlist&);
~PlaylistSource ();
const gchar * const id() { return playlist.name().c_str(); }
uint32_t length() { return playlist.length(); }
uint32_t read (Source::Data *dst, uint32_t start, uint32_t cnt) {
return playlist.read (dst, start, cnt, false);
}
uint32_t write (Source::Data *src, uint32_t where, uint32_t cnt) {
return playlist.write (src, where, cnt);
}
// int read_peaks (peak_data_t *, uint32_t npeaks, uint32_t start, uint32_t cnt);
// int build_peak (uint32_t first_frame, uint32_t cnt);
protected:
private:
Playlist& playlist;
};
}; /* namespace EDL */
#endif /* __playlist_seqsource_h__ */

1754
libs/ardour/ardour/session.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
/*
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$
*/
#ifndef __ardour_session_connection_h__
#define __ardour_session_connection_h__
#include <ardour/session.h>
#include <ardour/connection.h>
namespace ARDOUR {
template<class T> void
Session::foreach_connection (T *obj, void (T::*func)(Connection *))
{
LockMonitor lm (connection_lock, __LINE__, __FILE__);
for (ConnectionList::iterator i = _connections.begin(); i != _connections.end(); i++) {
(obj->*func) (*i);
}
}
} /* namespace */
#endif /* __ardour_session_connection_h__ */

View File

@@ -0,0 +1,42 @@
/*
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$
*/
#ifndef __ardour_session_diskstream_h__
#define __ardour_session_diskstream_h__
#include <ardour/session.h>
#include <ardour/diskstream.h>
namespace ARDOUR {
template<class T> void
Session::foreach_diskstream (T *obj, void (T::*func)(DiskStream&))
{
LockMonitor lm (diskstream_lock, __LINE__, __FILE__);
for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); i++) {
if (!(*i)->hidden()) {
(obj->*func) (**i);
}
}
}
} /* namespace */
#endif /* __ardour_session_diskstream_h__ */

View File

@@ -0,0 +1,47 @@
/*
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$
*/
#ifndef __ardour_session_playlist_h__
#define __ardour_session_playlist_h__
#include <ardour/session.h>
#include <ardour/playlist.h>
namespace ARDOUR {
template<class T> void
Session::foreach_playlist (T *obj, void (T::*func)(Playlist *))
{
LockMonitor lm (playlist_lock, __LINE__, __FILE__);
for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); i++) {
if (!(*i)->hidden()) {
(obj->*func) (*i);
}
}
for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); i++) {
if (!(*i)->hidden()) {
(obj->*func) (*i);
}
}
}
} /* namespace */
#endif /* __ardour_session_playlist_h__ */

View File

@@ -0,0 +1,19 @@
#ifndef __ardour_session_region_h__
#define __ardour_session_region_h__
#include <ardour/session.h>
#include <ardour/audioregion.h>
namespace ARDOUR {
template<class T> void Session::foreach_audio_region (T *obj, void (T::*func)(AudioRegion *))
{
LockMonitor lm (region_lock, __LINE__, __FILE__);
for (AudioRegionList::iterator i = audio_regions.begin(); i != audio_regions.end(); i++) {
(obj->*func) ((*i).second);
}
}
}
#endif /* __ardour_session_region_h__ */

View File

@@ -0,0 +1,89 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __ardour_session_route_h__
#define __ardour_session_route_h__
#include <iostream>
#include <pbd/lockmonitor.h>
#include <ardour/session.h>
#include <ardour/route.h>
namespace ARDOUR {
template<class T> void
Session::foreach_route (T *obj, void (T::*func)(Route&))
{
RouteList public_order;
{
LockMonitor lm (route_lock, __LINE__, __FILE__);
public_order = routes;
}
RoutePublicOrderSorter cmp;
public_order.sort (cmp);
for (RouteList::iterator i = public_order.begin(); i != public_order.end(); i++) {
(obj->*func) (**i);
}
}
template<class T> void
Session::foreach_route (T *obj, void (T::*func)(Route*))
{
RouteList public_order;
{
LockMonitor lm (route_lock, __LINE__, __FILE__);
public_order = routes;
}
RoutePublicOrderSorter cmp;
public_order.sort (cmp);
for (RouteList::iterator i = public_order.begin(); i != public_order.end(); i++) {
(obj->*func) (*i);
}
}
template<class T, class A> void
Session::foreach_route (T *obj, void (T::*func)(Route&, A), A arg1)
{
RouteList public_order;
{
LockMonitor lm (route_lock, __LINE__, __FILE__);
public_order = routes;
}
RoutePublicOrderSorter cmp;
public_order.sort (cmp);
for (RouteList::iterator i = public_order.begin(); i != public_order.end(); i++) {
(obj->*func) (**i, arg1);
}
}
} /* namespace */
#endif /* __ardour_session_route_h__ */

View File

@@ -0,0 +1,40 @@
/*
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$
*/
#ifndef __ardour_session_named_selection_h__
#define __ardour_session_named_selection_h__
#include <ardour/session.h>
#include <ardour/named_selection.h>
namespace ARDOUR {
template<class T> void
Session::foreach_named_selection (T& obj, void (T::*func)(NamedSelection&))
{
LockMonitor lm (named_selection_lock, __LINE__, __FILE__);
for (NamedSelectionList::iterator i = named_selections.begin(); i != named_selections.end(); i++) {
(obj.*func) (**i);
}
}
} /* namespace */
#endif /* __ardour_session_named_selection_h__ */

View File

@@ -0,0 +1,56 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __playlist_const_buffer_h__
#define __playlist_const_buffer_h__
#include <string>
#include <cstdlib>
#include "source.h"
namespace ARDOUR {
class SilentSource : public Source {
public:
SilentSource () {
_name = "Silent Source";
}
static bool is_silent_source (const string& name) {
return name == "Silent Source";
}
jack_nframes_t length() { return ~0U; }
jack_nframes_t read (Source::Data *dst, jack_nframes_t start, jack_nframes_t cnt) {
jack_nframes_t n = cnt;
while (n--) *dst++ = 0;
return cnt;
}
void peak (guint8 *max, guint8 *min, jack_nframes_t start, jack_nframes_t cnt) {
*max = *min = 0;
}
};
}
#endif /* __playlist_const_buffer_h__ */

151
libs/ardour/ardour/slave.h Normal file
View File

@@ -0,0 +1,151 @@
/*
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$
*/
#ifndef __ardour_slave_h__
#define __ardour_slave_h__
#include <vector>
#include <jack/jack.h>
#include <pthread.h>
#include <sigc++/signal.h>
#include <ardour/ardour.h>
#include <midi++/parser.h>
#include <midi++/types.h>
namespace MIDI {
class Port;
}
namespace ARDOUR {
class Session;
class Slave {
public:
Slave() { }
virtual ~Slave() {}
virtual bool speed_and_position (float&, jack_nframes_t&) = 0;
virtual bool locked() const = 0;
virtual bool ok() const = 0;
virtual bool starting() const { return false; }
virtual jack_nframes_t resolution() const = 0;
virtual bool requires_seekahead () const = 0;
};
class MTC_Slave : public Slave, public sigc::trackable {
public:
MTC_Slave (Session&, MIDI::Port&);
~MTC_Slave ();
void rebind (MIDI::Port&);
bool speed_and_position (float&, jack_nframes_t&);
bool locked() const;
bool ok() const;
void handle_locate (const MIDI::byte*);
jack_nframes_t resolution() const;
bool requires_seekahead () const { return true; }
private:
Session& session;
MIDI::Port* port;
std::vector<sigc::connection> connections;
struct SafeTime {
int guard1;
//SMPTE_Time mtc;
jack_nframes_t position;
jack_nframes_t timestamp;
int guard2;
SafeTime() {
guard1 = 0;
guard2 = 0;
timestamp = 0;
}
};
SafeTime current;
jack_nframes_t mtc_frame; /* current time */
jack_nframes_t last_inbound_frame; /* when we got it; audio clocked */
float mtc_speed;
jack_nframes_t first_mtc_frame;
jack_nframes_t first_mtc_time;
static const int32_t accumulator_size = 128;
float accumulator[accumulator_size];
int32_t accumulator_index;
bool have_first_accumulated_speed;
void reset ();
void update_mtc_qtr (MIDI::Parser&);
void update_mtc_time (const MIDI::byte *, bool);
void update_mtc_status (MIDI::Parser::MTC_Status);
void read_current (SafeTime *) const;
};
class ADAT_Slave : public Slave
{
public:
ADAT_Slave () {}
~ADAT_Slave () {}
bool speed_and_position (float& speed, jack_nframes_t& pos) {
speed = 0;
pos = 0;
return false;
}
bool locked() const { return false; }
bool ok() const { return false; }
jack_nframes_t resolution() const { return 1; }
bool requires_seekahead () const { return true; }
};
class JACK_Slave : public Slave
{
public:
JACK_Slave (jack_client_t*);
~JACK_Slave ();
bool speed_and_position (float& speed, jack_nframes_t& pos);
bool starting() const { return _starting; }
bool locked() const;
bool ok() const;
jack_nframes_t resolution() const { return 1; }
bool requires_seekahead () const { return false; }
private:
jack_client_t* jack;
float speed;
bool _starting;
};
} /* namespace */
#endif /* __ardour_slave_h__ */

View File

@@ -0,0 +1,37 @@
#ifndef __sndfile_helpers_h__
#define __sndfile_helpers_h__
#include <string>
#include <sndfile.h>
using std::string;
// Use this define when initializing arrarys for use in sndfile_*_format()
#define SNDFILE_STR_LENGTH 32
#define SNDFILE_HEADER_FORMATS 7
extern const char * const sndfile_header_formats_strings[SNDFILE_HEADER_FORMATS+1];
extern int sndfile_header_formats[SNDFILE_HEADER_FORMATS];
#define SNDFILE_BITDEPTH_FORMATS 5
extern const char * const sndfile_bitdepth_formats_strings[SNDFILE_BITDEPTH_FORMATS+1];
extern int sndfile_bitdepth_formats[SNDFILE_BITDEPTH_FORMATS];
#define SNDFILE_ENDIAN_FORMATS 2
extern const char * const sndfile_endian_formats_strings[SNDFILE_ENDIAN_FORMATS+1];
extern int sndfile_endian_formats[SNDFILE_ENDIAN_FORMATS];
int sndfile_bitdepth_format_from_string(string);
int sndfile_header_format_from_string(string);
int sndfile_endian_format_from_string(string);
int sndfile_data_width (int format);
// It'd be nice if libsndfile did this for us
string sndfile_major_format(int);
string sndfile_minor_format(int);
#endif /* __sndfile_helpers_h__ */

View File

@@ -0,0 +1,63 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __playlist_snd_file_buffer_h__
#define __playlist_snd_file_buffer_h__
#include <sndfile.h>
#include <ardour/source.h>
namespace ARDOUR {
class SndFileSource : public Source {
public:
SndFileSource (const string& path_plus_channel, bool build_peak = true);
SndFileSource (const XMLNode&);
~SndFileSource ();
jack_nframes_t length() const { return _info.frames; }
jack_nframes_t read (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const;
void mark_for_remove() {} // we never remove external sndfiles
string peak_path(string audio_path);
string old_peak_path(string audio_path);
string path() const { return _path; }
static void set_peak_dir (string dir) { peak_dir = dir; }
private:
static string peak_dir;
SNDFILE *sf;
SF_INFO _info;
uint16_t channel;
mutable float *tmpbuf;
mutable jack_nframes_t tmpbufsize;
mutable PBD::Lock _tmpbuf_lock;
string _path;
void init (const string &str, bool build_peak);
jack_nframes_t read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const;
};
}; /* namespace EDL */
#endif /* __playlist_snd_file_buffer_h__ */

View File

@@ -0,0 +1,54 @@
/*
Copyright (C) 2001 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$
*/
#ifndef __soundseq_h__
#define __soundseq_h__
#include "edl.h"
namespace ARDOUR {
typedef gint16 peak_datum;
struct peak_data_t {
peak_datum min;
peak_datum max;
};
const uint32_t frames_per_peak = 2048;
class Sound : public EDL::Piece {
public:
int peak (peak_data_t& pk, uint32_t start, uint32_t cnt);
int read_peaks (peak_data_t *, uint32_t npeaks, uint32_t start, uint32_t cnt);
int build_peak (uint32_t first_frame, uint32_t cnt);
};
class SoundPlaylist : public EDL::Playlist {
public:
int read_peaks (peak_data_t *, uint32_t npeaks, uint32_t start, uint32_t cnt);
};
} /* namespace ARDOUR */
#endif /* __soundseq_h__ */

182
libs/ardour/ardour/source.h Normal file
View File

@@ -0,0 +1,182 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __ardour_source_h__
#define __ardour_source_h__
#include <list>
#include <vector>
#include <string>
#include <time.h>
#include <sigc++/signal.h>
#include <ardour/ardour.h>
#include <ardour/stateful.h>
#include <pbd/xml++.h>
using std::list;
using std::vector;
using std::string;
namespace ARDOUR {
struct PeakData {
typedef Sample PeakDatum;
PeakDatum min;
PeakDatum max;
};
const jack_nframes_t frames_per_peak = 256;
class Source : public Stateful, public sigc::trackable
{
public:
Source (bool announce=true);
Source (const XMLNode&);
virtual ~Source ();
const string& name() const { return _name; }
ARDOUR::id_t id() const { return _id; }
/* returns the number of items in this `source' */
virtual jack_nframes_t length() const {
return _length;
}
virtual jack_nframes_t read (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const {
return 0;
}
virtual jack_nframes_t write (Sample *src, jack_nframes_t cnt) {
return 0;
}
uint32_t use_cnt() const { return _use_cnt; }
void use ();
void release ();
virtual void mark_for_remove() = 0;
virtual void mark_streaming_write_completed () {}
time_t timestamp() const { return _timestamp; }
void stamp (time_t when) { _timestamp = when; }
void set_captured_for (string str) { _captured_for = str; }
string captured_for() const { return _captured_for; }
uint32_t read_data_count() const { return _read_data_count; }
uint32_t write_data_count() const { return _write_data_count; }
int read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t start, jack_nframes_t cnt, double samples_per_unit) const;
int build_peaks ();
bool peaks_ready (sigc::slot<void>) const;
static sigc::signal<void,Source*> SourceCreated;
sigc::signal<void,Source *> GoingAway;
mutable sigc::signal<void> PeaksReady;
mutable sigc::signal<void,jack_nframes_t,jack_nframes_t> PeakRangeReady;
XMLNode& get_state ();
int set_state (const XMLNode&);
static int start_peak_thread ();
static void stop_peak_thread ();
static void set_build_missing_peakfiles (bool yn) {
_build_missing_peakfiles = yn;
}
static void set_build_peakfiles (bool yn) {
_build_peakfiles = yn;
}
protected:
static bool _build_missing_peakfiles;
static bool _build_peakfiles;
string _name;
uint32_t _use_cnt;
bool _peaks_built;
mutable PBD::Lock _lock;
jack_nframes_t _length;
bool next_peak_clear_should_notify;
string peakpath;
int peakfile; /* fd */
time_t _timestamp;
string _captured_for;
mutable uint32_t _read_data_count; // modified in read()
mutable uint32_t _write_data_count; // modified in write()
int initialize_peakfile (bool newfile, string path);
void build_peaks_from_scratch ();
int do_build_peak (jack_nframes_t, jack_nframes_t);
virtual jack_nframes_t read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const = 0;
virtual string peak_path(string audio_path) = 0;
virtual string old_peak_path(string audio_path) = 0;
static pthread_t peak_thread;
static bool have_peak_thread;
static void* peak_thread_work(void*);
static int peak_request_pipe[2];
struct PeakRequest {
enum Type {
Build,
Quit
};
};
static vector<Source*> pending_peak_sources;
static PBD::Lock pending_peak_sources_lock;
static void queue_for_peaks (Source&);
static void clear_queue_for_peaks ();
struct PeakBuildRecord {
jack_nframes_t frame;
jack_nframes_t cnt;
PeakBuildRecord (jack_nframes_t f, jack_nframes_t c)
: frame (f), cnt (c) {}
PeakBuildRecord (const PeakBuildRecord& other) {
frame = other.frame;
cnt = other.cnt;
}
};
list<Source::PeakBuildRecord *> pending_peak_builds;
private:
ARDOUR::id_t _id;
bool Source::file_changed (string path);
};
}
#endif /* __ardour_source_h__ */

View File

@@ -0,0 +1,90 @@
/* This code is based upon work that bore the legend:
*
* Copyright (C) 1997 David Mosberger
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __ardour_spline_h__
#define __ardour_spline_h__
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _spline Spline;
typedef struct _spline_point SplinePoint;
struct _spline_point
{
float x;
float y;
};
Spline *spline_new (void);
void spline_free (Spline *);
void spline_set (Spline *, uint32_t n, SplinePoint *);
void spline_add (Spline *, uint32_t n, SplinePoint *);
void spline_solve (Spline *);
float spline_eval (Spline *, float val);
void spline_fill (Spline *, float x0, float x1, float *vec, uint32_t veclen);
float spline_get_max_x (Spline *);
float spline_get_min_x (Spline *);
struct _spline
{
float *deriv2;
float *x;
float *y;
float max_x;
float min_x;
SplinePoint *points;
uint32_t npoints;
uint32_t space;
#ifdef __cplusplus
void set (uint32_t n, SplinePoint *points) {
spline_set (this, n, points);
}
void add (uint32_t n, SplinePoint *points) {
spline_add (this, n, points);
}
void solve () {
spline_solve (this);
}
float eval (float val) {
return spline_eval (this, val);
}
void fill (float x0, float x1, float *vec, uint32_t veclen) {
spline_fill (this, x0, x1, vec, veclen);
}
#endif /* __cplusplus */
};
#ifdef __cplusplus
}
#endif
#endif /* __ardour_spline_h__ */

View File

@@ -0,0 +1,48 @@
#ifndef __ardour_state_manager_h__
#define __ardour_state_manager_h__
#include <list>
#include <string>
#include <sigc++/signal.h>
#include <ardour/ardour.h>
namespace ARDOUR {
typedef uint32_t state_id_t;
class StateManager : virtual public sigc::trackable
{
public:
struct State {
std::string operation;
State (std::string why) : operation (why) {}
virtual ~State() {}
};
typedef std::list<State*> StateMap;
StateManager ();
virtual ~StateManager ();
virtual void drop_all_states ();
virtual void use_state (state_id_t);
virtual void save_state (std::string why);
sigc::signal<void,Change> StateChanged;
state_id_t _current_state_id;
protected:
StateMap states;
virtual Change restore_state (State&) = 0;
virtual State* state_factory (std::string why) const = 0;
virtual void send_state_changed (Change);
};
} // namespace ARDOUR
#endif /* __ardour_state_manager_h__ */

View File

@@ -0,0 +1,51 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __ardour_stateful_h__
#define __ardour_stateful_h__
#include <string>
class XMLNode;
class Stateful {
public:
Stateful();
virtual ~Stateful();
virtual XMLNode& get_state (void) = 0;
virtual int set_state (const XMLNode&) = 0;
/* Extra XML nodes */
void add_extra_xml (XMLNode&);
XMLNode *extra_xml (const std::string& str);
virtual void add_instant_xml (XMLNode&, const std::string& dir);
XMLNode *instant_xml (const std::string& str, const std::string& dir);
protected:
XMLNode *_extra_xml;
XMLNode *_instant_xml;
};
#endif /* __ardour_stateful_h__ */

323
libs/ardour/ardour/tempo.h Normal file
View File

@@ -0,0 +1,323 @@
/*
Copyright (C) 2000 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$
*/
#ifndef __ardour_tempo_h__
#define __ardour_tempo_h__
#include <list>
#include <string>
#include <vector>
#include <cmath>
#include <pthread.h>
#include <pbd/lockmonitor.h>
#include <pbd/undo.h>
#include <sigc++/signal.h>
#include <ardour/ardour.h>
#include <ardour/stateful.h>
#include <ardour/state_manager.h>
class XMLNode;
using std::list;
using std::vector;
namespace ARDOUR {
class Tempo {
public:
Tempo (double bpm)
: _beats_per_minute (bpm) {}
Tempo (const Tempo& other) {
_beats_per_minute = other._beats_per_minute;
}
void operator= (const Tempo& other) {
if (&other != this) {
_beats_per_minute = other._beats_per_minute;
}
}
double beats_per_minute () const { return _beats_per_minute; }
double frames_per_beat (jack_nframes_t sr) const {
return ((60.0 * sr) / _beats_per_minute);
}
protected:
double _beats_per_minute;
};
class Meter {
public:
static const double ticks_per_beat;
Meter (double bpb, double bt)
: _beats_per_bar (bpb), _note_type (bt) {}
Meter (const Meter& other) {
_beats_per_bar = other._beats_per_bar;
_note_type = other._note_type;
}
void operator= (const Meter& other) {
if (&other != this) {
_beats_per_bar = other._beats_per_bar;
_note_type = other._note_type;
}
}
double beats_per_bar () const { return _beats_per_bar; }
double note_divisor() const { return _note_type; }
double frames_per_bar (const Tempo&, jack_nframes_t sr) const;
protected:
/* this is the number of beats in a bar. it is a real value
because there are musical traditions on our planet
that do not limit themselves to integral numbers of beats
per bar.
*/
double _beats_per_bar;
/* this is the type of "note" that a beat represents. for example,
4.0 would be a quarter (crotchet) note, 8.0 would be an eighth
(quaver) note, etc.
*/
double _note_type;
};
class MetricSection {
public:
MetricSection (const BBT_Time& start)
: _start (start), _frame (0), _movable (true) {}
virtual ~MetricSection() {}
const BBT_Time& start() const { return _start; }
const jack_nframes_t frame() const { return _frame; }
void set_movable (bool yn) { _movable = yn; }
bool movable() const { return _movable; }
virtual void set_frame (jack_nframes_t f) {
_frame = f;
};
virtual void set_start (const BBT_Time& w) {
_start = w;
}
/* MeterSections are not stateful in the full sense,
but we do want them to control their own
XML state information.
*/
virtual XMLNode& get_state() const = 0;
private:
BBT_Time _start;
jack_nframes_t _frame;
bool _movable;
};
class MeterSection : public MetricSection, public Meter {
public:
MeterSection (const BBT_Time& start, double bpb, double note_type)
: MetricSection (start), Meter (bpb, note_type) {}
MeterSection (const XMLNode&);
static const string xml_state_node_name;
XMLNode& get_state() const;
};
class TempoSection : public MetricSection, public Tempo {
public:
TempoSection (const BBT_Time& start, double qpm)
: MetricSection (start), Tempo (qpm) {}
TempoSection (const XMLNode&);
static const string xml_state_node_name;
XMLNode& get_state() const;
};
typedef list<MetricSection*> Metrics;
class TempoMapState : public StateManager::State {
public:
TempoMapState (std::string why)
: StateManager::State (why) {
metrics = new Metrics;
}
Metrics *metrics;
};
class TempoMap : public Stateful, public StateManager {
public:
TempoMap (jack_nframes_t frame_rate);
~TempoMap();
/* measure-based stuff */
enum BBTPointType {
Bar,
Beat,
};
struct BBTPoint {
BBTPointType type;
jack_nframes_t frame;
const Meter* meter;
const Tempo* tempo;
uint32_t bar;
uint32_t beat;
BBTPoint (const Meter& m, const Tempo& t, jack_nframes_t f, BBTPointType ty, uint32_t b, uint32_t e)
: type (ty), frame (f), meter (&m), tempo (&t), bar (b), beat (e) {}
};
typedef vector<BBTPoint> BBTPointList;
template<class T> void apply_with_metrics (T& obj, void (T::*method)(const Metrics&)) {
LockMonitor lm (lock, __LINE__, __FILE__);
(obj.*method)(*metrics);
}
BBTPointList *get_points (jack_nframes_t start, jack_nframes_t end) const;
void bbt_time (jack_nframes_t when, BBT_Time&) const;
jack_nframes_t frame_time (const BBT_Time&) const;
jack_nframes_t bbt_duration_at (jack_nframes_t, const BBT_Time&, int dir) const;
static const Tempo& default_tempo() { return _default_tempo; }
static const Meter& default_meter() { return _default_meter; }
const Tempo& tempo_at (jack_nframes_t);
const Meter& meter_at (jack_nframes_t);
void add_tempo(const Tempo&, BBT_Time where);
void add_meter(const Meter&, BBT_Time where);
void move_tempo (TempoSection&, const BBT_Time& to);
void move_meter (MeterSection&, const BBT_Time& to);
void remove_tempo(const TempoSection&);
void remove_meter(const MeterSection&);
void replace_tempo (TempoSection& existing, const Tempo& replacement);
void replace_meter (MeterSection& existing, const Meter& replacement);
jack_nframes_t round_to_bar (jack_nframes_t frame, int dir);
jack_nframes_t round_to_beat (jack_nframes_t frame, int dir);
jack_nframes_t round_to_beat_subdivision (jack_nframes_t fr, int sub_num);
jack_nframes_t round_to_tick (jack_nframes_t frame, int dir);
void set_length (jack_nframes_t frames);
XMLNode& get_state (void);
int set_state (const XMLNode&);
void dump (std::ostream&) const;
void clear ();
UndoAction get_memento() const;
/* this is a helper class that we use to be able to keep
track of which meter *AND* tempo are in effect at
a given point in time.
*/
class Metric {
public:
Metric (const Meter& m, const Tempo& t) : _meter (&m), _tempo (&t), _frame (0) {}
void set_tempo (const Tempo& t) { _tempo = &t; }
void set_meter (const Meter& m) { _meter = &m; }
void set_frame (jack_nframes_t f) { _frame = f; }
void set_start (const BBT_Time& t) { _start = t; }
const Meter& meter() const { return *_meter; }
const Tempo& tempo() const { return *_tempo; }
jack_nframes_t frame() const { return _frame; }
const BBT_Time& start() const { return _start; }
private:
const Meter* _meter;
const Tempo* _tempo;
jack_nframes_t _frame;
BBT_Time _start;
};
Metric metric_at (BBT_Time bbt) const;
Metric metric_at (jack_nframes_t) const;
void bbt_time_with_metric (jack_nframes_t, BBT_Time&, const Metric&) const;
private:
static Tempo _default_tempo;
static Meter _default_meter;
Metrics *metrics;
jack_nframes_t _frame_rate;
jack_nframes_t last_bbt_when;
bool last_bbt_valid;
BBT_Time last_bbt;
mutable PBD::Lock lock;
void timestamp_metrics ();
jack_nframes_t round_to_type (jack_nframes_t fr, int dir, BBTPointType);
jack_nframes_t frame_time_unlocked (const BBT_Time&) const;
void bbt_time_unlocked (jack_nframes_t, BBT_Time&) const;
jack_nframes_t bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, int dir) const;
const MeterSection& first_meter() const;
const TempoSection& first_tempo() const;
jack_nframes_t count_frames_between (const BBT_Time&, const BBT_Time&) const;
jack_nframes_t count_frames_between_metrics (const Meter&, const Tempo&, const BBT_Time&, const BBT_Time&) const;
int move_metric_section (MetricSection&, const BBT_Time& to);
void do_insert (MetricSection* section);
Change restore_state (StateManager::State&);
StateManager::State* state_factory (std::string why) const;
bool in_set_state;
/* override state_manager::save_state so we can check in_set_state */
void save_state (std::string why);
};
}; /* namespace ARDOUR */
#endif /* __ardour_tempo_h__ */

View File

@@ -0,0 +1,13 @@
#ifndef __ardour_timestamps_h__
#define __ardour_timestamps_h__
#ifdef WITH_JACK_TIMESTAMPS
#include <jack/timestamps.h>
#else
#define jack_timestamp(s)
#define jack_init_timestamps(n)
#define jack_dump_timestamps(o)
#define jack_reset_timestamps()
#endif
#endif /* __ardour_timestamps_h__ */

243
libs/ardour/ardour/types.h Normal file
View File

@@ -0,0 +1,243 @@
/*
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$
*/
#ifndef __ardour_types_h__
#define __ardour_types_h__
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS /* PRI<foo>; C++ requires explicit requesting of these */
#endif
#include <inttypes.h>
#include <jack/types.h>
#include <map>
#if __GNUC__ < 3
typedef int intptr_t;
#endif
namespace ARDOUR {
class Source;
typedef jack_default_audio_sample_t Sample;
typedef float pan_t;
typedef float gain_t;
typedef uint32_t layer_t;
typedef uint64_t id_t;
enum IOChange {
NoChange = 0,
ConfigurationChanged = 0x1,
ConnectionsChanged = 0x2
};
enum OverlapType {
OverlapNone, // no overlap
OverlapInternal, // the overlap is 100% with the object
OverlapStart, // overlap covers start, but ends within
OverlapEnd, // overlap begins within and covers end
OverlapExternal // overlap extends to (at least) begin+end
};
OverlapType coverage (jack_nframes_t start_a, jack_nframes_t end_a,
jack_nframes_t start_b, jack_nframes_t end_b);
enum AutomationType {
GainAutomation = 0x1,
PanAutomation = 0x2,
PluginAutomation = 0x4,
SoloAutomation = 0x8,
MuteAutomation = 0x10,
};
enum AutoState {
Off = 0x0,
Write = 0x1,
Touch = 0x2,
Play = 0x4
};
enum AutoStyle {
Absolute = 0x1,
Trim = 0x2
};
enum AlignStyle {
CaptureTime,
ExistingMaterial
};
enum MeterPoint {
MeterInput,
MeterPreFader,
MeterPostFader
};
enum smpte_wrap_t {
smpte_wrap_none = 0,
smpte_wrap_frames,
smpte_wrap_seconds,
smpte_wrap_minutes,
smpte_wrap_hours
};
struct SMPTE_Time {
bool negative;
long hours;
long minutes;
long seconds;
long frames;
long subframes; // mostly not used
SMPTE_Time() {
negative = false;
hours = 0;
minutes = 0;
seconds = 0;
frames = 0;
subframes = 0;
}
};
struct BBT_Time {
uint32_t bars;
uint32_t beats;
uint32_t ticks;
BBT_Time() {
bars = 1;
beats = 1;
ticks = 0;
}
/* we can't define arithmetic operators for BBT_Time, because
the results depend on a TempoMap, but we can define
a useful check on the less-than condition.
*/
bool operator< (const BBT_Time& other) const {
return bars < other.bars ||
(bars == other.bars && beats < other.beats) ||
(bars == other.bars && beats == other.beats && ticks < other.ticks);
}
bool operator== (const BBT_Time& other) const {
return bars == other.bars && beats == other.beats && ticks == other.ticks;
}
};
struct AnyTime {
enum Type {
SMPTE,
BBT,
Frames,
Seconds
};
Type type;
SMPTE_Time smpte;
BBT_Time bbt;
union {
jack_nframes_t frames;
double seconds;
};
};
struct AudioRange {
jack_nframes_t start;
jack_nframes_t end;
uint32_t id;
AudioRange (jack_nframes_t s, jack_nframes_t e, uint32_t i) : start (s), end (e) , id (i) {}
jack_nframes_t length() { return end - start + 1; }
bool operator== (const AudioRange& other) const {
return start == other.start && end == other.end && id == other.id;
}
bool equal (const AudioRange& other) const {
return start == other.start && end == other.end;
}
OverlapType coverage (jack_nframes_t s, jack_nframes_t e) const {
return ARDOUR::coverage (start, end, s, e);
}
};
struct MusicRange {
BBT_Time start;
BBT_Time end;
uint32_t id;
MusicRange (BBT_Time& s, BBT_Time& e, uint32_t i)
: start (s), end (e), id (i) {}
bool operator== (const MusicRange& other) const {
return start == other.start && end == other.end && id == other.id;
}
bool equal (const MusicRange& other) const {
return start == other.start && end == other.end;
}
};
enum EditMode {
Slide,
Splice,
};
enum RegionPoint {
Start,
End,
SyncPoint
};
enum Change {
range_guarantee = ~0
};
enum Placement {
PreFader,
PostFader
};
enum CrossfadeModel {
FullCrossfade,
ShortCrossfade
};
struct InterThreadInfo {
volatile bool done;
volatile bool cancel;
volatile float progress;
pthread_t thread;
};
};
#endif /* __ardour_types_h__ */

View File

@@ -0,0 +1,59 @@
/*
Copyright (C) 1999 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$
*/
#ifndef __ardour_utils_h__
#define __ardour_utils_h__
#include <iostream>
#include <string>
#include <cmath>
#include "ardour.h"
class XMLNode;
using std::ostream;
void elapsed_time_to_str (char *buf, uint32_t seconds);
string legalize_for_path (std::string str);
ostream& operator<< (ostream& o, const ARDOUR::BBT_Time& bbt);
XMLNode* find_named_node (const XMLNode& node, std::string name);
string placement_as_string (ARDOUR::Placement);
static inline float f_max(float x, float a) {
x -= a;
x += fabsf (x);
x *= 0.5f;
x += a;
return (x);
}
int cmp_nocase (const std::string& s, const std::string& s2);
int tokenize_fullpath (string fullpath, string& path, string& name);
int touch_file(string path);
uint32_t long get_uid();
string region_name_from_path (string path);
#endif /* __ardour_utils_h__ */

View File

@@ -0,0 +1,112 @@
/*
Copyright (C) 2004 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
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$
*/
#ifndef __ardour_vst_plugin_h__
#define __ardour_vst_plugin_h__
#include <list>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <dlfcn.h>
#include <midi++/controllable.h>
#include <sigc++/signal.h>
#include <jack/types.h>
#include <ardour/stateful.h>
#include <ardour/plugin_state.h>
#include <ardour/plugin.h>
#include <ardour/vst_plugin.h>
using std::string;
using std::vector;
using std::list;
using std::map;
struct _FSTHandle;
struct _FST;
typedef struct _FSTHandle FSTHandle;
typedef struct _FST FST;
class AEffect;
namespace ARDOUR {
class AudioEngine;
class Session;
class VSTPlugin : public ARDOUR::Plugin
{
public:
VSTPlugin (ARDOUR::AudioEngine&, ARDOUR::Session&, FSTHandle* handle);
VSTPlugin (const VSTPlugin &);
~VSTPlugin ();
/* Plugin interface */
uint32_t unique_id() const;
const char * label() const;
const char * name() const;
const char * maker() const;
uint32_t parameter_count() const;
float default_value (uint32_t port);
jack_nframes_t latency() const;
void set_parameter (uint32_t port, float val);
float get_parameter (uint32_t port) const;
int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const;
std::set<uint32_t> automatable() const;
uint32_t nth_parameter (uint32_t port, bool& ok) const;
void activate ();
void deactivate ();
void set_block_size (jack_nframes_t nframes);
int connect_and_run (vector<Sample*>& bufs, uint32_t maxbuf, int32_t& in, int32_t& out, jack_nframes_t nframes, jack_nframes_t offset);
void store_state (ARDOUR::PluginState&);
void restore_state (ARDOUR::PluginState&);
string describe_parameter (uint32_t);
string state_node_name() const { return "vst"; }
void print_parameter (uint32_t, char*, uint32_t len) const;
bool parameter_is_audio(uint32_t i) const { return false; }
bool parameter_is_control(uint32_t i) const { return true; }
bool parameter_is_input(uint32_t i) const { return true; }
bool parameter_is_output(uint32_t i) const { return false; }
bool load_preset (const string preset_label );
bool save_preset(string name);
bool has_editor () const;
XMLNode& get_state();
int set_state(const XMLNode& node);
AEffect* plugin() const { return _plugin; }
FST* fst() const { return _fst; }
private:
FSTHandle* handle;
FST* _fst;
AEffect* _plugin;
bool been_resumed;
};
}
#endif /* __ardour_vst_plugin_h__ */

View File

@@ -0,0 +1,513 @@
/*
Copyright (C) 2003 Paul Davis
Author: Taybin Rutkin
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$
*/
#include <cstdio> // Needed so that libraptor (included in lrdf) won't complain
#include <iostream>
#include <sstream>
#include <cctype>
#include <lrdf.h>
#include <pbd/compose.h>
#include <ardour/ardour.h>
#include <ardour/configuration.h>
#include <ardour/audio_library.h>
#include <ardour/utils.h>
#include "i18n.h"
using namespace std;
using namespace ARDOUR;
namespace std {
struct UriSorter {
bool operator() (string a, string b) const {
return cmp_nocase(Library->get_label(a), Library->get_label(b)) == -1;
}
};
};
static char* GROUP = "http://ardour.org/ontology/Group";
static char* SOUNDFILE = "http://ardour.org/ontology/Soundfile";
static char* hasFile = "http://ardour.org/ontology/hasFile";
static char* memberOf = "http://ardour.org/ontology/memberOf";
static char* subGroupOf = "http://ardour.org/ontology/subGroupOf";
AudioLibrary::AudioLibrary ()
{
src = "file:" + Config->get_user_ardour_path() + "sfdb";
// workaround for possible bug in raptor that crashes when saving to a
// non-existant file.
touch_file(Config->get_user_ardour_path() + "sfdb");
lrdf_read_file(src.c_str());
lrdf_statement pattern;
pattern.subject = GROUP;
pattern.predicate = RDF_TYPE;
pattern.object = RDFS_CLASS;
pattern.object_type = lrdf_uri;
lrdf_statement* matches = lrdf_matches(&pattern);
// if empty DB, create basic schema
if (matches == 0) {
initialize_db ();
save_changes();
}
lrdf_free_statements(matches);
}
AudioLibrary::~AudioLibrary ()
{
}
void
AudioLibrary::initialize_db ()
{
// define ardour:Group
lrdf_add_triple(src.c_str(), GROUP, RDF_TYPE, RDFS_CLASS, lrdf_uri);
// define ardour:Soundfile
lrdf_add_triple(src.c_str(), SOUNDFILE, RDF_TYPE, RDFS_CLASS, lrdf_uri);
// add intergral fields
add_field("channels");
add_field("samplerate");
add_field("resolution");
add_field("format");
}
void
AudioLibrary::save_changes ()
{
if (lrdf_export_by_source(src.c_str(), src.substr(5).c_str())) {
warning << compose(_("Could not open %1. Audio Library not saved"), src) << endmsg;
}
}
string
AudioLibrary::add_group (string group, string parent_uri)
{
string local_group(compose("file:sfbd/group/%1", get_uid()));
lrdf_add_triple(src.c_str(), local_group.c_str(),
RDFS_BASE "label", group.c_str(), lrdf_literal);
if (parent_uri == ""){
lrdf_add_triple(src.c_str(), local_group.c_str(),
subGroupOf, GROUP, lrdf_uri);
} else {
lrdf_add_triple(src.c_str(), local_group.c_str(),
subGroupOf, parent_uri.c_str(), lrdf_uri);
}
added_group(local_group, parent_uri); /* EMIT SIGNAL */
return local_group;
}
void
AudioLibrary::remove_group (string uri)
{
list<string> items;
list<string>::iterator i;
get_members(items, uri);
for (i = items.begin(); i != items.end(); ++i) {
remove_member(*i);
}
items.clear();
get_groups(items, uri);
for (i = items.begin(); i != items.end(); ++i) {
remove_group(*i);
}
lrdf_remove_uri_matches(uri.c_str());
save_changes ();
removed_group(uri); /* EMIT SIGNAL */
}
void
AudioLibrary::get_groups (list<string>& groups, string parent_uri)
{
lrdf_statement pattern;
pattern.subject = 0;
pattern.predicate = subGroupOf;
if (parent_uri == ""){
pattern.object = strdup(GROUP);
} else {
pattern.object = strdup(parent_uri.c_str());
}
lrdf_statement* matches = lrdf_matches(&pattern);
lrdf_statement* current = matches;
while (current != 0) {
groups.push_back(current->subject);
current = current->next;
}
lrdf_free_statements(matches);
free (pattern.object);
UriSorter cmp;
groups.sort(cmp);
groups.unique();
}
string
AudioLibrary::add_member (string member, string parent_uri)
{
string local_member(compose("file:sfdb/soundfile/%1", get_uid()));
string file_uri(compose("file:%1", member));
lrdf_add_triple(src.c_str(), local_member.c_str(), RDF_TYPE,
SOUNDFILE, lrdf_uri);
lrdf_add_triple(src.c_str(), local_member.c_str(), hasFile,
file_uri.c_str(), lrdf_uri);
string::size_type size = member.find_last_of('/');
string label = member.substr(++size);
lrdf_add_triple(src.c_str(), local_member.c_str(), RDFS_BASE "label",
label.c_str(), lrdf_literal);
if (parent_uri == ""){
lrdf_add_triple(src.c_str(), local_member.c_str(), memberOf,
GROUP, lrdf_uri);
} else {
lrdf_add_triple(src.c_str(), local_member.c_str(), memberOf,
parent_uri.c_str(), lrdf_uri);
}
save_changes ();
added_member (local_member, parent_uri); /* EMIT SIGNAL */
return local_member;
}
void
AudioLibrary::remove_member (string uri)
{
lrdf_remove_uri_matches (uri.c_str());
save_changes ();
removed_member(uri); /* EMIT SIGNAL */
}
void
AudioLibrary::get_members (list<string>& members, string parent_uri)
{
lrdf_statement pattern;
pattern.subject = 0;
pattern.predicate = memberOf;
if (parent_uri == ""){
pattern.object = strdup(GROUP);
} else {
pattern.object = strdup(parent_uri.c_str());
}
lrdf_statement* matches = lrdf_matches(&pattern);
lrdf_statement* current = matches;
while (current != 0) {
members.push_back(current->subject);
current = current->next;
}
lrdf_free_statements(matches);
free (pattern.object);
UriSorter cmp;
members.sort(cmp);
members.unique();
}
void
AudioLibrary::search_members_and (list<string>& members,
const map<string,string>& fields)
{
lrdf_statement **head;
lrdf_statement* pattern = 0;
lrdf_statement* old = 0;
head = &pattern;
map<string,string>::const_iterator i;
for (i = fields.begin(); i != fields.end(); ++i){
pattern = new lrdf_statement;
pattern->subject = "?";
pattern->predicate = strdup(field_uri(i->first).c_str());
pattern->object = strdup((i->second).c_str());
pattern->next = old;
old = pattern;
}
if (*head != 0) {
lrdf_uris* ulist = lrdf_match_multi(*head);
for (uint32_t j = 0; ulist && j < ulist->count; ++j) {
// printf("AND: %s\n", ulist->items[j]);
members.push_back(ulist->items[j]);
}
lrdf_free_uris(ulist);
UriSorter cmp;
members.sort(cmp);
members.unique();
}
// memory clean up
pattern = *head;
while(pattern){
free(pattern->predicate);
free(pattern->object);
old = pattern;
pattern = pattern->next;
delete old;
}
}
void
AudioLibrary::search_members_or (list<string>& members,
const map<string,string>& fields)
{
map<string,string>::const_iterator i;
lrdf_statement pattern;
for (i = fields.begin(); i != fields.end(); ++i) {
pattern.subject = 0;
pattern.predicate = strdup(field_uri(i->first).c_str());
pattern.object = strdup((i->second).c_str());
pattern.object_type = lrdf_literal;
lrdf_statement* matched = lrdf_matches(&pattern);
lrdf_statement* old = matched;
while(matched) {
// printf ("OR: %s\n", matched->subject);
members.push_back(matched->subject);
matched = matched->next;
}
free(pattern.predicate);
free(pattern.object);
lrdf_free_statements (old);
}
UriSorter cmp;
members.sort(cmp);
members.unique();
}
string
AudioLibrary::get_member_filename (string uri)
{
lrdf_statement pattern;
pattern.subject = strdup(uri.c_str());
pattern.predicate = hasFile;
pattern.object = 0;
pattern.object_type = lrdf_uri;
lrdf_statement* matches = lrdf_matches(&pattern);
if (matches) {
string file = matches->object;
lrdf_free_statements(matches);
string::size_type pos = file.find(":");
return file.substr(++pos);
} else {
warning << _("Could not find member filename") << endmsg;
return "-Unknown-";
}
}
void
AudioLibrary::add_field (string name)
{
string local_field = field_uri(name);
lrdf_statement pattern;
pattern.subject = strdup(local_field.c_str());
pattern.predicate = RDF_TYPE;
pattern.object = RDF_BASE "Property";
pattern.object_type = lrdf_uri;
if(lrdf_exists_match(&pattern)) {
return;
}
// of type rdf:Property
lrdf_add_triple(src.c_str(), local_field.c_str(), RDF_TYPE,
RDF_BASE "Property", lrdf_uri);
// of range ardour:Soundfile
lrdf_add_triple(src.c_str(), local_field.c_str(), RDFS_BASE "range",
SOUNDFILE, lrdf_uri);
// of domain rdf:Literal
lrdf_add_triple(src.c_str(), local_field.c_str(), RDFS_BASE "domain",
RDF_BASE "Literal", lrdf_uri);
set_label (local_field, name);
save_changes();
fields_changed(); /* EMIT SIGNAL */
}
void
AudioLibrary::get_fields (list<string>& fields)
{
lrdf_statement pattern;
pattern.subject = 0;
pattern.predicate = RDFS_BASE "range";
pattern.object = SOUNDFILE;
pattern.object_type = lrdf_uri;
lrdf_statement* matches = lrdf_matches(&pattern);
lrdf_statement* current = matches;
while (current != 0) {
fields.push_back(get_label(current->subject));
current = current->next;
}
lrdf_free_statements(matches);
fields.sort();
fields.unique();
}
void
AudioLibrary::remove_field (string name)
{
lrdf_remove_uri_matches(field_uri(name).c_str());
save_changes();
fields_changed (); /* EMIT SIGNAL */
}
string
AudioLibrary::get_field (string uri, string field)
{
lrdf_statement pattern;
pattern.subject = strdup(uri.c_str());
pattern.predicate = strdup(field_uri(field).c_str());
pattern.object = 0;
pattern.object_type = lrdf_literal;
lrdf_statement* matches = lrdf_matches(&pattern);
free(pattern.subject);
free(pattern.predicate);
stringstream object;
if (matches != 0){
object << matches->object;
}
lrdf_free_statements(matches);
return object.str();
}
void
AudioLibrary::set_field (string uri, string field, string literal)
{
lrdf_statement pattern;
pattern.subject = strdup(uri.c_str());
string local_field = field_uri(field);
pattern.predicate = strdup(local_field.c_str());
pattern.object = 0;
pattern.object_type = lrdf_literal;
lrdf_remove_matches(&pattern);
free(pattern.subject);
free(pattern.predicate);
lrdf_add_triple(src.c_str(), uri.c_str(), local_field.c_str(),
literal.c_str(), lrdf_literal);
save_changes();
fields_changed(); /* EMIT SIGNAL */
}
string
AudioLibrary::field_uri (string name)
{
stringstream local_field;
local_field << "file:sfdb/fields/" << name;
return local_field.str();
}
string
AudioLibrary::get_label (string uri)
{
lrdf_statement pattern;
pattern.subject = strdup(uri.c_str());
pattern.predicate = RDFS_BASE "label";
pattern.object = 0;
pattern.object_type = lrdf_literal;
lrdf_statement* matches = lrdf_matches (&pattern);
free(pattern.subject);
stringstream label;
if (matches != 0){
label << matches->object;
}
lrdf_free_statements(matches);
return label.str();
}
void
AudioLibrary::set_label (string uri, string label)
{
lrdf_statement pattern;
pattern.subject = strdup(uri.c_str());
pattern.predicate = RDFS_BASE "label";
pattern.object = 0;
pattern.object_type = lrdf_literal;
lrdf_remove_matches(&pattern);
free(pattern.subject);
lrdf_add_triple(src.c_str(), uri.c_str(), RDFS_BASE "label",
label.c_str(), lrdf_literal);
}

View File

@@ -0,0 +1,873 @@
/*
Copyright (C) 2003 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$
*/
#include <algorithm>
#include <stdlib.h>
#include <sigc++/bind.h>
#include <ardour/types.h>
#include <ardour/configuration.h>
#include <ardour/audioplaylist.h>
#include <ardour/audioregion.h>
#include <ardour/crossfade.h>
#include <ardour/crossfade_compare.h>
#include <ardour/session.h>
#include "i18n.h"
using namespace ARDOUR;
using namespace sigc;
using namespace std;
AudioPlaylist::State::~State ()
{
}
AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
: Playlist (session, node, hidden)
{
in_set_state = true;
set_state (node);
in_set_state = false;
save_state (_("initial state"));
if (!hidden) {
PlaylistCreated (this); /* EMIT SIGNAL */
}
}
AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
: Playlist (session, name, hidden)
{
save_state (_("initial state"));
if (!hidden) {
PlaylistCreated (this); /* EMIT SIGNAL */
}
}
AudioPlaylist::AudioPlaylist (const AudioPlaylist& other, string name, bool hidden)
: Playlist (other, name, hidden)
{
save_state (_("initial state"));
if (!hidden) {
PlaylistCreated (this); /* EMIT SIGNAL */
}
}
AudioPlaylist::AudioPlaylist (const AudioPlaylist& other, jack_nframes_t start, jack_nframes_t cnt, string name, bool hidden)
: Playlist (other, start, cnt, name, hidden)
{
save_state (_("initial state"));
/* this constructor does NOT notify others (session) */
}
AudioPlaylist::~AudioPlaylist ()
{
set<Crossfade*> all_xfades;
set<Region*> all_regions;
GoingAway (this);
/* find every region we've ever used, and add it to the set of
all regions. same for xfades;
*/
for (RegionList::iterator x = regions.begin(); x != regions.end(); ++x) {
all_regions.insert (*x);
}
for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end(); ++x) {
all_xfades.insert (*x);
}
for (StateMap::iterator i = states.begin(); i != states.end(); ++i) {
AudioPlaylist::State* apstate = dynamic_cast<AudioPlaylist::State*> (*i);
for (RegionList::iterator r = apstate->regions.begin(); r != apstate->regions.end(); ++r) {
all_regions.insert (*r);
}
for (Crossfades::iterator xf = apstate->crossfades.begin(); xf != apstate->crossfades.end(); ++xf) {
all_xfades.insert (*xf);
}
delete apstate;
}
/* delete every region */
for (set<Region *>::iterator ar = all_regions.begin(); ar != all_regions.end(); ++ar) {
(*ar)->unlock_sources ();
delete *ar;
}
/* delete every crossfade */
for (set<Crossfade *>::iterator axf = all_xfades.begin(); axf != all_xfades.end(); ++axf) {
delete *axf;
}
}
struct RegionSortByLayer {
bool operator() (Region *a, Region *b) {
return a->layer() < b->layer();
}
};
jack_nframes_t
AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, jack_nframes_t start,
jack_nframes_t cnt, unsigned chan_n)
{
jack_nframes_t ret = cnt;
jack_nframes_t end;
jack_nframes_t read_frames;
jack_nframes_t skip_frames;
/* optimizing this memset() away involves a lot of conditionals
that may well cause more of a hit due to cache misses
and related stuff than just doing this here.
it would be great if someone could measure this
at some point.
one way or another, parts of the requested area
that are not written to by Region::region_at()
for all Regions that cover the area need to be
zeroed.
*/
memset (buf, 0, sizeof (Sample) * cnt);
/* this function is never called from a realtime thread, so
its OK to block (for short intervals).
*/
LockMonitor rm (region_lock, __LINE__, __FILE__);
end = start + cnt - 1;
read_frames = 0;
skip_frames = 0;
_read_data_count = 0;
map<uint32_t,vector<Region*> > relevant_regions;
map<uint32_t,vector<Crossfade*> > relevant_xfades;
vector<uint32_t> relevant_layers;
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
if ((*i)->coverage (start, end) != OverlapNone) {
relevant_regions[(*i)->layer()].push_back (*i);
relevant_layers.push_back ((*i)->layer());
}
}
for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
if ((*i)->coverage (start, end) != OverlapNone) {
relevant_xfades[(*i)->upper_layer()].push_back (*i);
}
}
// RegionSortByLayer layer_cmp;
// relevant_regions.sort (layer_cmp);
/* XXX this whole per-layer approach is a hack that
should be removed once Crossfades become
CrossfadeRegions and we just grab a list of relevant
regions and call read_at() on all of them.
*/
sort (relevant_layers.begin(), relevant_layers.end());
for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
vector<Region*>& r (relevant_regions[*l]);
vector<Crossfade*>& x (relevant_xfades[*l]);
for (vector<Region*>::iterator i = r.begin(); i != r.end(); ++i) {
(*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
_read_data_count += (*i)->read_data_count();
}
for (vector<Crossfade*>::iterator i = x.begin(); i != x.end(); ++i) {
(*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
/* don't JACK up _read_data_count, since its the same data as we just
read from the regions, and the OS should handle that for us.
*/
}
}
return ret;
}
void
AudioPlaylist::remove_dependents (Region& region)
{
Crossfades::iterator i, tmp;
AudioRegion* r = dynamic_cast<AudioRegion*> (&region);
if (r == 0) {
fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
<< endmsg;
return;
}
for (i = _crossfades.begin(); i != _crossfades.end(); ) {
tmp = i;
tmp++;
if ((*i)->involves (*r)) {
/* do not delete crossfades */
_crossfades.erase (i);
}
i = tmp;
}
}
void
AudioPlaylist::flush_notifications ()
{
Playlist::flush_notifications();
if (in_flush) {
return;
}
in_flush = true;
Crossfades::iterator a;
for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
NewCrossfade (*a); /* EMIT SIGNAL */
}
_pending_xfade_adds.clear ();
in_flush = false;
}
void
AudioPlaylist::refresh_dependents (Region& r)
{
AudioRegion* ar = dynamic_cast<AudioRegion*>(&r);
set<Crossfade*> updated;
if (ar == 0) {
return;
}
for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
Crossfades::iterator tmp;
tmp = x;
++tmp;
/* only update them once */
if ((*x)->involves (*ar)) {
if (find (updated.begin(), updated.end(), *x) == updated.end()) {
if ((*x)->refresh ()) {
/* not invalidated by the refresh */
updated.insert (*x);
}
}
}
x = tmp;
}
}
void
AudioPlaylist::check_dependents (Region& r, bool norefresh)
{
AudioRegion* other;
AudioRegion* region;
AudioRegion* top;
AudioRegion* bottom;
Crossfade* xfade;
if (in_set_state || in_partition) {
return;
}
if ((region = dynamic_cast<AudioRegion*> (&r)) == 0) {
fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
<< endmsg;
return;
}
if (!norefresh) {
refresh_dependents (r);
}
if (!Config->get_auto_xfade()) {
return;
}
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
other = dynamic_cast<AudioRegion*> (*i);
if (other == region) {
continue;
}
if (other->muted() || region->muted()) {
continue;
}
if (other->layer() < region->layer()) {
top = region;
bottom = other;
} else {
top = other;
bottom = region;
}
try {
if (top->coverage (bottom->position(), bottom->last_frame()) != OverlapNone) {
/* check if the upper region is within the lower region */
if (top->first_frame() > bottom->first_frame() &&
top->last_frame() < bottom->last_frame()) {
/* [ -------- top ------- ]
* {=========== bottom =============}
*/
/* to avoid discontinuities at the region boundaries of an internal
overlap (this region is completely within another), we create
two hidden crossfades at each boundary. this is not dependent
on the auto-xfade option, because we require it as basic
audio engineering.
*/
jack_nframes_t xfade_length = min ((jack_nframes_t) 720, top->length());
/* in, out */
xfade = new Crossfade (*top, *bottom, xfade_length, top->first_frame(), StartOfIn);
add_crossfade (*xfade);
xfade = new Crossfade (*bottom, *top, xfade_length, top->last_frame() - xfade_length, EndOfOut);
add_crossfade (*xfade);
} else {
xfade = new Crossfade (*other, *region, _session.get_xfade_model(), _session.get_crossfades_active());
add_crossfade (*xfade);
}
}
}
catch (failed_constructor& err) {
continue;
}
catch (Crossfade::NoCrossfadeHere& err) {
continue;
}
}
}
void
AudioPlaylist::add_crossfade (Crossfade& xfade)
{
Crossfades::iterator ci;
for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
if (*(*ci) == xfade) { // Crossfade::operator==()
break;
}
}
if (ci != _crossfades.end()) {
delete &xfade;
} else {
_crossfades.push_back (&xfade);
xfade.Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
xfade.StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
notify_crossfade_added (&xfade);
}
}
void AudioPlaylist::notify_crossfade_added (Crossfade *x)
{
if (atomic_read(&block_notifications)) {
_pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
} else {
NewCrossfade (x); /* EMIT SIGNAL */
}
}
void
AudioPlaylist::crossfade_invalidated (Crossfade* xfade)
{
Crossfades::iterator i;
xfade->in().resume_fade_in ();
xfade->out().resume_fade_out ();
if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
_crossfades.erase (i);
}
}
int
AudioPlaylist::set_state (const XMLNode& node)
{
XMLNode *child;
XMLNodeList nlist;
XMLNodeConstIterator niter;
if (!in_set_state) {
Playlist::set_state (node);
}
nlist = node.children();
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
child = *niter;
if (child->name() == "Crossfade") {
Crossfade *xfade;
try {
xfade = new Crossfade (*((const Playlist *)this), *child);
}
catch (failed_constructor& err) {
// cout << compose (_("could not create crossfade object in playlist %1"),
// _name)
// << endl;
continue;
}
Crossfades::iterator ci;
for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
if (*(*ci) == *xfade) {
break;
}
}
if (ci == _crossfades.end()) {
_crossfades.push_back (xfade);
xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
/* no need to notify here */
} else {
delete xfade;
}
}
}
return 0;
}
void
AudioPlaylist::drop_all_states ()
{
set<Crossfade*> all_xfades;
set<Region*> all_regions;
/* find every region we've ever used, and add it to the set of
all regions. same for xfades;
*/
for (StateMap::iterator i = states.begin(); i != states.end(); ++i) {
AudioPlaylist::State* apstate = dynamic_cast<AudioPlaylist::State*> (*i);
for (RegionList::iterator r = apstate->regions.begin(); r != apstate->regions.end(); ++r) {
all_regions.insert (*r);
}
for (Crossfades::iterator xf = apstate->crossfades.begin(); xf != apstate->crossfades.end(); ++xf) {
all_xfades.insert (*xf);
}
}
/* now remove from the "all" lists every region that is in the current list. */
for (list<Region*>::iterator i = regions.begin(); i != regions.end(); ++i) {
set<Region*>::iterator x = all_regions.find (*i);
if (x != all_regions.end()) {
all_regions.erase (x);
}
}
/* ditto for every crossfade */
for (list<Crossfade*>::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
set<Crossfade*>::iterator x = all_xfades.find (*i);
if (x != all_xfades.end()) {
all_xfades.erase (x);
}
}
/* delete every region that is left - these are all things that are part of our "history" */
for (set<Region *>::iterator ar = all_regions.begin(); ar != all_regions.end(); ++ar) {
(*ar)->unlock_sources ();
delete *ar;
}
/* delete every crossfade that is left (ditto as per regions) */
for (set<Crossfade *>::iterator axf = all_xfades.begin(); axf != all_xfades.end(); ++axf) {
delete *axf;
}
/* Now do the generic thing ... */
StateManager::drop_all_states ();
}
StateManager::State*
AudioPlaylist::state_factory (std::string why) const
{
State* state = new State (why);
state->regions = regions;
state->region_states.clear ();
for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
state->region_states.push_back ((*i)->get_memento());
}
state->crossfades = _crossfades;
state->crossfade_states.clear ();
for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
state->crossfade_states.push_back ((*i)->get_memento());
}
return state;
}
Change
AudioPlaylist::restore_state (StateManager::State& state)
{
{
RegionLock rlock (this);
State* apstate = dynamic_cast<State*> (&state);
in_set_state = true;
regions = apstate->regions;
for (list<UndoAction>::iterator s = apstate->region_states.begin(); s != apstate->region_states.end(); ++s) {
*s;
}
_crossfades = apstate->crossfades;
for (list<UndoAction>::iterator s = apstate->crossfade_states.begin(); s != apstate->crossfade_states.end(); ++s) {
*s;
}
in_set_state = false;
}
notify_length_changed ();
return Change (~0);
}
UndoAction
AudioPlaylist::get_memento () const
{
return sigc::bind (mem_fun (*(const_cast<AudioPlaylist*> (this)), &StateManager::use_state), _current_state_id);
}
void
AudioPlaylist::clear (bool with_delete, bool with_save)
{
if (with_delete) {
for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
delete *i;
}
}
_crossfades.clear ();
Playlist::clear (with_delete, with_save);
}
XMLNode&
AudioPlaylist::state (bool full_state)
{
XMLNode& node = Playlist::state (full_state);
if (full_state) {
for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
node.add_child_nocopy ((*i)->get_state());
}
}
return node;
}
void
AudioPlaylist::dump () const
{
Region *r;
Crossfade *x;
cerr << "Playlist \"" << _name << "\" " << endl
<< regions.size() << " regions "
<< _crossfades.size() << " crossfades"
<< endl;
for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
r = *i;
cerr << " " << r->name() << " @ " << r << " ["
<< r->start() << "+" << r->length()
<< "] at "
<< r->position()
<< " on layer "
<< r->layer ()
<< endl;
}
for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
x = *i;
cerr << " xfade ["
<< x->out().name()
<< ','
<< x->in().name()
<< " @ "
<< x->position()
<< " length = "
<< x->length ()
<< " active ? "
<< (x->active() ? "yes" : "no")
<< endl;
}
}
bool
AudioPlaylist::destroy_region (Region* region)
{
AudioRegion* r = dynamic_cast<AudioRegion*> (region);
bool changed = false;
Crossfades::iterator c, ctmp;
set<Crossfade*> unique_xfades;
if (r == 0) {
fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
<< endmsg;
/*NOTREACHED*/
return false;
}
{
RegionLock rlock (this);
RegionList::iterator i;
RegionList::iterator tmp;
for (i = regions.begin(); i != regions.end(); ) {
tmp = i;
++tmp;
if ((*i) == region) {
(*i)->unlock_sources ();
regions.erase (i);
changed = true;
}
i = tmp;
}
}
for (c = _crossfades.begin(); c != _crossfades.end(); ) {
ctmp = c;
++ctmp;
if ((*c)->involves (*r)) {
unique_xfades.insert (*c);
_crossfades.erase (c);
}
c = ctmp;
}
for (StateMap::iterator s = states.begin(); s != states.end(); ) {
StateMap::iterator tmp;
tmp = s;
++tmp;
State* astate = dynamic_cast<State*> (*s);
for (c = astate->crossfades.begin(); c != astate->crossfades.end(); ) {
ctmp = c;
++ctmp;
if ((*c)->involves (*r)) {
unique_xfades.insert (*c);
_crossfades.erase (c);
}
c = ctmp;
}
list<UndoAction>::iterator rsi, rsitmp;
RegionList::iterator ri, ritmp;
for (ri = astate->regions.begin(), rsi = astate->region_states.begin();
ri != astate->regions.end() && rsi != astate->region_states.end();) {
ritmp = ri;
++ritmp;
rsitmp = rsi;
++rsitmp;
if (region == (*ri)) {
astate->regions.erase (ri);
astate->region_states.erase (rsi);
}
ri = ritmp;
rsi = rsitmp;
}
s = tmp;
}
for (set<Crossfade*>::iterator c = unique_xfades.begin(); c != unique_xfades.end(); ++c) {
delete *c;
}
if (changed) {
/* overload this, it normally means "removed", not destroyed */
notify_region_removed (region);
}
return changed;
}
void
AudioPlaylist::crossfade_changed (Change ignored)
{
if (in_flush) {
return;
}
/* XXX is there a loop here? can an xfade change not happen
due to a playlist change? well, sure activation would
be an example. maybe we should check the type of change
that occured.
*/
maybe_save_state (_("xfade change"));
notify_modified ();
}
void
AudioPlaylist::get_equivalent_regions (const AudioRegion& other, vector<AudioRegion*>& results)
{
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
AudioRegion* ar = dynamic_cast<AudioRegion*> (*i);
if (ar && ar->equivalent (other)) {
results.push_back (ar);
}
}
}
void
AudioPlaylist::get_region_list_equivalent_regions (const AudioRegion& other, vector<AudioRegion*>& results)
{
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
AudioRegion* ar = dynamic_cast<AudioRegion*> (*i);
if (ar && ar->region_list_equivalent (other)) {
results.push_back (ar);
}
}
}
bool
AudioPlaylist::region_changed (Change what_changed, Region* region)
{
if (in_flush || in_set_state) {
return false;
}
Change our_interests = Change (AudioRegion::FadeInChanged|
AudioRegion::FadeOutChanged|
AudioRegion::FadeInActiveChanged|
AudioRegion::FadeOutActiveChanged|
AudioRegion::EnvelopeActiveChanged|
AudioRegion::ScaleAmplitudeChanged|
AudioRegion::EnvelopeChanged);
bool parent_wants_notify;
parent_wants_notify = Playlist::region_changed (what_changed, region);
maybe_save_state (_("region modified"));
if (parent_wants_notify || (what_changed & our_interests)) {
notify_modified ();
}
return true;
}
void
AudioPlaylist::crossfades_at (jack_nframes_t frame, Crossfades& clist)
{
RegionLock rlock (this);
for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
jack_nframes_t start, end;
start = (*i)->position();
end = start + (*i)->overlap_length(); // not length(), important difference
if (frame >= start && frame <= end) {
clist.push_back (*i);
}
}
}

1063
libs/ardour/audio_track.cc Normal file

File diff suppressed because it is too large Load Diff

1115
libs/ardour/audioengine.cc Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,87 @@
/*
Copyright (C) 2004 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
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$
*/
#include <time.h>
#include <cerrno>
#include <pbd/basename.h>
#include <ardour/filesource.h>
#include <ardour/session.h>
#include <ardour/audioregion.h>
#include <ardour/audiofilter.h>
#include "i18n.h"
using namespace ARDOUR;
int
AudioFilter::make_new_sources (AudioRegion& region, AudioRegion::SourceList& nsrcs)
{
vector<string> names = region.master_source_names();
for (uint32_t i = 0; i < region.n_channels(); ++i) {
string path = session.path_from_region_name (PBD::basename_nosuffix (names[i]), string (""));
if (path.length() == 0) {
error << compose (_("audiofilter: error creating name for new audio file based on %1"), region.name())
<< endmsg;
return -1;
}
try {
nsrcs.push_back (new FileSource (path, session.frame_rate()));
}
catch (failed_constructor& err) {
error << compose (_("audiofilter: error creating new audio file %1 (%2)"), path, strerror (errno)) << endmsg;
return -1;
}
}
return 0;
}
int
AudioFilter::finish (AudioRegion& region, AudioRegion::SourceList& nsrcs)
{
string region_name;
/* update headers on new sources */
time_t xnow;
struct tm* now;
time (&xnow);
now = localtime (&xnow);
for (AudioRegion::SourceList::iterator si = nsrcs.begin(); si != nsrcs.end(); ++si) {
dynamic_cast<FileSource*>((*si))->update_header (session.transport_frame(), *now, xnow);
}
/* create a new region */
region_name = session.new_region_name (region.name());
results.clear ();
results.push_back (new AudioRegion (nsrcs, 0, region.length(), region_name, 0,
Region::Flag (Region::WholeFile|Region::DefaultFlags)));
return 0;
}

1405
libs/ardour/audioregion.cc Normal file

File diff suppressed because it is too large Load Diff

181
libs/ardour/auditioner.cc Normal file
View File

@@ -0,0 +1,181 @@
/*
Copyright (C) 2001 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$
*/
#include <pbd/lockmonitor.h>
#include <ardour/diskstream.h>
#include <ardour/audioregion.h>
#include <ardour/route.h>
#include <ardour/session.h>
#include <ardour/auditioner.h>
#include <ardour/audioplaylist.h>
#include <ardour/panner.h>
using namespace std;
using namespace ARDOUR;
Auditioner::Auditioner (Session& s)
: AudioTrack (s, "auditioner", Route::Hidden)
{
string left = Config->get_auditioner_output_left();
string right = Config->get_auditioner_output_right();
if ((left.length() == 0) && (right.length() == 0)) {
return;
}
defer_pan_reset ();
if (left.length()) {
add_output_port (left, this);
}
if (right.length()) {
disk_stream().add_channel();
add_output_port (right, this);
}
allow_pan_reset ();
IO::output_changed.connect (mem_fun (*this, &Auditioner::output_changed));
the_region = 0;
atomic_set (&_active, 0);
}
Auditioner::~Auditioner ()
{
}
AudioPlaylist&
Auditioner::prepare_playlist ()
{
diskstream->playlist()->clear (false, false);
return *diskstream->playlist();
}
void
Auditioner::audition_current_playlist ()
{
if (atomic_read (&_active)) {
/* don't go via session for this, because we are going
to remain active.
*/
cancel_audition ();
}
LockMonitor lm (lock, __LINE__, __FILE__);
diskstream->seek (0);
length = diskstream->playlist()->get_maximum_extent();
current_frame = 0;
/* force a panner reset now that we have all channels */
_panner->reset (n_outputs(), diskstream->n_channels());
atomic_set (&_active, 1);
}
void
Auditioner::audition_region (AudioRegion& region)
{
if (atomic_read (&_active)) {
/* don't go via session for this, because we are going
to remain active.
*/
cancel_audition ();
}
LockMonitor lm (lock, __LINE__, __FILE__);
the_region = new AudioRegion (region);
the_region->set_position (0, this);
diskstream->playlist()->clear (true, false);
diskstream->playlist()->add_region (*the_region, 0, 1, false);
while (diskstream->n_channels() < the_region->n_channels()) {
diskstream->add_channel ();
}
while (diskstream->n_channels() > the_region->n_channels()) {
diskstream->remove_channel ();
}
/* force a panner reset now that we have all channels */
_panner->reset (n_outputs(), diskstream->n_channels());
length = the_region->length();
diskstream->seek (0);
current_frame = 0;
atomic_set (&_active, 1);
}
int
Auditioner::play_audition (jack_nframes_t nframes)
{
bool need_butler;
jack_nframes_t this_nframes;
int ret;
if (atomic_read (&_active) == 0) {
silence (nframes, 0);
return 0;
}
this_nframes = min (nframes, length - current_frame);
diskstream->prepare ();
if ((ret = roll (this_nframes, current_frame, current_frame + nframes, 0, false, false, false)) != 0) {
silence (nframes, 0);
return ret;
}
need_butler = diskstream->commit (this_nframes);
current_frame += this_nframes;
if (current_frame >= length) {
_session.cancel_audition ();
return 0;
} else {
return need_butler ? 1 : 0;
}
}
void
Auditioner::output_changed (IOChange change, void* src)
{
if (change & ConnectionsChanged) {
const char ** connections;
connections = output (0)->get_connections ();
if (connections) {
Config->set_auditioner_output_left (connections[0]);
free (connections);
}
connections = output (1)->get_connections ();
if (connections) {
Config->set_auditioner_output_right (connections[0]);
free (connections);
}
}
}

13
libs/ardour/automation.cc Normal file
View File

@@ -0,0 +1,13 @@
#include <stdint.h>
template<class AutomatedObject>
struct AutomationEvent {
uint32_t frame;
AutomatedObject *object;
void (AutomatedObject::*function) (void *);
void *arg;
void operator() (){
object->function (arg);
}
};

File diff suppressed because it is too large Load Diff

1105
libs/ardour/configuration.cc Normal file

File diff suppressed because it is too large Load Diff

275
libs/ardour/connection.cc Normal file
View File

@@ -0,0 +1,275 @@
/*
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$
*/
#include <algorithm>
#include <pbd/failed_constructor.h>
#include <ardour/ardour.h>
#include <ardour/connection.h>
#include <pbd/xml++.h>
#include "i18n.h"
using namespace ARDOUR;
using namespace PBD;
Connection::Connection (const XMLNode& node)
{
if (set_state (node)) {
throw failed_constructor();
}
}
InputConnection::InputConnection (const XMLNode& node)
: Connection (node)
{
}
OutputConnection::OutputConnection (const XMLNode& node)
: Connection (node)
{
}
void
Connection::set_name (string name, void *src)
{
_name = name;
NameChanged (src);
}
void
Connection::add_connection (int port, string portname)
{
{
LockMonitor lm (port_lock, __LINE__, __FILE__);
_ports[port].push_back (portname);
}
ConnectionsChanged (port); /* EMIT SIGNAL */
}
void
Connection::remove_connection (int port, string portname)
{
bool changed = false;
{
LockMonitor lm (port_lock, __LINE__, __FILE__);
PortList& pl = _ports[port];
PortList::iterator i = find (pl.begin(), pl.end(), portname);
if (i != pl.end()) {
pl.erase (i);
changed = true;
}
}
if (changed) {
ConnectionsChanged (port); /* EMIT SIGNAL */
}
}
const Connection::PortList&
Connection::port_connections (int port) const
{
LockMonitor lm (port_lock, __LINE__, __FILE__);
return _ports[port];
}
bool
Connection::operator== (const Connection& other) const
{
return other._ports == _ports;
}
void
Connection::add_port ()
{
{
LockMonitor lm (port_lock, __LINE__, __FILE__);
_ports.push_back (PortList());
}
ConfigurationChanged(); /* EMIT SIGNAL */
}
void
Connection::remove_port (int which_port)
{
bool changed = false;
{
LockMonitor lm (port_lock, __LINE__, __FILE__);
vector<PortList>::iterator i;
int n;
for (n = 0, i = _ports.begin(); i != _ports.end() && n < which_port; ++i, ++n);
if (i != _ports.end()) {
_ports.erase (i);
changed = true;
}
}
if (changed) {
ConfigurationChanged(); /* EMIT SIGNAL */
}
}
void
Connection::clear ()
{
{
LockMonitor lm (port_lock, __LINE__, __FILE__);
_ports.clear ();
}
ConfigurationChanged(); /* EMIT SIGNAL */
}
XMLNode&
Connection::get_state ()
{
XMLNode *node;
string str;
if (dynamic_cast<InputConnection *> (this)) {
node = new XMLNode ("InputConnection");
} else {
node = new XMLNode ("OutputConnection");
}
node->add_property ("name", _name);
for (vector<PortList>::iterator i = _ports.begin(); i != _ports.end(); ++i) {
str += '{';
for (vector<string>::iterator ii = (*i).begin(); ii != (*i).end(); ++ii) {
if (ii != (*i).begin()) {
str += ',';
}
str += *ii;
}
str += '}';
}
node->add_property ("connections", str);
return *node;
}
int
Connection::set_state (const XMLNode& node)
{
const XMLProperty *prop;
if ((prop = node.property ("name")) == 0) {
error << _("Node for Connection has no \"name\" property") << endmsg;
return -1;
}
_name = prop->value();
_sysdep = false;
if ((prop = node.property ("connections")) == 0) {
error << _("Node for Connection has no \"connections\" property") << endmsg;
return -1;
}
set_connections (prop->value());
return 0;
}
int
Connection::set_connections (const string& str)
{
vector<string> ports;
int i;
int n;
int nports;
if ((nports = count (str.begin(), str.end(), '{')) == 0) {
return 0;
}
for (n = 0; n < nports; ++n) {
add_port ();
}
string::size_type start, end, ostart;
ostart = 0;
start = 0;
end = 0;
i = 0;
while ((start = str.find_first_of ('{', ostart)) != string::npos) {
start += 1;
if ((end = str.find_first_of ('}', start)) == string::npos) {
error << compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
return -1;
}
if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
error << compose(_("bad input string in XML node \"%1\""), str) << endmsg;
return -1;
} else if (n > 0) {
for (int x = 0; x < n; ++x) {
add_connection (i, ports[x]);
}
}
ostart = end+1;
i++;
}
return 0;
}
int
Connection::parse_io_string (const string& str, vector<string>& ports)
{
string::size_type pos, opos;
if (str.length() == 0) {
return 0;
}
pos = 0;
opos = 0;
ports.clear ();
while ((pos = str.find_first_of (',', opos)) != string::npos) {
ports.push_back (str.substr (opos, pos - opos));
opos = pos + 1;
}
if (opos < str.length()) {
ports.push_back (str.substr(opos));
}
return ports.size();
}

877
libs/ardour/crossfade.cc Normal file
View File

@@ -0,0 +1,877 @@
/*
Copyright (C) 2003 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$
*/
#include <sigc++/bind.h>
#include <ardour/types.h>
#include <ardour/crossfade.h>
#include <ardour/crossfade_compare.h>
#include <ardour/audioregion.h>
#include <ardour/playlist.h>
#include <ardour/utils.h>
#include <ardour/session.h>
#include "i18n.h"
#include <locale.h>
using namespace std;
using namespace ARDOUR;
//using namespace sigc;
jack_nframes_t Crossfade::_short_xfade_length = 0;
Change Crossfade::ActiveChanged = ARDOUR::new_change();
/* XXX if and when we ever implement parallel processing of the process()
callback, these will need to be handled on a per-thread basis.
*/
Sample* Crossfade::crossfade_buffer_out = 0;
Sample* Crossfade::crossfade_buffer_in = 0;
void
Crossfade::set_buffer_size (jack_nframes_t sz)
{
if (crossfade_buffer_out) {
delete [] crossfade_buffer_out;
crossfade_buffer_out = 0;
}
if (crossfade_buffer_in) {
delete [] crossfade_buffer_in;
crossfade_buffer_in = 0;
}
if (sz) {
crossfade_buffer_out = new Sample[sz];
crossfade_buffer_in = new Sample[sz];
}
}
bool
Crossfade::operator== (const Crossfade& other)
{
return (_in == other._in) && (_out == other._out);
}
Crossfade::Crossfade (ARDOUR::AudioRegion& in, ARDOUR::AudioRegion& out,
jack_nframes_t length,
jack_nframes_t position,
AnchorPoint ap)
: _fade_in (0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
_fade_out (0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
{
_in = &in;
_out = &out;
_length = length;
_position = position;
_anchor_point = ap;
_follow_overlap = false;
_active = true;
_fixed = true;
initialize ();
}
Crossfade::Crossfade (ARDOUR::AudioRegion& a, ARDOUR::AudioRegion& b, CrossfadeModel model, bool act)
: _fade_in (0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
_fade_out (0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
{
_in_update = false;
_fixed = false;
if (compute (a, b, model)) {
throw failed_constructor();
}
_active = act;
initialize ();
}
Crossfade::Crossfade (const Playlist& playlist, XMLNode& node)
: _fade_in (0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
_fade_out (0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
{
Region* r;
XMLProperty* prop;
id_t id;
LocaleGuard lg (X_("POSIX"));
/* we have to find the in/out regions before we can do anything else */
if ((prop = node.property ("in")) == 0) {
error << _("Crossfade: no \"in\" region in state") << endmsg;
throw failed_constructor();
}
sscanf (prop->value().c_str(), "%llu", &id);
if ((r = playlist.find_region (id)) == 0) {
error << compose (_("Crossfade: no \"in\" region %1 found in playlist %2"), id, playlist.name())
<< endmsg;
throw failed_constructor();
}
if ((_in = dynamic_cast<AudioRegion*> (r)) == 0) {
throw failed_constructor();
}
if ((prop = node.property ("out")) == 0) {
error << _("Crossfade: no \"out\" region in state") << endmsg;
throw failed_constructor();
}
sscanf (prop->value().c_str(), "%llu", &id);
if ((r = playlist.find_region (id)) == 0) {
error << compose (_("Crossfade: no \"out\" region %1 found in playlist %2"), id, playlist.name())
<< endmsg;
throw failed_constructor();
}
if ((_out = dynamic_cast<AudioRegion*> (r)) == 0) {
throw failed_constructor();
}
_length = 0;
initialize();
if (set_state (node)) {
throw failed_constructor();
}
}
Crossfade::~Crossfade ()
{
for (StateMap::iterator i = states.begin(); i != states.end(); ++i) {
delete *i;
}
}
void
Crossfade::initialize ()
{
_in_update = false;
_out->suspend_fade_out ();
_in->suspend_fade_in ();
_fade_out.freeze ();
_fade_out.clear ();
_fade_out.add (0.0, 1.0);
_fade_out.add ((_length * 0.1), 0.99);
_fade_out.add ((_length * 0.2), 0.97);
_fade_out.add ((_length * 0.8), 0.03);
_fade_out.add ((_length * 0.9), 0.01);
_fade_out.add (_length, 0.0);
_fade_out.thaw ();
_fade_in.freeze ();
_fade_in.clear ();
_fade_in.add (0.0, 0.0);
_fade_in.add ((_length * 0.1), 0.01);
_fade_in.add ((_length * 0.2), 0.03);
_fade_in.add ((_length * 0.8), 0.97);
_fade_in.add ((_length * 0.9), 0.99);
_fade_in.add (_length, 1.0);
_fade_in.thaw ();
// _in->StateChanged.connect (slot (*this, &Crossfade::member_changed));
// _out->StateChanged.connect (slot (*this, &Crossfade::member_changed));
overlap_type = _in->coverage (_out->position(), _out->last_frame());
save_state ("initial");
}
int
Crossfade::compute (AudioRegion& a, AudioRegion& b, CrossfadeModel model)
{
AudioRegion* top;
AudioRegion* bottom;
jack_nframes_t short_xfade_length;
short_xfade_length = _short_xfade_length;
if (a.layer() < b.layer()) {
top = &b;
bottom = &a;
} else {
top = &a;
bottom = &b;
}
/* first check for matching ends */
if (top->first_frame() == bottom->first_frame()) {
/* Both regions start at the same point */
if (top->last_frame() < bottom->last_frame()) {
/* top ends before bottom, so put an xfade
in at the end of top.
*/
/* [-------- top ---------- ]
* {====== bottom =====================}
*/
_in = bottom;
_out = top;
if (top->last_frame() < short_xfade_length) {
_position = 0;
} else {
_position = top->last_frame() - short_xfade_length;
}
_length = min (short_xfade_length, top->length());
_follow_overlap = false;
_anchor_point = EndOfIn;
_active = true;
_fixed = true;
} else {
/* top ends after (or same time) as bottom - no xfade
*/
/* [-------- top ------------------------ ]
* {====== bottom =====================}
*/
throw NoCrossfadeHere();
}
} else if (top->last_frame() == bottom->last_frame()) {
/* Both regions end at the same point */
if (top->first_frame() > bottom->first_frame()) {
/* top starts after bottom, put an xfade in at the
start of top
*/
/* [-------- top ---------- ]
* {====== bottom =====================}
*/
_in = top;
_out = bottom;
_position = top->first_frame();
_length = min (short_xfade_length, top->length());
_follow_overlap = false;
_anchor_point = StartOfIn;
_active = true;
_fixed = true;
} else {
/* top starts before bottom - no xfade
*/
/* [-------- top ------------------------ ]
* {====== bottom =====================}
*/
throw NoCrossfadeHere();
}
} else {
/* OK, time to do more regular overlapping */
OverlapType ot = top->coverage (bottom->first_frame(), bottom->last_frame());
switch (ot) {
case OverlapNone:
/* should be NOTREACHED as a precondition of creating
a new crossfade, but we need to handle it here.
*/
throw NoCrossfadeHere();
break;
case OverlapInternal:
case OverlapExternal:
/* should be NOTREACHED because of tests above */
throw NoCrossfadeHere();
break;
case OverlapEnd: /* top covers start of bottom but ends within it */
/* [---- top ------------------------]
* { ==== bottom ============ }
*/
_in = bottom;
_out = top;
_position = bottom->first_frame();
_anchor_point = StartOfIn;
if (model == FullCrossfade) {
_length = _out->first_frame() + _out->length() - _in->first_frame();
/* leave active alone */
_follow_overlap = true;
} else {
_length = min (short_xfade_length, top->length());
_active = true;
_follow_overlap = false;
}
break;
case OverlapStart: /* top starts within bottom but covers bottom's end */
/* { ==== top ============ }
* [---- bottom -------------------]
*/
_in = top;
_out = bottom;
_position = top->first_frame();
_anchor_point = StartOfIn;
if (model == FullCrossfade) {
_length = _out->first_frame() + _out->length() - _in->first_frame();
/* leave active alone */
_follow_overlap = true;
} else {
_length = min (short_xfade_length, top->length());
_active = true;
_follow_overlap = false;
}
break;
}
}
return 0;
}
jack_nframes_t
Crossfade::read_at (Sample *buf, Sample *mixdown_buffer,
float *gain_buffer, jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n,
jack_nframes_t read_frames, jack_nframes_t skip_frames)
{
jack_nframes_t offset;
jack_nframes_t to_write;
if (!_active) {
return 0;
}
if (start < _position) {
/* handle an initial section of the read area that we do not
cover.
*/
offset = _position - start;
if (offset < cnt) {
cnt -= offset;
} else {
return 0;
}
start = _position;
buf += offset;
to_write = min (_length, cnt);
} else {
to_write = min (_length - (start - _position), cnt);
}
offset = start - _position;
_out->read_at (crossfade_buffer_out, mixdown_buffer, gain_buffer, start, to_write, chan_n, read_frames, skip_frames);
_in->read_at (crossfade_buffer_in, mixdown_buffer, gain_buffer, start, to_write, chan_n, read_frames, skip_frames);
float* fiv = new float[to_write];
float* fov = new float[to_write];
_fade_in.get_vector (offset, offset+to_write, fiv, to_write);
_fade_out.get_vector (offset, offset+to_write, fov, to_write);
/* note: although we have not explicitly taken into account the return values
from _out->read_at() or _in->read_at(), the length() function does this
implicitly. why? because it computes a value based on the in+out regions'
position and length, and so we know precisely how much data they could return.
*/
for (jack_nframes_t n = 0; n < to_write; ++n) {
buf[n] = (crossfade_buffer_out[n] * fov[n]) + (crossfade_buffer_in[n] * fiv[n]);
}
delete [] fov;
delete [] fiv;
return to_write;
}
OverlapType
Crossfade::coverage (jack_nframes_t start, jack_nframes_t end) const
{
jack_nframes_t my_end = _position + _length;
if ((start >= _position) && (end <= my_end)) {
return OverlapInternal;
}
if ((end >= _position) && (end <= my_end)) {
return OverlapStart;
}
if ((start >= _position) && (start <= my_end)) {
return OverlapEnd;
}
if ((_position >= start) && (_position <= end) && (my_end <= end)) {
return OverlapExternal;
}
return OverlapNone;
}
void
Crossfade::set_active (bool yn)
{
if (_active != yn) {
_active = yn;
save_state (_("active changed"));
send_state_changed (ActiveChanged);
}
}
bool
Crossfade::refresh ()
{
/* crossfades must be between non-muted regions */
if (_out->muted() || _in->muted()) {
Invalidated (this);
return false;
}
/* overlap type must be Start, End or External */
OverlapType ot;
ot = _in->coverage (_out->first_frame(), _out->last_frame());
switch (ot) {
case OverlapNone:
case OverlapInternal:
Invalidated (this);
return false;
default:
break;
}
/* overlap type must not have altered */
if (ot != overlap_type) {
Invalidated (this);
return false;
}
/* time to update */
return update (false);
}
bool
Crossfade::update (bool force)
{
jack_nframes_t newlen;
bool save = false;
if (_follow_overlap) {
newlen = _out->first_frame() + _out->length() - _in->first_frame();
} else {
newlen = _length;
}
if (newlen == 0) {
Invalidated (this);
return false;
}
_in_update = true;
if (force || (_follow_overlap && newlen != _length) || (_length > newlen)) {
double factor = newlen / (double) _length;
_fade_out.x_scale (factor);
_fade_in.x_scale (factor);
_length = newlen;
save = true;
}
switch (_anchor_point) {
case StartOfIn:
if (_position != _in->first_frame()) {
_position = _in->first_frame();
save = true;
}
break;
case EndOfIn:
if (_position != _in->last_frame() - _length) {
_position = _in->last_frame() - _length;
save = true;
}
break;
case EndOfOut:
if (_position != _out->last_frame() - _length) {
_position = _out->last_frame() - _length;
save = true;
}
}
if (save) {
save_state ("updated");
}
/* UI's may need to know that the overlap changed even
though the xfade length did not.
*/
send_state_changed (BoundsChanged); /* EMIT SIGNAL */
_in_update = false;
return true;
}
void
Crossfade::member_changed (Change what_changed)
{
Change what_we_care_about = Change (Region::MuteChanged|
Region::LayerChanged|
ARDOUR::BoundsChanged);
if (what_changed & what_we_care_about) {
refresh ();
}
}
Change
Crossfade::restore_state (StateManager::State& state)
{
CrossfadeState* xfstate = dynamic_cast<CrossfadeState*> (&state);
Change what_changed = Change (0);
_in_update = true;
xfstate->fade_in_memento ();
xfstate->fade_out_memento ();
if (_length != xfstate->length) {
what_changed = Change (what_changed|LengthChanged);
_length = xfstate->length;
}
if (_active != xfstate->active) {
what_changed = Change (what_changed|ActiveChanged);
_active = xfstate->active;
}
if (_position != xfstate->position) {
what_changed = Change (what_changed|PositionChanged);
_position = xfstate->position;
}
/* XXX what to do about notifications for these? I don't
think (G)UI cares about them because they are
implicit in the bounds.
*/
_follow_overlap = xfstate->follow_overlap;
_anchor_point = xfstate->anchor_point;
_in_update = false;
return Change (what_changed);
}
StateManager::State*
Crossfade::state_factory (std::string why) const
{
CrossfadeState* state = new CrossfadeState (why);
state->fade_in_memento = _fade_in.get_memento ();
state->fade_out_memento = _fade_out.get_memento ();
state->active = _active;
state->length = _length;
state->position = _position;
state->follow_overlap = _follow_overlap;
state->anchor_point = _anchor_point;
return state;
}
UndoAction
Crossfade::get_memento() const
{
return sigc::bind (mem_fun (*(const_cast<Crossfade *> (this)), &StateManager::use_state), _current_state_id);
}
XMLNode&
Crossfade::get_state ()
{
XMLNode* node = new XMLNode (X_("Crossfade"));
XMLNode* child;
char buf[64];
LocaleGuard lg (X_("POSIX"));
snprintf (buf, sizeof(buf), "%" PRIu64, _out->id());
node->add_property ("out", buf);
snprintf (buf, sizeof(buf), "%" PRIu64, _in->id());
node->add_property ("in", buf);
node->add_property ("active", (_active ? "yes" : "no"));
node->add_property ("follow-overlap", (_follow_overlap ? "yes" : "no"));
node->add_property ("fixed", (_fixed ? "yes" : "no"));
snprintf (buf, sizeof(buf), "%" PRIu32, _length);
node->add_property ("length", buf);
snprintf (buf, sizeof(buf), "%" PRIu32, (uint32_t) _anchor_point);
node->add_property ("anchor-point", buf);
snprintf (buf, sizeof(buf), "%" PRIu32, (uint32_t) _position);
node->add_property ("position", buf);
child = node->add_child ("FadeIn");
for (AutomationList::iterator ii = _fade_in.begin(); ii != _fade_in.end(); ++ii) {
XMLNode* pnode;
pnode = new XMLNode ("point");
snprintf (buf, sizeof (buf), "%" PRIu32, (jack_nframes_t) floor ((*ii)->when));
pnode->add_property ("x", buf);
snprintf (buf, sizeof (buf), "%f", (*ii)->value);
pnode->add_property ("y", buf);
child->add_child_nocopy (*pnode);
}
child = node->add_child ("FadeOut");
for (AutomationList::iterator ii = _fade_out.begin(); ii != _fade_out.end(); ++ii) {
XMLNode* pnode;
pnode = new XMLNode ("point");
snprintf (buf, sizeof (buf), "%" PRIu32, (jack_nframes_t) floor ((*ii)->when));
pnode->add_property ("x", buf);
snprintf (buf, sizeof (buf), "%f", (*ii)->value);
pnode->add_property ("y", buf);
child->add_child_nocopy (*pnode);
}
return *node;
}
int
Crossfade::set_state (const XMLNode& node)
{
XMLNodeConstIterator i;
XMLNodeList children;
XMLNode* fi;
XMLNode* fo;
const XMLProperty* prop;
LocaleGuard lg (X_("POSIX"));
if ((prop = node.property ("position")) != 0) {
_position = atoi (prop->value().c_str());
} else {
warning << _("old-style crossfade information - no position information") << endmsg;
_position = _in->first_frame();
}
if ((prop = node.property ("active")) != 0) {
_active = (prop->value() == "yes");
} else {
_active = true;
}
if ((prop = node.property ("follow-overlap")) != 0) {
_follow_overlap = (prop->value() == "yes");
} else {
_follow_overlap = false;
}
if ((prop = node.property ("fixed")) != 0) {
_fixed = (prop->value() == "yes");
} else {
_fixed = false;
}
if ((prop = node.property ("anchor-point")) != 0) {
_anchor_point = AnchorPoint (atoi ((prop->value().c_str())));
} else {
_anchor_point = StartOfIn;
}
if ((prop = node.property ("length")) != 0) {
_length = atol (prop->value().c_str());
} else {
/* XXX this branch is legacy code from before
the point where we stored xfade lengths.
*/
if ((_length = overlap_length()) == 0) {
throw failed_constructor();
}
}
if ((fi = find_named_node (node, "FadeIn")) == 0) {
return -1;
}
if ((fo = find_named_node (node, "FadeOut")) == 0) {
return -1;
}
/* fade in */
_fade_in.clear ();
children = fi->children();
for (i = children.begin(); i != children.end(); ++i) {
if ((*i)->name() == "point") {
jack_nframes_t x;
float y;
prop = (*i)->property ("x");
sscanf (prop->value().c_str(), "%" PRIu32, &x);
prop = (*i)->property ("y");
sscanf (prop->value().c_str(), "%f", &y);
_fade_in.add (x, y);
}
}
/* fade out */
_fade_out.clear ();
children = fo->children();
for (i = children.begin(); i != children.end(); ++i) {
if ((*i)->name() == "point") {
jack_nframes_t x;
float y;
XMLProperty* prop;
prop = (*i)->property ("x");
sscanf (prop->value().c_str(), "%" PRIu32, &x);
prop = (*i)->property ("y");
sscanf (prop->value().c_str(), "%f", &y);
_fade_out.add (x, y);
}
}
return 0;
}
bool
Crossfade::can_follow_overlap () const
{
return !_fixed;
}
void
Crossfade::set_follow_overlap (bool yn)
{
if (yn == _follow_overlap || _fixed) {
return;
}
_follow_overlap = yn;
if (!yn) {
set_length (_short_xfade_length);
} else {
set_length (_out->first_frame() + _out->length() - _in->first_frame());
}
}
jack_nframes_t
Crossfade::set_length (jack_nframes_t len)
{
jack_nframes_t limit;
switch (_anchor_point) {
case StartOfIn:
limit = _in->length();
break;
case EndOfIn:
limit = _in->length();
break;
case EndOfOut:
limit = _out->length();
break;
}
len = min (limit, len);
double factor = len / (double) _length;
_in_update = true;
_fade_out.x_scale (factor);
_fade_in.x_scale (factor);
_in_update = false;
_length = len;
save_state ("length changed");
send_state_changed (LengthChanged);
return len;
}
jack_nframes_t
Crossfade::overlap_length () const
{
if (_fixed) {
return _length;
}
return _out->first_frame() + _out->length() - _in->first_frame();
}
void
Crossfade::set_short_xfade_length (jack_nframes_t n)
{
_short_xfade_length = n;
}

449
libs/ardour/curve.cc Normal file
View File

@@ -0,0 +1,449 @@
/*
Copyright (C) 2001-2003 Paul Davis
Contains ideas derived from "Constrained Cubic Spline Interpolation"
by CJC Kruger (www.korf.co.uk/spline.pdf).
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$
*/
#include <iostream>
#include <float.h>
#include <cmath>
#include <climits>
#include <cfloat>
#include <cmath>
#include <pbd/lockmonitor.h>
#include <sigc++/bind.h>
#include "ardour/curve.h"
#include "i18n.h"
using namespace std;
using namespace ARDOUR;
using namespace PBD;
using namespace sigc;
Curve::Curve (double minv, double maxv, double canv, bool nostate)
: AutomationList (canv, nostate)
{
min_yval = minv;
max_yval = maxv;
}
Curve::Curve (const Curve& other)
: AutomationList (other)
{
min_yval = other.min_yval;
max_yval = other.max_yval;
}
Curve::Curve (const Curve& other, double start, double end)
: AutomationList (other, start, end)
{
min_yval = other.min_yval;
max_yval = other.max_yval;
}
Curve::~Curve ()
{
}
void
Curve::solve ()
{
uint32_t npoints;
if (!_dirty) {
return;
}
if ((npoints = events.size()) > 2) {
/* Compute coefficients needed to efficiently compute a constrained spline
curve. See "Constrained Cubic Spline Interpolation" by CJC Kruger
(www.korf.co.uk/spline.pdf) for more details.
*/
double x[npoints];
double y[npoints];
uint32_t i;
AutomationEventList::iterator xx;
for (i = 0, xx = events.begin(); xx != events.end(); ++xx, ++i) {
x[i] = (double) (*xx)->when;
y[i] = (double) (*xx)->value;
}
double lp0, lp1, fpone;
lp0 =(x[1] - x[0])/(y[1] - y[0]);
lp1 = (x[2] - x[1])/(y[2] - y[1]);
if (lp0*lp1 < 0) {
fpone = 0;
} else {
fpone = 2 / (lp1 + lp0);
}
double fplast = 0;
for (i = 0, xx = events.begin(); xx != events.end(); ++xx, ++i) {
CurvePoint* cp = dynamic_cast<CurvePoint*>(*xx);
if (cp == 0) {
fatal << _("programming error: ")
<< X_("non-CurvePoint event found in event list for a Curve")
<< endmsg;
/*NOTREACHED*/
}
double xdelta; /* gcc is wrong about possible uninitialized use */
double xdelta2; /* ditto */
double ydelta; /* ditto */
double fppL, fppR;
double fpi;
if (i > 0) {
xdelta = x[i] - x[i-1];
xdelta2 = xdelta * xdelta;
ydelta = y[i] - y[i-1];
}
/* compute (constrained) first derivatives */
if (i == 0) {
/* first segment */
fplast = ((3 * (y[1] - y[0]) / (2 * (x[1] - x[0]))) - (fpone * 0.5));
/* we don't store coefficients for i = 0 */
continue;
} else if (i == npoints - 1) {
/* last segment */
fpi = ((3 * ydelta) / (2 * xdelta)) - (fplast * 0.5);
} else {
/* all other segments */
double slope_before = ((x[i+1] - x[i]) / (y[i+1] - y[i]));
double slope_after = (xdelta / ydelta);
if (slope_after * slope_before < 0.0) {
/* slope changed sign */
fpi = 0.0;
} else {
fpi = 2 / (slope_before + slope_after);
}
}
/* compute second derivative for either side of control point `i' */
fppL = (((-2 * (fpi + (2 * fplast))) / (xdelta))) +
((6 * ydelta) / xdelta2);
fppR = (2 * ((2 * fpi) + fplast) / xdelta) -
((6 * ydelta) / xdelta2);
/* compute polynomial coefficients */
double b, c, d;
d = (fppR - fppL) / (6 * xdelta);
c = ((x[i] * fppL) - (x[i-1] * fppR))/(2 * xdelta);
double xim12, xim13;
double xi2, xi3;
xim12 = x[i-1] * x[i-1]; /* "x[i-1] squared" */
xim13 = xim12 * x[i-1]; /* "x[i-1] cubed" */
xi2 = x[i] * x[i]; /* "x[i] squared" */
xi3 = xi2 * x[i]; /* "x[i] cubed" */
b = (ydelta - (c * (xi2 - xim12)) - (d * (xi3 - xim13))) / xdelta;
/* store */
cp->coeff[0] = y[i-1] - (b * x[i-1]) - (c * xim12) - (d * xim13);
cp->coeff[1] = b;
cp->coeff[2] = c;
cp->coeff[3] = d;
fplast = fpi;
}
}
_dirty = false;
}
bool
Curve::rt_safe_get_vector (double x0, double x1, float *vec, int32_t veclen)
{
TentativeLockMonitor lm (lock, __LINE__, __FILE__);
if (!lm.locked()) {
return false;
} else {
_get_vector (x0, x1, vec, veclen);
return true;
}
}
void
Curve::get_vector (double x0, double x1, float *vec, int32_t veclen)
{
LockMonitor lm (lock, __LINE__, __FILE__);
_get_vector (x0, x1, vec, veclen);
}
void
Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
{
double rx, dx, lx, hx, max_x, min_x;
int32_t i;
int32_t original_veclen;
int32_t npoints;
if ((npoints = events.size()) == 0) {
for (i = 0; i < veclen; ++i) {
vec[i] = default_value;
}
return;
}
/* events is now known not to be empty */
max_x = events.back()->when;
min_x = events.front()->when;
lx = max (min_x, x0);
if (x1 < 0) {
x1 = events.back()->when;
}
hx = min (max_x, x1);
original_veclen = veclen;
if (x0 < min_x) {
/* fill some beginning section of the array with the
initial (used to be default) value
*/
double frac = (min_x - x0) / (x1 - x0);
int32_t subveclen = (int32_t) floor (veclen * frac);
subveclen = min (subveclen, veclen);
for (i = 0; i < subveclen; ++i) {
vec[i] = events.front()->value;
}
veclen -= subveclen;
vec += subveclen;
}
if (veclen && x1 > max_x) {
/* fill some end section of the array with the default or final value */
double frac = (x1 - max_x) / (x1 - x0);
int32_t subveclen = (int32_t) floor (original_veclen * frac);
float val;
subveclen = min (subveclen, veclen);
val = events.back()->value;
i = veclen - subveclen;
for (i = veclen - subveclen; i < veclen; ++i) {
vec[i] = val;
}
veclen -= subveclen;
}
if (veclen == 0) {
return;
}
if (npoints == 1 ) {
for (i = 0; i < veclen; ++i) {
vec[i] = events.front()->value;
}
return;
}
if (npoints == 2) {
/* linear interpolation between 2 points */
/* XXX I'm not sure that this is the right thing to
do here. but its not a common case for the envisaged
uses.
*/
if (veclen > 1) {
dx = (hx - lx) / (veclen - 1) ;
} else {
dx = 0; // not used
}
double slope = (events.back()->value - events.front()->value)/
(events.back()->when - events.front()->when);
double yfrac = dx*slope;
vec[0] = events.front()->value + slope * (lx - events.front()->when);
for (i = 1; i < veclen; ++i) {
vec[i] = vec[i-1] + yfrac;
}
return;
}
if (_dirty) {
solve ();
}
rx = lx;
if (veclen > 1) {
dx = (hx - lx) / veclen;
for (i = 0; i < veclen; ++i, rx += dx) {
vec[i] = multipoint_eval (rx);
}
}
}
double
Curve::unlocked_eval (double x)
{
if (_dirty) {
solve ();
}
return shared_eval (x);
}
double
Curve::multipoint_eval (double x)
{
pair<AutomationEventList::iterator,AutomationEventList::iterator> range;
if ((lookup_cache.left < 0) ||
((lookup_cache.left > x) ||
(lookup_cache.range.first == events.end()) ||
((*lookup_cache.range.second)->when < x))) {
TimeComparator cmp;
ControlEvent cp (x, 0.0);
lookup_cache.range = equal_range (events.begin(), events.end(), &cp, cmp);
}
range = lookup_cache.range;
/* EITHER
a) x is an existing control point, so first == existing point, second == next point
OR
b) x is between control points, so range is empty (first == second, points to where
to insert x)
*/
if (range.first == range.second) {
/* x does not exist within the list as a control point */
lookup_cache.left = x;
if (range.first == events.begin()) {
/* we're before the first point */
// return default_value;
events.front()->value;
}
if (range.second == events.end()) {
/* we're after the last point */
return events.back()->value;
}
double x2 = x * x;
CurvePoint* cp = dynamic_cast<CurvePoint*> (*range.second);
return cp->coeff[0] + (cp->coeff[1] * x) + (cp->coeff[2] * x2) + (cp->coeff[3] * x2 * x);
}
/* x is a control point in the data */
/* invalidate the cached range because its not usable */
lookup_cache.left = -1;
return (*range.first)->value;
}
ControlEvent*
Curve::point_factory (double when, double val) const
{
return new CurvePoint (when, val);
}
ControlEvent*
Curve::point_factory (const ControlEvent& other) const
{
return new CurvePoint (other.when, other.value);
}
Change
Curve::restore_state (StateManager::State& state)
{
mark_dirty ();
return AutomationList::restore_state (state);
}
extern "C" {
void
curve_get_vector_from_c (void *arg, double x0, double x1, float* vec, int32_t vecsize)
{
static_cast<Curve*>(arg)->get_vector (x0, x1, vec, vecsize);
}
}

View File

@@ -0,0 +1,73 @@
/*
Copyright (C) 2002 Andrew Morton
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$
*/
#include <cstdio>
#include <pbd/error.h>
#include <ardour/cycle_timer.h>
#include "i18n.h"
float CycleTimer::cycles_per_usec = 0;
float
CycleTimer::get_mhz()
{
FILE *f;
if ((f = fopen("/proc/cpuinfo", "r")) == 0) {
fatal << _("CycleTimer::get_mhz(): can't open /proc/cpuinfo") << endmsg;
/*NOTREACHED*/
return 0.0f;
}
while (true) {
float mhz;
int ret;
char buf[1000];
if (fgets (buf, sizeof(buf), f) == 0) {
fatal << _("CycleTimer::get_mhz(): cannot locate cpu MHz in /proc/cpuinfo") << endmsg;
/*NOTREACHED*/
return 0.0f;
}
#ifdef __powerpc__
int imhz;
/* why can't the PPC crew standardize their /proc/cpuinfo format ? */
ret = sscanf (buf, "clock\t: %dMHz", &imhz);
mhz = (float) imhz;
#else /* XXX don't assume its x86 just because its not power pc */
ret = sscanf (buf, "cpu MHz : %f", &mhz);
#endif
if (ret == 1) {
fclose(f);
return mhz;
}
}
fatal << _("cannot locate cpu MHz in /proc/cpuinfo") << endmsg;
/*NOTREACHED*/
return 0.0f;
}

1175
libs/ardour/default_click.cc Normal file

File diff suppressed because it is too large Load Diff

2338
libs/ardour/diskstream.cc Normal file

File diff suppressed because it is too large Load Diff

1101
libs/ardour/filesource.cc Normal file

File diff suppressed because it is too large Load Diff

62
libs/ardour/gain.cc Normal file
View File

@@ -0,0 +1,62 @@
/*
Copyright (C) 2000 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$
*/
#include <ardour/gain.h>
using namespace ARDOUR;
Gain::Gain ()
: Curve (0.0, 2.0, 1.0f) /* XXX yuck; clamps gain to -inf .. +6db */
{
}
Gain::Gain (const Gain& other)
: Curve (other)
{
}
Gain&
Gain::operator= (const Gain& other)
{
if (this != &other) {
Curve::operator= (other);
}
return *this;
}
void
Gain::fill_linear_volume_fade_in (Gain& gain, jack_nframes_t frames)
{
}
void
Gain::fill_linear_volume_fade_out (Gain& gain, jack_nframes_t frames)
{
}
void
Gain::fill_linear_fade_in (Gain& gain, jack_nframes_t frames)
{
}
void
Gain::fill_linear_fade_out (Gain& gain, jack_nframes_t frames)
{
}

475
libs/ardour/gdither.cc Normal file
View File

@@ -0,0 +1,475 @@
/*
* Copyright (C) 2002 Steve Harris <steve@plugin.org.uk>
*
* 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$
*/
#include <ardour/gdither_types_internal.h>
#include <ardour/gdither.h>
#include <ardour/noise.h>
/* this monstrosity is necessary to get access to lrintf() and random().
whoever is writing the glibc headers <cmath> and <cstdlib> should be
hauled off to a programmer re-education camp. for the rest of
their natural lives. or longer. <paul@linuxaudiosystems.com>
*/
#define _ISOC9X_SOURCE 1
#define _ISOC99_SOURCE 1
#ifdef __cplusplus
#include <cmath>
#else
#include <math.h>
#endif
#undef __USE_SVID
#define __USE_SVID 1
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#include <sys/types.h>
/* Lipshitz's minimally audible FIR, only really works for 46kHz-ish signals */
static const float shaped_bs[] = { 2.033f, -2.165f, 1.959f, -1.590f, 0.6149f };
/* Some useful constants */
#define MAX_U8 255
#define MIN_U8 0
#define SCALE_U8 128.0f
#define MAX_S16 32767
#define MIN_S16 -32768
#define SCALE_S16 32768.0f
#define MAX_S24 8388607
#define MIN_S24 -8388608
#define SCALE_S24 8388608.0f
GDither gdither_new(GDitherType type, uint32_t channels,
GDitherSize bit_depth, int dither_depth)
{
GDither s;
s = (GDither)calloc(1, sizeof(struct GDither_s));
s->type = type;
s->channels = channels;
s->bit_depth = (int)bit_depth;
if (dither_depth <= 0 || dither_depth > (int)bit_depth) {
dither_depth = (int)bit_depth;
}
s->dither_depth = dither_depth;
s->scale = (float)(1LL << (dither_depth - 1));
if (bit_depth == GDitherFloat || bit_depth == GDitherDouble) {
s->post_scale_fp = 1.0f / s->scale;
s->post_scale = 0;
} else {
s->post_scale_fp = 0.0f;
s->post_scale = 1 << ((int)bit_depth - dither_depth);
}
switch (bit_depth) {
case GDither8bit:
/* Unsigned 8 bit */
s->bias = 1.0f;
s->clamp_u = 255;
s->clamp_l = 0;
break;
case GDither16bit:
/* Signed 16 bit */
s->bias = 0.0f;
s->clamp_u = 32767;
s->clamp_l = -32768;
break;
case GDither32bit:
/* Signed 24 bit, in upper 24 bits of 32 bit word */
s->bias = 0.0f;
s->clamp_u = 8388607;
s->clamp_l = -8388608;
break;
case GDitherFloat:
/* normalised float */
s->bias = 0.0f;
s->clamp_u = lrintf(s->scale);
s->clamp_l = lrintf(-s->scale);
break;
case GDitherDouble:
/* normalised float */
s->bias = 0.0f;
s->clamp_u = lrintf(s->scale);
s->clamp_l = lrintf(-s->scale);
break;
case 23:
/* special performance test case */
s->scale = SCALE_S24;
s->post_scale = 256;
s->bias = 0.0f;
s->clamp_u = 8388607;
s->clamp_l = -8388608;
break;
default:
/* Not a bit depth we can handle */
free(s);
return NULL;
break;
}
switch (type) {
case GDitherNone:
case GDitherRect:
/* No state */
break;
case GDitherTri:
/* The last whitenoise sample */
s->tri_state = (float *) calloc(channels, sizeof(float));
break;
case GDitherShaped:
/* The error from the last few samples encoded */
s->shaped_state = (GDitherShapedState*)
calloc(channels, sizeof(GDitherShapedState));
break;
}
return s;
}
void gdither_free(GDither s)
{
if (s) {
free(s->tri_state);
free(s->shaped_state);
free(s);
}
}
inline static void gdither_innner_loop(const GDitherType dt,
const uint32_t stride, const float bias, const float scale,
const uint32_t post_scale, const int bit_depth,
const uint32_t channel, const uint32_t length, float *ts,
GDitherShapedState *ss, float *x, void *y, const int clamp_u,
const int clamp_l)
{
uint32_t pos, i;
u_int8_t *o8 = (u_int8_t*) y;
int16_t *o16 = (int16_t*) y;
int32_t *o32 = (int32_t*) y;
float tmp, r, ideal;
int64_t clamped;
i = channel;
for (pos = 0; pos < length; pos++, i += stride) {
tmp = x[i] * scale + bias;
switch (dt) {
case GDitherNone:
break;
case GDitherRect:
tmp -= GDITHER_NOISE;
break;
case GDitherTri:
r = GDITHER_NOISE - 0.5f;
tmp -= r - ts[channel];
ts[channel] = r;
break;
case GDitherShaped:
/* Save raw value for error calculations */
ideal = tmp;
/* Run FIR and add white noise */
ss->buffer[ss->phase] = GDITHER_NOISE * 0.5f;
tmp += ss->buffer[ss->phase] * shaped_bs[0]
+ ss->buffer[(ss->phase - 1) & GDITHER_SH_BUF_MASK]
* shaped_bs[1]
+ ss->buffer[(ss->phase - 2) & GDITHER_SH_BUF_MASK]
* shaped_bs[2]
+ ss->buffer[(ss->phase - 3) & GDITHER_SH_BUF_MASK]
* shaped_bs[3]
+ ss->buffer[(ss->phase - 4) & GDITHER_SH_BUF_MASK]
* shaped_bs[4];
/* Roll buffer and store last error */
ss->phase = (ss->phase + 1) & GDITHER_SH_BUF_MASK;
ss->buffer[ss->phase] = (float)lrintf(tmp) - ideal;
break;
}
clamped = lrintf(tmp);
if (clamped > clamp_u) {
clamped = clamp_u;
} else if (clamped < clamp_l) {
clamped = clamp_l;
}
switch (bit_depth) {
case GDither8bit:
o8[i] = (u_int8_t) (clamped * post_scale);
break;
case GDither16bit:
o16[i] = (int16_t) (clamped * post_scale);
break;
case GDither32bit:
o32[i] = (int32_t) (clamped * post_scale);
break;
}
}
}
/* floating pint version of the inner loop function */
inline static void gdither_innner_loop_fp(const GDitherType dt,
const uint32_t stride, const float bias, const float scale,
const float post_scale, const int bit_depth,
const uint32_t channel, const uint32_t length, float *ts,
GDitherShapedState *ss, float *x, void *y, const int clamp_u,
const int clamp_l)
{
uint32_t pos, i;
float *oflt = (float*) y;
double *odbl = (double*) y;
float tmp, r, ideal;
double clamped;
i = channel;
for (pos = 0; pos < length; pos++, i += stride) {
tmp = x[i] * scale + bias;
switch (dt) {
case GDitherNone:
break;
case GDitherRect:
tmp -= GDITHER_NOISE;
break;
case GDitherTri:
r = GDITHER_NOISE - 0.5f;
tmp -= r - ts[channel];
ts[channel] = r;
break;
case GDitherShaped:
/* Save raw value for error calculations */
ideal = tmp;
/* Run FIR and add white noise */
ss->buffer[ss->phase] = GDITHER_NOISE * 0.5f;
tmp += ss->buffer[ss->phase] * shaped_bs[0]
+ ss->buffer[(ss->phase - 1) & GDITHER_SH_BUF_MASK]
* shaped_bs[1]
+ ss->buffer[(ss->phase - 2) & GDITHER_SH_BUF_MASK]
* shaped_bs[2]
+ ss->buffer[(ss->phase - 3) & GDITHER_SH_BUF_MASK]
* shaped_bs[3]
+ ss->buffer[(ss->phase - 4) & GDITHER_SH_BUF_MASK]
* shaped_bs[4];
/* Roll buffer and store last error */
ss->phase = (ss->phase + 1) & GDITHER_SH_BUF_MASK;
ss->buffer[ss->phase] = (float)lrintf(tmp) - ideal;
break;
}
clamped = rintf(tmp);
if (clamped > clamp_u) {
clamped = clamp_u;
} else if (clamped < clamp_l) {
clamped = clamp_l;
}
switch (bit_depth) {
case GDitherFloat:
oflt[i] = (float) (clamped * post_scale);
break;
case GDitherDouble:
odbl[i] = (double) (clamped * post_scale);
break;
}
}
}
#define GDITHER_CONV_BLOCK 512
void gdither_run(GDither s, uint32_t channel, uint32_t length,
double *x, void *y)
{
float conv[GDITHER_CONV_BLOCK];
uint32_t i, pos;
char *ycast = (char *)y;
int step;
switch (s->bit_depth) {
case GDither8bit:
step = 1;
break;
case GDither16bit:
step = 2;
break;
case GDither32bit:
case GDitherFloat:
step = 4;
break;
case GDitherDouble:
step = 8;
break;
default:
step = 0;
break;
}
pos = 0;
while (pos < length) {
for (i=0; (i + pos) < length && i < GDITHER_CONV_BLOCK; i++) {
conv[i] = x[pos + i];
}
gdither_runf(s, channel, i, conv, ycast + s->channels * step);
pos += i;
}
}
void gdither_runf(GDither s, uint32_t channel, uint32_t length,
float *x, void *y)
{
uint32_t pos, i;
float tmp;
int64_t clamped;
GDitherShapedState *ss = NULL;
if (!s || channel >= s->channels) {
return;
}
if (s->shaped_state) {
ss = s->shaped_state + channel;
}
if (s->type == GDitherNone && s->bit_depth == 23) {
int32_t *o32 = (int32_t*) y;
for (pos = 0; pos < length; pos++) {
i = channel + (pos * s->channels);
tmp = x[i] * 8388608.0f;
clamped = lrintf(tmp);
if (clamped > 8388607) {
clamped = 8388607;
} else if (clamped < -8388608) {
clamped = -8388608;
}
o32[i] = (int32_t) (clamped * 256);
}
return;
}
/* some common case handling code - looks a bit wierd, but it allows
* the compiler to optiomise out the branches in the inner loop */
if (s->bit_depth == 8 && s->dither_depth == 8) {
switch (s->type) {
case GDitherNone:
gdither_innner_loop(GDitherNone, s->channels, 128.0f, SCALE_U8,
1, 8, channel, length, NULL, NULL, x, y,
MAX_U8, MIN_U8);
break;
case GDitherRect:
gdither_innner_loop(GDitherRect, s->channels, 128.0f, SCALE_U8,
1, 8, channel, length, NULL, NULL, x, y,
MAX_U8, MIN_U8);
break;
case GDitherTri:
gdither_innner_loop(GDitherTri, s->channels, 128.0f, SCALE_U8,
1, 8, channel, length, s->tri_state,
NULL, x, y, MAX_U8, MIN_U8);
break;
case GDitherShaped:
gdither_innner_loop(GDitherShaped, s->channels, 128.0f, SCALE_U8,
1, 8, channel, length, NULL,
ss, x, y, MAX_U8, MIN_U8);
break;
}
} else if (s->bit_depth == s->dither_depth == 16) {
switch (s->type) {
case GDitherNone:
gdither_innner_loop(GDitherNone, s->channels, 0.0f, SCALE_S16,
1, 16, channel, length, NULL, NULL, x, y,
MAX_S16, MIN_S16);
break;
case GDitherRect:
gdither_innner_loop(GDitherRect, s->channels, 0.0f, SCALE_S16,
1, 16, channel, length, NULL, NULL, x, y,
MAX_S16, MIN_S16);
break;
case GDitherTri:
gdither_innner_loop(GDitherTri, s->channels, 0.0f, SCALE_S16,
1, 16, channel, length, s->tri_state,
NULL, x, y, MAX_S16, MIN_S16);
break;
case GDitherShaped:
gdither_innner_loop(GDitherShaped, s->channels, 0.0f,
SCALE_S16, 1, 16, channel, length, NULL,
ss, x, y, MAX_S16, MIN_S16);
break;
}
} else if (s->bit_depth == 32 && s->dither_depth == 24) {
switch (s->type) {
case GDitherNone:
gdither_innner_loop(GDitherNone, s->channels, 0.0f, SCALE_S24,
256, 32, channel, length, NULL, NULL, x,
y, MAX_S24, MIN_S24);
break;
case GDitherRect:
gdither_innner_loop(GDitherRect, s->channels, 0.0f, SCALE_S24,
256, 32, channel, length, NULL, NULL, x,
y, MAX_S24, MIN_S24);
break;
case GDitherTri:
gdither_innner_loop(GDitherTri, s->channels, 0.0f, SCALE_S24,
256, 32, channel, length, s->tri_state,
NULL, x, y, MAX_S24, MIN_S24);
break;
case GDitherShaped:
gdither_innner_loop(GDitherShaped, s->channels, 0.0f, SCALE_S24,
256, 32, channel, length,
NULL, ss, x, y, MAX_S24, MIN_S24);
break;
}
} else if (s->bit_depth == GDitherFloat || s->bit_depth == GDitherDouble) {
gdither_innner_loop_fp(s->type, s->channels, s->bias, s->scale,
s->post_scale_fp, s->bit_depth, channel, length,
s->tri_state, ss, x, y, s->clamp_u, s->clamp_l);
} else {
/* no special case handling, just process it from the struct */
gdither_innner_loop(s->type, s->channels, s->bias, s->scale,
s->post_scale, s->bit_depth, channel,
length, s->tri_state, ss, x, y, s->clamp_u,
s->clamp_l);
}
}
/* vi:set ts=8 sts=4 sw=4: */

82
libs/ardour/gettext.h Normal file
View File

@@ -0,0 +1,82 @@
/* Convenience header for conditional use of GNU <libintl.h>.
Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published
by the Free Software Foundation; either version 2, 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA. */
#ifndef _LIBGETTEXT_H
#define _LIBGETTEXT_H 1
/* NLS can be disabled through the configure --disable-nls option. */
#if ENABLE_NLS
/* Get declarations of GNU message catalog functions. */
# include <libintl.h>
#else
/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
chokes if dcgettext is defined as a macro. So include it now, to make
later inclusions of <locale.h> a NOP. We don't include <libintl.h>
as well because people using "gettext.h" will not include <libintl.h>,
and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
is OK. */
#if defined(__sun)
# include <locale.h>
#endif
/* Disabled NLS.
The casts to 'const char *' serve the purpose of producing warnings
for invalid uses of the value returned from these functions.
On pre-ANSI systems without 'const', the config.h file is supposed to
contain "#define const". */
/* other headers may have included libintl.h */
# undef gettext
# undef dgettext
# undef dcgettext
# undef ngettext
# undef dngettext
# undef dcngettext
# undef textdomain
# undef bindtextdomain
# undef bind_textdomain_codeset
# define gettext(Msgid) ((const char *) (Msgid))
# define dgettext(Domainname, Msgid) ((const char *) (Msgid))
# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid))
# define ngettext(Msgid1, Msgid2, N) \
((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
# define dngettext(Domainname, Msgid1, Msgid2, N) \
((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
# define textdomain(Domainname) ((const char *) (Domainname))
# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset))
#endif
/* A pseudo function call that serves as a marker for the automated
extraction of messages, but does not call gettext(). The run-time
translation is done at a different place in the code.
The argument, String, should be a literal string. Concatenated strings
and other string expressions won't work.
The macro's expansion is not parenthesized, so that it is suitable as
initializer for static 'char[]' or 'const char[]' variables. */
#define gettext_noop(String) String
#endif /* _LIBGETTEXT_H */

Some files were not shown because too many files have changed in this diff Show More