diff options
author | Hans Fugal <hans@fugal.net> | 2006-08-04 02:18:45 +0000 |
---|---|---|
committer | Hans Fugal <hans@fugal.net> | 2006-08-04 02:18:45 +0000 |
commit | 79986643c0c904f6574bb5323e2233a43a9e622e (patch) | |
tree | 859323dbb096ac1658359881e7d11415b6588caa | |
parent | b0b723445816bc968a6a183c6619fccc61e82859 (diff) |
r269@gandalf: fugalh | 2006-08-03 20:18:05 -0600
Trunk merge conflicts resolved
git-svn-id: svn://localhost/ardour2/branches/undo@756 d708f5d6-7413-0410-9779-e7cbd77b26cf
372 files changed, 20725 insertions, 10216 deletions
diff --git a/SConstruct b/SConstruct index 1dd250edfb..e93aad96a8 100644 --- a/SConstruct +++ b/SConstruct @@ -31,6 +31,7 @@ opts.AddOptions( PathOption('DESTDIR', 'Set the intermediate install "prefix"', '/'), EnumOption('DIST_TARGET', 'Build target for cross compiling packagers', 'auto', allowed_values=('auto', 'i386', 'i686', 'x86_64', 'powerpc', 'tiger', 'panther', 'none' ), ignorecase=2), BoolOption('DMALLOC', 'Compile and link using the dmalloc library', 0), + BoolOption('EXTRA_WARN', 'Compile with -Wextra, -ansi, and -pedantic. Might break compilation. For pedants', 0), BoolOption('FFT_ANALYSIS', 'Include FFT analysis window', 0), BoolOption('FPU_OPTIMIZATION', 'Build runtime checked assembler code', 1), BoolOption('LIBLO', 'Compile with support for liblo library', 1), @@ -50,18 +51,25 @@ opts.AddOptions( class LibraryInfo(Environment): def __init__(self,*args,**kw): Environment.__init__ (self,*args,**kw) - + def Merge (self,others): for other in others: self.Append (LIBS = other.get ('LIBS',[])) - self.Append (LIBPATH = other.get ('LIBPATH', [])) + self.Append (LIBPATH = other.get ('LIBPATH', [])) self.Append (CPPPATH = other.get('CPPPATH', [])) self.Append (LINKFLAGS = other.get('LINKFLAGS', [])) self.Replace(LIBPATH = list(Set(self.get('LIBPATH', [])))) self.Replace(CPPPATH = list(Set(self.get('CPPPATH',[])))) #doing LINKFLAGS breaks -framework #doing LIBS break link order dependency - + + def ENV_update(self, src_ENV): + for k in src_ENV.keys(): + if k in self['ENV'].keys() and k in [ 'PATH', 'LD_LIBRARY_PATH', + 'LIB', 'INCLUDE' ]: + self['ENV'][k]=SCons.Util.AppendPath(self['ENV'][k], src_ENV[k]) + else: + self['ENV'][k]=src_ENV[k] env = LibraryInfo (options = opts, CPPPATH = [ '.' ], @@ -72,68 +80,69 @@ env = LibraryInfo (options = opts, DISTCHECKDIR = '#ardour-' + version + '/check' ) +env.ENV_update(os.environ) #---------------------------------------------------------------------- # Builders #---------------------------------------------------------------------- # Handy subst-in-file builder -# +# def do_subst_in_file(targetfile, sourcefile, dict): - """Replace all instances of the keys of dict with their values. - For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'}, - then all instances of %VERSION% in the file will be replaced with 1.2345 etc. - """ - try: - f = open(sourcefile, 'rb') - contents = f.read() - f.close() - except: - raise SCons.Errors.UserError, "Can't read source file %s"%sourcefile - for (k,v) in dict.items(): - contents = re.sub(k, v, contents) - try: - f = open(targetfile, 'wb') - f.write(contents) - f.close() - except: - raise SCons.Errors.UserError, "Can't write target file %s"%targetfile - return 0 # success - + """Replace all instances of the keys of dict with their values. + For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'}, + then all instances of %VERSION% in the file will be replaced with 1.2345 etc. + """ + try: + f = open(sourcefile, 'rb') + contents = f.read() + f.close() + except: + raise SCons.Errors.UserError, "Can't read source file %s"%sourcefile + for (k,v) in dict.items(): + contents = re.sub(k, v, contents) + try: + f = open(targetfile, 'wb') + f.write(contents) + f.close() + except: + raise SCons.Errors.UserError, "Can't write target file %s"%targetfile + return 0 # success + def subst_in_file(target, source, env): - if not env.has_key('SUBST_DICT'): - raise SCons.Errors.UserError, "SubstInFile requires SUBST_DICT to be set." - d = dict(env['SUBST_DICT']) # copy it - for (k,v) in d.items(): - if callable(v): - d[k] = env.subst(v()) - elif SCons.Util.is_String(v): - d[k]=env.subst(v) - else: - raise SCons.Errors.UserError, "SubstInFile: key %s: %s must be a string or callable"%(k, repr(v)) - for (t,s) in zip(target, source): - return do_subst_in_file(str(t), str(s), d) - + if not env.has_key('SUBST_DICT'): + raise SCons.Errors.UserError, "SubstInFile requires SUBST_DICT to be set." + d = dict(env['SUBST_DICT']) # copy it + for (k,v) in d.items(): + if callable(v): + d[k] = env.subst(v()) + elif SCons.Util.is_String(v): + d[k]=env.subst(v) + else: + raise SCons.Errors.UserError, "SubstInFile: key %s: %s must be a string or callable"%(k, repr(v)) + for (t,s) in zip(target, source): + return do_subst_in_file(str(t), str(s), d) + def subst_in_file_string(target, source, env): - """This is what gets printed on the console.""" - return '\n'.join(['Substituting vars from %s into %s'%(str(s), str(t)) - for (t,s) in zip(target, source)]) - + """This is what gets printed on the console.""" + return '\n'.join(['Substituting vars from %s into %s'%(str(s), str(t)) + for (t,s) in zip(target, source)]) + def subst_emitter(target, source, env): - """Add dependency from substituted SUBST_DICT to target. - Returns original target, source tuple unchanged. - """ - d = env['SUBST_DICT'].copy() # copy it - for (k,v) in d.items(): - if callable(v): - d[k] = env.subst(v()) - elif SCons.Util.is_String(v): - d[k]=env.subst(v) - Depends(target, SCons.Node.Python.Value(d)) - # Depends(target, source) # this doesn't help the install-sapphire-linux.sh problem - return target, source - + """Add dependency from substituted SUBST_DICT to target. + Returns original target, source tuple unchanged. + """ + d = env['SUBST_DICT'].copy() # copy it + for (k,v) in d.items(): + if callable(v): + d[k] = env.subst(v()) + elif SCons.Util.is_String(v): + d[k]=env.subst(v) + Depends(target, SCons.Node.Python.Value(d)) + # Depends(target, source) # this doesn't help the install-sapphire-linux.sh problem + return target, source + subst_action = Action (subst_in_file, subst_in_file_string) env['BUILDERS']['SubstInFile'] = Builder(action=subst_action, emitter=subst_emitter) @@ -141,31 +150,31 @@ env['BUILDERS']['SubstInFile'] = Builder(action=subst_action, emitter=subst_emit # internationalization # -# po_helper +# po_builder: builder function to copy po files to the parent directory while updating them # -# this is not a builder. we can't list the .po files as a target, -# because then scons -c will remove them (even Precious doesn't alter -# this). this function is called whenever a .mo file is being -# built, and will conditionally update the .po file if necessary. +# first source: .po file +# second source: .pot file # -def po_helper(po,pot): +def po_builder(target,source,env): + os.spawnvp (os.P_WAIT, 'cp', ['cp', str(source[0]), str(target[0])]) args = [ 'msgmerge', '--update', - po, - pot, + str(target[0]), + str(source[1]) ] - print 'Updating ' + po + print 'Updating ' + str(target[0]) return os.spawnvp (os.P_WAIT, 'msgmerge', args) +po_bld = Builder (action = po_builder) +env.Append(BUILDERS = {'PoBuild' : po_bld}) + # mo_builder: builder function for (binary) message catalogs (.mo) # # first source: .po file -# second source: .pot file # def mo_builder(target,source,env): - po_helper (source[0].get_path(), source[1].get_path()) args = [ 'msgfmt', '-c', '-o', @@ -183,15 +192,15 @@ env.Append(BUILDERS = {'MoBuild' : mo_bld}) # def pot_builder(target,source,env): - args = [ 'xgettext', + args = [ 'xgettext', '--keyword=_', '--keyword=N_', '--from-code=UTF-8', - '-o', target[0].get_path(), + '-o', target[0].get_path(), "--default-domain=" + env['PACKAGE'], '--copyright-holder="Paul Davis"' ] args += [ src.get_path() for src in source ] - + return os.spawnvp (os.P_WAIT, 'xgettext', args) pot_bld = Builder (action = pot_builder) @@ -204,33 +213,33 @@ env.Append(BUILDERS = {'PotBuild' : pot_bld}) def i18n (buildenv, sources, installenv): domain = buildenv['PACKAGE'] potfile = buildenv['POTFILE'] - + installenv.Alias ('potupdate', buildenv.PotBuild (potfile, sources)) - + p_oze = [ os.path.basename (po) for po in glob.glob ('po/*.po') ] languages = [ po.replace ('.po', '') for po in p_oze ] - m_oze = [ po.replace (".po", ".mo") for po in p_oze ] - for mo in m_oze[:]: - po = 'po/' + mo.replace (".mo", ".po") - installenv.Alias ('install', buildenv.MoBuild (mo, [ po, potfile ])) - - for lang in languages[:]: + for po_file in p_oze: + buildenv.PoBuild(po_file, ['po/'+po_file, potfile]) + mo_file = po_file.replace (".po", ".mo") + installenv.Alias ('install', buildenv.MoBuild (mo_file, po_file)) + + for lang in languages: modir = (os.path.join (install_prefix, 'share/locale/' + lang + '/LC_MESSAGES/')) moname = domain + '.mo' installenv.Alias('install', installenv.InstallAs (os.path.join (modir, moname), lang + '.mo')) # # A generic builder for version.cc files -# +# # note: requires that DOMAIN, MAJOR, MINOR, MICRO are set in the construction environment # note: assumes one source files, the header that declares the version variables -# +# def version_builder (target, source, env): text = "int " + env['DOMAIN'] + "_major_version = " + str (env['MAJOR']) + ";\n" text += "int " + env['DOMAIN'] + "_minor_version = " + str (env['MINOR']) + ";\n" text += "int " + env['DOMAIN'] + "_micro_version = " + str (env['MICRO']) + ";\n" - + try: o = file (target[0].get_path(), 'w') o.write (text) @@ -238,14 +247,14 @@ def version_builder (target, source, env): except IOError: print "Could not open", target[0].get_path(), " for writing\n" sys.exit (-1) - + text = "#ifndef __" + env['DOMAIN'] + "_version_h__\n" text += "#define __" + env['DOMAIN'] + "_version_h__\n" text += "extern int " + env['DOMAIN'] + "_major_version;\n" text += "extern int " + env['DOMAIN'] + "_minor_version;\n" text += "extern int " + env['DOMAIN'] + "_micro_version;\n" text += "#endif /* __" + env['DOMAIN'] + "_version_h__ */\n" - + try: o = file (target[1].get_path(), 'w') o.write (text) @@ -253,7 +262,7 @@ def version_builder (target, source, env): except IOError: print "Could not open", target[1].get_path(), " for writing\n" sys.exit (-1) - + return None version_bld = Builder (action = version_builder) @@ -276,8 +285,8 @@ def versioned_builder(target,source,env): except IOError: print "Could not CVS/Entries for reading" return -1 - - last_date = "" + + last_date = "" lines = o.readlines() for line in lines: if line[0:12] == '/SConscript/': @@ -285,20 +294,20 @@ def versioned_builder(target,source,env): last_date = parts[3] break o.close () - + if last_date == "": print "No SConscript CVS update info found - versioned executable cannot be built" return -1 - + tag = time.strftime ('%Y%M%d%H%m', time.strptime (last_date)) print "The current build ID is " + tag - + tagged_executable = source[0].get_path() + '-' + tag - + if os.path.exists (tagged_executable): print "Replacing existing executable with the same build tag." os.unlink (tagged_executable) - + return os.link (source[0].get_path(), tagged_executable) verbuild = Builder (action = versioned_builder) @@ -310,13 +319,13 @@ env.Append (BUILDERS = {'VersionedExecutable' : verbuild}) def distcopy (target, source, env): treedir = str (target[0]) - + try: os.mkdir (treedir) except OSError, (errnum, strerror): if errnum != errno.EEXIST: print 'mkdir ', treedir, ':', strerror - + cmd = 'tar cf - ' # # we don't know what characters might be in the file names @@ -328,7 +337,7 @@ def distcopy (target, source, env): p = os.popen (cmd) return p.close () -def tarballer (target, source, env): +def tarballer (target, source, env): cmd = 'tar -jcf ' + str (target[0]) + ' ' + str(source[0]) + " --exclude '*~'" print 'running ', cmd, ' ... ' p = os.popen (cmd) @@ -359,7 +368,7 @@ if env['VST']: env['VST'] = 0; else: print "OK, VST support will be enabled" - + # ---------------------------------------------------------------------- # Construction environment setup @@ -381,7 +390,7 @@ libraries['raptor'].ParseConfig('pkg-config --cflags --libs raptor') libraries['samplerate'] = LibraryInfo() libraries['samplerate'].ParseConfig('pkg-config --cflags --libs samplerate') -if env['FFT_ANALYSIS']: +if env['FFT_ANALYSIS']: libraries['fftw3f'] = LibraryInfo() libraries['fftw3f'].ParseConfig('pkg-config --cflags --libs fftw3f') @@ -420,9 +429,8 @@ libraries['ardour_cp'] = LibraryInfo (LIBS='ardour_cp', LIBPATH='#libs/surfaces/ libraries['ardour'] = LibraryInfo (LIBS='ardour', LIBPATH='#libs/ardour', CPPPATH='#libs/ardour') libraries['midi++2'] = LibraryInfo (LIBS='midi++', LIBPATH='#libs/midi++2', CPPPATH='#libs/midi++2') -libraries['pbd3'] = LibraryInfo (LIBS='pbd', LIBPATH='#libs/pbd3', CPPPATH='#libs/pbd3') +libraries['pbd'] = LibraryInfo (LIBS='pbd', LIBPATH='#libs/pbd', CPPPATH='#libs/pbd') libraries['gtkmm2ext'] = LibraryInfo (LIBS='gtkmm2ext', LIBPATH='#libs/gtkmm2ext', CPPPATH='#libs/gtkmm2ext') -#libraries['cassowary'] = LibraryInfo(LIBS='cassowary', LIBPATH='#libs/cassowary', CPPPATH='#libs/cassowary') # # Check for libusb @@ -434,7 +442,7 @@ if conf.CheckLib ('usb', 'usb_interrupt_write'): have_libusb = True else: have_libusb = False - + libraries['usb'] = conf.Finish () # @@ -443,7 +451,7 @@ libraries['usb'] = conf.Finish () libraries['flac'] = LibraryInfo () conf = Configure (libraries['flac']) -conf.CheckLib ('FLAC', 'FLAC__stream_decoder_new') +conf.CheckLib ('FLAC', 'FLAC__stream_decoder_new', language='CXX') libraries['flac'] = conf.Finish () # @@ -451,7 +459,7 @@ libraries['flac'] = conf.Finish () if env['LIBLO']: libraries['lo'] = LibraryInfo () - + conf = Configure (libraries['lo']) if conf.CheckLib ('lo', 'lo_server_new') == False: print "liblo does not appear to be installed." @@ -473,14 +481,14 @@ if conf.CheckLib ('dmallocth', 'dmalloc_shutdown'): have_libdmalloc = True else: have_libdmalloc = False - + libraries['dmalloc'] = conf.Finish () # # # Audio/MIDI library (needed for MIDI, since audio is all handled via JACK) -# +# conf = Configure(env) @@ -498,11 +506,11 @@ elif conf.CheckCHeader('/System/Library/Frameworks/CoreMIDI.framework/Headers/Co else: print "It appears you don't have the required MIDI libraries installed." sys.exit (1) - + env = conf.Finish() if env['SYSLIBS']: - + libraries['sigc2'] = LibraryInfo() libraries['sigc2'].ParseConfig('pkg-config --cflags --libs sigc++-2.0') libraries['glibmm2'] = LibraryInfo() @@ -521,7 +529,7 @@ if env['SYSLIBS']: # # cannot use system one for the time being # - + libraries['sndfile'] = LibraryInfo(LIBS='libsndfile', LIBPATH='#libs/libsndfile', CPPPATH=['#libs/libsndfile', '#libs/libsndfile/src']) @@ -531,22 +539,29 @@ if env['SYSLIBS']: # libraries['flowcanvas'] = LibraryInfo(LIBS='flowcanvas', LIBPATH='#/libs/flowcanvas', CPPPATH='#libs/flowcanvas') libraries['soundtouch'] = LibraryInfo() - libraries['soundtouch'].ParseConfig ('pkg-config --cflags --libs soundtouch-1.0') + libraries['soundtouch'].ParseConfig ('pkg-config --cflags --libs libSoundTouch') + libraries['appleutility'] = LibraryInfo(LIBS='libappleutility', + LIBPATH='#libs/appleutility', + CPPPATH='#libs/appleutility') + coredirs = [ 'templates' ] - + subdirs = [ 'libs/libsndfile', - 'libs/pbd3', + 'libs/pbd', 'libs/midi++2', 'libs/ardour' ] - + if env['VST']: subdirs = ['libs/fst'] + subdirs + ['vst'] + if env['COREAUDIO']: + subdirs = subdirs + ['libs/appleutility'] + gtk_subdirs = [ # 'libs/flowcanvas', 'libs/gtkmm2ext', @@ -575,7 +590,7 @@ else: libraries['libgnomecanvasmm'] = LibraryInfo(LIBS='libgnomecanvasmm', LIBPATH='#libs/libgnomecanvasmm', CPPPATH='#libs/libgnomecanvasmm') - + libraries['soundtouch'] = LibraryInfo(LIBS='soundtouch', LIBPATH='#libs/soundtouch', CPPPATH=['#libs', '#libs/soundtouch']) @@ -585,24 +600,29 @@ else: # libraries['libglademm'] = LibraryInfo(LIBS='libglademm', # LIBPATH='#libs/libglademm', # CPPPATH='#libs/libglademm') + libraries['appleutility'] = LibraryInfo(LIBS='libappleutility', + LIBPATH='#libs/appleutility', + CPPPATH='#libs/appleutility') coredirs = [ 'libs/soundtouch', 'templates' ] - + subdirs = [ -# 'libs/cassowary', 'libs/sigc++2', 'libs/libsndfile', - 'libs/pbd3', + 'libs/pbd', 'libs/midi++2', 'libs/ardour' ] - + if env['VST']: subdirs = ['libs/fst'] + subdirs + ['vst'] + if env['COREAUDIO']: + subdirs = subdirs + ['libs/appleutility'] + gtk_subdirs = [ 'libs/glibmm2', 'libs/gtkmm2/pango', @@ -627,7 +647,7 @@ if env['SURFACES']: surface_subdirs += [ 'libs/surfaces/tranzport' ] if os.access ('libs/surfaces/sony9pin', os.F_OK): surface_subdirs += [ 'libs/surfaces/sony9pin' ] - + opts.Save('scache.conf', env) Help(opts.GenerateHelpText(env)) @@ -646,7 +666,7 @@ if os.environ.has_key('CXX'): if os.environ.has_key('DISTCC_HOSTS'): env['ENV']['DISTCC_HOSTS'] = os.environ['DISTCC_HOSTS'] env['ENV']['HOME'] = os.environ['HOME'] - + final_prefix = '$PREFIX' install_prefix = '$DESTDIR/$PREFIX' @@ -670,7 +690,7 @@ if have_cxx[0] != 1: exit (1) else: print "Congratulations, you have a functioning C++ compiler." - + env = conf.Finish() # @@ -724,37 +744,37 @@ if config[config_cpu] == 'powerpc' and env['DIST_TARGET'] != 'none': if config[config_arch] == 'apple': opt_flags.extend ([ "-mcpu=7450", "-faltivec"]) else: - opt_flags.extend ([ "-mcpu=7400", "-maltivec", "-mabi=altivec"]) + opt_flags.extend ([ "-mcpu=7400", "-maltivec", "-mabi=altivec"]) else: opt_flags.extend([ "-mcpu=750", "-mmultiple" ]) opt_flags.extend (["-mhard-float", "-mpowerpc-gfxopt"]) elif ((re.search ("i[0-9]86", config[config_cpu]) != None) or (re.search ("x86_64", config[config_cpu]) != None)) and env['DIST_TARGET'] != 'none': - + build_host_supports_sse = 0 debug_flags.append ("-DARCH_X86") opt_flags.append ("-DARCH_X86") - + if config[config_kernel] == 'linux' : - - if env['DIST_TARGET'] != 'i386': - + + if env['DIST_TARGET'] != 'i386': + flag_line = os.popen ("cat /proc/cpuinfo | grep '^flags'").read()[:-1] x86_flags = flag_line.split (": ")[1:][0].split (' ') - + if "mmx" in x86_flags: opt_flags.append ("-mmmx") if "sse" in x86_flags: build_host_supports_sse = 1 if "3dnow" in x86_flags: opt_flags.append ("-m3dnow") - + if config[config_cpu] == "i586": opt_flags.append ("-march=i586") elif config[config_cpu] == "i686": opt_flags.append ("-march=i686") - + if ((env['DIST_TARGET'] == 'i686') or (env['DIST_TARGET'] == 'x86_64')) and build_host_supports_sse: opt_flags.extend (["-msse", "-mfpmath=sse"]) debug_flags.extend (["-msse", "-mfpmath=sse"]) @@ -783,7 +803,7 @@ env.Append(CONFIG_ARCH=config[config_arch]) # -# ARCH="..." overrides all +# ARCH="..." overrides all # if env['ARCH'] != '': @@ -812,6 +832,10 @@ else: env.Append(CCFLAGS="-Wall") env.Append(CXXFLAGS="-Woverloaded-virtual") +if env['EXTRA_WARN']: + env.Append(CCFLAGS="-Wextra -pedantic") + env.Append(CXXFLAGS="-ansi") + if env['LIBLO']: env.Append(CCFLAGS="-DHAVE_LIBLO") @@ -822,34 +846,47 @@ if env['LIBLO']: env.Merge ([ libraries['core'] ]) # -# i18n support +# fix scons nitpickiness on APPLE # -conf = Configure (env) +if env['DIST_TARGET'] == 'panther' or env['DIST_TARGET'] == 'tiger': + env.Append(CCFLAGS="-I/opt/local/include", LINKFLAGS="-L/opt/local/lib") +# +# i18n support +# + +conf = Configure (env) if env['NLS']: + nls_error = 'This system is not configured for internationalized applications. An english-only version will be built:' print 'Checking for internationalization support ...' have_gettext = conf.TryAction(Action('xgettext --version')) if have_gettext[0] != 1: - print 'This system is not configured for internationalized applications (no xgettext command). An english-only version will be built\n' + nls_error += ' No xgettext command.' env['NLS'] = 0 - - if conf.CheckCHeader('libintl.h') == None: - print 'This system is not configured for internationalized applications (no libintl.h). An english-only version will be built\n' - env['NLS'] = 0 - - have_intltool = conf.TryAction(Action('intltool-update --version')) - if have_intltool[0] != 1: - print 'This system is not configured for internationalized applications (no intltool-update command). An english-only version will be built\n' + else: + print "Found xgettext" + + have_msgmerge = conf.TryAction(Action('msgmerge --version')) + if have_msgmerge[0] != 1: + nls_error += ' No msgmerge command.' env['NLS'] = 0 + else: + print "Found msgmerge" - + if not conf.CheckCHeader('libintl.h'): + nls_error += ' No libintl.h.' + env['NLS'] = 0 + + if env['NLS'] == 0: + print nls_error + else: + print "International version will be built." env = conf.Finish() if env['NLS'] == 1: env.Append(CCFLAGS="-DENABLE_NLS") - Export('env install_prefix final_prefix config_prefix final_config_prefix libraries i18n version subst_dict') # @@ -903,18 +940,18 @@ env.Distribute (env['DISTTREE'], glob.glob ('DOCUMENTATION/FAQ*') + glob.glob ('DOCUMENTATION/README*') ) - + srcdist = env.Tarball(env['TARBALL'], env['DISTTREE']) env.Alias ('srctar', srcdist) # -# don't leave the distree around +# don't leave the distree around # env.AddPreAction (env['DISTTREE'], Action ('rm -rf ' + str (File (env['DISTTREE'])))) env.AddPostAction (srcdist, Action ('rm -rf ' + str (File (env['DISTTREE'])))) # # the subdirs -# +# for subdir in coredirs: SConscript (subdir + '/SConscript') @@ -922,7 +959,7 @@ for subdir in coredirs: for sublistdir in [ subdirs, gtk_subdirs, surface_subdirs ]: for subdir in sublistdir: SConscript (subdir + '/SConscript') - + # cleanup env.Clean ('scrub', [ 'scache.conf', '.sconf_temp', '.sconsign.dblite', 'config.log']) diff --git a/ardour.dox b/ardour.dox index 8bd87d6fa3..a72ecbc588 100644 --- a/ardour.dox +++ b/ardour.dox @@ -459,7 +459,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = libs/pbd3 libs/midi++2 libs/ardour libs/gtkmm2ext gtk2_ardour +INPUT = libs/pbd libs/midi++2 libs/ardour libs/gtkmm2ext gtk2_ardour # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp diff --git a/gtk2_ardour/SConscript b/gtk2_ardour/SConscript index 65f8dfca73..d004c9c4c6 100644 --- a/gtk2_ardour/SConscript +++ b/gtk2_ardour/SConscript @@ -27,7 +27,7 @@ gtkardour.Merge ([ libraries['ardour_cp'], libraries['gtkmm2ext'], libraries['midi++2'], - libraries['pbd3'], + libraries['pbd'], libraries['gtkmm2'], libraries['glib2'], libraries['libgnomecanvas2'], @@ -57,6 +57,10 @@ if gtkardour['FFT_ANALYSIS']: gtkardour.Merge ([libraries['fftw3f']]) gtkardour.Append(CCFLAGS='-DFFT_ANALYSIS') +if gtkardour['COREAUDIO']: + gtkardour.Append(CCFLAGS='-DHAVE_COREAUDIO') + gtkardour.Merge([libraries['appleutility']]) + skipped_files=Split(""" connection_editor.cc """) @@ -75,6 +79,7 @@ ardour_ui_ed.cc ardour_ui_mixer.cc ardour_ui_options.cc audio_clock.cc +route_time_axis.cc audio_time_axis.cc automation_gain_line.cc automation_line.cc @@ -141,8 +146,6 @@ marker.cc marker_time_axis.cc marker_time_axis_view.cc marker_view.cc -meter_bridge.cc -meter_bridge_strip.cc mixer_strip.cc mixer_ui.cc new_session_dialog.cc @@ -159,10 +162,11 @@ public_editor.cc redirect_automation_line.cc redirect_automation_time_axis.cc redirect_box.cc -region_editor.cc +audio_region_editor.cc region_gain_line.cc region_selection.cc -regionview.cc +region_view.cc +audio_region_view.cc route_params_ui.cc route_redirect_selection.cc route_ui.cc @@ -170,7 +174,8 @@ selection.cc sfdb_ui.cc send_ui.cc streamview.cc -taperegionview.cc +audio_streamview.cc +tape_region_view.cc tempo_dialog.cc time_axis_view.cc time_axis_view_item.cc @@ -255,8 +260,7 @@ else: env.Alias('install', env.InstallAs(os.path.join(install_prefix, 'bin')+'/ardour2', ardoursh)) if env['NLS']: - Export('gtkardour', 'intl_files') - SConscript ('po/SConscript') + i18n (gtkardour, gtkardour_files+skipped_files+fft_analysis_files, env) # configuration files env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour2_ui.rc')) diff --git a/gtk2_ardour/actions.cc b/gtk2_ardour/actions.cc index ee688c3660..2197d4dc00 100644 --- a/gtk2_ardour/actions.cc +++ b/gtk2_ardour/actions.cc @@ -19,7 +19,7 @@ */ #include <vector> -#include <string.h> +#include <string> #include <gtk/gtkaccelmap.h> #include <gtk/gtkuimanager.h> diff --git a/gtk2_ardour/analysis_window.cc b/gtk2_ardour/analysis_window.cc index b8318f45fe..f742afd727 100644 --- a/gtk2_ardour/analysis_window.cc +++ b/gtk2_ardour/analysis_window.cc @@ -26,7 +26,7 @@ #include <gtkmm/treeiter.h> #include <ardour/audioregion.h> -#include <ardour/playlist.h> +#include <ardour/audioplaylist.h> #include <ardour/types.h> #include "analysis_window.h" @@ -35,7 +35,7 @@ #include "time_axis_view.h" #include "public_editor.h" #include "selection.h" -#include "regionview.h" +#include "audio_region_view.h" #include "i18n.h" @@ -45,16 +45,15 @@ using namespace PBD; AnalysisWindow::AnalysisWindow() : ArdourDialog(_("analysis window")), - fft_graph (2048), - source_selection_label (_("Signal source")), source_selection_ranges_rb (_("Selected ranges")), source_selection_regions_rb (_("Selected regions")), - + display_model_label (_("Display model")), display_model_composite_separate_rb (_("Composite graphs for each track")), - display_model_composite_all_tracks_rb (_("Composite graph of all tracks")) + display_model_composite_all_tracks_rb (_("Composite graph of all tracks")), + fft_graph (2048) { track_list_ready = false; @@ -226,18 +225,23 @@ AnalysisWindow::analyze_data (Gtk::Button *button) Selection s = PublicEditor::instance().get_selection(); TimeSelection ts = s.time; - AudioRegionSelection ars = s.audio_regions; + RegionSelection ars = s.regions; for (TrackSelection::iterator i = s.tracks.begin(); i != s.tracks.end(); ++i) { - ARDOUR::Playlist *pl = (*i)->playlist(); + ARDOUR::AudioPlaylist *pl + = dynamic_cast<ARDOUR::AudioPlaylist*>((*i)->playlist()); + + if (!pl) + continue; + RouteUI *rui = dynamic_cast<RouteUI *>(*i); // Busses don't have playlists, so we need to check that we actually are working with a playlist if (!pl || !rui) continue; - FFTResult *res = fft_graph.prepareResult(*&rui->color(), *&rui->route().name()); + FFTResult *res = fft_graph.prepareResult(rui->color(), rui->route()->name()); // if timeSelection if (source_selection_ranges_rb.get_active()) { @@ -275,24 +279,29 @@ AnalysisWindow::analyze_data (Gtk::Button *button) TimeAxisView *current_axis = (*i); - for (std::set<AudioRegionView *>::iterator j = ars.begin(); j != ars.end(); ++j) { + for (std::set<RegionView *>::iterator j = ars.begin(); j != ars.end(); ++j) { + // Check that the region is actually audio (so we can analyze it) + AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*j); + if (!arv) + continue; + // Check that the region really is selected on _this_ track/solo - if ( &(*j)->get_time_axis_view() != current_axis) + if ( &arv->get_time_axis_view() != current_axis) continue; -// cerr << " - " << (*j)->region.name() << ": " << (*j)->region.length() << " samples starting at " << (*j)->region.position() << endl; +// cerr << " - " << (*j)->region().name() << ": " << (*j)->region().length() << " samples starting at " << (*j)->region().position() << endl; jack_nframes_t i = 0; int n; - while ( i < (*j)->region.length() ) { + while ( i < arv->region().length() ) { // TODO: What about stereo+ channels? composite all to one, I guess n = fft_graph.windowSize(); - if (i + n >= (*j)->region.length() ) { - n = (*j)->region.length() - i; + if (i + n >= arv->region().length() ) { + n = arv->region().length() - i; } - - n = (*j)->region.read_at(buf, mixbuf, gain, work, (*j)->region.position() + i, n); + + n = arv->audio_region().read_at(buf, mixbuf, gain, work, arv->region().position() + i, n); if ( n < fft_graph.windowSize()) { for (int j = n; j < fft_graph.windowSize(); j++) { @@ -313,9 +322,9 @@ AnalysisWindow::analyze_data (Gtk::Button *button) Gtk::TreeModel::Row newrow = *(tlmodel)->append(); - newrow[tlcols.trackname] = rui->route().name(); + newrow[tlcols.trackname] = rui->route()->name(); newrow[tlcols.visible] = true; - newrow[tlcols.color] = *&rui->color(); + newrow[tlcols.color] = rui->color(); newrow[tlcols.graph] = res; } diff --git a/gtk2_ardour/ardev_common.sh b/gtk2_ardour/ardev_common.sh index 5c68933a96..bf644f3e84 100755 --- a/gtk2_ardour/ardev_common.sh +++ b/gtk2_ardour/ardev_common.sh @@ -2,7 +2,10 @@ export ARDOUR_PATH=./glade:./pixmaps:. -export LD_LIBRARY_PATH=../libs/surfaces/control_protocol:../libs/ardour:../libs/midi++2:../libs/pbd3:../libs/soundtouch:../libs/gtkmm2ext:../libs/sigc++2:../libs/glibmm2:../libs/gtkmm2/atk:../libs/gtkmm2/pango:../libs/gtkmm2/gdk:../libs/gtkmm2/gtk:../libs/libgnomecanvasmm:../libs/libsndfile:$LD_LIBRARY_PATH +export LD_LIBRARY_PATH=../libs/surfaces/control_protocol:../libs/ardour:../libs/midi++2:../libs/pbd:../libs/soundtouch:../libs/gtkmm2ext:../libs/sigc++2:../libs/glibmm2:../libs/gtkmm2/atk:../libs/gtkmm2/pango:../libs/gtkmm2/gdk:../libs/gtkmm2/gtk:../libs/libgnomecanvasmm:../libs/libsndfile:../libs/appleutility:$LD_LIBRARY_PATH # DYLD_LIBRARY_PATH is for darwin. export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH + +# LADSPA_PATH for OSX +export LADSPA_PATH=$LADSPA_PATH:/Library/Audio/Plug-Ins/LADSPA diff --git a/gtk2_ardour/ardour.menus b/gtk2_ardour/ardour.menus index 9293883067..b1064b8e87 100644 --- a/gtk2_ardour/ardour.menus +++ b/gtk2_ardour/ardour.menus @@ -15,8 +15,10 @@ <separator/> <menu action='addExistingAudioFiles'> <menuitem action='addExternalAudioAsRegion'/> - <menuitem action='addExternalAudioAsTrack'/> <menuitem action='addExternalAudioToTrack'/> + <separator/> + <menuitem action='addExternalAudioAsTrack'/> + <menuitem action='addExternalAudioAsTapeTrack'/> </menu> <separator/> <menu name='Export' action='Export'> diff --git a/gtk2_ardour/ardour2_ui.rc b/gtk2_ardour/ardour2_ui.rc index ac4f055df6..5422a63b8b 100644 --- a/gtk2_ardour/ardour2_ui.rc +++ b/gtk2_ardour/ardour2_ui.rc @@ -219,6 +219,14 @@ style "mute_button" = "small_button" fg[PRELIGHT] = { 0, 0, 0 } } + +style "multiline_combo" = "small_button" +{ + font_name = "sans 8" + xthickness = 0 + ythickness = 0 +} + style "mixer_mute_button" = "mute_button" { font_name = "sans 7" @@ -936,6 +944,7 @@ widget "*TrackRecordEnableButton" style "track_rec_enable_button" widget "*TrackRecordEnableButton*" style "track_rec_enable_button" widget "*TrackMuteButton*" style "mute_button" widget "*TrackLoopButton*" style "track_loop_button" +widget "*PanAutomationLineSelector*" style "multiline_combo" widget "*EditorTimeButton*" style "time_button" widget "*EditorMixerButton*" style "default_buttons_menus" widget "*SoloButton*" style "solo_button" diff --git a/gtk2_ardour/ardour_dialog.h b/gtk2_ardour/ardour_dialog.h index a23dcda9e0..069768c143 100644 --- a/gtk2_ardour/ardour_dialog.h +++ b/gtk2_ardour/ardour_dialog.h @@ -26,7 +26,7 @@ namespace ARDOUR { class Session; -}; +} /* * This virtual parent class is so that each dialog box uses the @@ -55,3 +55,4 @@ class ArdourDialog : public Gtk::Dialog }; #endif // __ardour_dialog_h__ + diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index f452ec9c7e..e5367d6280 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -46,6 +46,7 @@ #include <midi++/mmc.h> #include <ardour/ardour.h> +#include <ardour/session_route.h> #include <ardour/port.h> #include <ardour/audioengine.h> #include <ardour/playlist.h> @@ -53,7 +54,6 @@ #include <ardour/audio_diskstream.h> #include <ardour/audiofilesource.h> #include <ardour/recent_sessions.h> -#include <ardour/session_diskstream.h> #include <ardour/port.h> #include <ardour/audio_track.h> @@ -116,16 +116,15 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile) shuttle_units_button (_("% ")), - punch_in_button (_("punch\nin")), - punch_out_button (_("punch\nout")), - auto_return_button (_("auto\nreturn")), - auto_play_button (_("auto\nplay")), - auto_input_button (_("auto\ninput")), - click_button (_("click")), - auditioning_alert_button (_("AUDITIONING")), + punch_in_button (_("Punch In")), + punch_out_button (_("Punch Out")), + auto_return_button (_("Auto Return")), + auto_play_button (_("Autuo Play")), + auto_input_button (_("Auto Input")), + click_button (_("Click")), + auditioning_alert_button (_("AUDITION")), solo_alert_button (_("SOLO")), shown_flag (false) - { using namespace Gtk::Menu_Helpers; @@ -186,8 +185,8 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile) gettimeofday (&last_shuttle_request, 0); ARDOUR::AudioDiskstream::DeleteSources.connect (mem_fun(*this, &ARDOUR_UI::delete_sources_in_the_right_thread)); - ARDOUR::AudioDiskstream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler)); - ARDOUR::AudioDiskstream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler)); + ARDOUR::Diskstream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler)); + ARDOUR::Diskstream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler)); /* handle pending state with a dialog */ @@ -339,15 +338,15 @@ ARDOUR_UI::save_ardour_state () Config->add_extra_xml (*node); Config->save_state(); - XMLNode& enode (static_cast<Stateful*>(editor)->get_state()); - XMLNode& mnode (mixer->get_state()); + XMLNode enode(static_cast<Stateful*>(editor)->get_state()); + XMLNode mnode(mixer->get_state()); if (session) { - session->add_instant_xml(enode, session->path()); - session->add_instant_xml(mnode, session->path()); + session->add_instant_xml (enode, session->path()); + session->add_instant_xml (mnode, session->path()); } else { - Config->add_instant_xml(enode, get_user_ardour_path()); - Config->add_instant_xml(mnode, get_user_ardour_path()); + Config->add_instant_xml (enode, get_user_ardour_path()); + Config->add_instant_xml (mnode, get_user_ardour_path()); } /* keybindings */ @@ -507,11 +506,11 @@ ARDOUR_UI::update_sample_rate (jack_nframes_t ignored) jack_nframes_t rate = engine->frame_rate(); if (fmod (rate, 1000.0) != 0.0) { - snprintf (buf, sizeof (buf), _("SR: %.1f kHz / %4.1f msecs"), + snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f msecs"), (float) rate/1000.0f, (engine->frames_per_cycle() / (float) rate) * 1000.0f); } else { - snprintf (buf, sizeof (buf), _("SR: %u kHz / %4.1f msecs"), + snprintf (buf, sizeof (buf), _("%u kHz / %4.1f msecs"), rate/1000, (engine->frames_per_cycle() / (float) rate) * 1000.0f); } @@ -524,7 +523,7 @@ void ARDOUR_UI::update_cpu_load () { char buf[32]; - snprintf (buf, sizeof (buf), _("DSP Load: %.1f%%"), engine->get_cpu_load()); + snprintf (buf, sizeof (buf), _("DSP: %.1f%%"), engine->get_cpu_load()); cpu_load_label.set_text (buf); } @@ -543,9 +542,10 @@ ARDOUR_UI::update_buffer_load () } void -ARDOUR_UI::count_recenabled_diskstreams (AudioDiskstream& ds) +ARDOUR_UI::count_recenabled_diskstreams (Route& route) { - if (ds.record_enabled()) { + Track* track = dynamic_cast<Track*>(&route); + if (track && track->diskstream().record_enabled()) { rec_enabled_diskstreams++; } } @@ -561,7 +561,7 @@ ARDOUR_UI::update_disk_space() char buf[64]; if (frames == max_frames) { - strcpy (buf, _("space: 24hrs+")); + strcpy (buf, _("Disk: 24hrs+")); } else { int hrs; int mins; @@ -571,7 +571,7 @@ ARDOUR_UI::update_disk_space() if (session->actively_recording()){ rec_enabled_diskstreams = 0; - session->foreach_audio_diskstream (this, &ARDOUR_UI::count_recenabled_diskstreams); + session->foreach_route (this, &ARDOUR_UI::count_recenabled_diskstreams); if (rec_enabled_diskstreams) { frames /= rec_enabled_diskstreams; @@ -591,7 +591,7 @@ ARDOUR_UI::update_disk_space() frames -= mins * fr * 60; secs = frames / fr; - snprintf (buf, sizeof(buf), _("space: %02dh:%02dm:%02ds"), hrs, mins, secs); + snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs); } disk_space_label.set_text (buf); @@ -876,7 +876,7 @@ ARDOUR_UI::session_add_midi_track () void ARDOUR_UI::session_add_audio_route (bool disk, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode) { - Route* route; + boost::shared_ptr<Route> route; if (session == 0) { warning << _("You cannot add a track without a session already loaded.") << endmsg; @@ -918,7 +918,7 @@ restart JACK with more ports.")); } void -ARDOUR_UI::diskstream_added (AudioDiskstream* ds) +ARDOUR_UI::diskstream_added (Diskstream* ds) { } @@ -1159,32 +1159,25 @@ ARDOUR_UI::transport_forward (int option) } void -ARDOUR_UI::toggle_monitor_enable (guint32 dstream) +ARDOUR_UI::toggle_record_enable (uint32_t dstream) { if (session == 0) { return; } - AudioDiskstream *ds; + boost::shared_ptr<Route> r; + + if ((r = session->route_by_remote_id (dstream)) != 0) { - if ((ds = session->diskstream_by_id (dstream)) != 0) { - Port *port = ds->io()->input (0); - port->request_monitor_input (!port->monitoring_input()); - } -} + Track* t; -void -ARDOUR_UI::toggle_record_enable (guint32 dstream) -{ + if ((t = dynamic_cast<Track*>(r.get())) != 0) { + t->diskstream().set_record_enabled (!t->diskstream().record_enabled()); + } + } if (session == 0) { return; } - - AudioDiskstream *ds; - - if ((ds = session->diskstream_by_id (dstream)) != 0) { - ds->set_record_enabled (!ds->record_enabled(), this); - } } void @@ -1385,63 +1378,6 @@ ARDOUR_UI::stop_blinking () } } - -void -ARDOUR_UI::add_diskstream_to_menu (AudioDiskstream& dstream) -{ - using namespace Gtk; - using namespace Menu_Helpers; - - if (dstream.hidden()) { - return; - } - - MenuList& items = diskstream_menu->items(); - items.push_back (MenuElem (dstream.name(), bind (mem_fun(*this, &ARDOUR_UI::diskstream_selected), (gint32) dstream.id()))); -} - -void -ARDOUR_UI::diskstream_selected (gint32 id) -{ - selected_dstream = id; - Main::quit (); -} - -gint32 -ARDOUR_UI::select_diskstream (GdkEventButton *ev) -{ - using namespace Gtk; - using namespace Menu_Helpers; - - if (session == 0) { - return -1; - } - - diskstream_menu = new Menu(); - diskstream_menu->set_name ("ArdourContextMenu"); - using namespace Gtk; - using namespace Menu_Helpers; - - MenuList& items = diskstream_menu->items(); - items.push_back (MenuElem (_("No Stream"), (bind (mem_fun(*this, &ARDOUR_UI::diskstream_selected), -1)))); - - session->foreach_audio_diskstream (this, &ARDOUR_UI::add_diskstream_to_menu); - - if (ev) { - diskstream_menu->popup (ev->button, ev->time); - } else { - diskstream_menu->popup (0, 0); - } - - selected_dstream = -1; - - Main::run (); - - delete diskstream_menu; - - return selected_dstream; -} - void ARDOUR_UI::name_io_setup (AudioEngine& engine, string& buf, @@ -2217,11 +2153,11 @@ ARDOUR_UI::halt_on_xrun_message () } void -ARDOUR_UI::delete_sources_in_the_right_thread (list<ARDOUR::AudioFileSource*>* deletion_list) +ARDOUR_UI::delete_sources_in_the_right_thread (list<ARDOUR::Source*>* deletion_list) { ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::delete_sources_in_the_right_thread), deletion_list)); - for (list<AudioFileSource*>::iterator i = deletion_list->begin(); i != deletion_list->end(); ++i) { + for (list<Source*>::iterator i = deletion_list->begin(); i != deletion_list->end(); ++i) { delete *i; } diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h index 678342f32b..297c9c3c65 100644 --- a/gtk2_ardour/ardour_ui.h +++ b/gtk2_ardour/ardour_ui.h @@ -79,7 +79,7 @@ class ColorManager; namespace Gtkmm2ext { class TearOff; -}; +} namespace ARDOUR { class AudioEngine; @@ -87,11 +87,11 @@ namespace ARDOUR { class Port; class IO; class ControlProtocolInfo; -}; +} namespace ALSA { class MultiChannelDevice; -}; +} #define FRAME_NAME "BaseFrame" @@ -154,8 +154,6 @@ class ARDOUR_UI : public Gtkmm2ext::UI void toggle_tempo_window (); void toggle_editing_space(); - gint32 select_diskstream (GdkEventButton *ev); - Gtk::Tooltips& tooltips() { return _tooltips; } static sigc::signal<void,bool> Blink; @@ -522,7 +520,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI sigc::connection point_one_second_connection; sigc::connection point_zero_one_second_connection; - void diskstream_added (ARDOUR::AudioDiskstream*); + void diskstream_added (ARDOUR::Diskstream*); gint session_menu (GdkEventButton *); @@ -536,14 +534,8 @@ class ARDOUR_UI : public Gtkmm2ext::UI void save_template (); - void session_add_audio_route (bool disk, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode); - void add_diskstream_to_menu (ARDOUR::AudioDiskstream&); - void diskstream_selected (gint32); - Gtk::Menu *diskstream_menu; - gint32 selected_dstream; - void set_transport_sensitivity (bool); void remove_last_capture (); @@ -626,11 +618,10 @@ class ARDOUR_UI : public Gtkmm2ext::UI void test_binding_action (const char *); void start_keyboard_prefix(); - void toggle_record_enable (guint32); - void toggle_monitor_enable (guint32); + void toggle_record_enable (uint32_t); uint32_t rec_enabled_diskstreams; - void count_recenabled_diskstreams (ARDOUR::AudioDiskstream&); + void count_recenabled_diskstreams (ARDOUR::Route&); About* about; bool shown_flag; @@ -649,7 +640,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI struct timeval last_peak_grab; struct timeval last_shuttle_request; - void delete_sources_in_the_right_thread (list<ARDOUR::AudioFileSource*>*); + void delete_sources_in_the_right_thread (list<ARDOUR::Source*>*); void editor_display_control_changed (Editing::DisplayControl c); @@ -716,5 +707,5 @@ class ARDOUR_UI : public Gtkmm2ext::UI void toggle_control_protocol (ARDOUR::ControlProtocolInfo*); }; - #endif /* __ardour_gui_h__ */ + diff --git a/gtk2_ardour/ardour_ui2.cc b/gtk2_ardour/ardour_ui2.cc index f92201e36c..44287fe61e 100644 --- a/gtk2_ardour/ardour_ui2.cc +++ b/gtk2_ardour/ardour_ui2.cc @@ -359,10 +359,10 @@ ARDOUR_UI::setup_transport () auditioning_alert_button.set_name ("TransportAuditioningAlert"); auditioning_alert_button.signal_pressed().connect (mem_fun(*this,&ARDOUR_UI::audition_alert_toggle)); - alert_box.pack_start (solo_alert_button); - alert_box.pack_start (auditioning_alert_button); + alert_box.pack_start (solo_alert_button, false, false); + alert_box.pack_start (auditioning_alert_button, false, false); - transport_tearoff_hbox.set_border_width (5); + transport_tearoff_hbox.set_border_width (3); transport_tearoff_hbox.pack_start (goto_start_button, false, false); transport_tearoff_hbox.pack_start (goto_end_button, false, false); @@ -398,6 +398,7 @@ ARDOUR_UI::setup_transport () mtc_port_changed (); sync_option_combo.set_active_text (positional_sync_strings.front()); sync_option_combo.signal_changed().connect (mem_fun (*this, &ARDOUR_UI::sync_option_changed)); + Gtkmm2ext::set_size_request_to_display_given_text (sync_option_combo, "Internal", 22, 10); shbox->pack_start (*sdframe, false, false); shbox->pack_start (shuttle_units_button, true, true); @@ -406,37 +407,52 @@ ARDOUR_UI::setup_transport () svbox->pack_start (*sframe, false, false); svbox->pack_start (*shbox, false, false); - transport_tearoff_hbox.pack_start (*svbox, false, false, 5); + transport_tearoff_hbox.pack_start (*svbox, false, false, 3); transport_tearoff_hbox.pack_start (auto_loop_button, false, false); transport_tearoff_hbox.pack_start (play_selection_button, false, false); transport_tearoff_hbox.pack_start (roll_button, false, false); transport_tearoff_hbox.pack_start (stop_button, false, false); - transport_tearoff_hbox.pack_start (rec_button, false, false, 10); - - transport_tearoff_hbox.pack_start (primary_clock, false, false, 5); - transport_tearoff_hbox.pack_start (secondary_clock, false, false, 5); - - transport_tearoff_hbox.pack_start (sync_option_combo, false, false); - transport_tearoff_hbox.pack_start (time_master_button, false, false); - transport_tearoff_hbox.pack_start (punch_in_button, false, false); - transport_tearoff_hbox.pack_start (punch_out_button, false, false); - transport_tearoff_hbox.pack_start (auto_input_button, false, false); - transport_tearoff_hbox.pack_start (auto_return_button, false, false); - transport_tearoff_hbox.pack_start (auto_play_button, false, false); - transport_tearoff_hbox.pack_start (click_button, false, false); + transport_tearoff_hbox.pack_start (rec_button, false, false, 6); + + HBox* clock_box = manage (new HBox); + clock_box->pack_start (primary_clock, false, false); + clock_box->pack_start (secondary_clock, false, false); + VBox* time_controls_box = manage (new VBox); + time_controls_box->pack_start (sync_option_combo, false, false); + time_controls_box->pack_start (time_master_button, false, false); + clock_box->pack_start (*time_controls_box, false, false, 1); + transport_tearoff_hbox.pack_start (*clock_box, false, false, 0); + + HBox* toggle_box = manage(new HBox); + + VBox* punch_box = manage (new VBox); + punch_box->pack_start (punch_in_button, false, false); + punch_box->pack_start (punch_out_button, false, false); + toggle_box->pack_start (*punch_box, false, false); + + VBox* auto_box = manage (new VBox); + auto_box->pack_start (auto_play_button, false, false); + auto_box->pack_start (auto_return_button, false, false); + toggle_box->pack_start (*auto_box, false, false); + + VBox* io_box = manage (new VBox); + io_box->pack_start (auto_input_button, false, false); + io_box->pack_start (click_button, false, false); + toggle_box->pack_start (*io_box, false, false); /* desensitize */ set_transport_sensitivity (false); -// transport_tearoff_hbox.pack_start (preroll_button, false, false); -// transport_tearoff_hbox.pack_start (preroll_clock, false, false); +// toggle_box->pack_start (preroll_button, false, false); +// toggle_box->pack_start (preroll_clock, false, false); -// transport_tearoff_hbox.pack_start (postroll_button, false, false); -// transport_tearoff_hbox.pack_start (postroll_clock, false, false); +// toggle_box->pack_start (postroll_button, false, false); +// toggle_box->pack_start (postroll_clock, false, false); - transport_tearoff_hbox.pack_start (alert_box, false, false, 5); + transport_tearoff_hbox.pack_start (*toggle_box, false, false, 4); + transport_tearoff_hbox.pack_start (alert_box, false, false); } void @@ -820,7 +836,7 @@ ARDOUR_UI::set_shuttle_units (ShuttleUnits u) shuttle_units_button.set_label("% "); break; case Semitones: - shuttle_units_button.set_label(_("st")); + shuttle_units_button.set_label(_("ST")); break; } } @@ -864,7 +880,7 @@ ARDOUR_UI::update_speed_display () { if (!session) { if (last_speed_displayed != 0) { - speed_display_label.set_text (_("stopped")); + speed_display_label.set_text (_("stop")); last_speed_displayed = 0; } return; @@ -877,7 +893,7 @@ ARDOUR_UI::update_speed_display () if (x != 0) { if (shuttle_units == Percentage) { - snprintf (buf, sizeof (buf), "%.4f", x); + snprintf (buf, sizeof (buf), "%.2f", x); } else { if (x < 0) { snprintf (buf, sizeof (buf), "< %.1f", 12.0 * fast_log2 (-x)); @@ -887,7 +903,7 @@ ARDOUR_UI::update_speed_display () } speed_display_label.set_text (buf); } else { - speed_display_label.set_text (_("stopped")); + speed_display_label.set_text (_("stop")); } last_speed_displayed = x; @@ -904,7 +920,7 @@ ARDOUR_UI::set_transport_sensitivity (bool yn) void ARDOUR_UI::editor_realized () { - set_size_request_to_display_given_text (speed_display_box, _("stopped"), 2, 2); + set_size_request_to_display_given_text (speed_display_box, _("-0.55"), 2, 2); /* XXX: this should really be saved in instant.xml or something similar and restored from there */ shuttle_style_button.set_active_text (_("sprung")); const guint32 FUDGE = 20; // Combo's are stupid - they steal space from the entry for the button diff --git a/gtk2_ardour/ardour_ui_dialogs.cc b/gtk2_ardour/ardour_ui_dialogs.cc index 202fa88b59..25f3068a81 100644 --- a/gtk2_ardour/ardour_ui_dialogs.cc +++ b/gtk2_ardour/ardour_ui_dialogs.cc @@ -76,8 +76,8 @@ ARDOUR_UI::connect_to_session (Session *s) rec_button.set_sensitive (true); shuttle_box.set_sensitive (true); - if (session->n_audio_diskstreams() == 0) { - session->AudioDiskstreamAdded.connect (mem_fun(*this, &ARDOUR_UI::diskstream_added)); + if (session->n_diskstreams() == 0) { + session->DiskstreamAdded.connect (mem_fun(*this, &ARDOUR_UI::diskstream_added)); } if (connection_editor) { diff --git a/gtk2_ardour/ardour_ui_ed.cc b/gtk2_ardour/ardour_ui_ed.cc index 1bc2de26d1..238f81dd4f 100644 --- a/gtk2_ardour/ardour_ui_ed.cc +++ b/gtk2_ardour/ardour_ui_ed.cc @@ -264,31 +264,26 @@ ARDOUR_UI::install_actions () ActionManager::session_sensitive_actions.push_back (act); ActionManager::transport_sensitive_actions.push_back (act); - /* XXX the newline in the displayed names of these action is really wrong, but its because we want the button - that proxies for these action to be more compact. It would be nice to find a way to override the action - name appearance on the buttons. - */ - - act = ActionManager::register_toggle_action (transport_actions, X_("TogglePunchIn"), _("Punch\nin"), mem_fun(*this, &ARDOUR_UI::toggle_punch_in)); + act = ActionManager::register_toggle_action (transport_actions, X_("TogglePunchIn"), _("Punch In"), mem_fun(*this, &ARDOUR_UI::toggle_punch_in)); ActionManager::session_sensitive_actions.push_back (act); ActionManager::transport_sensitive_actions.push_back (act); - act = ActionManager::register_toggle_action (transport_actions, X_("TogglePunchOut"), _("Punch\nout"), mem_fun(*this, &ARDOUR_UI::toggle_punch_out)); + act = ActionManager::register_toggle_action (transport_actions, X_("TogglePunchOut"), _("Punch Out"), mem_fun(*this, &ARDOUR_UI::toggle_punch_out)); ActionManager::session_sensitive_actions.push_back (act); ActionManager::transport_sensitive_actions.push_back (act); act = ActionManager::register_toggle_action (transport_actions, X_("ToggleClick"), _("Click"), mem_fun(*this, &ARDOUR_UI::toggle_click)); ActionManager::session_sensitive_actions.push_back (act); ActionManager::transport_sensitive_actions.push_back (act); - act = ActionManager::register_toggle_action (transport_actions, X_("ToggleAutoInput"), _("Auto\ninput"), mem_fun(*this, &ARDOUR_UI::toggle_auto_input)); + act = ActionManager::register_toggle_action (transport_actions, X_("ToggleAutoInput"), _("Auto Input"), mem_fun(*this, &ARDOUR_UI::toggle_auto_input)); ActionManager::session_sensitive_actions.push_back (act); ActionManager::transport_sensitive_actions.push_back (act); - act = ActionManager::register_toggle_action (transport_actions, X_("ToggleAutoPlay"), _("Auto\nplay"), mem_fun(*this, &ARDOUR_UI::toggle_auto_play)); + act = ActionManager::register_toggle_action (transport_actions, X_("ToggleAutoPlay"), _("Auto Play"), mem_fun(*this, &ARDOUR_UI::toggle_auto_play)); ActionManager::session_sensitive_actions.push_back (act); ActionManager::transport_sensitive_actions.push_back (act); - act = ActionManager::register_toggle_action (transport_actions, X_("ToggleAutoReturn"), _("Auto\nreturn"), mem_fun(*this, &ARDOUR_UI::toggle_auto_return)); + act = ActionManager::register_toggle_action (transport_actions, X_("ToggleAutoReturn"), _("Auto Return"), mem_fun(*this, &ARDOUR_UI::toggle_auto_return)); ActionManager::session_sensitive_actions.push_back (act); ActionManager::transport_sensitive_actions.push_back (act); - act = ActionManager::register_toggle_action (transport_actions, X_("ToggleTimeMaster"), _("Time\nmaster"), mem_fun(*this, &ARDOUR_UI::toggle_time_master)); + act = ActionManager::register_toggle_action (transport_actions, X_("ToggleTimeMaster"), _("Master"), mem_fun(*this, &ARDOUR_UI::toggle_time_master)); ActionManager::session_sensitive_actions.push_back (act); act = ActionManager::register_action (common_actions, X_("ToggleRecordEnableTrack1"), _("Toggle Record Enable Track1"), bind (mem_fun(*this, &ARDOUR_UI::toggle_record_enable), 0U)); diff --git a/gtk2_ardour/audio_clock.h b/gtk2_ardour/audio_clock.h index 14dc6ba673..9ff5f45ddf 100644 --- a/gtk2_ardour/audio_clock.h +++ b/gtk2_ardour/audio_clock.h @@ -30,7 +30,7 @@ namespace ARDOUR { class Session; -}; +} class AudioClock : public Gtk::HBox { @@ -40,7 +40,7 @@ class AudioClock : public Gtk::HBox BBT, MinSec, Frames, - Off, + Off }; AudioClock (const string& name, bool editable, bool is_duration = false, bool with_tempo_meter = false); @@ -87,7 +87,7 @@ class AudioClock : public Gtk::HBox Bars, Beats, Ticks, - AudioFrames, + AudioFrames }; Gtk::EventBox audio_frames_ebox; diff --git a/gtk2_ardour/region_editor.cc b/gtk2_ardour/audio_region_editor.cc index 413ff01753..194f358b42 100644 --- a/gtk2_ardour/region_editor.cc +++ b/gtk2_ardour/audio_region_editor.cc @@ -24,8 +24,8 @@ #include <gtkmm2ext/stop_signal.h> #include <cmath> -#include "region_editor.h" -#include "regionview.h" +#include "audio_region_editor.h" +#include "audio_region_view.h" #include "ardour_ui.h" #include "utils.h" #include "gui_thread.h" @@ -37,9 +37,8 @@ using namespace PBD; using namespace sigc; using namespace std; -AudioRegionEditor::AudioRegionEditor (Session&s, AudioRegion& r, AudioRegionView& rv) - : ArdourDialog ("audio region editor"), - _session (s), +AudioRegionEditor::AudioRegionEditor (Session& s, AudioRegion& r, AudioRegionView& rv) + : RegionEditor (s), _region (r), _region_view (rv), name_label (_("NAME:")), diff --git a/gtk2_ardour/audio_region_editor.h b/gtk2_ardour/audio_region_editor.h new file mode 100644 index 0000000000..38cd920e5e --- /dev/null +++ b/gtk2_ardour/audio_region_editor.h @@ -0,0 +1,186 @@ +/* + 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 __gtk_ardour_audio_region_edit_h__ +#define __gtk_ardour_audio_region_edit_h__ + +#include <map> + +#include <gtkmm/label.h> +#include <gtkmm/entry.h> +#include <gtkmm/box.h> +#include <gtkmm/togglebutton.h> +#include <gtkmm/button.h> +#include <gtkmm/arrow.h> +#include <gtkmm/frame.h> +#include <gtkmm/table.h> +#include <gtkmm/alignment.h> +#include <gtkmm/adjustment.h> +#include <gtkmm/separator.h> +#include <gtkmm/spinbutton.h> + +#include <libgnomecanvas/libgnomecanvas.h> +#include <sigc++/signal.h> + +#include "audio_clock.h" +#include "ardour_dialog.h" +#include "region_editor.h" + +namespace ARDOUR { + class AudioRegion; + class Session; +} + +class AudioRegionView; + +class AudioRegionEditor : public RegionEditor +{ + public: + AudioRegionEditor (ARDOUR::Session&, ARDOUR::AudioRegion&, AudioRegionView& rv); + ~AudioRegionEditor (); + + private: + ARDOUR::AudioRegion& _region; + AudioRegionView& _region_view; + + void connect_editor_events (); + + Gtk::Label name_label; + Gtk::Entry name_entry; + Gtk::HBox name_hbox; + + Gtk::HBox top_row_hbox; + Gtk::HBox top_row_button_hbox; + + Gtk::ToggleButton lock_button; + Gtk::ToggleButton mute_button; + Gtk::ToggleButton opaque_button; + Gtk::ToggleButton envelope_active_button; + Gtk::ToggleButton envelope_view_button; + + Gtk::Button raise_button; + Gtk::Arrow raise_arrow; + Gtk::Button lower_button; + Gtk::Arrow lower_arrow; + Gtk::Frame layer_frame; + Gtk::Label layer_value_label; + Gtk::Label layer_label; + Gtk::HBox layer_hbox; + + Gtk::ToggleButton audition_button; + + Gtk::HBox lower_hbox; + + Gtk::Table time_table; + + Gtk::Label start_label; + Gtk::Label end_label; + Gtk::Label length_label; + Gtk::Alignment start_alignment; + Gtk::Alignment end_alignment; + Gtk::Alignment length_alignment; + + AudioClock start_clock; + AudioClock end_clock; + AudioClock length_clock; + AudioClock sync_offset_clock; + + Gtk::Table envelope_loop_table; + Gtk::Button loop_button; + Gtk::Label loop_label; + Gtk::Label envelope_label; + + Gtk::Table fade_in_table; + Gtk::Label fade_in_label; + Gtk::Alignment fade_in_label_align; + Gtk::Label fade_in_active_button_label; + Gtk::ToggleButton fade_in_active_button; + Gtk::Label fade_in_length_label; + + Gtk::Adjustment fade_in_length_adjustment; + Gtk::SpinButton fade_in_length_spinner; + + Gtk::Table fade_out_table; + Gtk::Label fade_out_label; + Gtk::Alignment fade_out_label_align; + Gtk::Label fade_out_active_button_label; + Gtk::ToggleButton fade_out_active_button; + Gtk::Label fade_out_length_label; + + Gtk::Adjustment fade_out_length_adjustment; + Gtk::SpinButton fade_out_length_spinner; + + Gtk::HSeparator sep3; + Gtk::VSeparator sep1; + Gtk::VSeparator sep2; + + void region_changed (ARDOUR::Change); + void bounds_changed (ARDOUR::Change); + void name_changed (); + void opacity_changed (); + void mute_changed (); + void envelope_active_changed (); + void lock_changed (); + void layer_changed (); + + void fade_in_length_adjustment_changed (); + void fade_out_length_adjustment_changed (); + void fade_in_changed (); + void fade_out_changed (); + void audition_state_changed (bool); + + void activation (); + + void name_entry_changed (); + void start_clock_changed (); + void end_clock_changed (); + void length_clock_changed (); + + gint envelope_active_button_press (GdkEventButton *); + gint envelope_active_button_release (GdkEventButton *); + + void audition_button_toggled (); + void envelope_view_button_toggled (); + void lock_button_clicked (); + void mute_button_clicked (); + void opaque_button_clicked (); + void raise_button_clicked (); + void lower_button_clicked (); + + void fade_in_active_toggled (); + void fade_out_active_toggled (); + void fade_in_active_changed (); + void fade_out_active_changed (); + + void fade_in_realized (); + void fade_out_realized (); + + void start_editing_fade_in (); + void start_editing_fade_out (); + void stop_editing_fade_in (); + void stop_editing_fade_out (); + + gint bpressed (GdkEventButton* ev, Gtk::SpinButton* but, void (AudioRegionEditor::*pmf)()); + gint breleased (GdkEventButton* ev, Gtk::SpinButton* but, void (AudioRegionEditor::*pmf)()); + + bool spin_arrow_grab; +}; + +#endif /* __gtk_ardour_audio_region_edit_h__ */ diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc new file mode 100644 index 0000000000..feb8f4fd0b --- /dev/null +++ b/gtk2_ardour/audio_region_view.cc @@ -0,0 +1,1127 @@ +/* + Copyright (C) 2001-2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <cmath> +#include <cassert> +#include <algorithm> + +#include <gtkmm.h> + +#include <gtkmm2ext/gtk_ui.h> + +#include <ardour/playlist.h> +#include <ardour/audioregion.h> +#include <ardour/audiosource.h> +#include <ardour/audio_diskstream.h> + +#include "streamview.h" +#include "audio_region_view.h" +#include "audio_time_axis.h" +#include "simplerect.h" +#include "simpleline.h" +#include "waveview.h" +#include "public_editor.h" +#include "audio_region_editor.h" +#include "region_gain_line.h" +#include "ghostregion.h" +#include "audio_time_axis.h" +#include "utils.h" +#include "rgb_macros.h" +#include "gui_thread.h" + +#include "i18n.h" + +using namespace sigc; +using namespace ARDOUR; +using namespace PBD; +using namespace Editing; +using namespace ArdourCanvas; + +static const int32_t sync_mark_width = 9; + +AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, AudioRegion& r, double spu, + Gdk::Color& basic_color) + : RegionView (parent, tv, r, spu, basic_color) + , sync_mark(0) + , zero_line(0) + , fade_in_shape(0) + , fade_out_shape(0) + , fade_in_handle(0) + , fade_out_handle(0) + , gain_line(0) + , _amplitude_above_axis(1.0) + , _flags(0) + , fade_color(0) +{ +} + +AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, AudioRegion& r, double spu, + Gdk::Color& basic_color, TimeAxisViewItem::Visibility visibility) + : RegionView (parent, tv, r, spu, basic_color, visibility) + , sync_mark(0) + , zero_line(0) + , fade_in_shape(0) + , fade_out_shape(0) + , fade_in_handle(0) + , fade_out_handle(0) + , gain_line(0) + , _amplitude_above_axis(1.0) + , _flags(0) + , fade_color(0) +{ +} + +void +AudioRegionView::init (Gdk::Color& basic_color, bool wfd) +{ + // FIXME: Some redundancy here with RegionView::init. Need to figure out + // where order is important and where it isn't... + + RegionView::init(basic_color, wfd); + + XMLNode *node; + + _amplitude_above_axis = 1.0; + zero_line = 0; + _flags = 0; + + if ((node = _region.extra_xml ("GUI")) != 0) { + set_flags (node); + } else { + _flags = WaveformVisible; + store_flags (); + } + + if (trackview.editor.new_regionviews_display_gain()) { + _flags |= EnvelopeVisible; + } + + compute_colors (basic_color); + + create_waves (); + + fade_in_shape = new ArdourCanvas::Polygon (*group); + fade_in_shape->property_fill_color_rgba() = fade_color; + fade_in_shape->set_data ("regionview", this); + + fade_out_shape = new ArdourCanvas::Polygon (*group); + fade_out_shape->property_fill_color_rgba() = fade_color; + fade_out_shape->set_data ("regionview", this); + + + { + uint32_t r,g,b,a; + UINT_TO_RGBA(fill_color,&r,&g,&b,&a); + + + fade_in_handle = new ArdourCanvas::SimpleRect (*group); + fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,0); + fade_in_handle->property_outline_pixels() = 0; + fade_in_handle->property_y1() = 2.0; + fade_in_handle->property_y2() = 7.0; + + fade_in_handle->set_data ("regionview", this); + + fade_out_handle = new ArdourCanvas::SimpleRect (*group); + fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,0); + fade_out_handle->property_outline_pixels() = 0; + fade_out_handle->property_y1() = 2.0; + fade_out_handle->property_y2() = 7.0; + + fade_out_handle->set_data ("regionview", this); + } + + string foo = _region.name(); + foo += ':'; + foo += "gain"; + + gain_line = new AudioRegionGainLine (foo, trackview.session(), *this, *group, audio_region().envelope()); + + if (!(_flags & EnvelopeVisible)) { + gain_line->hide (); + } else { + gain_line->show (); + } + + reset_width_dependent_items ((double) _region.length() / samples_per_unit); + + gain_line->reset (); + + set_height (trackview.height); + + region_muted (); + region_sync_changed (); + region_resized (BoundsChanged); + set_waveview_data_src(); + region_locked (); + envelope_active_changed (); + fade_in_active_changed (); + fade_out_active_changed (); + + _region.StateChanged.connect (mem_fun(*this, &AudioRegionView::region_changed)); + + fade_in_shape->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_in_event), fade_in_shape, this)); + fade_in_handle->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_in_handle_event), fade_in_handle, this)); + fade_out_shape->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_out_event), fade_out_shape, this)); + fade_out_handle->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_out_handle_event), fade_out_handle, this)); + + set_colors (); + + /* XXX sync mark drag? */ +} + +AudioRegionView::~AudioRegionView () +{ + in_destructor = true; + + RegionViewGoingAway (this); /* EMIT_SIGNAL */ + + for (vector<GnomeCanvasWaveViewCache *>::iterator cache = wave_caches.begin(); cache != wave_caches.end() ; ++cache) { + gnome_canvas_waveview_cache_destroy (*cache); + } + + /* all waveviews etc will be destroyed when the group is destroyed */ + + if (gain_line) { + delete gain_line; + } +} + +ARDOUR::AudioRegion& +AudioRegionView::audio_region() const +{ + // "Guaranteed" to succeed... + return dynamic_cast<AudioRegion&>(_region); +} + +void +AudioRegionView::region_changed (Change what_changed) +{ + ENSURE_GUI_THREAD (bind (mem_fun(*this, &AudioRegionView::region_changed), what_changed)); + + RegionView::region_changed(what_changed); + + if (what_changed & AudioRegion::ScaleAmplitudeChanged) { + region_scale_amplitude_changed (); + } + if (what_changed & AudioRegion::FadeInChanged) { + fade_in_changed (); + } + if (what_changed & AudioRegion::FadeOutChanged) { + fade_out_changed (); + } + if (what_changed & AudioRegion::FadeInActiveChanged) { + fade_in_active_changed (); + } + if (what_changed & AudioRegion::FadeOutActiveChanged) { + fade_out_active_changed (); + } + if (what_changed & AudioRegion::EnvelopeActiveChanged) { + envelope_active_changed (); + } +} + +void +AudioRegionView::fade_in_changed () +{ + reset_fade_in_shape (); +} + +void +AudioRegionView::fade_out_changed () +{ + reset_fade_out_shape (); +} + +void +AudioRegionView::set_fade_in_active (bool yn) +{ + audio_region().set_fade_in_active (yn); +} + +void +AudioRegionView::set_fade_out_active (bool yn) +{ + audio_region().set_fade_out_active (yn); +} + +void +AudioRegionView::fade_in_active_changed () +{ + uint32_t r,g,b,a; + uint32_t col; + UINT_TO_RGBA(fade_color,&r,&g,&b,&a); + + if (audio_region().fade_in_active()) { + col = RGBA_TO_UINT(r,g,b,120); + fade_in_shape->property_fill_color_rgba() = col; + fade_in_shape->property_width_pixels() = 0; + fade_in_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,0); + } else { + col = RGBA_TO_UINT(r,g,b,0); + fade_in_shape->property_fill_color_rgba() = col; + fade_in_shape->property_width_pixels() = 1; + fade_in_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,255); + } +} + +void +AudioRegionView::fade_out_active_changed () +{ + uint32_t r,g,b,a; + uint32_t col; + UINT_TO_RGBA(fade_color,&r,&g,&b,&a); + + if (audio_region().fade_out_active()) { + col = RGBA_TO_UINT(r,g,b,120); + fade_out_shape->property_fill_color_rgba() = col; + fade_out_shape->property_width_pixels() = 0; + fade_out_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,0); + } else { + col = RGBA_TO_UINT(r,g,b,0); + fade_out_shape->property_fill_color_rgba() = col; + fade_out_shape->property_width_pixels() = 1; + fade_out_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,255); + } +} + + +void +AudioRegionView::region_scale_amplitude_changed () +{ + ENSURE_GUI_THREAD (mem_fun(*this, &AudioRegionView::region_scale_amplitude_changed)); + + for (uint32_t n = 0; n < waves.size(); ++n) { + // force a reload of the cache + waves[n]->property_data_src() = &_region; + } +} + +void +AudioRegionView::region_resized (Change what_changed) +{ + RegionView::region_resized(what_changed); + + if (what_changed & Change (StartChanged|LengthChanged)) { + + for (uint32_t n = 0; n < waves.size(); ++n) { + waves[n]->property_region_start() = _region.start(); + } + + for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { + + for (vector<WaveView*>::iterator w = (*i)->waves.begin(); w != (*i)->waves.end(); ++w) { + (*w)->property_region_start() = _region.start(); + } + } + } +} + +void +AudioRegionView::reset_width_dependent_items (double pixel_width) +{ + RegionView::reset_width_dependent_items(pixel_width); + assert(_pixel_width == pixel_width); + + if (zero_line) { + zero_line->property_x2() = pixel_width - 1.0; + } + + if (fade_in_handle) { + if (pixel_width <= 6.0) { + fade_in_handle->hide(); + fade_out_handle->hide(); + } else { + if (_height < 5.0) { + fade_in_handle->hide(); + fade_out_handle->hide(); + } else { + fade_in_handle->show(); + fade_out_handle->show(); + } + } + } + + reset_fade_shapes (); +} + +void +AudioRegionView::region_muted () +{ + RegionView::region_muted(); + + for (uint32_t n=0; n < waves.size(); ++n) { + if (_region.muted()) { + waves[n]->property_wave_color() = color_map[cMutedWaveForm]; + } else { + waves[n]->property_wave_color() = color_map[cWaveForm]; + } + } +} + + +void +AudioRegionView::set_height (gdouble height) +{ + uint32_t wcnt = waves.size(); + + // FIXME: ick + TimeAxisViewItem::set_height (height - 2); + + _height = height; + + for (uint32_t n=0; n < wcnt; ++n) { + gdouble ht; + + if ((height) <= NAME_HIGHLIGHT_THRESH) { + ht = ((height-2*wcnt) / (double) wcnt); + } else { + ht = (((height-2*wcnt) - NAME_HIGHLIGHT_SIZE) / (double) wcnt); + } + + gdouble yoff = n * (ht+1); + + waves[n]->property_height() = ht; + waves[n]->property_y() = yoff + 2; + } + + if (gain_line) { + if ((height/wcnt) < NAME_HIGHLIGHT_SIZE) { + gain_line->hide (); + } else { + if (_flags & EnvelopeVisible) { + gain_line->show (); + } + } + gain_line->set_height ((uint32_t) rint (height - NAME_HIGHLIGHT_SIZE)); + } + + manage_zero_line (); + reset_fade_shapes (); + + if (name_text) { + name_text->raise_to_top(); + } +} + +void +AudioRegionView::manage_zero_line () +{ + if (!zero_line) { + return; + } + + if (_height >= 100) { + gdouble wave_midpoint = (_height - NAME_HIGHLIGHT_SIZE) / 2.0; + zero_line->property_y1() = wave_midpoint; + zero_line->property_y2() = wave_midpoint; + zero_line->show(); + } else { + zero_line->hide(); + } +} + +void +AudioRegionView::reset_fade_shapes () +{ + reset_fade_in_shape (); + reset_fade_out_shape (); +} + +void +AudioRegionView::reset_fade_in_shape () +{ + reset_fade_in_shape_width ((jack_nframes_t) audio_region().fade_in().back()->when); +} + +void +AudioRegionView::reset_fade_in_shape_width (jack_nframes_t width) +{ + if (fade_in_handle == 0) { + return; + } + + /* smallest size for a fade is 64 frames */ + + width = std::max ((jack_nframes_t) 64, width); + + Points* points; + double pwidth = width / samples_per_unit; + uint32_t npoints = std::min (gdk_screen_width(), (int) pwidth); + double h; + + if (_height < 5) { + fade_in_shape->hide(); + fade_in_handle->hide(); + return; + } + + double handle_center; + handle_center = pwidth; + + if (handle_center > 7.0) { + handle_center -= 3.0; + } else { + handle_center = 3.0; + } + + fade_in_handle->property_x1() = handle_center - 3.0; + fade_in_handle->property_x2() = handle_center + 3.0; + + if (pwidth < 5) { + fade_in_shape->hide(); + return; + } + + fade_in_shape->show(); + + float curve[npoints]; + audio_region().fade_in().get_vector (0, audio_region().fade_in().back()->when, curve, npoints); + + points = get_canvas_points ("fade in shape", npoints+3); + + if (_height > NAME_HIGHLIGHT_THRESH) { + h = _height - NAME_HIGHLIGHT_SIZE; + } else { + h = _height; + } + + /* points *MUST* be in anti-clockwise order */ + + uint32_t pi, pc; + double xdelta = pwidth/npoints; + + for (pi = 0, pc = 0; pc < npoints; ++pc) { + (*points)[pi].set_x(1 + (pc * xdelta)); + (*points)[pi++].set_y(2 + (h - (curve[pc] * h))); + } + + /* fold back */ + + (*points)[pi].set_x(pwidth); + (*points)[pi++].set_y(2); + + (*points)[pi].set_x(1); + (*points)[pi++].set_y(2); + + /* connect the dots ... */ + + (*points)[pi] = (*points)[0]; + + fade_in_shape->property_points() = *points; + delete points; +} + +void +AudioRegionView::reset_fade_out_shape () +{ + reset_fade_out_shape_width ((jack_nframes_t) audio_region().fade_out().back()->when); +} + +void +AudioRegionView::reset_fade_out_shape_width (jack_nframes_t width) +{ + if (fade_out_handle == 0) { + return; + } + + /* smallest size for a fade is 64 frames */ + + width = std::max ((jack_nframes_t) 64, width); + + Points* points; + double pwidth = width / samples_per_unit; + uint32_t npoints = std::min (gdk_screen_width(), (int) pwidth); + double h; + + if (_height < 5) { + fade_out_shape->hide(); + fade_out_handle->hide(); + return; + } + + double handle_center; + handle_center = (_region.length() - width) / samples_per_unit; + + if (handle_center > 7.0) { + handle_center -= 3.0; + } else { + handle_center = 3.0; + } + + fade_out_handle->property_x1() = handle_center - 3.0; + fade_out_handle->property_x2() = handle_center + 3.0; + + /* don't show shape if its too small */ + + if (pwidth < 5) { + fade_out_shape->hide(); + return; + } + + fade_out_shape->show(); + + float curve[npoints]; + audio_region().fade_out().get_vector (0, audio_region().fade_out().back()->when, curve, npoints); + + if (_height > NAME_HIGHLIGHT_THRESH) { + h = _height - NAME_HIGHLIGHT_SIZE; + } else { + h = _height; + } + + /* points *MUST* be in anti-clockwise order */ + + points = get_canvas_points ("fade out shape", npoints+3); + + uint32_t pi, pc; + double xdelta = pwidth/npoints; + + for (pi = 0, pc = 0; pc < npoints; ++pc) { + (*points)[pi].set_x(_pixel_width - 1 - pwidth + (pc*xdelta)); + (*points)[pi++].set_y(2 + (h - (curve[pc] * h))); + } + + /* fold back */ + + (*points)[pi].set_x(_pixel_width); + (*points)[pi++].set_y(h); + + (*points)[pi].set_x(_pixel_width); + (*points)[pi++].set_y(2); + + /* connect the dots ... */ + + (*points)[pi] = (*points)[0]; + + fade_out_shape->property_points() = *points; + delete points; +} + +void +AudioRegionView::set_samples_per_unit (gdouble spu) +{ + RegionView::set_samples_per_unit (spu); + + for (uint32_t n=0; n < waves.size(); ++n) { + waves[n]->property_samples_per_unit() = spu; + } + + if (gain_line) { + gain_line->reset (); + } + reset_fade_shapes (); +} + +void +AudioRegionView::set_amplitude_above_axis (gdouble spp) +{ + for (uint32_t n=0; n < waves.size(); ++n) { + waves[n]->property_amplitude_above_axis() = spp; + } +} + +void +AudioRegionView::compute_colors (Gdk::Color& basic_color) +{ + RegionView::compute_colors(basic_color); + + uint32_t r, g, b, a; + + /* gain color computed in envelope_active_changed() */ + + UINT_TO_RGBA (fill_color, &r, &g, &b, &a); + fade_color = RGBA_TO_UINT(r,g,b,120); +} + +void +AudioRegionView::set_colors () +{ + RegionView::set_colors(); + + if (gain_line) { + gain_line->set_line_color (audio_region().envelope_active() ? color_map[cGainLine] : color_map[cGainLineInactive]); + } + + for (uint32_t n=0; n < waves.size(); ++n) { + if (_region.muted()) { + waves[n]->property_wave_color() = color_map[cMutedWaveForm]; + } else { + waves[n]->property_wave_color() = color_map[cWaveForm]; + } + } +} + +void +AudioRegionView::show_region_editor () +{ + if (editor == 0) { + editor = new AudioRegionEditor (trackview.session(), audio_region(), *this); + // GTK2FIX : how to ensure float without realizing + // editor->realize (); + // trackview.editor.ensure_float (*editor); + } + + editor->show_all (); + editor->get_window()->raise(); +} + +void +AudioRegionView::set_waveform_visible (bool yn) +{ + if (((_flags & WaveformVisible) != yn)) { + if (yn) { + for (uint32_t n=0; n < waves.size(); ++n) { + waves[n]->show(); + } + _flags |= WaveformVisible; + } else { + for (uint32_t n=0; n < waves.size(); ++n) { + waves[n]->hide(); + } + _flags &= ~WaveformVisible; + } + store_flags (); + } +} + +void +AudioRegionView::temporarily_hide_envelope () +{ + if (gain_line) { + gain_line->hide (); + } +} + +void +AudioRegionView::unhide_envelope () +{ + if (gain_line && (_flags & EnvelopeVisible)) { + gain_line->show (); + } +} + +void +AudioRegionView::set_envelope_visible (bool yn) +{ + if (gain_line && ((_flags & EnvelopeVisible) != yn)) { + if (yn) { + gain_line->show (); + _flags |= EnvelopeVisible; + } else { + gain_line->hide (); + _flags &= ~EnvelopeVisible; + } + store_flags (); + } +} + +void +AudioRegionView::create_waves () +{ + bool create_zero_line = true; + + RouteTimeAxisView& atv (*(dynamic_cast<RouteTimeAxisView*>(&trackview))); // ick + + if (!atv.get_diskstream()) { + return; + } + + uint32_t nchans = atv.get_diskstream()->n_channels(); + + /* in tmp_waves, set up null pointers for each channel so the vector is allocated */ + for (uint32_t n = 0; n < nchans; ++n) { + tmp_waves.push_back (0); + } + + for (uint32_t n = 0; n < nchans; ++n) { + + if (n >= audio_region().n_channels()) { + break; + } + + wave_caches.push_back (WaveView::create_cache ()); + + if (wait_for_data) { + if (audio_region().source(n).peaks_ready (bind (mem_fun(*this, &AudioRegionView::peaks_ready_handler), n), data_ready_connection)) { + create_one_wave (n, true); + } else { + create_zero_line = false; + } + } else { + create_one_wave (n, true); + } + } + + if (create_zero_line) { + zero_line = new ArdourCanvas::SimpleLine (*group); + zero_line->property_x1() = (gdouble) 1.0; + zero_line->property_x2() = (gdouble) (_region.length() / samples_per_unit) - 1.0; + zero_line->property_color_rgba() = (guint) color_map[cZeroLine]; + manage_zero_line (); + } +} + +void +AudioRegionView::create_one_wave (uint32_t which, bool direct) +{ + RouteTimeAxisView& atv (*(dynamic_cast<RouteTimeAxisView*>(&trackview))); // ick + uint32_t nchans = atv.get_diskstream()->n_channels(); + uint32_t n; + uint32_t nwaves = std::min (nchans, audio_region().n_channels()); + gdouble ht; + + if (trackview.height < NAME_HIGHLIGHT_SIZE) { + ht = ((trackview.height) / (double) nchans); + } else { + ht = ((trackview.height - NAME_HIGHLIGHT_SIZE) / (double) nchans); + } + + gdouble yoff = which * ht; + + WaveView *wave = new WaveView(*group); + + wave->property_data_src() = (gpointer) &_region; + wave->property_cache() = wave_caches[which]; + wave->property_cache_updater() = true; + wave->property_channel() = which; + wave->property_length_function() = (gpointer) region_length_from_c; + wave->property_sourcefile_length_function() = (gpointer) sourcefile_length_from_c; + wave->property_peak_function() = (gpointer) region_read_peaks_from_c; + wave->property_x() = 0.0; + wave->property_y() = yoff; + wave->property_height() = (double) ht; + wave->property_samples_per_unit() = samples_per_unit; + wave->property_amplitude_above_axis() = _amplitude_above_axis; + wave->property_wave_color() = _region.muted() ? color_map[cMutedWaveForm] : color_map[cWaveForm]; + wave->property_region_start() = _region.start(); + + if (!(_flags & WaveformVisible)) { + wave->hide(); + } + + /* note: calling this function is serialized by the lock + held in the peak building thread that signals that + peaks are ready for use *or* by the fact that it is + called one by one from the GUI thread. + */ + + if (which < nchans) { + tmp_waves[which] = wave; + } else { + /* n-channel track, >n-channel source */ + } + + /* see if we're all ready */ + + for (n = 0; n < nchans; ++n) { + if (tmp_waves[n] == 0) { + break; + } + } + + if (n == nwaves && waves.empty()) { + /* all waves are ready */ + tmp_waves.resize(nwaves); + + waves = tmp_waves; + tmp_waves.clear (); + + if (!zero_line) { + zero_line = new ArdourCanvas::SimpleLine (*group); + zero_line->property_x1() = (gdouble) 1.0; + zero_line->property_x2() = (gdouble) (_region.length() / samples_per_unit) - 1.0; + zero_line->property_color_rgba() = (guint) color_map[cZeroLine]; + manage_zero_line (); + } + } +} + +void +AudioRegionView::peaks_ready_handler (uint32_t which) +{ + Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &AudioRegionView::create_one_wave), which, false)); + + if (!waves.empty()) { + /* all waves created, don't hook into peaks ready anymore */ + data_ready_connection.disconnect (); + } +} + +void +AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev) +{ + if (gain_line == 0) { + return; + } + + double x, y; + + /* don't create points that can't be seen */ + + set_envelope_visible (true); + + x = ev->button.x; + y = ev->button.y; + + item->w2i (x, y); + + jack_nframes_t fx = trackview.editor.pixel_to_frame (x); + + if (fx > _region.length()) { + return; + } + + /* compute vertical fractional position */ + + y = 1.0 - (y / (trackview.height - NAME_HIGHLIGHT_SIZE)); + + /* map using gain line */ + + gain_line->view_to_model_y (y); + + trackview.session().begin_reversible_command (_("add gain control point")); + trackview.session().add_undo (audio_region().envelope().get_memento()); + + + if (!audio_region().envelope_active()) { + trackview.session().add_undo( bind( mem_fun(audio_region(), &AudioRegion::set_envelope_active), false) ); + audio_region().set_envelope_active(true); + trackview.session().add_redo( bind( mem_fun(audio_region(), &AudioRegion::set_envelope_active), true) ); + } + + audio_region().envelope().add (fx, y); + + trackview.session().add_redo_no_execute (audio_region().envelope().get_memento()); + trackview.session().commit_reversible_command (); +} + +void +AudioRegionView::remove_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev) +{ + ControlPoint *cp = reinterpret_cast<ControlPoint *> (item->get_data ("control_point")); + audio_region().envelope().erase (cp->model); +} + +void +AudioRegionView::store_flags() +{ + XMLNode *node = new XMLNode ("GUI"); + + node->add_property ("waveform-visible", (_flags & WaveformVisible) ? "yes" : "no"); + node->add_property ("envelope-visible", (_flags & EnvelopeVisible) ? "yes" : "no"); + + _region.add_extra_xml (*node); +} + +void +AudioRegionView::set_flags (XMLNode* node) +{ + XMLProperty *prop; + + if ((prop = node->property ("waveform-visible")) != 0) { + if (prop->value() == "yes") { + _flags |= WaveformVisible; + } + } + + if ((prop = node->property ("envelope-visible")) != 0) { + if (prop->value() == "yes") { + _flags |= EnvelopeVisible; + } + } +} + +void +AudioRegionView::set_waveform_shape (WaveformShape shape) +{ + bool yn; + + /* this slightly odd approach is to leave the door open to + other "shapes" such as spectral displays, etc. + */ + + switch (shape) { + case Rectified: + yn = true; + break; + + default: + yn = false; + break; + } + + if (yn != (bool) (_flags & WaveformRectified)) { + for (vector<WaveView *>::iterator wave = waves.begin(); wave != waves.end() ; ++wave) { + (*wave)->property_rectified() = yn; + } + + if (zero_line) { + if (yn) { + zero_line->hide(); + } else { + zero_line->show(); + } + } + + if (yn) { + _flags |= WaveformRectified; + } else { + _flags &= ~WaveformRectified; + } + } +} + +GhostRegion* +AudioRegionView::add_ghost (AutomationTimeAxisView& atv) +{ + RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&trackview); + assert(rtv); + + double unit_position = _region.position () / samples_per_unit; + GhostRegion* ghost = new GhostRegion (atv, unit_position); + uint32_t nchans; + + nchans = rtv->get_diskstream()->n_channels(); + + for (uint32_t n = 0; n < nchans; ++n) { + + if (n >= audio_region().n_channels()) { + break; + } + + WaveView *wave = new WaveView(*ghost->group); + + wave->property_data_src() = &_region; + wave->property_cache() = wave_caches[n]; + wave->property_cache_updater() = false; + wave->property_channel() = n; + wave->property_length_function() = (gpointer)region_length_from_c; + wave->property_sourcefile_length_function() = (gpointer) sourcefile_length_from_c; + wave->property_peak_function() = (gpointer) region_read_peaks_from_c; + wave->property_x() = 0.0; + wave->property_samples_per_unit() = samples_per_unit; + wave->property_amplitude_above_axis() = _amplitude_above_axis; + wave->property_wave_color() = color_map[cGhostTrackWave]; + wave->property_region_start() = _region.start(); + + ghost->waves.push_back(wave); + } + + ghost->set_height (); + ghost->set_duration (_region.length() / samples_per_unit); + ghosts.push_back (ghost); + + ghost->GoingAway.connect (mem_fun(*this, &AudioRegionView::remove_ghost)); + + return ghost; +} + +void +AudioRegionView::entered () +{ + if (gain_line && _flags & EnvelopeVisible) { + gain_line->show_all_control_points (); + } + + uint32_t r,g,b,a; + UINT_TO_RGBA(fade_color,&r,&g,&b,&a); + a=255; + + if (fade_in_handle) { + fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a); + fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a); + } +} + +void +AudioRegionView::exited () +{ + if (gain_line) { + gain_line->hide_all_but_selected_control_points (); + } + + uint32_t r,g,b,a; + UINT_TO_RGBA(fade_color,&r,&g,&b,&a); + a=0; + + if (fade_in_handle) { + fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a); + fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a); + } +} + +void +AudioRegionView::envelope_active_changed () +{ + if (gain_line) { + gain_line->set_line_color (audio_region().envelope_active() ? color_map[cGainLine] : color_map[cGainLineInactive]); + } +} + +void +AudioRegionView::set_waveview_data_src() +{ + + double unit_length= _region.length() / samples_per_unit; + + for (uint32_t n = 0; n < waves.size(); ++n) { + // TODO: something else to let it know the channel + waves[n]->property_data_src() = &_region; + } + + for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { + + (*i)->set_duration (unit_length); + + for (vector<WaveView*>::iterator w = (*i)->waves.begin(); w != (*i)->waves.end(); ++w) { + (*w)->property_data_src() = &_region; + } + } + +} + +void +AudioRegionView::color_handler (ColorID id, uint32_t val) +{ + switch (id) { + case cMutedWaveForm: + case cWaveForm: + set_colors (); + break; + + case cGainLineInactive: + case cGainLine: + envelope_active_changed(); + break; + + case cZeroLine: + if (zero_line) { + zero_line->property_color_rgba() = (guint) color_map[cZeroLine]; + } + break; + + case cGhostTrackWave: + break; + + default: + break; + } +} diff --git a/gtk2_ardour/regionview.h b/gtk2_ardour/audio_region_view.h index f49b46aea4..ec3ea6c4c5 100644 --- a/gtk2_ardour/regionview.h +++ b/gtk2_ardour/audio_region_view.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2001-2004 Paul Davis + Copyright (C) 2001-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,12 +14,10 @@ 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 __gtk_ardour_region_view_h__ -#define __gtk_ardour_region_view_h__ +#ifndef __gtk_ardour_audio_region_view_h__ +#define __gtk_ardour_audio_region_view_h__ #include <vector> @@ -28,6 +26,8 @@ #include <sigc++/signal.h> #include <ardour/region.h> +#include "region_view.h" +#include "route_time_axis.h" #include "time_axis_view_item.h" #include "automation_line.h" #include "enums.h" @@ -46,51 +46,38 @@ class AudioRegionEditor; class GhostRegion; class AutomationTimeAxisView; -class AudioRegionView : public TimeAxisViewItem +class AudioRegionView : public RegionView { public: AudioRegionView (ArdourCanvas::Group *, - AudioTimeAxisView&, + RouteTimeAxisView&, ARDOUR::AudioRegion&, double initial_samples_per_unit, Gdk::Color& basic_color); ~AudioRegionView (); - virtual void init (double amplitude_above_axis, Gdk::Color& base_color, bool wait_for_waves); + virtual void init (Gdk::Color& base_color, bool wait_for_data = false); + + ARDOUR::AudioRegion& audio_region() const; - ARDOUR::AudioRegion& region; // ok, let 'em have it - bool is_valid() const { return valid; } - void set_valid (bool yn) { valid = yn; } - void set_height (double); void set_samples_per_unit (double); - bool set_duration (jack_nframes_t, void*); void set_amplitude_above_axis (gdouble spp); - void move (double xdelta, double ydelta); - - void raise (); - void raise_to_top (); - void lower (); - void lower_to_bottom (); - - bool set_position(jack_nframes_t pos, void* src, double* delta = 0); - - void temporarily_hide_envelope (); // dangerous - void unhide_envelope (); // dangerous + void temporarily_hide_envelope (); ///< Dangerous! + void unhide_envelope (); ///< Dangerous! void set_envelope_visible (bool); void set_waveform_visible (bool yn); void set_waveform_shape (WaveformShape); bool waveform_rectified() const { return _flags & WaveformRectified; } - bool waveform_visible() const { return _flags & WaveformVisible; } - bool envelope_visible() const { return _flags & EnvelopeVisible; } + bool waveform_visible() const { return _flags & WaveformVisible; } + bool envelope_visible() const { return _flags & EnvelopeVisible; } void show_region_editor (); - void hide_region_editor(); void add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *event); void remove_gain_point_event (ArdourCanvas::Item *item, GdkEvent *event); @@ -100,19 +87,13 @@ class AudioRegionView : public TimeAxisViewItem void region_changed (ARDOUR::Change); void envelope_active_changed (); - static sigc::signal<void,AudioRegionView*> AudioRegionViewGoingAway; - sigc::signal<void> GoingAway; - GhostRegion* add_ghost (AutomationTimeAxisView&); - void remove_ghost (GhostRegion*); void reset_fade_in_shape_width (jack_nframes_t); void reset_fade_out_shape_width (jack_nframes_t); void set_fade_in_active (bool); void set_fade_out_active (bool); - uint32_t get_fill_color (); - virtual void entered (); virtual void exited (); @@ -124,44 +105,18 @@ class AudioRegionView : public TimeAxisViewItem */ AudioRegionView (ArdourCanvas::Group *, - AudioTimeAxisView&, - ARDOUR::AudioRegion&, - double initial_samples_per_unit, - Gdk::Color& basic_color, - TimeAxisViewItem::Visibility); + RouteTimeAxisView&, + ARDOUR::AudioRegion&, + double samples_per_unit, + Gdk::Color& basic_color, + TimeAxisViewItem::Visibility); enum Flags { EnvelopeVisible = 0x1, WaveformVisible = 0x4, WaveformRectified = 0x8 }; - - vector<ArdourCanvas::WaveView *> waves; /* waveviews */ - vector<ArdourCanvas::WaveView *> tmp_waves; /* see ::create_waves()*/ - ArdourCanvas::Polygon* sync_mark; /* polgyon for sync position */ - ArdourCanvas::Text* no_wave_msg; /* text */ - ArdourCanvas::SimpleLine* zero_line; /* simpleline */ - ArdourCanvas::Polygon* fade_in_shape; /* polygon */ - ArdourCanvas::Polygon* fade_out_shape; /* polygon */ - ArdourCanvas::SimpleRect* fade_in_handle; /* simplerect */ - ArdourCanvas::SimpleRect* fade_out_handle; /* simplerect */ - - AudioRegionGainLine* gain_line; - AudioRegionEditor *editor; - - vector<ControlPoint *> control_points; - double _amplitude_above_axis; - double current_visible_sync_position; - - uint32_t _flags; - uint32_t fade_color; - bool valid; /* see StreamView::redisplay_diskstream() */ - double _pixel_width; - double _height; - bool in_destructor; - bool wait_for_waves; - sigc::connection peaks_ready_connection; - + void reset_fade_shapes (); void reset_fade_in_shape (); void reset_fade_out_shape (); @@ -173,34 +128,37 @@ class AudioRegionView : public TimeAxisViewItem void region_resized (ARDOUR::Change); void region_moved (void *); void region_muted (); - void region_locked (); - void region_opacity (); - void region_layered (); - void region_renamed (); - void region_sync_changed (); void region_scale_amplitude_changed (); - static gint _lock_toggle (ArdourCanvas::Item*, GdkEvent*, void*); - void lock_toggle (); - void create_waves (); void create_one_wave (uint32_t, bool); void manage_zero_line (); void peaks_ready_handler (uint32_t); - void reset_name (gdouble width); void set_flags (XMLNode *); void store_flags (); void set_colors (); void compute_colors (Gdk::Color&); - virtual void set_frame_color (); void reset_width_dependent_items (double pixel_width); void set_waveview_data_src(); + + void color_handler (ColorID, uint32_t); vector<GnomeCanvasWaveViewCache*> wave_caches; - vector<GhostRegion*> ghosts; - - void color_handler (ColorID, uint32_t); + vector<ArdourCanvas::WaveView *> waves; + vector<ArdourCanvas::WaveView *> tmp_waves; ///< see ::create_waves() + ArdourCanvas::Polygon* sync_mark; ///< polgyon for sync position + ArdourCanvas::SimpleLine* zero_line; + ArdourCanvas::Polygon* fade_in_shape; + ArdourCanvas::Polygon* fade_out_shape; + ArdourCanvas::SimpleRect* fade_in_handle; + ArdourCanvas::SimpleRect* fade_out_handle; + AudioRegionGainLine* gain_line; + + double _amplitude_above_axis; + + uint32_t _flags; + uint32_t fade_color; }; -#endif /* __gtk_ardour_region_view_h__ */ +#endif /* __gtk_ardour_audio_region_view_h__ */ diff --git a/gtk2_ardour/regionview.cc b/gtk2_ardour/audio_regionview.cc index dcc71a03c4..e2d20c0cc0 100644 --- a/gtk2_ardour/regionview.cc +++ b/gtk2_ardour/audio_regionview.cc @@ -15,7 +15,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ + $Id: regionview.cc 678 2006-07-11 15:45:19Z paul $ */ #include <cmath> @@ -29,10 +29,9 @@ #include <ardour/audioregion.h> #include <ardour/audiosource.h> #include <ardour/audio_diskstream.h> -#include <pbd/memento_command.h> #include "streamview.h" -#include "regionview.h" +#include "region_view.h" #include "audio_time_axis.h" #include "simplerect.h" #include "simpleline.h" @@ -519,7 +518,7 @@ AudioRegionView::set_height (gdouble height) for (uint32_t n=0; n < wcnt; ++n) { gdouble ht; - if ((height) < NAME_HIGHLIGHT_THRESH) { + if ((height) <= NAME_HIGHLIGHT_THRESH) { ht = ((height-2*wcnt) / (double) wcnt); } else { ht = (((height-2*wcnt) - NAME_HIGHLIGHT_SIZE) / (double) wcnt); @@ -1145,20 +1144,18 @@ AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev) gain_line->view_to_model_y (y); trackview.session().begin_reversible_command (_("add gain control point")); - XMLNode &before = region.envelope().get_state(); + trackview.session().add_undo (region.envelope().get_memento()); if (!region.envelope_active()) { - XMLNode &before = region.get_state(); + trackview.session().add_undo( bind( mem_fun(region, &AudioRegion::set_envelope_active), false) ); region.set_envelope_active(true); - XMLNode &after = region.get_state(); - trackview.session().add_command(new MementoCommand<AudioRegion>(region, before, after)); + trackview.session().add_redo( bind( mem_fun(region, &AudioRegion::set_envelope_active), true) ); } region.envelope().add (fx, y); - XMLNode &after = region.envelope().get_state(); - trackview.session().add_command(new MementoCommand<Curve>(region.envelope(), before, after)); + trackview.session().add_redo_no_execute (region.envelope().get_memento()); trackview.session().commit_reversible_command (); } diff --git a/gtk2_ardour/audio_streamview.cc b/gtk2_ardour/audio_streamview.cc new file mode 100644 index 0000000000..82349947c6 --- /dev/null +++ b/gtk2_ardour/audio_streamview.cc @@ -0,0 +1,700 @@ +/* + Copyright (C) 2001, 2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <cmath> +#include <cassert> + +#include <gtkmm.h> + +#include <gtkmm2ext/gtk_ui.h> + +#include <ardour/audioplaylist.h> +#include <ardour/audioregion.h> +#include <ardour/audiosource.h> +#include <ardour/audio_diskstream.h> +#include <ardour/audio_track.h> +#include <ardour/playlist_templates.h> +#include <ardour/source.h> + +#include "audio_streamview.h" +#include "audio_region_view.h" +#include "tape_region_view.h" +#include "audio_time_axis.h" +#include "canvas-waveview.h" +#include "canvas-simplerect.h" +#include "region_selection.h" +#include "selection.h" +#include "public_editor.h" +#include "ardour_ui.h" +#include "crossfade_view.h" +#include "rgb_macros.h" +#include "gui_thread.h" +#include "utils.h" +#include "color.h" + +using namespace ARDOUR; +using namespace PBD; +using namespace Editing; + +AudioStreamView::AudioStreamView (AudioTimeAxisView& tv) + : StreamView (tv) +{ + crossfades_visible = true; + + if (tv.is_audio_track()) + stream_base_color = color_map[cAudioTrackBase]; + else + stream_base_color = color_map[cAudioBusBase]; + + canvas_rect->property_fill_color_rgba() = stream_base_color; + canvas_rect->property_outline_color_rgba() = color_map[cAudioTrackOutline]; + + _amplitude_above_axis = 1.0; + + use_rec_regions = tv.editor.show_waveforms_recording (); + last_rec_peak_frame = 0; +} + +AudioStreamView::~AudioStreamView () +{ +} + +int +AudioStreamView::set_height (gdouble h) +{ + /* limit the values to something sane-ish */ + if (h < 10.0 || h > 1000.0) { + return -1; + } + + StreamView::set_height(h); + + for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + (*i)->set_height (h); + } + + return 0; +} + +int +AudioStreamView::set_samples_per_unit (gdouble spp) +{ + StreamView::set_samples_per_unit(spp); + + for (CrossfadeViewList::iterator xi = crossfade_views.begin(); xi != crossfade_views.end(); ++xi) { + (*xi)->set_samples_per_unit (spp); + } + + return 0; +} + +int +AudioStreamView::set_amplitude_above_axis (gdouble app) +{ + RegionViewList::iterator i; + + if (app < 1.0) { + return -1; + } + + _amplitude_above_axis = app; + + for (i = region_views.begin(); i != region_views.end(); ++i) { + AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i); + if (arv) + arv->set_amplitude_above_axis (app); + } + + return 0; +} + +void +AudioStreamView::add_region_view_internal (Region *r, bool wait_for_waves) +{ + ENSURE_GUI_THREAD (bind (mem_fun (*this, &AudioStreamView::add_region_view), r)); + + AudioRegion* region = dynamic_cast<AudioRegion*> (r); + + if (region == 0) { + return; + } + + AudioRegionView *region_view; + list<RegionView *>::iterator i; + + for (i = region_views.begin(); i != region_views.end(); ++i) { + if (&(*i)->region() == r) { + + /* great. we already have a AudioRegionView for this Region. use it again. */ + + (*i)->set_valid (true); + return; + } + } + + switch (_trackview.audio_track()->mode()) { + case Normal: + region_view = new AudioRegionView (canvas_group, _trackview, *region, + _samples_per_unit, region_color); + break; + case Destructive: + region_view = new TapeAudioRegionView (canvas_group, _trackview, *region, + _samples_per_unit, region_color); + break; + } + + region_view->init (region_color, wait_for_waves); + region_view->set_amplitude_above_axis(_amplitude_above_axis); + region_views.push_front (region_view); + + /* follow global waveform setting */ + + region_view->set_waveform_visible(_trackview.editor.show_waveforms()); + + /* catch regionview going away */ + + region->GoingAway.connect (mem_fun (*this, &AudioStreamView::remove_region_view)); + + RegionViewAdded (region_view); +} + +void +AudioStreamView::remove_region_view (Region *r) +{ + ENSURE_GUI_THREAD (bind (mem_fun (*this, &AudioStreamView::remove_region_view), r)); + + for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end();) { + list<CrossfadeView*>::iterator tmp; + + tmp = i; + ++tmp; + + AudioRegion* ar = dynamic_cast<AudioRegion*>(r); + if (ar && (*i)->crossfade.involves (*ar)) { + delete *i; + crossfade_views.erase (i); + } + + i = tmp; + } + + StreamView::remove_region_view(r); +} + +void +AudioStreamView::undisplay_diskstream () +{ + StreamView::undisplay_diskstream(); + + for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + delete *i; + } + + crossfade_views.clear (); +} + +void +AudioStreamView::playlist_modified () +{ + ENSURE_GUI_THREAD (mem_fun (*this, &AudioStreamView::playlist_modified)); + + StreamView::playlist_modified(); + + /* if the playlist is modified, make sure xfades are on top and all the regionviews are stacked + correctly. + */ + + for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + (*i)->get_canvas_group()->raise_to_top(); + } +} + +void +AudioStreamView::playlist_changed (Diskstream *ds) +{ + ENSURE_GUI_THREAD (bind (mem_fun (*this, &AudioStreamView::playlist_changed), ds)); + + StreamView::playlist_changed(ds); + + AudioPlaylist* apl = dynamic_cast<AudioPlaylist*>(ds->playlist()); + if (apl) + playlist_connections.push_back (apl->NewCrossfade.connect (mem_fun (*this, &AudioStreamView::add_crossfade))); +} + +void +AudioStreamView::add_crossfade (Crossfade *crossfade) +{ + AudioRegionView* lview = 0; + AudioRegionView* rview = 0; + + ENSURE_GUI_THREAD (bind (mem_fun (*this, &AudioStreamView::add_crossfade), crossfade)); + + /* first see if we already have a CrossfadeView for this Crossfade */ + + for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + if (&(*i)->crossfade == crossfade) { + if (!crossfades_visible) { + (*i)->hide(); + } else { + (*i)->show (); + } + (*i)->set_valid (true); + return; + } + } + + /* create a new one */ + + for (list<RegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) { + AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*i); + + if (!lview && arv && &(arv->region()) == &crossfade->out()) { + lview = arv; + } + if (!rview && arv && &(arv->region()) == &crossfade->in()) { + rview = arv; + } + } + + CrossfadeView *cv = new CrossfadeView (_trackview.canvas_display, + _trackview, + *crossfade, + _samples_per_unit, + region_color, + *lview, *rview); + + crossfade->Invalidated.connect (mem_fun (*this, &AudioStreamView::remove_crossfade)); + crossfade_views.push_back (cv); + + if (!crossfades_visible) { + cv->hide (); + } +} + +void +AudioStreamView::remove_crossfade (Crossfade *xfade) +{ + ENSURE_GUI_THREAD (bind (mem_fun (*this, &AudioStreamView::remove_crossfade), xfade)); + + for (list<CrossfadeView*>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + if (&(*i)->crossfade == xfade) { + delete *i; + crossfade_views.erase (i); + break; + } + } +} + +void +AudioStreamView::redisplay_diskstream () +{ + list<RegionView *>::iterator i, tmp; + list<CrossfadeView*>::iterator xi, tmpx; + + + for (i = region_views.begin(); i != region_views.end(); ++i) { + (*i)->set_valid (false); + } + + for (xi = crossfade_views.begin(); xi != crossfade_views.end(); ++xi) { + (*xi)->set_valid (false); + if ((*xi)->visible()) { + (*xi)->show (); + } + } + + if (_trackview.is_audio_track()) { + _trackview.get_diskstream()->playlist()->foreach_region (static_cast<StreamView*>(this), &StreamView::add_region_view); + AudioPlaylist* apl = dynamic_cast<AudioPlaylist*>(_trackview.get_diskstream()->playlist()); + if (apl) + apl->foreach_crossfade (this, &AudioStreamView::add_crossfade); + } + + for (i = region_views.begin(); i != region_views.end(); ) { + tmp = i; + tmp++; + + if (!(*i)->is_valid()) { + delete *i; + region_views.erase (i); + } + + i = tmp; + } + + for (xi = crossfade_views.begin(); xi != crossfade_views.end();) { + tmpx = xi; + tmpx++; + + if (!(*xi)->valid()) { + delete *xi; + crossfade_views.erase (xi); + } + + xi = tmpx; + } + + /* now fix layering */ + + playlist_modified (); +} + +void +AudioStreamView::set_show_waveforms (bool yn) +{ + for (list<RegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) { + AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i); + if (arv) + arv->set_waveform_visible (yn); + } +} + +void +AudioStreamView::set_waveform_shape (WaveformShape shape) +{ + for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) { + AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i); + if (arv) + arv->set_waveform_shape (shape); + } +} + +void +AudioStreamView::setup_rec_box () +{ + // cerr << _trackview.name() << " streamview SRB\n"; + + if (_trackview.session().transport_rolling()) { + + // cerr << "\trolling\n"; + + if (!rec_active && + _trackview.session().record_status() == Session::Recording && + _trackview.get_diskstream()->record_enabled()) { + + if (_trackview.audio_track()->mode() == Normal && use_rec_regions && rec_regions.size() == rec_rects.size()) { + + /* add a new region, but don't bother if they set use_rec_regions mid-record */ + + AudioRegion::SourceList sources; + + for (list<sigc::connection>::iterator prc = peak_ready_connections.begin(); prc != peak_ready_connections.end(); ++prc) { + (*prc).disconnect(); + } + peak_ready_connections.clear(); + + // FIXME + AudioDiskstream* ads = dynamic_cast<AudioDiskstream*>(_trackview.get_diskstream()); + assert(ads); + + for (uint32_t n=0; n < ads->n_channels(); ++n) { + AudioSource *src = (AudioSource *) ads->write_source (n); + if (src) { + sources.push_back (src); + peak_ready_connections.push_back (src->PeakRangeReady.connect (bind (mem_fun (*this, &AudioStreamView::rec_peak_range_ready), src))); + } + } + + // handle multi + + jack_nframes_t start = 0; + if (rec_regions.size() > 0) { + start = rec_regions.back()->start() + _trackview.get_diskstream()->get_captured_frames(rec_regions.size()-1); + } + + AudioRegion * region = new AudioRegion(sources, start, 1 , "", 0, (Region::Flag)(Region::DefaultFlags | Region::DoNotSaveState), false); + region->set_position (_trackview.session().transport_frame(), this); + rec_regions.push_back (region); + /* catch it if it goes away */ + region->GoingAway.connect (mem_fun (*this, &AudioStreamView::remove_rec_region)); + + /* we add the region later */ + } + + /* start a new rec box */ + + AudioTrack* at; + + at = _trackview.audio_track(); /* we know what it is already */ + AudioDiskstream& ds = at->audio_diskstream(); + jack_nframes_t frame_pos = ds.current_capture_start (); + gdouble xstart = _trackview.editor.frame_to_pixel (frame_pos); + gdouble xend; + uint32_t fill_color; + + switch (_trackview.audio_track()->mode()) { + case Normal: + xend = xstart; + fill_color = color_map[cRecordingRectFill]; + break; + + case Destructive: + xend = xstart + 2; + fill_color = color_map[cRecordingRectFill]; + /* make the recording rect translucent to allow + the user to see the peak data coming in, etc. + */ + fill_color = UINT_RGBA_CHANGE_A (fill_color, 120); + break; + } + + ArdourCanvas::SimpleRect * rec_rect = new Gnome::Canvas::SimpleRect (*canvas_group); + rec_rect->property_x1() = xstart; + rec_rect->property_y1() = 1.0; + rec_rect->property_x2() = xend; + rec_rect->property_y2() = (double) _trackview.height - 1; + rec_rect->property_outline_color_rgba() = color_map[cRecordingRectOutline]; + rec_rect->property_fill_color_rgba() = fill_color; + + RecBoxInfo recbox; + recbox.rectangle = rec_rect; + recbox.start = _trackview.session().transport_frame(); + recbox.length = 0; + + rec_rects.push_back (recbox); + + screen_update_connection.disconnect(); + screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (mem_fun (*this, &AudioStreamView::update_rec_box)); + rec_updating = true; + rec_active = true; + + } else if (rec_active && + (_trackview.session().record_status() != Session::Recording || + !_trackview.get_diskstream()->record_enabled())) { + + screen_update_connection.disconnect(); + rec_active = false; + rec_updating = false; + + } + + } else { + + // cerr << "\tNOT rolling, rec_rects = " << rec_rects.size() << " rec_regions = " << rec_regions.size() << endl; + + if (!rec_rects.empty() || !rec_regions.empty()) { + + /* disconnect rapid update */ + screen_update_connection.disconnect(); + + for (list<sigc::connection>::iterator prc = peak_ready_connections.begin(); prc != peak_ready_connections.end(); ++prc) { + (*prc).disconnect(); + } + peak_ready_connections.clear(); + + rec_updating = false; + rec_active = false; + last_rec_peak_frame = 0; + + /* remove temp regions */ + for (list<Region*>::iterator iter=rec_regions.begin(); iter != rec_regions.end(); ) + { + list<Region*>::iterator tmp; + + tmp = iter; + ++tmp; + + /* this will trigger the remove_region_view */ + delete *iter; + + iter = tmp; + } + + rec_regions.clear(); + + // cerr << "\tclear " << rec_rects.size() << " rec rects\n"; + + + /* transport stopped, clear boxes */ + for (vector<RecBoxInfo>::iterator iter=rec_rects.begin(); iter != rec_rects.end(); ++iter) { + RecBoxInfo &rect = (*iter); + delete rect.rectangle; + } + + rec_rects.clear(); + + } + } +} + +void +AudioStreamView::foreach_crossfadeview (void (CrossfadeView::*pmf)(void)) +{ + for (list<CrossfadeView*>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + ((*i)->*pmf) (); + } +} + +void +AudioStreamView::rec_peak_range_ready (jack_nframes_t start, jack_nframes_t cnt, Source * src) +{ + // this is called from the peak building thread + + ENSURE_GUI_THREAD(bind (mem_fun (*this, &AudioStreamView::rec_peak_range_ready), start, cnt, src)); + + if (rec_peak_ready_map.size() == 0 || start+cnt > last_rec_peak_frame) { + last_rec_peak_frame = start + cnt; + } + + rec_peak_ready_map[src] = true; + + if (rec_peak_ready_map.size() == _trackview.get_diskstream()->n_channels()) { + this->update_rec_regions (); + rec_peak_ready_map.clear(); + } +} + +void +AudioStreamView::update_rec_regions () +{ + if (use_rec_regions) { + + uint32_t n = 0; + + for (list<Region*>::iterator iter = rec_regions.begin(); iter != rec_regions.end(); n++) { + + list<Region*>::iterator tmp; + + tmp = iter; + ++tmp; + + if (!canvas_item_visible (rec_rects[n].rectangle)) { + /* rect already hidden, this region is done */ + iter = tmp; + continue; + } + + // FIXME + AudioRegion * region = dynamic_cast<AudioRegion*>(*iter); + assert(region); + + jack_nframes_t origlen = region->length(); + + if (region == rec_regions.back() && rec_active) { + + if (last_rec_peak_frame > region->start()) { + + jack_nframes_t nlen = last_rec_peak_frame - region->start(); + + if (nlen != region->length()) { + + region->freeze (); + region->set_position (_trackview.get_diskstream()->get_capture_start_frame(n), this); + region->set_length (nlen, this); + region->thaw ("updated"); + + if (origlen == 1) { + /* our special initial length */ + add_region_view_internal (region, false); + } + + /* also update rect */ + ArdourCanvas::SimpleRect * rect = rec_rects[n].rectangle; + gdouble xend = _trackview.editor.frame_to_pixel (region->position() + region->length()); + rect->property_x2() = xend; + } + } + + } else { + + jack_nframes_t nlen = _trackview.get_diskstream()->get_captured_frames(n); + + if (nlen != region->length()) { + + if (region->source(0).length() >= region->start() + nlen) { + + region->freeze (); + region->set_position (_trackview.get_diskstream()->get_capture_start_frame(n), this); + region->set_length (nlen, this); + region->thaw ("updated"); + + if (origlen == 1) { + /* our special initial length */ + add_region_view_internal (region, false); + } + + /* also hide rect */ + ArdourCanvas::Item * rect = rec_rects[n].rectangle; + rect->hide(); + + } + } + } + + iter = tmp; + } + } +} + +void +AudioStreamView::show_all_xfades () +{ + foreach_crossfadeview (&CrossfadeView::show); + crossfades_visible = true; +} + +void +AudioStreamView::hide_all_xfades () +{ + foreach_crossfadeview (&CrossfadeView::hide); + crossfades_visible = false; +} + +void +AudioStreamView::hide_xfades_involving (AudioRegionView& rv) +{ + for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + if ((*i)->crossfade.involves (rv.audio_region())) { + (*i)->fake_hide (); + } + } +} + +void +AudioStreamView::reveal_xfades_involving (AudioRegionView& rv) +{ + for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + if ((*i)->crossfade.involves (rv.audio_region()) && (*i)->visible()) { + (*i)->show (); + } + } +} + +void +AudioStreamView::color_handler (ColorID id, uint32_t val) +{ + switch (id) { + case cAudioTrackBase: + if (_trackview.is_track()) { + canvas_rect->property_fill_color_rgba() = val; + } + break; + case cAudioBusBase: + if (!_trackview.is_track()) { + canvas_rect->property_fill_color_rgba() = val; + } + break; + case cAudioTrackOutline: + canvas_rect->property_outline_color_rgba() = val; + break; + + default: + break; + } +} + diff --git a/gtk2_ardour/audio_streamview.h b/gtk2_ardour/audio_streamview.h new file mode 100644 index 0000000000..05ce8125f6 --- /dev/null +++ b/gtk2_ardour/audio_streamview.h @@ -0,0 +1,110 @@ +/* + Copyright (C) 2001, 2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __ardour_audio_streamview_h__ +#define __ardour_audio_streamview_h__ + +#include <list> +#include <map> +#include <cmath> + +#include <ardour/location.h> +#include "enums.h" +#include "simplerect.h" +#include "color.h" +#include "streamview.h" + +namespace Gdk { + class Color; +} + +namespace ARDOUR { + class Route; + class Diskstream; + class Crossfade; + class PeakData; + class AudioRegion; + class Source; +} + +class PublicEditor; +class Selectable; +class AudioTimeAxisView; +class AudioRegionView; +class RegionSelection; +class CrossfadeView; +class Selection; + +class AudioStreamView : public StreamView +{ + public: + AudioStreamView (AudioTimeAxisView&); + ~AudioStreamView (); + + void set_waveform_shape (WaveformShape); + + int set_height (gdouble h); + int set_samples_per_unit (gdouble spp); + + int set_amplitude_above_axis (gdouble app); + gdouble get_amplitude_above_axis () { return _amplitude_above_axis; } + + void set_show_waveforms (bool yn); + void set_show_waveforms_recording (bool yn) { use_rec_regions = yn; } + + void foreach_crossfadeview (void (CrossfadeView::*pmf)(void)); + + void show_all_xfades (); + void hide_all_xfades (); + void hide_xfades_involving (AudioRegionView&); + void reveal_xfades_involving (AudioRegionView&); + + private: + void setup_rec_box (); + void rec_peak_range_ready (jack_nframes_t start, jack_nframes_t cnt, ARDOUR::Source* src); + void update_rec_regions (); + + void add_region_view_internal (ARDOUR::Region*, bool wait_for_waves); + void remove_region_view (ARDOUR::Region* ); + void remove_audio_region_view (ARDOUR::AudioRegion* ); + void remove_audio_rec_region (ARDOUR::AudioRegion*); + + void undisplay_diskstream (); + void redisplay_diskstream (); + void playlist_modified (); + void playlist_changed (ARDOUR::Diskstream *ds); + + void add_crossfade (ARDOUR::Crossfade*); + void remove_crossfade (ARDOUR::Crossfade*); + + void color_handler (ColorID id, uint32_t val); + + + double _amplitude_above_axis; + + typedef list<CrossfadeView*> CrossfadeViewList; + CrossfadeViewList crossfade_views; + bool crossfades_visible; + + list<sigc::connection> peak_ready_connections; + jack_nframes_t last_rec_peak_frame; + map<ARDOUR::Source*, bool> rec_peak_ready_map; + +}; + +#endif /* __ardour_audio_streamview_h__ */ diff --git a/gtk2_ardour/audio_time_axis.cc b/gtk2_ardour/audio_time_axis.cc index 857adff6b9..9ae94d1fe0 100644 --- a/gtk2_ardour/audio_time_axis.cc +++ b/gtk2_ardour/audio_time_axis.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,6 +20,7 @@ #include <cstdlib> #include <cmath> +#include <cassert> #include <algorithm> #include <string> @@ -32,16 +33,15 @@ #include <pbd/whitespace.h> #include <pbd/memento_command.h> -#include <gtkmm2ext/bindable_button.h> #include <gtkmm2ext/gtk_ui.h> #include <gtkmm2ext/selector.h> #include <gtkmm2ext/stop_signal.h> +#include <gtkmm2ext/bindable_button.h> #include <gtkmm2ext/utils.h> #include <ardour/audioplaylist.h> #include <ardour/audio_diskstream.h> #include <ardour/insert.h> -#include <ardour/ladspa_plugin.h> #include <ardour/location.h> #include <ardour/panner.h> #include <ardour/playlist.h> @@ -53,27 +53,20 @@ #include "audio_time_axis.h" #include "automation_gain_line.h" #include "automation_pan_line.h" -#include "automation_time_axis.h" #include "canvas_impl.h" #include "crossfade_view.h" #include "enums.h" #include "gain_automation_time_axis.h" -#include "gui_thread.h" #include "keyboard.h" #include "pan_automation_time_axis.h" #include "playlist_selector.h" #include "plugin_selector.h" #include "plugin_ui.h" -#include "point_selection.h" #include "prompter.h" #include "public_editor.h" -#include "redirect_automation_line.h" -#include "redirect_automation_time_axis.h" -#include "regionview.h" -#include "rgb_macros.h" -#include "selection.h" +#include "audio_region_view.h" #include "simplerect.h" -#include "streamview.h" +#include "audio_streamview.h" #include "utils.h" #include <ardour/audio_track.h> @@ -82,202 +75,76 @@ using namespace ARDOUR; using namespace PBD; -using namespace LADSPA; using namespace Gtk; using namespace Editing; -AudioTimeAxisView::AudioTimeAxisView (PublicEditor& ed, Session& sess, Route& rt, Canvas& canvas) - : AxisView(sess), - RouteUI(rt, sess, _("m"), _("s"), _("r")), // mute, solo, and record - TimeAxisView(sess,ed,(TimeAxisView*) 0, canvas), - parent_canvas (canvas), - button_table (3, 3), - edit_group_button (_("g")), // group - playlist_button (_("p")), - size_button (_("h")), // height - automation_button (_("a")), - visual_button (_("v")) - +AudioTimeAxisView::AudioTimeAxisView (PublicEditor& ed, Session& sess, boost::shared_ptr<Route> rt, Canvas& canvas) + : AxisView(sess) + , RouteTimeAxisView(ed, sess, rt, canvas) { - _has_state = true; + // Make sure things are sane... + assert(!is_track() || is_audio_track()); + subplugin_menu.set_name ("ArdourContextMenu"); - playlist_menu = 0; - playlist_action_menu = 0; - automation_action_menu = 0; gain_track = 0; pan_track = 0; - view = 0; - timestretch_rect = 0; waveform_item = 0; pan_automation_item = 0; gain_automation_item = 0; - no_redraw = false; - view = new StreamView (*this); + _view = new AudioStreamView (*this); add_gain_automation_child (); add_pan_automation_child (); ignore_toggle = false; - rec_enable_button->set_active (false); mute_button->set_active (false); solo_button->set_active (false); - rec_enable_button->set_name ("TrackRecordEnableButton"); - mute_button->set_name ("TrackMuteButton"); - solo_button->set_name ("SoloButton"); - edit_group_button.set_name ("TrackGroupButton"); - playlist_button.set_name ("TrackPlaylistButton"); - automation_button.set_name ("TrackAutomationButton"); - size_button.set_name ("TrackSizeButton"); - visual_button.set_name ("TrackVisualButton"); - hide_button.set_name ("TrackRemoveButton"); - - hide_button.add (*(manage (new Image (get_xpm("small_x.xpm"))))); - - solo_button->signal_button_press_event().connect (mem_fun (*this, &AudioTimeAxisView::select_me), false); - mute_button->signal_button_press_event().connect (mem_fun (*this, &AudioTimeAxisView::select_me), false); - rec_enable_button->signal_button_press_event().connect (mem_fun (*this, &AudioTimeAxisView::select_me), false); - playlist_button.signal_button_press_event().connect (mem_fun (*this, &AudioTimeAxisView::select_me), false); - automation_button.signal_button_press_event().connect (mem_fun (*this, &AudioTimeAxisView::select_me), false); - size_button.signal_button_press_event().connect (mem_fun (*this, &AudioTimeAxisView::select_me), false); - visual_button.signal_button_press_event().connect (mem_fun (*this, &AudioTimeAxisView::select_me), false); - hide_button.signal_button_press_event().connect (mem_fun (*this, &AudioTimeAxisView::select_me), false); - - solo_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::solo_press), false); - solo_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::solo_release), false); - mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press), false); - mute_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::mute_release), false); - rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press)); - edit_group_button.signal_button_release_event().connect (mem_fun(*this, &AudioTimeAxisView::edit_click), false); - playlist_button.signal_clicked().connect (mem_fun(*this, &AudioTimeAxisView::playlist_click)); - automation_button.signal_clicked().connect (mem_fun(*this, &AudioTimeAxisView::automation_click)); - size_button.signal_button_release_event().connect (mem_fun(*this, &AudioTimeAxisView::size_click), false); - visual_button.signal_clicked().connect (mem_fun(*this, &AudioTimeAxisView::visual_click)); - hide_button.signal_clicked().connect (mem_fun(*this, &AudioTimeAxisView::hide_click)); - - if (is_audio_track()) { - controls_table.attach (*rec_enable_button, 5, 6, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); - } - controls_table.attach (*mute_button, 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); - controls_table.attach (*solo_button, 7, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::FILL|Gtk::EXPAND, 0, 0); - - controls_table.attach (edit_group_button, 6, 7, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); - - ARDOUR_UI::instance()->tooltips().set_tip(*rec_enable_button, _("Record")); - ARDOUR_UI::instance()->tooltips().set_tip(*solo_button,_("Solo")); - ARDOUR_UI::instance()->tooltips().set_tip(*mute_button,_("Mute")); - ARDOUR_UI::instance()->tooltips().set_tip(edit_group_button,_("Edit Group")); - ARDOUR_UI::instance()->tooltips().set_tip(size_button,_("Display Height")); - ARDOUR_UI::instance()->tooltips().set_tip(playlist_button,_("Playlist")); - ARDOUR_UI::instance()->tooltips().set_tip(automation_button, _("Automation")); - ARDOUR_UI::instance()->tooltips().set_tip(visual_button, _("Visual options")); - ARDOUR_UI::instance()->tooltips().set_tip(hide_button, _("Hide this track")); - - label_view (); - - controls_table.attach (hide_button, 0, 1, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - controls_table.attach (visual_button, 1, 2, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - controls_table.attach (size_button, 2, 3, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - controls_table.attach (automation_button, 3, 4, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - - if (is_audio_track() && audio_track()->mode() == ARDOUR::Normal) { - controls_table.attach (playlist_button, 5, 6, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - } - - /* remove focus from the buttons */ - - automation_button.unset_flags (Gtk::CAN_FOCUS); - solo_button->unset_flags (Gtk::CAN_FOCUS); - mute_button->unset_flags (Gtk::CAN_FOCUS); - edit_group_button.unset_flags (Gtk::CAN_FOCUS); - size_button.unset_flags (Gtk::CAN_FOCUS); - playlist_button.unset_flags (Gtk::CAN_FOCUS); - hide_button.unset_flags (Gtk::CAN_FOCUS); - visual_button.unset_flags (Gtk::CAN_FOCUS); + if (is_audio_track()) + controls_ebox.set_name ("AudioTimeAxisViewControlsBaseUnselected"); + else // bus + controls_ebox.set_name ("AudioBusControlsBaseUnselected"); /* map current state of the route */ - update_diskstream_display (); - solo_changed(0); - mute_changed(0); redirects_changed (0); reset_redirect_automation_curves (); - y_position = -1; ensure_xml_node (); set_state (*xml_node); - _route.mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)); - _route.solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)); - _route.redirects_changed.connect (mem_fun(*this, &AudioTimeAxisView::redirects_changed)); - _route.name_changed.connect (mem_fun(*this, &AudioTimeAxisView::route_name_changed)); - _route.solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)); - _route.panner().Changed.connect (mem_fun(*this, &AudioTimeAxisView::update_pans)); + _route->panner().Changed.connect (mem_fun(*this, &AudioTimeAxisView::update_pans)); if (is_audio_track()) { - /* track */ - - audio_track()->FreezeChange.connect (mem_fun(*this, &AudioTimeAxisView::map_frozen)); - - audio_track()->diskstream_changed.connect (mem_fun(*this, &AudioTimeAxisView::diskstream_changed)); - get_diskstream()->speed_changed.connect (mem_fun(*this, &AudioTimeAxisView::speed_changed)); - controls_ebox.set_name ("AudioTrackControlsBaseUnselected"); controls_base_selected_name = "AudioTrackControlsBaseSelected"; controls_base_unselected_name = "AudioTrackControlsBaseUnselected"; /* ask for notifications of any new RegionViews */ + _view->RegionViewAdded.connect (mem_fun(*this, &AudioTimeAxisView::region_view_added)); + _view->attach (); - view->AudioRegionViewAdded.connect (mem_fun(*this, &AudioTimeAxisView::region_view_added)); - - view->attach (); - - /* pick up the correct freeze state */ - - map_frozen (); + } else { /* bus */ - } else { - - /* bus */ - - controls_ebox.set_name ("BusControlsBaseUnselected"); - controls_base_selected_name = "BusControlsBaseSelected"; - controls_base_unselected_name = "BusControlsBaseUnselected"; + controls_ebox.set_name ("AudioBusControlsBaseUnselected"); + controls_base_selected_name = "AudioBusControlsBaseSelected"; + controls_base_unselected_name = "AudioBusControlsBaseUnselected"; } - - editor.ZoomChanged.connect (mem_fun(*this, &AudioTimeAxisView::reset_samples_per_unit)); - ColorChanged.connect (mem_fun (*this, &AudioTimeAxisView::color_handler)); } AudioTimeAxisView::~AudioTimeAxisView () { - GoingAway (); /* EMIT_SIGNAL */ - - if (playlist_menu) { - delete playlist_menu; - playlist_menu = 0; - } - - if (playlist_action_menu) { - delete playlist_action_menu; - playlist_action_menu = 0; - } - - vector_delete (&redirect_automation_curves); - - for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { - delete *i; - } +} - if (view) { - delete view; - view = 0; - } +AudioStreamView* +AudioTimeAxisView::audio_view() +{ + return dynamic_cast<AudioStreamView*>(_view); } guint32 @@ -299,233 +166,6 @@ AudioTimeAxisView::hide () } void -AudioTimeAxisView::set_playlist (AudioPlaylist *newplaylist) -{ - AudioPlaylist *pl; - - modified_connection.disconnect (); - state_changed_connection.disconnect (); - - if ((pl = dynamic_cast<AudioPlaylist*> (playlist())) != 0) { - state_changed_connection = pl->StateChanged.connect (mem_fun(*this, &AudioTimeAxisView::playlist_state_changed)); - modified_connection = pl->Modified.connect (mem_fun(*this, &AudioTimeAxisView::playlist_modified)); - } -} - -void -AudioTimeAxisView::playlist_modified () -{ -} - -gint -AudioTimeAxisView::edit_click (GdkEventButton *ev) -{ - if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) { - _route.set_edit_group (0, this); - return FALSE; - } - - using namespace Menu_Helpers; - - MenuList& items = edit_group_menu.items (); - RadioMenuItem::Group group; - - items.clear (); - items.push_back (RadioMenuElem (group, _("No group"), - bind (mem_fun(*this, &AudioTimeAxisView::set_edit_group_from_menu), (RouteGroup *) 0))); - - if (_route.edit_group() == 0) { - static_cast<RadioMenuItem*>(&items.back())->set_active (); - } - - _session.foreach_edit_group (bind (mem_fun (*this, &AudioTimeAxisView::add_edit_group_menu_item), &group)); - edit_group_menu.popup (ev->button, ev->time); - - return FALSE; -} - -void -AudioTimeAxisView::add_edit_group_menu_item (RouteGroup *eg, RadioMenuItem::Group* group) -{ - using namespace Menu_Helpers; - - MenuList &items = edit_group_menu.items(); - - cerr << "adding edit group called " << eg->name() << endl; - - items.push_back (RadioMenuElem (*group, eg->name(), bind (mem_fun(*this, &AudioTimeAxisView::set_edit_group_from_menu), eg))); - if (_route.edit_group() == eg) { - static_cast<RadioMenuItem*>(&items.back())->set_active (); - } -} - -void -AudioTimeAxisView::set_edit_group_from_menu (RouteGroup *eg) - -{ - _route.set_edit_group (eg, this); -} - -void -AudioTimeAxisView::playlist_state_changed (Change ignored) -{ - // ENSURE_GUI_THREAD (bind (mem_fun(*this, &AudioTimeAxisView::playlist_state_changed), ignored)); - // why are we here ? -} - -void -AudioTimeAxisView::playlist_changed () - -{ - label_view (); - - if (is_audio_track()) { - set_playlist (get_diskstream()->playlist()); - } -} - -void -AudioTimeAxisView::label_view () -{ - string x = _route.name(); - - if (x != name_entry.get_text()) { - name_entry.set_text (x); - } - - ARDOUR_UI::instance()->tooltips().set_tip (name_entry, x); -} - -void -AudioTimeAxisView::route_name_changed (void *src) -{ - editor.route_name_changed (this); - label_view (); -} - -void -AudioTimeAxisView::take_name_changed (void *src) - -{ - if (src != this) { - label_view (); - } -} - -void -AudioTimeAxisView::playlist_click () -{ - // always build a new action menu - - if (playlist_action_menu == 0) { - playlist_action_menu = new Menu; - playlist_action_menu->set_name ("ArdourContextMenu"); - } - - build_playlist_menu(playlist_action_menu); - - playlist_action_menu->popup (1, 0); -} - -void -AudioTimeAxisView::automation_click () -{ - if (automation_action_menu == 0) { - /* this seems odd, but the automation action - menu is built as part of the display menu. - */ - build_display_menu (); - } - automation_action_menu->popup (1, 0); -} - -void -AudioTimeAxisView::show_timestretch (jack_nframes_t start, jack_nframes_t end) -{ - double x1; - double x2; - double y2; - - TimeAxisView::show_timestretch (start, end); - - hide_timestretch (); - -#if 0 - if (ts.empty()) { - return; - } - - - /* check that the time selection was made in our route, or our edit group. - remember that edit_group() == 0 implies the route is *not* in a edit group. - */ - - if (!(ts.track == this || (ts.group != 0 && ts.group == _route.edit_group()))) { - /* this doesn't apply to us */ - return; - } - - /* ignore it if our edit group is not active */ - - if ((ts.track != this) && _route.edit_group() && !_route.edit_group()->is_active()) { - return; - } -#endif - - if (timestretch_rect == 0) { - timestretch_rect = new SimpleRect (*canvas_display); - timestretch_rect->property_x1() = 0.0; - timestretch_rect->property_y1() = 0.0; - timestretch_rect->property_x2() = 0.0; - timestretch_rect->property_y2() = 0.0; - timestretch_rect->property_fill_color_rgba() = color_map[cTimeStretchFill]; - timestretch_rect->property_outline_color_rgba() = color_map[cTimeStretchOutline]; - } - - timestretch_rect->show (); - timestretch_rect->raise_to_top (); - - x1 = start / editor.get_current_zoom(); - x2 = (end - 1) / editor.get_current_zoom(); - y2 = height - 2; - - timestretch_rect->property_x1() = x1; - timestretch_rect->property_y1() = 1.0; - timestretch_rect->property_x2() = x2; - timestretch_rect->property_y2() = y2; -} - -void -AudioTimeAxisView::hide_timestretch () -{ - TimeAxisView::hide_timestretch (); - - if (timestretch_rect) { - timestretch_rect->hide (); - } -} - -void -AudioTimeAxisView::show_selection (TimeSelection& ts) -{ - -#if 0 - /* ignore it if our edit group is not active or if the selection was started - in some other track or edit group (remember that edit_group() == 0 means - that the track is not in an edit group). - */ - - if (((ts.track != this && !is_child (ts.track)) && _route.edit_group() && !_route.edit_group()->is_active()) || - (!(ts.track == this || is_child (ts.track) || (ts.group != 0 && ts.group == _route.edit_group())))) { - hide_selection (); - return; - } -#endif - - TimeAxisView::show_selection (ts); -} - -void AudioTimeAxisView::set_state (const XMLNode& node) { const XMLProperty *prop; @@ -578,153 +218,14 @@ AudioTimeAxisView::set_state (const XMLNode& node) } void -AudioTimeAxisView::set_height (TrackHeight h) -{ - bool height_changed = (height == 0) || (h != height_style); - - TimeAxisView::set_height (h); - - ensure_xml_node (); - - view->set_height ((double) height); - - switch (height_style) { - case Largest: - xml_node->add_property ("track_height", "largest"); - show_name_entry (); - hide_name_label (); - controls_table.show_all(); - break; - case Large: - xml_node->add_property ("track_height", "large"); - show_name_entry (); - hide_name_label (); - controls_table.show_all(); - break; - case Larger: - xml_node->add_property ("track_height", "larger"); - show_name_entry (); - hide_name_label (); - controls_table.show_all(); - break; - case Normal: - xml_node->add_property ("track_height", "normal"); - show_name_entry (); - hide_name_label (); - controls_table.show_all(); - break; - case Smaller: - xml_node->add_property ("track_height", "smaller"); - controls_table.show_all (); - show_name_entry (); - hide_name_label (); - edit_group_button.hide (); - hide_button.hide (); - visual_button.hide (); - size_button.hide (); - automation_button.hide (); - playlist_button.hide (); - break; - case Small: - xml_node->add_property ("track_height", "small"); - controls_table.hide_all (); - controls_table.show (); - hide_name_entry (); - show_name_label (); - name_label.set_text (_route.name()); - break; - } - - if (height_changed) { - /* only emit the signal if the height really changed */ - _route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ - } -} - -void -AudioTimeAxisView::select_track_color () -{ - if (RouteUI::choose_color ()) { - - if (view) { - view->apply_color (_color, StreamView::RegionColor); - } - } -} - -void -AudioTimeAxisView::reset_redirect_automation_curves () -{ - for (vector<RedirectAutomationLine*>::iterator i = redirect_automation_curves.begin(); i != redirect_automation_curves.end(); ++i) { - (*i)->reset(); - } -} - -void -AudioTimeAxisView::reset_samples_per_unit () -{ - set_samples_per_unit (editor.get_current_zoom()); -} - -void -AudioTimeAxisView::set_samples_per_unit (double spu) -{ - double speed = 1.0; - - if (get_diskstream() != 0) { - speed = get_diskstream()->speed(); - } - - if (view) { - view->set_samples_per_unit (spu * speed); - } - - TimeAxisView::set_samples_per_unit (spu * speed); -} - -void -AudioTimeAxisView::build_display_menu () +AudioTimeAxisView::build_automation_action_menu () { using namespace Menu_Helpers; - /* get the size menu ready */ - - build_size_menu (); - - /* prepare it */ - - TimeAxisView::build_display_menu (); - - /* now fill it with our stuff */ - - MenuList& items = display_menu->items(); - display_menu->set_name ("ArdourContextMenu"); - - items.push_back (MenuElem (_("Height"), *size_menu)); - items.push_back (MenuElem (_("Color"), mem_fun(*this, &AudioTimeAxisView::select_track_color))); - - - items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Hide all crossfades"), mem_fun(*this, &AudioTimeAxisView::hide_all_xfades))); - items.push_back (MenuElem (_("Show all crossfades"), mem_fun(*this, &AudioTimeAxisView::show_all_xfades))); - items.push_back (SeparatorElem()); - - build_remote_control_menu (); - items.push_back (MenuElem (_("Remote Control ID"), *remote_control_menu)); + RouteTimeAxisView::build_automation_action_menu (); - automation_action_menu = manage (new Menu); MenuList& automation_items = automation_action_menu->items(); - automation_action_menu->set_name ("ArdourContextMenu"); - automation_items.push_back (MenuElem (_("Show all automation"), - mem_fun(*this, &AudioTimeAxisView::show_all_automation))); - - automation_items.push_back (MenuElem (_("Show existing automation"), - mem_fun(*this, &AudioTimeAxisView::show_existing_automation))); - - automation_items.push_back (MenuElem (_("Hide all automation"), - mem_fun(*this, &AudioTimeAxisView::hide_all_automation))); - automation_items.push_back (SeparatorElem()); automation_items.push_back (CheckMenuElem (_("Fader"), @@ -736,11 +237,21 @@ AudioTimeAxisView::build_display_menu () mem_fun(*this, &AudioTimeAxisView::toggle_pan_track))); pan_automation_item = static_cast<CheckMenuItem*> (&automation_items.back()); pan_automation_item->set_active(show_pan_automation); + +} + +void +AudioTimeAxisView::append_extra_display_menu_items () +{ + using namespace Menu_Helpers; - automation_items.push_back (MenuElem (_("Plugins"), subplugin_menu)); + MenuList& items = display_menu->items(); - items.push_back (MenuElem (_("Automation"), *automation_action_menu)); + // crossfade stuff + items.push_back (MenuElem (_("Hide all crossfades"), mem_fun(*this, &AudioTimeAxisView::hide_all_xfades))); + items.push_back (MenuElem (_("Show all crossfades"), mem_fun(*this, &AudioTimeAxisView::show_all_xfades))); + // waveform menu Menu *waveform_menu = manage(new Menu); MenuList& waveform_items = waveform_menu->items(); waveform_menu->set_name ("ArdourContextMenu"); @@ -760,401 +271,55 @@ AudioTimeAxisView::build_display_menu () rectified_item = static_cast<RadioMenuItem *> (&waveform_items.back()); items.push_back (MenuElem (_("Waveform"), *waveform_menu)); - - if (is_audio_track()) { - - Menu* alignment_menu = manage (new Menu); - MenuList& alignment_items = alignment_menu->items(); - alignment_menu->set_name ("ArdourContextMenu"); - - RadioMenuItem::Group align_group; - - alignment_items.push_back (RadioMenuElem (align_group, _("Align with existing material"), bind (mem_fun(*this, &AudioTimeAxisView::set_align_style), ExistingMaterial))); - align_existing_item = dynamic_cast<RadioMenuItem*>(&alignment_items.back()); - if (get_diskstream()->alignment_style() == ExistingMaterial) { - align_existing_item->set_active(); - } - alignment_items.push_back (RadioMenuElem (align_group, _("Align with capture time"), bind (mem_fun(*this, &AudioTimeAxisView::set_align_style), CaptureTime))); - align_capture_item = dynamic_cast<RadioMenuItem*>(&alignment_items.back()); - if (get_diskstream()->alignment_style() == CaptureTime) { - align_capture_item->set_active(); - } - - items.push_back (MenuElem (_("Alignment"), *alignment_menu)); - - get_diskstream()->AlignmentStyleChanged.connect (mem_fun(*this, &AudioTimeAxisView::align_style_changed)); - } - - items.push_back (SeparatorElem()); - items.push_back (CheckMenuElem (_("Active"), mem_fun(*this, &RouteUI::toggle_route_active))); - route_active_menu_item = dynamic_cast<CheckMenuItem *> (&items.back()); - route_active_menu_item->set_active (_route.active()); - - items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Remove"), mem_fun(*this, &RouteUI::remove_this_route))); - -} - -void -AudioTimeAxisView::align_style_changed () -{ - switch (get_diskstream()->alignment_style()) { - case ExistingMaterial: - if (!align_existing_item->get_active()) { - align_existing_item->set_active(); - } - break; - case CaptureTime: - if (!align_capture_item->get_active()) { - align_capture_item->set_active(); - } - break; - } -} - -void -AudioTimeAxisView::set_align_style (AlignStyle style) -{ - get_diskstream()->set_align_style (style); -} - -void -AudioTimeAxisView::rename_current_playlist () -{ - ArdourPrompter prompter (true); - string name; - - AudioPlaylist *pl; - AudioDiskstream *ds; - - if (((ds = get_diskstream()) == 0) || ds->destructive() || ((pl = ds->playlist()) == 0)) { - return; - } - - prompter.set_prompt (_("Name for playlist")); - prompter.set_initial_text (pl->name()); - prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT); - prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false); - - switch (prompter.run ()) { - case Gtk::RESPONSE_ACCEPT: - prompter.get_result (name); - if (name.length()) { - pl->set_name (name); - } - break; - - default: - break; - } -} - -void -AudioTimeAxisView::use_copy_playlist (bool prompt) -{ - AudioPlaylist *pl; - AudioDiskstream *ds; - string name; - - if (((ds = get_diskstream()) == 0) || ds->destructive() || ((pl = ds->playlist()) == 0)) { - return; - } - - name = Playlist::bump_name (pl->name(), _session); - - if (prompt) { - - ArdourPrompter prompter (true); - - prompter.set_prompt (_("Name for Playlist")); - prompter.set_initial_text (name); - prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT); - prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false); - prompter.show_all (); - - switch (prompter.run ()) { - case Gtk::RESPONSE_ACCEPT: - prompter.get_result (name); - break; - - default: - return; - } - } - - if (name.length()) { - ds->use_copy_playlist (); - pl = ds->playlist(); - pl->set_name (name); - } -} - -void -AudioTimeAxisView::use_new_playlist (bool prompt) -{ - AudioPlaylist *pl; - AudioDiskstream *ds; - string name; - - if (((ds = get_diskstream()) == 0) || ds->destructive() || ((pl = ds->playlist()) == 0)) { - return; - } - - name = Playlist::bump_name (pl->name(), _session); - - if (prompt) { - - ArdourPrompter prompter (true); - - prompter.set_prompt (_("Name for Playlist")); - prompter.set_initial_text (name); - prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT); - prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false); - - switch (prompter.run ()) { - case Gtk::RESPONSE_ACCEPT: - prompter.get_result (name); - break; - - default: - return; - } - } - - if (name.length()) { - ds->use_new_playlist (); - pl = ds->playlist(); - pl->set_name (name); - } -} - -void -AudioTimeAxisView::clear_playlist () -{ - AudioPlaylist *pl; - AudioDiskstream *ds; - - if ((ds = get_diskstream()) != 0) { - if ((pl = ds->playlist()) != 0) { - editor.clear_playlist (*pl); - } - } } void AudioTimeAxisView::toggle_waveforms () { - if (view && waveform_item && !ignore_toggle) { - view->set_show_waveforms (waveform_item->get_active()); + AudioStreamView* asv = audio_view(); + assert(asv); + + if (asv && waveform_item && !ignore_toggle) { + asv->set_show_waveforms (waveform_item->get_active()); } } void AudioTimeAxisView::set_show_waveforms (bool yn) { + AudioStreamView* asv = audio_view(); + assert(asv); + if (waveform_item) { waveform_item->set_active (yn); } else { - view->set_show_waveforms (yn); + asv->set_show_waveforms (yn); } } void AudioTimeAxisView::set_show_waveforms_recording (bool yn) { - if (view) { - view->set_show_waveforms_recording (yn); - } -} + AudioStreamView* asv = audio_view(); -void -AudioTimeAxisView::set_waveform_shape (WaveformShape shape) -{ - if (view) { - view->set_waveform_shape (shape); + if (asv) { + asv->set_show_waveforms_recording (yn); } } void -AudioTimeAxisView::speed_changed () -{ - Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &AudioTimeAxisView::reset_samples_per_unit)); -} - -void -AudioTimeAxisView::diskstream_changed (void *src) -{ - Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &AudioTimeAxisView::update_diskstream_display)); -} - -void -AudioTimeAxisView::update_diskstream_display () +AudioTimeAxisView::set_waveform_shape (WaveformShape shape) { - AudioDiskstream *ds; + AudioStreamView* asv = audio_view(); - if ((ds = get_diskstream()) != 0) { - set_playlist (ds->playlist ()); + if (asv) { + asv->set_waveform_shape (shape); } map_frozen (); } void -AudioTimeAxisView::selection_click (GdkEventButton* ev) -{ - PublicEditor::TrackViewList* tracks = editor.get_valid_views (this, _route.edit_group()); - - switch (Keyboard::selection_type (ev->state)) { - case Selection::Toggle: - /* XXX this is not right */ - editor.get_selection().add (*tracks); - break; - - case Selection::Set: - editor.get_selection().set (*tracks); - break; - - case Selection::Extend: - /* not defined yet */ - break; - } - - delete tracks; -} - -void -AudioTimeAxisView::set_selected_regionviews (AudioRegionSelection& regions) -{ - if (view) { - view->set_selected_regionviews (regions); - } -} - -void -AudioTimeAxisView::set_selected_points (PointSelection& points) -{ - for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) { - (*i)->set_selected_points (points); - } -} - -void -AudioTimeAxisView::get_selectables (jack_nframes_t start, jack_nframes_t end, double top, double bot, list<Selectable*>& results) -{ - double speed = 1.0; - - if (get_diskstream() != 0) { - speed = get_diskstream()->speed(); - } - - jack_nframes_t start_adjusted = session_frame_to_track_frame(start, speed); - jack_nframes_t end_adjusted = session_frame_to_track_frame(end, speed); - - if (view && ((top < 0.0 && bot < 0.0)) || touched (top, bot)) { - view->get_selectables (start_adjusted, end_adjusted, results); - } - - /* pick up visible automation tracks */ - - for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) { - if (!(*i)->hidden()) { - (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results); - } - } -} - -void -AudioTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& results) -{ - if (view) { - view->get_inverted_selectables (sel, results); - } - - for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) { - if (!(*i)->hidden()) { - (*i)->get_inverted_selectables (sel, results); - } - } - - return; -} - -RouteGroup* -AudioTimeAxisView::edit_group() const -{ - return _route.edit_group(); -} - -string -AudioTimeAxisView::name() const -{ - return _route.name(); -} - -Playlist * -AudioTimeAxisView::playlist () const -{ - AudioDiskstream *ds; - - if ((ds = get_diskstream()) != 0) { - return ds->playlist(); - } else { - return 0; - } -} - -void -AudioTimeAxisView::name_entry_changed () -{ - string x; - - x = name_entry.get_text (); - - if (x == _route.name()) { - return; - } - - if (x.length() == 0) { - name_entry.set_text (_route.name()); - return; - } - - strip_whitespace_edges(x); - - if (_session.route_name_unique (x)) { - _route.set_name (x, this); - } else { - ARDOUR_UI::instance()->popup_error (_("a track already exists with that name")); - name_entry.set_text (_route.name()); - } -} - -void -AudioTimeAxisView::visual_click () -{ - popup_display_menu (0); -} - -void -AudioTimeAxisView::hide_click () -{ - editor.hide_track_in_display (*this); -} - -Region* -AudioTimeAxisView::find_next_region (jack_nframes_t pos, RegionPoint point, int32_t dir) -{ - AudioDiskstream *stream; - AudioPlaylist *playlist; - - if ((stream = get_diskstream()) != 0 && (playlist = stream->playlist()) != 0) { - return playlist->find_next_region (pos, point, dir); - } - - return 0; -} - -void AudioTimeAxisView::add_gain_automation_child () { XMLProperty* prop; @@ -1166,13 +331,13 @@ AudioTimeAxisView::add_gain_automation_child () *this, parent_canvas, _("gain"), - _route.gain_automation_curve()); + _route->gain_automation_curve()); line = new AutomationGainLine ("automation gain", _session, *gain_track, *gain_track->canvas_display, - _route.gain_automation_curve()); + _route->gain_automation_curve()); line->set_line_color (color_map[cAutomationLine]); @@ -1241,11 +406,11 @@ AudioTimeAxisView::update_pans () /* we don't draw lines for "greater than stereo" panning. */ - if (_route.n_outputs() > 2) { + if (_route->n_outputs() > 2) { return; } - for (p = _route.panner().begin(); p != _route.panner().end(); ++p) { + for (p = _route->panner().begin(); p != _route->panner().end(); ++p) { AutomationLine* line; @@ -1253,7 +418,7 @@ AudioTimeAxisView::update_pans () *pan_track->canvas_display, (*p)->automation()); - if (p == _route.panner().begin()) { + if (p == _route->panner().begin()) { /* first line is a nice orange */ line->set_line_color (color_map[cLeftPanAutomationLine]); } else { @@ -1285,7 +450,7 @@ AudioTimeAxisView::toggle_gain_track () /* now trigger a redisplay */ if (!no_redraw) { - _route.gui_changed (X_("track_height"), (void *) 0); /* EMIT_SIGNAL */ + _route->gui_changed (X_("track_height"), (void *) 0); /* EMIT_SIGNAL */ } } } @@ -1299,7 +464,7 @@ AudioTimeAxisView::gain_hidden () gain_automation_item->set_active (false); } - _route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ } void @@ -1321,7 +486,7 @@ AudioTimeAxisView::toggle_pan_track () /* now trigger a redisplay */ if (!no_redraw) { - _route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ } } } @@ -1335,322 +500,7 @@ AudioTimeAxisView::pan_hidden () pan_automation_item->set_active (false); } - _route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ -} - -AudioTimeAxisView::RedirectAutomationInfo::~RedirectAutomationInfo () -{ - for (vector<RedirectAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) { - delete *i; - } -} - - -AudioTimeAxisView::RedirectAutomationNode::~RedirectAutomationNode () -{ - parent.remove_ran (this); - - if (view) { - delete view; - } -} - -void -AudioTimeAxisView::remove_ran (RedirectAutomationNode* ran) -{ - if (ran->view) { - remove_child (ran->view); - } -} - -AudioTimeAxisView::RedirectAutomationNode* -AudioTimeAxisView::find_redirect_automation_node (Redirect *redirect, uint32_t what) -{ - for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { - - if ((*i)->redirect == redirect) { - - for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { - if ((*ii)->what == what) { - return *ii; - } - } - } - } - - return 0; -} - -static string -legalize_for_xml_node (string str) -{ - string::size_type pos; - string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+=:"; - string legal; - - legal = str; - pos = 0; - - while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) { - legal.replace (pos, 1, "_"); - pos += 1; - } - - return legal; -} - - -void -AudioTimeAxisView::add_redirect_automation_curve (Redirect *redirect, uint32_t what) -{ - RedirectAutomationLine* ral; - string name; - RedirectAutomationNode* ran; - - if ((ran = find_redirect_automation_node (redirect, what)) == 0) { - fatal << _("programming error: ") - << string_compose (X_("redirect automation curve for %1:%2 not registered with audio track!"), - redirect->name(), what) - << endmsg; - /*NOTREACHED*/ - return; - } - - if (ran->view) { - return; - } - - name = redirect->describe_parameter (what); - - /* create a string that is a legal XML node name that can be used to refer to this redirect+port combination */ - - char state_name[256]; - snprintf (state_name, sizeof (state_name), "Redirect-%s-%" PRIu32, legalize_for_xml_node (redirect->name()).c_str(), what); - - ran->view = new RedirectAutomationTimeAxisView (_session, _route, editor, *this, parent_canvas, name, what, *redirect, state_name); - - ral = new RedirectAutomationLine (name, - *redirect, what, _session, *ran->view, - *ran->view->canvas_display, redirect->automation_list (what)); - - ral->set_line_color (color_map[cRedirectAutomationLine]); - ral->queue_reset (); - - ran->view->add_line (*ral); - - ran->view->Hiding.connect (bind (mem_fun(*this, &AudioTimeAxisView::redirect_automation_track_hidden), ran, redirect)); - - if (!ran->view->marked_for_display()) { - ran->view->hide (); - } else { - ran->menu_item->set_active (true); - } - - add_child (ran->view); - - view->foreach_regionview (bind (mem_fun(*this, &AudioTimeAxisView::add_ghost_to_redirect), ran->view)); - - redirect->mark_automation_visible (what, true); -} - -void -AudioTimeAxisView::redirect_automation_track_hidden (AudioTimeAxisView::RedirectAutomationNode* ran, Redirect* r) -{ - if (!_hidden) { - ran->menu_item->set_active (false); - } - - r->mark_automation_visible (ran->what, false); - - _route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ -} - -void -AudioTimeAxisView::add_existing_redirect_automation_curves (Redirect *redirect) -{ - set<uint32_t> s; - RedirectAutomationLine *ral; - - redirect->what_has_visible_automation (s); - - for (set<uint32_t>::iterator i = s.begin(); i != s.end(); ++i) { - - if ((ral = find_redirect_automation_curve (redirect, *i)) != 0) { - ral->queue_reset (); - } else { - add_redirect_automation_curve (redirect, (*i)); - } - } -} - -void -AudioTimeAxisView::add_redirect_to_subplugin_menu (Redirect* r) -{ - using namespace Menu_Helpers; - RedirectAutomationInfo *rai; - list<RedirectAutomationInfo*>::iterator x; - - const std::set<uint32_t>& automatable = r->what_can_be_automated (); - std::set<uint32_t> has_visible_automation; - - r->what_has_visible_automation(has_visible_automation); - - if (automatable.empty()) { - return; - } - - for (x = redirect_automation.begin(); x != redirect_automation.end(); ++x) { - if ((*x)->redirect == r) { - break; - } - } - - if (x == redirect_automation.end()) { - - rai = new RedirectAutomationInfo (r); - redirect_automation.push_back (rai); - - } else { - - rai = *x; - - } - - /* any older menu was deleted at the top of redirects_changed() - when we cleared the subplugin menu. - */ - - rai->menu = manage (new Menu); - MenuList& items = rai->menu->items(); - rai->menu->set_name ("ArdourContextMenu"); - - items.clear (); - - for (std::set<uint32_t>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) { - - RedirectAutomationNode* ran; - CheckMenuItem* mitem; - - string name = r->describe_parameter (*i); - - items.push_back (CheckMenuElem (name)); - mitem = dynamic_cast<CheckMenuItem*> (&items.back()); - - if (has_visible_automation.find((*i)) != has_visible_automation.end()) { - mitem->set_active(true); - } - - if ((ran = find_redirect_automation_node (r, *i)) == 0) { - - /* new item */ - - ran = new RedirectAutomationNode (*i, mitem, *this); - - rai->lines.push_back (ran); - - } else { - - ran->menu_item = mitem; - - } - - mitem->signal_toggled().connect (bind (mem_fun(*this, &AudioTimeAxisView::redirect_menu_item_toggled), rai, ran)); - } - - /* add the menu for this redirect, because the subplugin - menu is always cleared at the top of redirects_changed(). - this is the result of some poor design in gtkmm and/or - GTK+. - */ - - subplugin_menu.items().push_back (MenuElem (r->name(), *rai->menu)); - rai->valid = true; -} - -void -AudioTimeAxisView::redirect_menu_item_toggled (AudioTimeAxisView::RedirectAutomationInfo* rai, - AudioTimeAxisView::RedirectAutomationNode* ran) -{ - bool showit = ran->menu_item->get_active(); - bool redraw = false; - - if (ran->view == 0 && showit) { - add_redirect_automation_curve (rai->redirect, ran->what); - redraw = true; - } - - if (showit != ran->view->marked_for_display()) { - - if (showit) { - ran->view->set_marked_for_display (true); - ran->view->canvas_display->show(); - } else { - rai->redirect->mark_automation_visible (ran->what, true); - ran->view->set_marked_for_display (false); - ran->view->hide (); - } - - redraw = true; - - } - - if (redraw && !no_redraw) { - - /* now trigger a redisplay */ - - _route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ - - } -} - -void -AudioTimeAxisView::redirects_changed (void *src) -{ - using namespace Menu_Helpers; - - for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { - (*i)->valid = false; - } - - subplugin_menu.items().clear (); - - _route.foreach_redirect (this, &AudioTimeAxisView::add_redirect_to_subplugin_menu); - _route.foreach_redirect (this, &AudioTimeAxisView::add_existing_redirect_automation_curves); - - for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ) { - - list<RedirectAutomationInfo*>::iterator tmp; - - tmp = i; - ++tmp; - - if (!(*i)->valid) { - - delete *i; - redirect_automation.erase (i); - - } - - i = tmp; - } - - /* change in visibility was possible */ - - _route.gui_changed ("track_height", this); -} - -RedirectAutomationLine * -AudioTimeAxisView::find_redirect_automation_curve (Redirect *redirect, uint32_t what) -{ - RedirectAutomationNode* ran; - - if ((ran = find_redirect_automation_node (redirect, what)) != 0) { - if (ran->view) { - return dynamic_cast<RedirectAutomationLine*> (ran->view->lines.front()); - } - } - - return 0; + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ } void @@ -1661,19 +511,11 @@ AudioTimeAxisView::show_all_automation () pan_automation_item->set_active (true); gain_automation_item->set_active (true); - for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { - for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { - if ((*ii)->view == 0) { - add_redirect_automation_curve ((*i)->redirect, (*ii)->what); - } - - (*ii)->menu_item->set_active (true); - } - } + RouteTimeAxisView::show_all_automation (); no_redraw = false; - _route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ } void @@ -1684,17 +526,11 @@ AudioTimeAxisView::show_existing_automation () pan_automation_item->set_active (true); gain_automation_item->set_active (true); - for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { - for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { - if ((*ii)->view != 0) { - (*ii)->menu_item->set_active (true); - } - } - } + RouteTimeAxisView::show_existing_automation (); no_redraw = false; - _route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ } void @@ -1705,236 +541,61 @@ AudioTimeAxisView::hide_all_automation () pan_automation_item->set_active (false); gain_automation_item->set_active (false); - for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { - for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { - (*ii)->menu_item->set_active (false); - } - } + RouteTimeAxisView::hide_all_automation(); no_redraw = false; - _route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ -} - -bool -AudioTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) -{ - Playlist* what_we_got; - AudioDiskstream* ds = get_diskstream(); - Playlist* playlist; - bool ret = false; - - if (ds == 0) { - /* route is a bus, not a track */ - return false; - } - - playlist = ds->playlist(); - - - TimeSelection time (selection.time); - float speed = ds->speed(); - if (speed != 1.0f) { - for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) { - (*i).start = session_frame_to_track_frame((*i).start, speed); - (*i).end = session_frame_to_track_frame((*i).end, speed); - } - } - - XMLNode &before = playlist->get_state(); - switch (op) { - case Cut: - if ((what_we_got = playlist->cut (time)) != 0) { - editor.get_cut_buffer().add (what_we_got); - XMLNode &after = playlist->get_state(); - _session.add_command (new MementoCommand<Playlist>(*playlist, before, after)); - ret = true; - } - break; - case Copy: - if ((what_we_got = playlist->copy (time)) != 0) { - editor.get_cut_buffer().add (what_we_got); - } - break; - - case Clear: - if ((what_we_got = playlist->cut (time)) != 0) { - XMLNode &after = playlist->get_state(); - _session.add_command(new MementoCommand<Playlist>(*playlist, before, after)); - what_we_got->unref (); - ret = true; - } - break; - } - - return ret; -} - -bool -AudioTimeAxisView::paste (jack_nframes_t pos, float times, Selection& selection, size_t nth) -{ - if (!is_audio_track()) { - return false; - } - - Playlist* playlist = get_diskstream()->playlist(); - PlaylistSelection::iterator p; - - for (p = selection.playlists.begin(); p != selection.playlists.end() && nth; ++p, --nth); - - if (p == selection.playlists.end()) { - return false; - } - - if (get_diskstream()->speed() != 1.0f) - pos = session_frame_to_track_frame(pos, get_diskstream()->speed() ); - - XMLNode &before = playlist->get_state(); - playlist->paste (**p, pos, times); - _session.add_command(new MementoCommand<Playlist>(*playlist, before, - playlist->get_state())); - - return true; -} - -void -AudioTimeAxisView::region_view_added (AudioRegionView* arv) -{ - for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) { - AutomationTimeAxisView* atv; - - if ((atv = dynamic_cast<AutomationTimeAxisView*> (*i)) != 0) { - arv->add_ghost (*atv); - } - } -} - -void -AudioTimeAxisView::add_ghost_to_redirect (AudioRegionView* arv, AutomationTimeAxisView* atv) -{ - arv->add_ghost (*atv); -} - -list<TimeAxisView*> -AudioTimeAxisView::get_child_list() -{ - - list<TimeAxisView*>redirect_children; - - for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) { - if (!(*i)->hidden()) { - redirect_children.push_back(*i); - } - } - return redirect_children; -} - - -void -AudioTimeAxisView::build_playlist_menu (Gtk::Menu * menu) -{ - using namespace Menu_Helpers; - - if (!menu || !is_audio_track()) { - return; - } - - MenuList& playlist_items = menu->items(); - menu->set_name ("ArdourContextMenu"); - playlist_items.clear(); - - if (playlist_menu) { - delete playlist_menu; - } - playlist_menu = new Menu; - playlist_menu->set_name ("ArdourContextMenu"); - - playlist_items.push_back (MenuElem (string_compose (_("Current: %1"), get_diskstream()->playlist()->name()))); - playlist_items.push_back (SeparatorElem()); - - playlist_items.push_back (MenuElem (_("Rename"), mem_fun(*this, &AudioTimeAxisView::rename_current_playlist))); - playlist_items.push_back (SeparatorElem()); - - playlist_items.push_back (MenuElem (_("New"), mem_fun(editor, &PublicEditor::new_playlists))); - playlist_items.push_back (MenuElem (_("New Copy"), mem_fun(editor, &PublicEditor::copy_playlists))); - playlist_items.push_back (SeparatorElem()); - playlist_items.push_back (MenuElem (_("Clear Current"), mem_fun(editor, &PublicEditor::clear_playlists))); - playlist_items.push_back (SeparatorElem()); - playlist_items.push_back (MenuElem(_("Select"), mem_fun(*this, &AudioTimeAxisView::show_playlist_selector))); - -} - -void -AudioTimeAxisView::show_playlist_selector () -{ - editor.playlist_selector().show_for (this); -} - - -void -AudioTimeAxisView::map_frozen () -{ - if (!is_audio_track()) { - return; - } - - ENSURE_GUI_THREAD (mem_fun(*this, &AudioTimeAxisView::map_frozen)); - - - switch (audio_track()->freeze_state()) { - case AudioTrack::Frozen: - playlist_button.set_sensitive (false); - rec_enable_button->set_sensitive (false); - break; - default: - playlist_button.set_sensitive (true); - rec_enable_button->set_sensitive (true); - break; - } + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ } void AudioTimeAxisView::show_all_xfades () { - if (view) { - view->show_all_xfades (); + AudioStreamView* asv = audio_view(); + + if (asv) { + asv->show_all_xfades (); } } void AudioTimeAxisView::hide_all_xfades () { - if (view) { - view->hide_all_xfades (); + AudioStreamView* asv = audio_view(); + + if (asv) { + asv->hide_all_xfades (); } } void AudioTimeAxisView::hide_dependent_views (TimeAxisViewItem& tavi) { + AudioStreamView* asv = audio_view(); AudioRegionView* rv; - if (view && (rv = dynamic_cast<AudioRegionView*>(&tavi)) != 0) { - view->hide_xfades_involving (*rv); + if (asv && (rv = dynamic_cast<AudioRegionView*>(&tavi)) != 0) { + asv->hide_xfades_involving (*rv); } } void AudioTimeAxisView::reveal_dependent_views (TimeAxisViewItem& tavi) { + AudioStreamView* asv = audio_view(); AudioRegionView* rv; - if (view && (rv = dynamic_cast<AudioRegionView*>(&tavi)) != 0) { - view->reveal_xfades_involving (*rv); + if (asv && (rv = dynamic_cast<AudioRegionView*>(&tavi)) != 0) { + asv->reveal_xfades_involving (*rv); } } void AudioTimeAxisView::route_active_changed () { - RouteUI::route_active_changed (); + RouteTimeAxisView::route_active_changed (); if (is_audio_track()) { - if (_route.active()) { + if (_route->active()) { controls_ebox.set_name ("AudioTrackControlsBaseUnselected"); controls_base_selected_name = "AudioTrackControlsBaseSelected"; controls_base_unselected_name = "AudioTrackControlsBaseUnselected"; @@ -1944,7 +605,7 @@ AudioTimeAxisView::route_active_changed () controls_base_unselected_name = "AudioTrackControlsBaseInactiveUnselected"; } } else { - if (_route.active()) { + if (_route->active()) { controls_ebox.set_name ("BusControlsBaseUnselected"); controls_base_selected_name = "BusControlsBaseSelected"; controls_base_unselected_name = "BusControlsBaseUnselected"; @@ -1962,24 +623,3 @@ AudioTimeAxisView::get_child_xml_node (const string & childname) return RouteUI::get_child_xml_node (childname); } -void -AudioTimeAxisView::color_handler (ColorID id, uint32_t val) -{ - switch (id) { - case cTimeStretchOutline: - timestretch_rect->property_outline_color_rgba() = val; - break; - case cTimeStretchFill: - timestretch_rect->property_fill_color_rgba() = val; - break; - default: - break; - } -} - -bool -AudioTimeAxisView::select_me (GdkEventButton* ev) -{ - editor.get_selection().add (this); - return false; -} diff --git a/gtk2_ardour/audio_time_axis.h b/gtk2_ardour/audio_time_axis.h index b319d0ea99..2162771285 100644 --- a/gtk2_ardour/audio_time_axis.h +++ b/gtk2_ardour/audio_time_axis.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,8 +18,8 @@ $Id$ */ -#ifndef __ardour_trackview_h__ -#define __ardour_trackview_h__ +#ifndef __ardour_audio_time_axis_h__ +#define __ardour_audio_time_axis_h__ #include <gtkmm/table.h> #include <gtkmm/button.h> @@ -33,19 +33,14 @@ #include <list> #include <ardour/types.h> -#include <ardour/region.h> #include "ardour_dialog.h" #include "route_ui.h" #include "enums.h" -#include "time_axis_view.h" +#include "route_time_axis.h" #include "canvas.h" #include "color.h" -namespace ALSA { - class MultiChannelDevice; -} - namespace ARDOUR { class Session; class AudioDiskstream; @@ -56,247 +51,58 @@ namespace ARDOUR { class AudioPlaylist; } -namespace LADSPA { - class Manager; - class Plugin; -} - class PublicEditor; class AudioThing; -class StreamView; +class AudioStreamView; class Selection; class Selectable; +class RegionView; class AudioRegionView; class AutomationLine; class AutomationGainLine; class AutomationPanLine; -class RedirectAutomationLine; class TimeSelection; class AutomationTimeAxisView; -class AudioTimeAxisView : public RouteUI, public TimeAxisView +class AudioTimeAxisView : public RouteTimeAxisView { public: - AudioTimeAxisView (PublicEditor&, ARDOUR::Session&, ARDOUR::Route&, ArdourCanvas::Canvas& canvas); + AudioTimeAxisView (PublicEditor&, ARDOUR::Session&, boost::shared_ptr<ARDOUR::Route>, ArdourCanvas::Canvas& canvas); virtual ~AudioTimeAxisView (); + + AudioStreamView* audio_view(); - void show_selection (TimeSelection&); - void automation_control_point_changed (ARDOUR::AutomationType); - - void set_samples_per_unit (double); - void set_height (TimeAxisView::TrackHeight); void set_show_waveforms (bool yn); void set_show_waveforms_recording (bool yn); - void show_timestretch (jack_nframes_t start, jack_nframes_t end); - void hide_timestretch (); - void selection_click (GdkEventButton*); - void set_selected_regionviews (AudioRegionSelection&); - void set_selected_points (PointSelection&); - void get_selectables (jack_nframes_t start, jack_nframes_t end, double top, double bot, list<Selectable *>&); - void get_inverted_selectables (Selection&, list<Selectable*>&); void show_all_xfades (); void hide_all_xfades (); void hide_dependent_views (TimeAxisViewItem&); void reveal_dependent_views (TimeAxisViewItem&); - ARDOUR::Region* find_next_region (jack_nframes_t pos, ARDOUR::RegionPoint, int32_t dir); - - string name() const; - - ARDOUR::RouteGroup* edit_group() const; - - void build_playlist_menu (Gtk::Menu *); - ARDOUR::Playlist* playlist() const; - - /* overridden from parent to store display state */ + /* Overridden from parent to store display state */ guint32 show_at (double y, int& nth, Gtk::VBox *parent); void hide (); - /* need accessors/mutators */ - - StreamView *view; - - /* editing operations */ - - bool cut_copy_clear (Selection&, Editing::CutCopyOp); - bool paste (jack_nframes_t, float times, Selection&, size_t nth); - - list<TimeAxisView*>get_child_list(); - void set_state (const XMLNode&); XMLNode* get_child_xml_node (const string & childname); - /* the editor calls these when mapping an operation across multiple tracks */ - - void use_new_playlist (bool prompt); - void use_copy_playlist (bool prompt); - void clear_playlist (); - private: - friend class StreamView; + friend class AudioStreamView; friend class AudioRegionView; - - ArdourCanvas::Canvas& parent_canvas; - - bool no_redraw; - - AutomationTimeAxisView *gain_track; - AutomationTimeAxisView *pan_track; - - void update_automation_view (ARDOUR::AutomationType); - void reset_redirect_automation_curves (); - - Gtk::HBox other_button_hbox; - - Gtk::Table button_table; - - Gtk::Button redirect_button; - Gtk::Button edit_group_button; - Gtk::Button playlist_button; - Gtk::Button size_button; - Gtk::Button automation_button; - Gtk::Button hide_button; - Gtk::Button visual_button; - - void route_active_changed (); - - void diskstream_changed (void *src); - void update_diskstream_display (); - gint edit_click (GdkEventButton *); - - // variables to get the context menu - // automation buttons correctly initialized - bool show_gain_automation; - bool show_pan_automation; - - void build_redirect_window (); - void redirect_click (); - void redirect_add (); - void redirect_remove (); - void redirect_edit (); - void redirect_relist (); - void redirect_row_selected (gint row, gint col, GdkEvent *ev); - void add_to_redirect_display (ARDOUR::Redirect *); - void redirects_changed (void *); - - sigc::connection modified_connection; - sigc::connection state_changed_connection; - - void take_name_changed (void *); - void route_name_changed (void *); - void name_entry_changed (); - - void on_area_realize (); - - virtual void label_view (); - - Gtk::Menu edit_group_menu; - - void add_edit_group_menu_item (ARDOUR::RouteGroup *, Gtk::RadioMenuItem::Group*); - void set_edit_group_from_menu (ARDOUR::RouteGroup *); - - void reset_samples_per_unit (); + void route_active_changed (); - void select_track_color(); + void build_automation_action_menu (); + void append_extra_display_menu_items (); - virtual void build_display_menu (); - - Gtk::CheckMenuItem* waveform_item; - Gtk::RadioMenuItem* traditional_item; - Gtk::RadioMenuItem* rectified_item; - - Gtk::RadioMenuItem* align_existing_item; - Gtk::RadioMenuItem* align_capture_item; - - void align_style_changed (); - void set_align_style (ARDOUR::AlignStyle); - void toggle_show_waveforms (); - void set_waveform_shape (WaveformShape); void toggle_waveforms (); - Gtk::Menu *playlist_menu; - Gtk::Menu *playlist_action_menu; - Gtk::MenuItem *playlist_item; - - /* playlist */ - - void set_playlist (ARDOUR::AudioPlaylist *); - void playlist_click (); - void show_playlist_selector (); - - void playlist_changed (); - void playlist_state_changed (ARDOUR::Change); - void playlist_modified (); - - void add_playlist_to_playlist_menu (ARDOUR::Playlist*); - void rename_current_playlist (); - - /* automation stuff */ - - Gtk::Menu* automation_action_menu; - Gtk::CheckMenuItem* gain_automation_item; - Gtk::CheckMenuItem* pan_automation_item; - - void automation_click (); - void clear_automation (); - void hide_all_automation (); void show_all_automation (); void show_existing_automation (); + void hide_all_automation (); - struct RedirectAutomationNode { - uint32_t what; - Gtk::CheckMenuItem* menu_item; - AutomationTimeAxisView* view; - AudioTimeAxisView& parent; - - RedirectAutomationNode (uint32_t w, Gtk::CheckMenuItem* mitem, AudioTimeAxisView& p) - : what (w), menu_item (mitem), view (0), parent (p) {} - - ~RedirectAutomationNode (); - }; - - struct RedirectAutomationInfo { - ARDOUR::Redirect* redirect; - bool valid; - Gtk::Menu* menu; - vector<RedirectAutomationNode*> lines; - - RedirectAutomationInfo (ARDOUR::Redirect* r) - : redirect (r), valid (true) {} - - ~RedirectAutomationInfo (); - }; - - list<RedirectAutomationInfo*> redirect_automation; - RedirectAutomationNode* find_redirect_automation_node (ARDOUR::Redirect *redirect, uint32_t what); - - Gtk::Menu subplugin_menu; - void add_redirect_to_subplugin_menu (ARDOUR::Redirect *); - - void remove_ran (RedirectAutomationNode* ran); - - void redirect_menu_item_toggled (AudioTimeAxisView::RedirectAutomationInfo*, - AudioTimeAxisView::RedirectAutomationNode*); - void redirect_automation_track_hidden (RedirectAutomationNode*, ARDOUR::Redirect*); - - vector<RedirectAutomationLine*> redirect_automation_curves; - RedirectAutomationLine *find_redirect_automation_curve (ARDOUR::Redirect*,uint32_t); - void add_redirect_automation_curve (ARDOUR::Redirect*, uint32_t); - void add_existing_redirect_automation_curves (ARDOUR::Redirect*); - - ArdourCanvas::SimpleRect *timestretch_rect; - - void timestretch (jack_nframes_t start, jack_nframes_t end); - - void visual_click (); - void hide_click (); - gint when_displayed (GdkEventAny*); - - void speed_changed (); - void add_gain_automation_child (); void add_pan_automation_child (); void add_parameter_automation_child (); @@ -309,14 +115,19 @@ class AudioTimeAxisView : public RouteUI, public TimeAxisView void update_pans (); - void region_view_added (AudioRegionView*); - void add_ghost_to_redirect (AudioRegionView*, AutomationTimeAxisView*); - - void map_frozen (); + AutomationTimeAxisView* gain_track; + AutomationTimeAxisView* pan_track; - void color_handler (ColorID, uint32_t); - bool select_me (GdkEventButton*); + // Set from XML so context menu automation buttons can be correctly initialized + bool show_gain_automation; + bool show_pan_automation; + + Gtk::CheckMenuItem* waveform_item; + Gtk::RadioMenuItem* traditional_item; + Gtk::RadioMenuItem* rectified_item; + Gtk::CheckMenuItem* gain_automation_item; + Gtk::CheckMenuItem* pan_automation_item; }; -#endif /* __ardour_trackview_h__ */ +#endif /* __ardour_audio_time_axis_h__ */ diff --git a/gtk2_ardour/automation_time_axis.cc b/gtk2_ardour/automation_time_axis.cc index 080a440bc9..6e2a93889f 100644 --- a/gtk2_ardour/automation_time_axis.cc +++ b/gtk2_ardour/automation_time_axis.cc @@ -21,7 +21,7 @@ using namespace PBD; using namespace Gtk; using namespace Editing; -AutomationTimeAxisView::AutomationTimeAxisView (Session& s, Route& r, PublicEditor& e, TimeAxisView& rent, +AutomationTimeAxisView::AutomationTimeAxisView (Session& s, boost::shared_ptr<Route> r, PublicEditor& e, TimeAxisView& rent, ArdourCanvas::Canvas& canvas, const string & nom, const string & state_name, const string & nomparent) @@ -41,6 +41,7 @@ AutomationTimeAxisView::AutomationTimeAxisView (Session& s, Route& r, PublicEdit auto_write_item = 0; auto_play_item = 0; ignore_state_request = false; + first_call_to_set_height = true; // base_rect = gnome_canvas_item_new (GNOME_CANVAS_GROUP(canvas_display), // gnome_canvas_simplerect_get_type(), @@ -73,6 +74,8 @@ AutomationTimeAxisView::AutomationTimeAxisView (Session& s, Route& r, PublicEdit clear_button.set_name ("TrackVisualButton"); hide_button.set_name ("TrackRemoveButton"); + controls_table.set_no_show_all(); + ARDOUR_UI::instance()->tooltips().set_tip(height_button, _("track height")); ARDOUR_UI::instance()->tooltips().set_tip(auto_button, _("automation state")); ARDOUR_UI::instance()->tooltips().set_tip(clear_button, _("clear track")); @@ -116,6 +119,7 @@ AutomationTimeAxisView::AutomationTimeAxisView (Session& s, Route& r, PublicEdit plugname = new Label (pname); plugname->set_name (X_("TrackPlugName")); plugname->set_alignment (1.0, 0.5); + plugname->show(); name_label.set_name (X_("TrackParameterName")); controls_table.remove (name_hbox); controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); @@ -139,9 +143,9 @@ AutomationTimeAxisView::AutomationTimeAxisView (Session& s, Route& r, PublicEdit controls_table.attach (hide_button, 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); controls_table.attach (height_button, 0, 1, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - controls_table.attach (auto_button, 6, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - controls_table.attach (clear_button, 6, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - + controls_table.attach (auto_button, 5, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + controls_table.attach (clear_button, 5, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + controls_table.show_all (); height_button.signal_clicked().connect (mem_fun(*this, &AutomationTimeAxisView::height_clicked)); @@ -282,11 +286,11 @@ AutomationTimeAxisView::set_height (TrackHeight ht) uint32_t h = height_to_pixels (ht); bool changed = (height != (uint32_t) h); + bool changed_between_small_and_normal = ( (ht == Small || ht == Smaller) ^ (height_style == Small || height_style == Smaller) ); + TimeAxisView* state_parent = get_parent_with_state (); XMLNode* xml_node = state_parent->get_child_xml_node (_state_name); - controls_table.show_all (); - TimeAxisView::set_height (ht); base_rect->property_y2() = h; @@ -298,119 +302,91 @@ AutomationTimeAxisView::set_height (TrackHeight ht) (*i)->set_height (); } - switch (height) { + + switch (ht) { case Largest: xml_node->add_property ("track_height", "largest"); - controls_table.remove (name_hbox); - if (plugname) { - if (plugname_packed) { - controls_table.remove (*plugname); - plugname_packed = false; - } - controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - plugname_packed = true; - controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - } else { - controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - } - controls_table.show_all (); - hide_name_entry (); - show_name_label (); break; case Large: xml_node->add_property ("track_height", "large"); - controls_table.remove (name_hbox); - if (plugname) { - if (plugname_packed) { - controls_table.remove (*plugname); - plugname_packed = false; - } - controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - plugname_packed = true; - } else { - controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - } - controls_table.show_all (); - hide_name_entry (); - show_name_label (); break; case Larger: xml_node->add_property ("track_height", "larger"); - controls_table.remove (name_hbox); - if (plugname) { - if (plugname_packed) { - controls_table.remove (*plugname); - plugname_packed = false; - } - controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - plugname_packed = true; - } else { - controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - } - controls_table.show_all (); - hide_name_entry (); - show_name_label (); break; case Normal: xml_node->add_property ("track_height", "normal"); - controls_table.remove (name_hbox); - if (plugname) { - if (plugname_packed) { - controls_table.remove (*plugname); - plugname_packed = false; - } - controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - plugname_packed = true; - controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - } else { - controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - } - controls_table.show_all (); - hide_name_entry (); - show_name_label (); break; case Smaller: xml_node->add_property ("track_height", "smaller"); - controls_table.remove (name_hbox); - if (plugname) { - if (plugname_packed) { - controls_table.remove (*plugname); - plugname_packed = false; - } - } - controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - controls_table.hide_all (); - hide_name_entry (); - show_name_label (); - name_hbox.show_all (); - controls_table.show (); break; case Small: xml_node->add_property ("track_height", "small"); - controls_table.remove (name_hbox); - if (plugname) { - if (plugname_packed) { - controls_table.remove (*plugname); - plugname_packed = false; - } - } - controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - controls_table.hide_all (); - hide_name_entry (); - show_name_label (); - name_hbox.show_all (); - controls_table.show (); break; } + if (changed_between_small_and_normal || first_call_to_set_height) { + first_call_to_set_height = false; + switch (ht) { + case Largest: + case Large: + case Larger: + case Normal: + + controls_table.remove (name_hbox); + + if (plugname) { + if (plugname_packed) { + controls_table.remove (*plugname); + plugname_packed = false; + } + controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + plugname_packed = true; + controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + } else { + controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + } + hide_name_entry (); + show_name_label (); + name_hbox.show_all (); + + auto_button.show(); + height_button.show(); + clear_button.show(); + hide_button.show_all(); + break; + + case Smaller: + case Small: + + controls_table.remove (name_hbox); + if (plugname) { + if (plugname_packed) { + controls_table.remove (*plugname); + plugname_packed = false; + } + } + controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + controls_table.hide_all (); + hide_name_entry (); + show_name_label (); + name_hbox.show_all (); + + auto_button.hide(); + height_button.hide(); + clear_button.hide(); + hide_button.hide(); + break; + } + } + if (changed) { /* only emit the signal if the height really changed */ - route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ + route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ } } diff --git a/gtk2_ardour/automation_time_axis.h b/gtk2_ardour/automation_time_axis.h index deb08b41f0..0cd9acc034 100644 --- a/gtk2_ardour/automation_time_axis.h +++ b/gtk2_ardour/automation_time_axis.h @@ -4,6 +4,9 @@ #include <vector> #include <list> #include <string> + +#include <boost/shared_ptr.hpp> + #include <ardour/types.h> #include "canvas.h" @@ -21,7 +24,7 @@ namespace ARDOUR { class PublicEditor; class TimeSelection; -class AudioRegionSelection; +class RegionSelection; class PointSelection; class AutomationLine; class GhostRegion; @@ -31,7 +34,7 @@ class Selectable; class AutomationTimeAxisView : public TimeAxisView { public: AutomationTimeAxisView (ARDOUR::Session&, - ARDOUR::Route&, + boost::shared_ptr<ARDOUR::Route>, PublicEditor&, TimeAxisView& parent, ArdourCanvas::Canvas& canvas, @@ -41,14 +44,14 @@ class AutomationTimeAxisView : public TimeAxisView { ~AutomationTimeAxisView(); - void set_height (TimeAxisView::TrackHeight); + virtual void set_height (TimeAxisView::TrackHeight); void set_samples_per_unit (double); std::string name() const { return _name; } virtual void add_automation_event (ArdourCanvas::Item *item, GdkEvent *event, jack_nframes_t, double) = 0; - void clear_lines (); - void add_line (AutomationLine&); + virtual void clear_lines (); + virtual void add_line (AutomationLine&); vector<AutomationLine*> lines; @@ -75,12 +78,14 @@ class AutomationTimeAxisView : public TimeAxisView { XMLNode* get_state_node (); protected: - ARDOUR::Route& route; + boost::shared_ptr<ARDOUR::Route> route; ArdourCanvas::SimpleRect* base_rect; string _name; string _state_name; bool in_destructor; + bool first_call_to_set_height; + Gtk::Button hide_button; Gtk::Button height_button; Gtk::Button clear_button; diff --git a/gtk2_ardour/canvas-waveview.h b/gtk2_ardour/canvas-waveview.h index 97ac91f622..75281f69eb 100644 --- a/gtk2_ardour/canvas-waveview.h +++ b/gtk2_ardour/canvas-waveview.h @@ -80,10 +80,10 @@ struct _GnomeCanvasWaveView void (*gain_curve_function)(void *arg, double start, double end, float* vector, guint32 veclen); void *gain_src; - /* x-axis: samples per canvas unit. */ + /** x-axis: samples per canvas unit. */ double samples_per_unit; - /* y-axis: amplitude_above_axis. + /** y-axis: amplitude_above_axis. * * the default is that an (scaled, normalized -1.0 ... +1.0) amplitude of 1.0 * corresponds to the top of the area assigned to the waveview. @@ -92,8 +92,8 @@ struct _GnomeCanvasWaveView * smaller values will decrease the vertical scale, moving peaks/troughs toward * the middle of the area assigned to the waveview. */ - double amplitude_above_axis; + double x; double y; double height; diff --git a/gtk2_ardour/crossfade_edit.cc b/gtk2_ardour/crossfade_edit.cc index 5b587594de..b2967dc4a9 100644 --- a/gtk2_ardour/crossfade_edit.cc +++ b/gtk2_ardour/crossfade_edit.cc @@ -1077,7 +1077,7 @@ CrossfadeEditor::peaks_ready (AudioRegion* r, WhichFade which) void CrossfadeEditor::audition_both () { - AudioPlaylist& pl (session.the_auditioner().prepare_playlist()); + AudioPlaylist& pl (session.the_auditioner()->prepare_playlist()); jack_nframes_t preroll; jack_nframes_t postroll; jack_nframes_t length; @@ -1140,7 +1140,7 @@ CrossfadeEditor::audition_left_dry () void CrossfadeEditor::audition_left () { - AudioPlaylist& pl (session.the_auditioner().prepare_playlist()); + AudioPlaylist& pl (session.the_auditioner()->prepare_playlist()); AudioRegion* left = new AudioRegion (xfade.out(), xfade.out().length() - xfade.length(), xfade.length(), "xfade left", 0, Region::DefaultFlags, false); @@ -1172,7 +1172,7 @@ CrossfadeEditor::audition_right_dry () void CrossfadeEditor::audition_right () { - AudioPlaylist& pl (session.the_auditioner().prepare_playlist()); + AudioPlaylist& pl (session.the_auditioner()->prepare_playlist()); AudioRegion* left = new AudioRegion (xfade.out(), xfade.out().length() - xfade.length(), xfade.length(), "xfade out", 0, Region::DefaultFlags, false); diff --git a/gtk2_ardour/crossfade_view.cc b/gtk2_ardour/crossfade_view.cc index 350698ec48..087af25e73 100644 --- a/gtk2_ardour/crossfade_view.cc +++ b/gtk2_ardour/crossfade_view.cc @@ -29,7 +29,7 @@ #include "rgb_macros.h" #include "audio_time_axis.h" #include "public_editor.h" -#include "regionview.h" +#include "audio_region_view.h" #include "utils.h" #include "canvas_impl.h" @@ -43,7 +43,7 @@ using namespace Canvas; sigc::signal<void,CrossfadeView*> CrossfadeView::GoingAway; CrossfadeView::CrossfadeView (ArdourCanvas::Group *parent, - AudioTimeAxisView &tv, + RouteTimeAxisView &tv, Crossfade& xf, double spu, Gdk::Color& basic_color, @@ -227,7 +227,7 @@ CrossfadeView::set_valid (bool yn) AudioRegionView& CrossfadeView::upper_regionview () const { - if (left_view.region.layer() > right_view.region.layer()) { + if (left_view.region().layer() > right_view.region().layer()) { return left_view; } else { return right_view; diff --git a/gtk2_ardour/crossfade_view.h b/gtk2_ardour/crossfade_view.h index 403edfe297..adbd74b420 100644 --- a/gtk2_ardour/crossfade_view.h +++ b/gtk2_ardour/crossfade_view.h @@ -28,13 +28,13 @@ #include "time_axis_view_item.h" -class AudioTimeAxisView; +class RouteTimeAxisView; class AudioRegionView; struct CrossfadeView : public TimeAxisViewItem { CrossfadeView (ArdourCanvas::Group*, - AudioTimeAxisView&, + RouteTimeAxisView&, ARDOUR::Crossfade&, double initial_samples_per_unit, Gdk::Color& basic_color, diff --git a/gtk2_ardour/editing_syms.h b/gtk2_ardour/editing_syms.h index cf36550fb4..654ddc8852 100644 --- a/gtk2_ardour/editing_syms.h +++ b/gtk2_ardour/editing_syms.h @@ -56,4 +56,5 @@ DISPLAYCONTROL(ShowWaveformsRecording) IMPORTMODE(ImportAsRegion) IMPORTMODE(ImportAsTrack) +IMPORTMODE(ImportAsTapeTrack) IMPORTMODE(ImportToTrack) diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 6472974093..513251085c 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -57,10 +57,10 @@ #include "keyboard.h" #include "marker.h" #include "playlist_selector.h" -#include "regionview.h" +#include "audio_region_view.h" #include "rgb_macros.h" #include "selection.h" -#include "streamview.h" +#include "audio_streamview.h" #include "time_axis_view.h" #include "utils.h" #include "crossfade_view.h" @@ -102,8 +102,8 @@ static const int32_t slide_index = 0; static const int32_t splice_index = 1; static const gchar *edit_mode_strings[] = { - N_("Slide"), - N_("Splice"), + N_("Slide Edit"), + N_("Splice Edit"), 0 }; @@ -132,17 +132,17 @@ static const gchar *snap_type_strings[] = { }; static const gchar *snap_mode_strings[] = { - N_("Normal"), - N_("Magnetic"), + N_("Normal Snap"), + N_("Magnetic Snap"), 0 }; static const gchar *zoom_focus_strings[] = { - N_("Left"), - N_("Right"), - N_("Center"), - N_("Playhead"), - N_("Edit Cursor"), + N_("Focus Left"), + N_("Focus Right"), + N_("Focus Center"), + N_("Focus Play"), + N_("Focus Edit"), 0 }; @@ -205,37 +205,20 @@ Editor::Editor (AudioEngine& eng) /* tool bar related */ - selection_start_clock (X_("SelectionStartClock"), true), - selection_end_clock (X_("SelectionEndClock"), true), edit_cursor_clock (X_("EditCursorClock"), true), zoom_range_clock (X_("ZoomRangeClock"), true, true), toolbar_selection_clock_table (2,3), - mouse_mode_button_table (2, 3), - - mouse_select_button (_("range")), - mouse_move_button (_("object")), - mouse_gain_button (_("gain")), - mouse_zoom_button (_("zoom")), - mouse_timefx_button (_("timefx")), - mouse_audition_button (_("listen")), - automation_mode_button (_("mode")), global_automation_button (_("automation")), - edit_mode_label (_("Edit Mode")), - snap_type_label (_("Snap To")), - snap_mode_label(_("Snap Mode")), - zoom_focus_label (_("Zoom Focus")), - /* <CMT Additions> */ image_socket_listener(0), /* </CMT Additions> */ /* nudge */ - nudge_label (_("Nudge")), nudge_clock (X_("NudgeClock"), true, true) { @@ -346,6 +329,7 @@ Editor::Editor (AudioEngine& eng) reset_hscrollbar_stepping (); zoom_focus = ZoomFocusLeft; + set_zoom_focus (ZoomFocusLeft); zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed)); initialize_rulers (); @@ -466,36 +450,7 @@ Editor::Editor (AudioEngine& eng) edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0); - zoom_in_button.set_name ("EditorTimeButton"); - zoom_out_button.set_name ("EditorTimeButton"); - ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom in")); - ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom out")); - - zoom_out_full_button.set_name ("EditorTimeButton"); - ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to session")); - - zoom_in_button.add (*(manage (new Image (Stock::ZOOM_IN, ICON_SIZE_BUTTON)))); - zoom_out_button.add (*(manage (new Image (Stock::ZOOM_OUT, ICON_SIZE_BUTTON)))); - zoom_out_full_button.add (*(manage (new Image (Stock::ZOOM_FIT, ICON_SIZE_BUTTON)))); - - zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false)); - zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true)); - zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session)); - - zoom_indicator_box.pack_start (zoom_out_button, false, false); - zoom_indicator_box.pack_start (zoom_in_button, false, false); - zoom_indicator_box.pack_start (zoom_range_clock, false, false); - zoom_indicator_box.pack_start (zoom_out_full_button, false, false); - - zoom_indicator_label.set_text (_("Zoom Span")); - zoom_indicator_label.set_name ("ToolBarLabel"); - - zoom_indicator_vbox.set_spacing (3); - zoom_indicator_vbox.set_border_width (3); - zoom_indicator_vbox.pack_start (zoom_indicator_label, false, false); - zoom_indicator_vbox.pack_start (zoom_indicator_box, false, false); - - bottom_hbox.set_border_width (3); + bottom_hbox.set_border_width (2); bottom_hbox.set_spacing (3); route_display_model = ListStore::create(route_display_columns); @@ -718,15 +673,15 @@ Editor::Editor (AudioEngine& eng) _playlist_selector = new PlaylistSelector(); _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector))); - AudioRegionView::AudioRegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_audio_regionview)); + RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview)); /* nudge stuff */ nudge_forward_button.add (*(manage (new Image (get_xpm("right_arrow.xpm"))))); nudge_backward_button.add (*(manage (new Image (get_xpm("left_arrow.xpm"))))); - ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge region/selection forwards")); - ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge region/selection backwards")); + ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards")); + ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards")); nudge_forward_button.set_name ("TransportButton"); nudge_backward_button.set_name ("TransportButton"); @@ -776,7 +731,7 @@ Editor::add_toplevel_controls (Container& cont) } void -Editor::catch_vanishing_audio_regionview (AudioRegionView *rv) +Editor::catch_vanishing_regionview (RegionView *rv) { /* note: the selection will take care of the vanishing audioregionview by itself. @@ -792,7 +747,7 @@ Editor::catch_vanishing_audio_regionview (AudioRegionView *rv) } void -Editor::set_entered_regionview (AudioRegionView* rv) +Editor::set_entered_regionview (RegionView* rv) { if (rv == entered_regionview) { return; @@ -914,7 +869,7 @@ Editor::set_frames_per_unit (double fpu) void Editor::instant_save () { - if (!constructed || !ARDOUR_UI::instance()->session_loaded) { + if (!constructed || !ARDOUR_UI::instance()->session_loaded) { return; } @@ -1222,7 +1177,7 @@ Editor::connect_to_session (Session *t) session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state))); session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change))); - session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route_p))); + session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route))); session_connections.push_back (session->AudioRegionAdded.connect (mem_fun(*this, &Editor::handle_new_audio_region))); session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::handle_audio_region_removed))); session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration))); @@ -1243,8 +1198,6 @@ Editor::connect_to_session (Session *t) edit_groups_changed (); edit_cursor_clock.set_session (session); - selection_start_clock.set_session (session); - selection_end_clock.set_session (session); zoom_range_clock.set_session (session); _playlist_selector->set_session (session); nudge_clock.set_session (session); @@ -1377,7 +1330,7 @@ Editor::connect_to_session (Session *t) AudioTimeAxisView *atv; if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) { - if (atv->route().master()) { + if (atv->route()->master()) { route_list_display.get_selection()->unselect (i); } } @@ -1448,7 +1401,7 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i switch (item_type) { case FadeInItem: case FadeInHandleItem: - if (arv->region.fade_in_active()) { + if (arv->audio_region().fade_in_active()) { items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), false))); } else { items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), true))); @@ -1456,16 +1409,16 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Linear))); - items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogB))); - items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Fast))); - items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogA))); - items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Slow))); + items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_in_shape), AudioRegion::Linear))); + items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_in_shape), AudioRegion::LogB))); + items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_in_shape), AudioRegion::Fast))); + items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_in_shape), AudioRegion::LogA))); + items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_in_shape), AudioRegion::Slow))); break; case FadeOutItem: case FadeOutHandleItem: - if (arv->region.fade_out_active()) { + if (arv->audio_region().fade_out_active()) { items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), false))); } else { items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), true))); @@ -1473,11 +1426,11 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Linear))); - items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Fast))); - items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogB))); - items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogA))); - items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Slow))); + items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_out_shape), AudioRegion::Linear))); + items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_out_shape), AudioRegion::Fast))); + items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_out_shape), AudioRegion::LogB))); + items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_out_shape), AudioRegion::LogA))); + items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_out_shape), AudioRegion::Slow))); break; default: @@ -1499,8 +1452,8 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, switch (item_type) { case RegionItem: - case AudioRegionViewName: - case AudioRegionViewNameHighlight: + case RegionViewName: + case RegionViewNameHighlight: if (with_selection) { build_menu_function = &Editor::build_track_selection_context_menu; } else { @@ -1540,25 +1493,26 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, switch (item_type) { case RegionItem: - case AudioRegionViewName: - case AudioRegionViewNameHighlight: + case RegionViewName: + case RegionViewNameHighlight: if (!with_selection) { if (region_edit_menu_split_item) { - if (clicked_regionview && clicked_regionview->region.covers (edit_cursor->current_frame)) { + if (clicked_regionview && clicked_regionview->region().covers (edit_cursor->current_frame)) { ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, true); } else { ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, false); } } + /* if (region_edit_menu_split_multichannel_item) { - if (clicked_regionview && clicked_regionview->region.n_channels() > 1) { + if (clicked_regionview && clicked_regionview->region().n_channels() > 1) { // GTK2FIX find the action, change its sensitivity // region_edit_menu_split_multichannel_item->set_sensitive (true); } else { // GTK2FIX see above // region_edit_menu_split_multichannel_item->set_sensitive (false); } - } + }*/ } break; @@ -1638,13 +1592,13 @@ Editor::build_track_region_context_menu (jack_nframes_t frame) AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview); if (atv) { - AudioDiskstream* ds; + Diskstream* ds; Playlist* pl; if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) { Playlist::RegionList* regions = pl->regions_at ((jack_nframes_t) floor ( (double)frame * ds->speed())); for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { - add_region_context_items (atv->view, (*i), edit_items); + add_region_context_items (atv->audio_view(), (*i), edit_items); } delete regions; } @@ -1665,7 +1619,7 @@ Editor::build_track_crossfade_context_menu (jack_nframes_t frame) AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview); if (atv) { - AudioDiskstream* ds; + Diskstream* ds; Playlist* pl; AudioPlaylist* apl; @@ -1679,11 +1633,11 @@ Editor::build_track_crossfade_context_menu (jack_nframes_t frame) bool many = xfades.size() > 1; for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) { - add_crossfade_context_items (atv->view, (*i), edit_items, many); + add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many); } for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { - add_region_context_items (atv->view, (*i), edit_items); + add_region_context_items (atv->audio_view(), (*i), edit_items); } delete regions; @@ -1749,7 +1703,7 @@ Editor::build_track_selection_context_menu (jack_nframes_t ignored) } void -Editor::add_crossfade_context_items (StreamView* view, Crossfade* xfade, Menu_Helpers::MenuList& edit_items, bool many) +Editor::add_crossfade_context_items (AudioStreamView* view, Crossfade* xfade, Menu_Helpers::MenuList& edit_items, bool many) { using namespace Menu_Helpers; Menu *xfade_menu = manage (new Menu); @@ -1806,7 +1760,7 @@ Editor::xfade_edit_right_region () } void -Editor::add_region_context_items (StreamView* sv, Region* region, Menu_Helpers::MenuList& edit_items) +Editor::add_region_context_items (AudioStreamView* sv, Region* region, Menu_Helpers::MenuList& edit_items) { using namespace Menu_Helpers; Menu *region_menu = manage (new Menu); @@ -2185,7 +2139,6 @@ Editor::set_state (const XMLNode& node) yoff = atoi(geometry->property("y_off")->value()); } - set_geometry_hints (vpacker, g, Gdk::HINT_BASE_SIZE); set_default_size (g.base_width, g.base_height); move (x, y); @@ -2297,7 +2250,7 @@ Editor::get_state () char buf[32]; if (is_realized()) { - Glib::RefPtr<Gdk::Window> win = get_window(); + Glib::RefPtr<Gdk::Window> win = get_window(); int x, y, xoff, yoff, width, height; win->get_root_origin(x, y); @@ -2586,30 +2539,56 @@ void Editor::setup_toolbar () { string pixmap_path; + + const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button + + + /* Mode Buttons (tool selection) */ + vector<ToggleButton *> mouse_mode_buttons; + mouse_move_button.add (*(manage (new Image (get_xpm("tool_object.xpm"))))); + mouse_move_button.set_relief(Gtk::RELIEF_NONE); mouse_mode_buttons.push_back (&mouse_move_button); + mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm"))))); + mouse_select_button.set_relief(Gtk::RELIEF_NONE); mouse_mode_buttons.push_back (&mouse_select_button); + mouse_gain_button.add (*(manage (new Image (get_xpm("tool_gain.xpm"))))); + mouse_gain_button.set_relief(Gtk::RELIEF_NONE); mouse_mode_buttons.push_back (&mouse_gain_button); + mouse_zoom_button.add (*(manage (new Image (get_xpm("tool_zoom.xpm"))))); + mouse_zoom_button.set_relief(Gtk::RELIEF_NONE); mouse_mode_buttons.push_back (&mouse_zoom_button); + mouse_timefx_button.add (*(manage (new Image (get_xpm("tool_stretch.xpm"))))); + mouse_timefx_button.set_relief(Gtk::RELIEF_NONE); mouse_mode_buttons.push_back (&mouse_timefx_button); + mouse_audition_button.add (*(manage (new Image (get_xpm("tool_audition.xpm"))))); + mouse_audition_button.set_relief(Gtk::RELIEF_NONE); mouse_mode_buttons.push_back (&mouse_audition_button); + mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons); - mouse_mode_button_table.set_homogeneous (true); - mouse_mode_button_table.set_col_spacings (2); - mouse_mode_button_table.set_row_spacings (2); - mouse_mode_button_table.set_border_width (5); + HBox* mode_box = manage(new HBox); + mode_box->set_border_width (2); + mode_box->set_spacing(4); + mouse_mode_button_box.set_spacing(1); + mouse_mode_button_box.pack_start(mouse_move_button, true, true); + mouse_mode_button_box.pack_start(mouse_select_button, true, true); + mouse_mode_button_box.pack_start(mouse_zoom_button, true, true); + mouse_mode_button_box.pack_start(mouse_gain_button, true, true); + mouse_mode_button_box.pack_start(mouse_timefx_button, true, true); + mouse_mode_button_box.pack_start(mouse_audition_button, true, true); + mouse_mode_button_box.set_homogeneous(true); - mouse_mode_button_table.attach (mouse_move_button, 0, 1, 0, 1); - mouse_mode_button_table.attach (mouse_select_button, 1, 2, 0, 1); - mouse_mode_button_table.attach (mouse_zoom_button, 2, 3, 0, 1); - - mouse_mode_button_table.attach (mouse_gain_button, 0, 1, 1, 2); - mouse_mode_button_table.attach (mouse_timefx_button, 1, 2, 1, 2); - mouse_mode_button_table.attach (mouse_audition_button, 2, 3, 1, 2); + edit_mode_selector.set_name ("EditModeSelector"); + Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, "Splice Edit", 2+FUDGE, 10); + set_popdown_strings (edit_mode_selector, internationalize (edit_mode_strings)); + edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done)); - mouse_mode_tearoff = manage (new TearOff (mouse_mode_button_table)); + mode_box->pack_start(edit_mode_selector); + mode_box->pack_start(mouse_mode_button_box); + + mouse_mode_tearoff = manage (new TearOff (*mode_box)); mouse_mode_tearoff->set_name ("MouseModeBase"); mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), @@ -2628,12 +2607,12 @@ Editor::setup_toolbar () mouse_timefx_button.set_name ("MouseModeButton"); mouse_audition_button.set_name ("MouseModeButton"); - ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("select/move objects")); - ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("select/move ranges")); - ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("draw gain automation")); - ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("select zoom range")); - ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("stretch/shrink regions")); - ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("listen to specific regions")); + ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects")); + ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges")); + ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation")); + ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range")); + ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions")); + ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions")); mouse_move_button.unset_flags (CAN_FOCUS); mouse_select_button.unset_flags (CAN_FOCUS); @@ -2652,160 +2631,82 @@ Editor::setup_toolbar () mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition)); // mouse_move_button.set_active (true); + - /* automation control */ - - global_automation_button.set_name ("MouseModeButton"); - automation_mode_button.set_name ("MouseModeButton"); - - automation_box.set_spacing (2); - automation_box.set_border_width (2); - automation_box.pack_start (global_automation_button, false, false); - automation_box.pack_start (automation_mode_button, false, false); - - /* Edit mode */ - - edit_mode_label.set_name ("ToolBarLabel"); - - edit_mode_selector.set_name ("EditModeSelector"); + /* Zoom */ + + zoom_box.set_spacing (1); + zoom_box.set_border_width (2); - edit_mode_box.set_spacing (3); - edit_mode_box.set_border_width (3); + zoom_in_button.set_name ("EditorTimeButton"); + zoom_in_button.add (*(manage (new Image (get_xpm("zoom_in.xpm"))))); + zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false)); + ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In")); + + zoom_out_button.set_name ("EditorTimeButton"); + zoom_out_button.add (*(manage (new Image (get_xpm("zoom_out.xpm"))))); + zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true)); + ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out")); - /* XXX another disgusting hack because of the way combo boxes size themselves */ + zoom_out_full_button.set_name ("EditorTimeButton"); + zoom_out_full_button.add (*(manage (new Image (get_xpm("zoom_full.xpm"))))); + zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session)); + ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session")); + + zoom_box.pack_start (zoom_out_button, false, false); + zoom_box.pack_start (zoom_in_button, false, false); + zoom_box.pack_start (zoom_range_clock, false, false); + zoom_box.pack_start (zoom_out_full_button, false, false); + + ARDOUR_UI::instance()->tooltips().set_tip (zoom_range_clock, _("Current Zoom Range\n(Width of visible area)")); + + zoom_focus_selector.set_name ("ZoomFocusSelector"); + Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Focus Center", 2+FUDGE, 0); + set_popdown_strings (zoom_focus_selector, internationalize (zoom_focus_strings)); + zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done)); - const guint32 FUDGE = 20; // Combo's are stupid - they steal space from the entry for the button - Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, "EdgtMode", 2+FUDGE, 10); - set_popdown_strings (edit_mode_selector, internationalize (edit_mode_strings)); - edit_mode_box.pack_start (edit_mode_label, false, false); - edit_mode_box.pack_start (edit_mode_selector, false, false); + zoom_box.pack_start (zoom_focus_selector, false, false); - edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done)); - /* Snap Type */ + /* Edit Cursor / Snap */ - snap_type_label.set_name ("ToolBarLabel"); + snap_box.set_spacing (1); + snap_box.set_border_width (2); snap_type_selector.set_name ("SnapTypeSelector"); - - snap_type_box.set_spacing (3); - snap_type_box.set_border_width (3); - - /* XXX another disgusting hack because of the way combo boxes size themselves */ - Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10); set_popdown_strings (snap_type_selector, internationalize (snap_type_strings)); - - snap_type_box.pack_start (snap_type_label, false, false); - snap_type_box.pack_start (snap_type_selector, false, false); - snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done)); - - /* Snap mode, not snap type */ - - snap_mode_label.set_name ("ToolBarLabel"); + ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Unit to snap cursors and ranges to")); snap_mode_selector.set_name ("SnapModeSelector"); - - snap_mode_box.set_spacing (3); - snap_mode_box.set_border_width (3); - - Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "SngpMode", 2+FUDGE, 10); + Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10); set_popdown_strings (snap_mode_selector, internationalize (snap_mode_strings)); - - snap_mode_box.pack_start (snap_mode_label, false, false); - snap_mode_box.pack_start (snap_mode_selector, false, false); - snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done)); - /* Zoom focus mode */ - - zoom_focus_label.set_name ("ToolBarLabel"); - - zoom_focus_selector.set_name ("ZoomFocusSelector"); - - zoom_focus_box.set_spacing (3); - zoom_focus_box.set_border_width (3); - - /* XXX another disgusting hack because of the way combo boxes size themselves */ - - Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Edgt Cursor", 2+FUDGE, 10); - set_popdown_strings (zoom_focus_selector, internationalize (zoom_focus_strings)); - - zoom_focus_box.pack_start (zoom_focus_label, false, false); - zoom_focus_box.pack_start (zoom_focus_selector, false, false); - - zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done)); - - /* selection/cursor clocks */ - - toolbar_selection_cursor_label.set_name ("ToolBarLabel"); - selection_start_clock_label.set_name ("ToolBarLabel"); - selection_end_clock_label.set_name ("ToolBarLabel"); - edit_cursor_clock_label.set_name ("ToolBarLabel"); - - selection_start_clock_label.set_text (_("Start:")); - selection_end_clock_label.set_text (_("End:")); - edit_cursor_clock_label.set_text (_("Edit")); - - /* the zoom in/out buttons are generally taller than the clocks, so - put all the toolbar clocks into a size group with one of the - buttons to make them all equal height. + snap_box.pack_start (edit_cursor_clock, false, false); + snap_box.pack_start (snap_mode_selector, false, false); + snap_box.pack_start (snap_type_selector, false, false); - this also applies to the various toolbar combos - */ - - RefPtr<SizeGroup> toolbar_clock_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL); - toolbar_clock_size_group->add_widget (zoom_out_button); - toolbar_clock_size_group->add_widget (edit_cursor_clock); - toolbar_clock_size_group->add_widget (zoom_range_clock); - toolbar_clock_size_group->add_widget (nudge_clock); - toolbar_clock_size_group->add_widget (edit_mode_selector); - toolbar_clock_size_group->add_widget (snap_type_selector); - toolbar_clock_size_group->add_widget (snap_mode_selector); - toolbar_clock_size_group->add_widget (zoom_focus_selector); - - HBox* edit_clock_hbox = manage (new HBox()); - VBox* edit_clock_vbox = manage (new VBox()); - - edit_clock_hbox->pack_start (edit_cursor_clock, false, false); - - edit_clock_vbox->set_spacing (3); - edit_clock_vbox->set_border_width (3); - edit_clock_vbox->pack_start (edit_cursor_clock_label, false, false); - edit_clock_vbox->pack_start (*edit_clock_hbox, false, false); - - HBox* hbox = new HBox; - hbox->pack_start (*edit_clock_vbox, false, false); - hbox->pack_start (zoom_indicator_vbox, false, false); - hbox->pack_start (zoom_focus_box, false, false); - hbox->pack_start (snap_type_box, false, false); - hbox->pack_start (snap_mode_box, false, false); - hbox->pack_start (edit_mode_box, false, false); + /* Nudge */ - VBox *vbox = manage (new VBox); + HBox *nudge_box = manage (new HBox); + nudge_box->set_spacing(1); + nudge_box->set_border_width (2); - vbox->set_spacing (3); - vbox->set_border_width (3); - - HBox *nbox = manage (new HBox); - nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false)); nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false)); - nbox->pack_start (nudge_backward_button, false, false); - nbox->pack_start (nudge_forward_button, false, false); - nbox->pack_start (nudge_clock, false, false, 5); - - nudge_label.set_name ("ToolBarLabel"); + nudge_box->pack_start (nudge_backward_button, false, false); + nudge_box->pack_start (nudge_forward_button, false, false); + nudge_box->pack_start (nudge_clock, false, false); - vbox->pack_start (nudge_label, false, false); - vbox->pack_start (*nbox, false, false); - hbox->pack_start (*vbox, false, false); + /* Pack everything in... */ - hbox->show_all (); + HBox* hbox = new HBox; + hbox->set_spacing(10); tools_tearoff = new TearOff (*hbox); tools_tearoff->set_name ("MouseModeBase"); @@ -2819,11 +2720,18 @@ Editor::setup_toolbar () tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), &tools_tearoff->tearoff_window(), 0)); - toolbar_hbox.set_spacing (8); - toolbar_hbox.set_border_width (2); + toolbar_hbox.set_spacing (10); + toolbar_hbox.set_border_width (1); - toolbar_hbox.pack_start (*tools_tearoff, false, false); toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false); + toolbar_hbox.pack_start (*tools_tearoff, false, false); + + + hbox->pack_start (snap_box, false, false); + hbox->pack_start (zoom_box, false, false); + hbox->pack_start (*nudge_box, false, false); + + hbox->show_all (); toolbar_base.set_name ("ToolBarBase"); toolbar_base.add (toolbar_hbox); @@ -3055,7 +2963,7 @@ Editor::get_relevant_audio_tracks (AudioTimeAxisView& base, set<AudioTimeAxisVie continue; } - RouteGroup* group = atv->route().edit_group(); + RouteGroup* group = atv->route()->edit_group(); if (group && group->is_active()) { @@ -3067,7 +2975,7 @@ Editor::get_relevant_audio_tracks (AudioTimeAxisView& base, set<AudioTimeAxisVie if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) { - if (tatv->route().edit_group() == group) { + if (tatv->route()->edit_group() == group) { relevant_tracks.insert (tatv); } } @@ -3102,31 +3010,31 @@ Editor::mapover_audio_tracks (slot<void,AudioTimeAxisView&,uint32_t> sl) } void -Editor::mapped_set_selected_regionview_from_click (AudioTimeAxisView& atv, uint32_t ignored, - AudioRegionView* basis, vector<AudioRegionView*>* all_equivs) +Editor::mapped_set_selected_regionview_from_click (RouteTimeAxisView& tv, uint32_t ignored, + RegionView* basis, vector<RegionView*>* all_equivs) { - AudioPlaylist* pl; - vector<AudioRegion*> results; - AudioRegionView* marv; - AudioDiskstream* ds; + Playlist* pl; + vector<Region*> results; + RegionView* marv; + Diskstream* ds; - if ((ds = atv.get_diskstream()) == 0) { + if ((ds = tv.get_diskstream()) == 0) { /* bus */ return; } - if (&atv == &basis->get_time_axis_view()) { + if (&tv == &basis->get_time_axis_view()) { /* looking in same track as the original */ return; } - if ((pl = ds->playlist()) != 0) { - pl->get_equivalent_regions (basis->region, results); + if ((pl = dynamic_cast<Playlist*>(ds->playlist())) != 0) { + pl->get_equivalent_regions (basis->region(), results); } - for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) { - if ((marv = atv.view->find_view (**ir)) != 0) { + for (vector<Region*>::iterator ir = results.begin(); ir != results.end(); ++ir) { + if ((marv = tv.view()->find_view (**ir)) != 0) { all_equivs->push_back (marv); } } @@ -3135,7 +3043,7 @@ Editor::mapped_set_selected_regionview_from_click (AudioTimeAxisView& atv, uint3 bool Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool no_track_remove) { - vector<AudioRegionView*> all_equivalent_regions; + vector<RegionView*> all_equivalent_regions; bool commit = false; if (!clicked_regionview || !clicked_audio_trackview) { @@ -3190,7 +3098,7 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, commit = true; } - for (vector<AudioRegionView*>::iterator i = all_equivalent_regions.begin(); i != all_equivalent_regions.end(); ++i) { + for (vector<RegionView*>::iterator i = all_equivalent_regions.begin(); i != all_equivalent_regions.end(); ++i) { selection->add (*i); } } @@ -3223,58 +3131,58 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, last_frame = 0; first_frame = max_frames; - for (AudioRegionSelection::iterator x = selection->audio_regions.begin(); x != selection->audio_regions.end(); ++x) { + for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) { if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) { - if ((*x)->region.last_frame() > last_frame) { - last_frame = (*x)->region.last_frame(); + if ((*x)->region().last_frame() > last_frame) { + last_frame = (*x)->region().last_frame(); } - if ((*x)->region.first_frame() < first_frame) { - first_frame = (*x)->region.first_frame(); + if ((*x)->region().first_frame() < first_frame) { + first_frame = (*x)->region().first_frame(); } } } /* 2. figure out the boundaries for our search for new objects */ - switch (clicked_regionview->region.coverage (first_frame, last_frame)) { + switch (clicked_regionview->region().coverage (first_frame, last_frame)) { case OverlapNone: cerr << "no overlap, first = " << first_frame << " last = " << last_frame << " region = " - << clicked_regionview->region.first_frame() << " .. " << clicked_regionview->region.last_frame() << endl; + << clicked_regionview->region().first_frame() << " .. " << clicked_regionview->region().last_frame() << endl; - if (last_frame < clicked_regionview->region.first_frame()) { + if (last_frame < clicked_regionview->region().first_frame()) { first_frame = last_frame; - last_frame = clicked_regionview->region.last_frame(); + last_frame = clicked_regionview->region().last_frame(); } else { last_frame = first_frame; - first_frame = clicked_regionview->region.first_frame(); + first_frame = clicked_regionview->region().first_frame(); } break; case OverlapExternal: cerr << "external overlap, first = " << first_frame << " last = " << last_frame << " region = " - << clicked_regionview->region.first_frame() << " .. " << clicked_regionview->region.last_frame() << endl; + << clicked_regionview->region().first_frame() << " .. " << clicked_regionview->region().last_frame() << endl; - if (last_frame < clicked_regionview->region.first_frame()) { + if (last_frame < clicked_regionview->region().first_frame()) { first_frame = last_frame; - last_frame = clicked_regionview->region.last_frame(); + last_frame = clicked_regionview->region().last_frame(); } else { last_frame = first_frame; - first_frame = clicked_regionview->region.first_frame(); + first_frame = clicked_regionview->region().first_frame(); } break; case OverlapInternal: cerr << "internal overlap, first = " << first_frame << " last = " << last_frame << " region = " - << clicked_regionview->region.first_frame() << " .. " << clicked_regionview->region.last_frame() << endl; + << clicked_regionview->region().first_frame() << " .. " << clicked_regionview->region().last_frame() << endl; - if (last_frame < clicked_regionview->region.first_frame()) { + if (last_frame < clicked_regionview->region().first_frame()) { first_frame = last_frame; - last_frame = clicked_regionview->region.last_frame(); + last_frame = clicked_regionview->region().last_frame(); } else { last_frame = first_frame; - first_frame = clicked_regionview->region.first_frame(); + first_frame = clicked_regionview->region().first_frame(); } break; @@ -3300,18 +3208,18 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, /* 3. convert to a vector of audio regions */ - vector<AudioRegionView*> audio_regions; + vector<RegionView*> regions; for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) { - AudioRegionView* arv; + RegionView* arv; - if ((arv = dynamic_cast<AudioRegionView*>(*x)) != 0) { - audio_regions.push_back (arv); + if ((arv = dynamic_cast<RegionView*>(*x)) != 0) { + regions.push_back (arv); } } - if (!audio_regions.empty()) { - selection->add (audio_regions); + if (!regions.empty()) { + selection->add (regions); commit = true; } } @@ -3321,37 +3229,32 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, } void -Editor::set_selected_regionview_from_region_list (Region& r, Selection::Operation op) +Editor::set_selected_regionview_from_region_list (Region& region, Selection::Operation op) { - vector<AudioRegionView*> all_equivalent_regions; - AudioRegion* region; - - if ((region = dynamic_cast<AudioRegion*>(&r)) == 0) { - return; - } + vector<RegionView*> all_equivalent_regions; for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - AudioTimeAxisView* tatv; + RouteTimeAxisView* tatv; - if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) { + if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) { - AudioPlaylist* pl; - vector<AudioRegion*> results; - AudioRegionView* marv; - AudioDiskstream* ds; + Playlist* pl; + vector<Region*> results; + RegionView* marv; + Diskstream* ds; if ((ds = tatv->get_diskstream()) == 0) { /* bus */ continue; } - if ((pl = ds->playlist()) != 0) { - pl->get_region_list_equivalent_regions (*region, results); + if ((pl = dynamic_cast<Playlist*>(ds->playlist())) != 0) { + pl->get_region_list_equivalent_regions (region, results); } - for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) { - if ((marv = tatv->view->find_view (**ir)) != 0) { + for (vector<Region*>::iterator ir = results.begin(); ir != results.end(); ++ir) { + if ((marv = tatv->view()->find_view (**ir)) != 0) { all_equivalent_regions.push_back (marv); } } @@ -3380,10 +3283,10 @@ Editor::set_selected_regionview_from_region_list (Region& r, Selection::Operatio bool Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, Region* r) { - AudioRegionView* rv; - AudioRegion* ar; + RegionView* rv; + Region* ar; - if ((ar = dynamic_cast<AudioRegion*> (r)) == 0) { + if ((ar = dynamic_cast<Region*> (r)) == 0) { return TRUE; } @@ -3395,7 +3298,7 @@ Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, a single other region. */ - if (selection->audio_regions.size() > 1) { + if (selection->regions.size() > 1) { return TRUE; } @@ -3560,7 +3463,7 @@ Editor::duplicate_dialog (bool dup_region) if (sscanf (text.c_str(), "%f", ×) == 1) { if (dup_region) { - AudioRegionSelection regions; + RegionSelection regions; regions.add (clicked_regionview); duplicate_some_regions (regions, times); } else { @@ -3611,9 +3514,9 @@ Editor::edit_mode_selection_done () string choice = edit_mode_selector.get_active_text(); EditMode mode = Slide; - if (choice == _("Splice")) { + if (choice == _("Splice Edit")) { mode = Splice; - } else if (choice == _("Slide")) { + } else if (choice == _("Slide Edit")) { mode = Slide; } @@ -3629,18 +3532,18 @@ Editor::snap_type_selection_done () string choice = snap_type_selector.get_active_text(); SnapType snaptype = SnapToFrame; - + if (choice == _("Beats/3")) { - snaptype = SnapToAThirdBeat; - } else if (choice == _("Beats/4")) { - snaptype = SnapToAQuarterBeat; - } else if (choice == _("Beats/8")) { - snaptype = SnapToAEighthBeat; - } else if (choice == _("Beats/16")) { - snaptype = SnapToASixteenthBeat; - } else if (choice == _("Beats/32")) { - snaptype = SnapToAThirtysecondBeat; - } else if (choice == _("Beats")) { + snaptype = SnapToAThirdBeat; + } else if (choice == _("Beats/4")) { + snaptype = SnapToAQuarterBeat; + } else if (choice == _("Beats/8")) { + snaptype = SnapToAEighthBeat; + } else if (choice == _("Beats/16")) { + snaptype = SnapToASixteenthBeat; + } else if (choice == _("Beats/32")) { + snaptype = SnapToAThirtysecondBeat; + } else if (choice == _("Beats")) { snaptype = SnapToBeat; } else if (choice == _("Bars")) { snaptype = SnapToBar; @@ -3668,10 +3571,10 @@ Editor::snap_type_selection_done () snaptype = SnapToSeconds; } else if (choice == _("Minutes")) { snaptype = SnapToMinutes; - } else if (choice == _("None")) { + } else if (choice == _("None")) { snaptype = SnapToFrame; } - + set_snap_to (snaptype); } @@ -3685,9 +3588,9 @@ Editor::snap_mode_selection_done () string choice = snap_mode_selector.get_active_text(); SnapMode mode = SnapNormal; - if (choice == _("Normal")) { + if (choice == _("Normal Snap")) { mode = SnapNormal; - } else if (choice == _("Magnetic")) { + } else if (choice == _("Magnetic Snap")) { mode = SnapMagnetic; } @@ -3704,15 +3607,15 @@ Editor::zoom_focus_selection_done () string choice = zoom_focus_selector.get_active_text(); ZoomFocus focus_type = ZoomFocusLeft; - if (choice == _("Left")) { + if (choice == _("Focus Left")) { focus_type = ZoomFocusLeft; - } else if (choice == _("Right")) { + } else if (choice == _("Focus Right")) { focus_type = ZoomFocusRight; - } else if (choice == _("Center")) { + } else if (choice == _("Focus Center")) { focus_type = ZoomFocusCenter; - } else if (choice == _("Playhead")) { + } else if (choice == _("Focus Playhead")) { focus_type = ZoomFocusPlayhead; - } else if (choice == _("Edit Cursor")) { + } else if (choice == _("Focus Edit Cursor")) { focus_type = ZoomFocusEdit; } @@ -3782,7 +3685,7 @@ void Editor::region_selection_changed () { for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - (*i)->set_selected_regionviews (selection->audio_regions); + (*i)->set_selected_regionviews (selection->regions); } } @@ -4052,8 +3955,8 @@ Editor::playlist_deletion_dialog (Playlist* pl) bool Editor::audio_region_selection_covers (jack_nframes_t where) { - for (AudioRegionSelection::iterator a = selection->audio_regions.begin(); a != selection->audio_regions.end(); ++a) { - if ((*a)->region.covers (where)) { + for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) { + if ((*a)->region().covers (where)) { return true; } } @@ -4064,10 +3967,10 @@ Editor::audio_region_selection_covers (jack_nframes_t where) void Editor::prepare_for_cleanup () { - cut_buffer->clear_audio_regions (); + cut_buffer->clear_regions (); cut_buffer->clear_playlists (); - selection->clear_audio_regions (); + selection->clear_regions (); selection->clear_playlists (); } diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 478a8c96ab..c31dfd5ede 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -40,7 +40,7 @@ #include <gtkmm2ext/click_box.h> #include <gtkmm2ext/dndtreeview.h> -#include <ardour/stateful.h> +#include <pbd/stateful.h> #include <ardour/session.h> #include <ardour/tempo.h> #include <ardour/location.h> @@ -69,6 +69,7 @@ namespace ARDOUR { class AudioDiskstream; class RouteGroup; class Playlist; + class AudioPlaylist; class Region; class Location; class TempoSection; @@ -83,6 +84,7 @@ namespace LADSPA { } class TimeAxisView; +class RouteTimeAxisView; class AudioTimeAxisView; class AutomationTimeAxisView; class AudioRegionView; @@ -100,6 +102,7 @@ class TrackSelection; class AutomationSelection; class MixerStrip; class StreamView; +class AudioStreamView; class ControlPoint; #ifdef FFT_ANALYSIS class AnalysisWindow; @@ -405,8 +408,8 @@ class Editor : public PublicEditor TimeAxisView* clicked_trackview; AudioTimeAxisView* clicked_audio_trackview; - AudioRegionView* clicked_regionview; - AudioRegionView* latest_regionview; + RegionView* clicked_regionview; + RegionView* latest_regionview; uint32_t clicked_selection; CrossfadeView* clicked_crossfadeview; ControlPoint* clicked_control_point; @@ -416,7 +419,7 @@ class Editor : public PublicEditor /* functions to be passed to mapover_audio_tracks(), possibly with sigc::bind()-supplied arguments */ - void mapped_set_selected_regionview_from_click (AudioTimeAxisView&, uint32_t, AudioRegionView*, vector<AudioRegionView*>*); + void mapped_set_selected_regionview_from_click (RouteTimeAxisView&, uint32_t, RegionView*, vector<RegionView*>*); void mapped_use_new_playlist (AudioTimeAxisView&, uint32_t); void mapped_use_copy_playlist (AudioTimeAxisView&, uint32_t); void mapped_clear_playlist (AudioTimeAxisView&, uint32_t); @@ -426,7 +429,7 @@ class Editor : public PublicEditor void button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type); bool button_release_can_deselect; - void catch_vanishing_audio_regionview (AudioRegionView *); + void catch_vanishing_regionview (RegionView *); bool set_selected_control_point_from_click (bool press, Selection::Operation op = Selection::Set, bool with_undo = true, bool no_remove=false); bool set_selected_track_from_click (bool press, Selection::Operation op = Selection::Set, bool with_undo = true, bool no_remove=false); @@ -434,7 +437,7 @@ class Editor : public PublicEditor void set_selected_regionview_from_region_list (ARDOUR::Region& region, Selection::Operation op = Selection::Set); bool set_selected_regionview_from_map_event (GdkEventAny*, StreamView*, ARDOUR::Region*); - void collect_new_region_view (AudioRegionView *); + void collect_new_region_view (RegionView *); Gtk::Menu track_context_menu; Gtk::Menu track_region_context_menu; @@ -455,12 +458,11 @@ class Editor : public PublicEditor Gtk::Menu* build_track_selection_context_menu (jack_nframes_t); void add_dstream_context_items (Gtk::Menu_Helpers::MenuList&); void add_bus_context_items (Gtk::Menu_Helpers::MenuList&); - void add_region_context_items (StreamView*, ARDOUR::Region*, Gtk::Menu_Helpers::MenuList&); - void add_crossfade_context_items (StreamView*, ARDOUR::Crossfade*, Gtk::Menu_Helpers::MenuList&, bool many); + void add_region_context_items (AudioStreamView*, ARDOUR::Region*, Gtk::Menu_Helpers::MenuList&); + void add_crossfade_context_items (AudioStreamView*, ARDOUR::Crossfade*, Gtk::Menu_Helpers::MenuList&, bool many); void add_selection_context_items (Gtk::Menu_Helpers::MenuList&); - void handle_new_route (ARDOUR::Route&); - void handle_new_route_p (ARDOUR::Route*); + void handle_new_route (boost::shared_ptr<ARDOUR::Route>); void remove_route (TimeAxisView *); bool route_removal; @@ -854,7 +856,7 @@ class Editor : public PublicEditor void lower_region_to_bottom (); void split_region (); void split_region_at (jack_nframes_t); - void split_regions_at (jack_nframes_t, AudioRegionSelection&); + void split_regions_at (jack_nframes_t, RegionSelection&); void crop_region_to_selection (); void set_a_regions_sync_position (ARDOUR::Region&, jack_nframes_t); void set_region_sync_from_edit_cursor (); @@ -867,13 +869,13 @@ class Editor : public PublicEditor void remove_clicked_region (); void destroy_clicked_region (); void edit_region (); - void duplicate_some_regions (AudioRegionSelection&, float times); + void duplicate_some_regions (RegionSelection&, float times); void duplicate_selection (float times); void region_fill_selection (); void region_fill_track (); - void audition_playlist_region_standalone (ARDOUR::AudioRegion&); - void audition_playlist_region_via_route (ARDOUR::AudioRegion&, ARDOUR::Route&); + void audition_playlist_region_standalone (ARDOUR::Region&); + void audition_playlist_region_via_route (ARDOUR::Region&, ARDOUR::Route&); void split_multichannel_region(); void reverse_region (); void normalize_region (); @@ -1020,7 +1022,7 @@ class Editor : public PublicEditor bool have_pending_keyboard_selection; jack_nframes_t pending_keyboard_selection_start; - ARDOUR::AudioRegion* select_region_for_operation (int dir, TimeAxisView **tv); + ARDOUR::Region* select_region_for_operation (int dir, TimeAxisView **tv); void extend_selection_to_end_of_region (bool next); void extend_selection_to_start_of_region (bool previous); @@ -1094,7 +1096,7 @@ class Editor : public PublicEditor void remove_gain_control_point (ArdourCanvas::Item*, GdkEvent*); void remove_control_point (ArdourCanvas::Item*, GdkEvent*); - void mouse_brush_insert_region (AudioRegionView*, jack_nframes_t pos); + void mouse_brush_insert_region (RegionView*, jack_nframes_t pos); void brush (jack_nframes_t); void show_verbose_time_cursor (jack_nframes_t frame, double offset = 0, double xpos=-1, double ypos=-1); @@ -1112,10 +1114,10 @@ class Editor : public PublicEditor bool canvas_fade_in_handle_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*); bool canvas_fade_out_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*); bool canvas_fade_out_handle_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*); - bool canvas_region_view_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*); - bool canvas_region_view_name_highlight_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*); - bool canvas_region_view_name_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*); - bool canvas_stream_view_event (GdkEvent* event,ArdourCanvas::Item*, AudioTimeAxisView*); + bool canvas_region_view_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*); + bool canvas_region_view_name_highlight_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*); + bool canvas_region_view_name_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*); + bool canvas_stream_view_event (GdkEvent* event,ArdourCanvas::Item*, RouteTimeAxisView*); bool canvas_marker_event (GdkEvent* event,ArdourCanvas::Item*, Marker*); bool canvas_zoom_rect_event (GdkEvent* event,ArdourCanvas::Item*); bool canvas_tempo_marker_event (GdkEvent* event,ArdourCanvas::Item*, TempoMarker*); @@ -1263,12 +1265,7 @@ class Editor : public PublicEditor void editor_mixer_button_toggled (); - AudioClock selection_start_clock; - Gtk::Label selection_start_clock_label; - AudioClock selection_end_clock; - Gtk::Label selection_end_clock_label; AudioClock edit_cursor_clock; - Gtk::Label edit_cursor_clock_label; AudioClock zoom_range_clock; Gtk::Button zoom_in_button; Gtk::Button zoom_out_button; @@ -1280,8 +1277,8 @@ class Editor : public PublicEditor Gtk::Table toolbar_selection_clock_table; Gtk::Label toolbar_selection_cursor_label; - Gtk::Table mouse_mode_button_table; - Gtkmm2ext::TearOff* mouse_mode_tearoff; + Gtk::HBox mouse_mode_button_box; + Gtkmm2ext::TearOff* mouse_mode_tearoff; Gtk::ToggleButton mouse_select_button; Gtk::ToggleButton mouse_move_button; Gtk::ToggleButton mouse_gain_button; @@ -1299,32 +1296,23 @@ class Editor : public PublicEditor Gtk::ToggleButton global_automation_button; Gtk::ComboBoxText edit_mode_selector; - Gtk::Label edit_mode_label; - Gtk::VBox edit_mode_box; + Gtk::VBox edit_mode_box; void edit_mode_selection_done (); Gtk::ComboBoxText snap_type_selector; - Gtk::Label snap_type_label; - Gtk::VBox snap_type_box; + Gtk::ComboBoxText snap_mode_selector; + Gtk::HBox snap_box; void snap_type_selection_done (); - - Gtk::ComboBoxText snap_mode_selector; - Gtk::Label snap_mode_label; - Gtk::VBox snap_mode_box; - void snap_mode_selection_done (); Gtk::ComboBoxText zoom_focus_selector; - Gtk::Label zoom_focus_label; Gtk::VBox zoom_focus_box; void zoom_focus_selection_done (); - Gtk::Label zoom_indicator_label; - Gtk::HBox zoom_indicator_box; - Gtk::VBox zoom_indicator_vbox; + Gtk::HBox zoom_box; void update_zoom_indicator (); void zoom_adjustment_changed(); @@ -1533,12 +1521,12 @@ class Editor : public PublicEditor void start_trim (ArdourCanvas::Item*, GdkEvent*); void point_trim (GdkEvent*); void trim_motion_callback (ArdourCanvas::Item*, GdkEvent*); - void single_contents_trim (AudioRegionView&, jack_nframes_t, bool, bool, bool); - void single_start_trim (AudioRegionView&, jack_nframes_t, bool, bool); - void single_end_trim (AudioRegionView&, jack_nframes_t, bool, bool); + void single_contents_trim (RegionView&, jack_nframes_t, bool, bool, bool); + void single_start_trim (RegionView&, jack_nframes_t, bool, bool); + void single_end_trim (RegionView&, jack_nframes_t, bool, bool); void trim_finished_callback (ArdourCanvas::Item*, GdkEvent*); - void thaw_region_after_trim (AudioRegionView& rv); + void thaw_region_after_trim (RegionView& rv); void trim_region_to_edit_cursor (); void trim_region_from_edit_cursor (); @@ -1592,7 +1580,7 @@ class Editor : public PublicEditor void export_range (jack_nframes_t start, jack_nframes_t end); void export_range_markers (); - int write_region_selection(AudioRegionSelection&); + int write_region_selection(RegionSelection&); bool write_region (string path, ARDOUR::AudioRegion&); void export_region (); void bounce_region_selection (); @@ -1600,7 +1588,7 @@ class Editor : public PublicEditor void external_edit_region (); int write_audio_selection (TimeSelection&); - bool write_audio_range (ARDOUR::Playlist&, uint32_t channels, list<ARDOUR::AudioRange>&); + bool write_audio_range (ARDOUR::AudioPlaylist&, uint32_t channels, list<ARDOUR::AudioRange>&); void write_selection (); @@ -1671,7 +1659,7 @@ class Editor : public PublicEditor struct TimeStretchDialog : public ArdourDialog { ARDOUR::Session::TimeStretchRequest request; Editor& editor; - AudioRegionSelection regions; + RegionSelection regions; Gtk::ProgressBar progress_bar; Gtk::ToggleButton quick_button; Gtk::ToggleButton antialias_button; @@ -1697,7 +1685,7 @@ class Editor : public PublicEditor TimeStretchDialog* current_timestretch; static void* timestretch_thread (void *arg); - int run_timestretch (AudioRegionSelection&, float fraction); + int run_timestretch (RegionSelection&, float fraction); void do_timestretch (TimeStretchDialog&); /* editor-mixer strip */ @@ -1776,7 +1764,6 @@ class Editor : public PublicEditor Gtk::Button nudge_backward_button; Gtk::HBox nudge_hbox; Gtk::VBox nudge_vbox; - Gtk::Label nudge_label; AudioClock nudge_clock; jack_nframes_t get_nudge_distance (jack_nframes_t pos, jack_nframes_t& next); @@ -1799,11 +1786,11 @@ class Editor : public PublicEditor sigc::connection step_timeout; TimeAxisView* entered_track; - AudioRegionView* entered_regionview; + RegionView* entered_regionview; bool clear_entered_track; gint left_track_canvas (GdkEventCrossing*); void set_entered_track (TimeAxisView*); - void set_entered_regionview (AudioRegionView*); + void set_entered_regionview (RegionView*); gint left_automation_track (); bool _new_regionviews_show_envelope; diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index e20e6ee8eb..65195ca822 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -357,6 +357,8 @@ Editor::register_actions () ActionManager::session_sensitive_actions.push_back (act); act = ActionManager::register_action (editor_actions, X_("addExternalAudioAsTrack"), _("as Tracks"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportAsTrack)); ActionManager::session_sensitive_actions.push_back (act); + act = ActionManager::register_action (editor_actions, X_("addExternalAudioAsTapeTrack"), _("as Tape Tracks"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportAsTapeTrack)); + ActionManager::session_sensitive_actions.push_back (act); act = ActionManager::register_action (editor_actions, X_("addExternalAudioToTrack"), _("to Tracks"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)); ActionManager::session_sensitive_actions.push_back (act); diff --git a/gtk2_ardour/editor_audio_import.cc b/gtk2_ardour/editor_audio_import.cc index 2c64f2cf15..7524f9605c 100644 --- a/gtk2_ardour/editor_audio_import.cc +++ b/gtk2_ardour/editor_audio_import.cc @@ -268,7 +268,7 @@ Editor::embed_sndfile (Glib::ustring path, bool split, bool multiple_files, bool idspec += string_compose(":%1", n); try { - source = AudioFileSource::create (idspec.c_str()); + source = AudioFileSource::create (idspec.c_str(), (mode == ImportAsTrack ? AudioFileSource::Destructive : AudioFileSource::Flag (0))); sources.push_back(source); } @@ -306,16 +306,18 @@ Editor::embed_sndfile (Glib::ustring path, bool split, bool multiple_files, bool } int - Editor::finish_bringing_in_audio (AudioRegion& region, uint32_t in_chans, uint32_t out_chans, AudioTrack* track, jack_nframes_t& pos, ImportMode mode) - { - switch (mode) { - case ImportAsRegion: - /* relax, its been done */ - break; +Editor::finish_bringing_in_audio (AudioRegion& region, uint32_t in_chans, uint32_t out_chans, AudioTrack* track, jack_nframes_t& pos, ImportMode mode) +{ + AudioRegion* copy; + + switch (mode) { + case ImportAsRegion: + /* relax, its been done */ + break; case ImportToTrack: if (track) { - Playlist* playlist = track->disk_stream().playlist(); + Playlist* playlist = track->diskstream().playlist(); AudioRegion* copy = new AudioRegion (region); begin_reversible_command (_("insert sndfile")); @@ -329,11 +331,21 @@ int break; case ImportAsTrack: - AudioTrack* at = session->new_audio_track (in_chans, out_chans); - AudioRegion* copy = new AudioRegion (region); - at->disk_stream().playlist()->add_region (*copy, pos); + { + boost::shared_ptr<AudioTrack> at (session->new_audio_track (in_chans, out_chans, Normal)); + copy = new AudioRegion (region); + at->diskstream().playlist()->add_region (*copy, pos); + break; + } + + case ImportAsTapeTrack: + { + boost::shared_ptr<AudioTrack> at (session->new_audio_track (in_chans, out_chans, Destructive)); + copy = new AudioRegion (region); + at->diskstream().playlist()->add_region (*copy, pos); break; } + } return 0; } diff --git a/gtk2_ardour/editor_audiotrack.cc b/gtk2_ardour/editor_audiotrack.cc index acad3371a0..5b575b4814 100644 --- a/gtk2_ardour/editor_audiotrack.cc +++ b/gtk2_ardour/editor_audiotrack.cc @@ -4,7 +4,7 @@ #include "editor.h" #include "editing.h" #include "audio_time_axis.h" -#include "regionview.h" +#include "region_view.h" #include "selection.h" using namespace ARDOUR; diff --git a/gtk2_ardour/editor_canvas.cc b/gtk2_ardour/editor_canvas.cc index 41350a1da4..e8ba2b8a60 100644 --- a/gtk2_ardour/editor_canvas.cc +++ b/gtk2_ardour/editor_canvas.cc @@ -128,7 +128,7 @@ Editor::initialize_canvas () time_line_group = new ArdourCanvas::Group (*track_canvas.root(), 0.0, 0.0); cursor_group = new ArdourCanvas::Group (*track_canvas.root(), 0.0, 0.0); - + time_canvas.set_name ("EditorTimeCanvas"); time_canvas.add_events (Gdk::POINTER_MOTION_HINT_MASK); time_canvas.set_flags (CAN_FOCUS); diff --git a/gtk2_ardour/editor_canvas_events.cc b/gtk2_ardour/editor_canvas_events.cc index 43114534c5..8e635bbe13 100644 --- a/gtk2_ardour/editor_canvas_events.cc +++ b/gtk2_ardour/editor_canvas_events.cc @@ -26,8 +26,8 @@ #include "editor.h" #include "public_editor.h" -#include "regionview.h" -#include "streamview.h" +#include "audio_region_view.h" +#include "audio_streamview.h" #include "crossfade_view.h" #include "audio_time_axis.h" #include "region_gain_line.h" @@ -212,7 +212,7 @@ Editor::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type) } bool -Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv) +Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView *rv) { gint ret = FALSE; @@ -251,7 +251,7 @@ Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, Aud } bool -Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, AudioTimeAxisView *tv) +Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv) { bool ret = FALSE; @@ -262,7 +262,7 @@ Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, Aud clicked_regionview = 0; clicked_control_point = 0; clicked_trackview = tv; - clicked_audio_trackview = tv; + clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(tv); ret = button_press_handler (item, event, StreamItem); break; @@ -512,22 +512,25 @@ Editor::canvas_crossfade_view_event (GdkEvent* event, ArdourCanvas::Item* item, if ((atv = dynamic_cast<AudioTimeAxisView*>(&tv)) != 0) { if (atv->is_audio_track()) { - - AudioPlaylist* pl = atv->get_diskstream()->playlist(); - Playlist::RegionList* rl = pl->regions_at (event_frame (event)); - if (!rl->empty()) { - DescendingRegionLayerSorter cmp; - rl->sort (cmp); + AudioPlaylist* pl; + if ((pl = dynamic_cast<AudioPlaylist*> (atv->get_diskstream()->playlist())) != 0) { + + Playlist::RegionList* rl = pl->regions_at (event_frame (event)); + + if (!rl->empty()) { + DescendingRegionLayerSorter cmp; + rl->sort (cmp); - AudioRegionView* arv = atv->view->find_view (*(dynamic_cast<AudioRegion*> (rl->front()))); + RegionView* rv = atv->view()->find_view (*rl->front()); - /* proxy */ - - delete rl; + /* proxy */ - return canvas_region_view_event (event, arv->get_canvas_group(), arv); - } + delete rl; + + return canvas_region_view_event (event, rv->get_canvas_group(), rv); + } + } } } @@ -696,7 +699,7 @@ Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* it bool -Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, AudioRegionView* rv) +Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv) { bool ret = false; @@ -708,20 +711,20 @@ Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas:: clicked_control_point = 0; clicked_trackview = &clicked_regionview->get_time_axis_view(); clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(clicked_trackview); - ret = button_press_handler (item, event, AudioRegionViewNameHighlight); + ret = button_press_handler (item, event, RegionViewNameHighlight); break; case GDK_BUTTON_RELEASE: - ret = button_release_handler (item, event, AudioRegionViewNameHighlight); + ret = button_release_handler (item, event, RegionViewNameHighlight); break; case GDK_MOTION_NOTIFY: - ret = motion_handler (item, event, AudioRegionViewNameHighlight); + ret = motion_handler (item, event, RegionViewNameHighlight); break; case GDK_ENTER_NOTIFY: - ret = enter_handler (item, event, AudioRegionViewNameHighlight); + ret = enter_handler (item, event, RegionViewNameHighlight); break; case GDK_LEAVE_NOTIFY: - ret = leave_handler (item, event, AudioRegionViewNameHighlight); + ret = leave_handler (item, event, RegionViewNameHighlight); break; default: @@ -732,7 +735,7 @@ Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas:: } bool -Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView* rv) +Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv) { bool ret = false; @@ -744,20 +747,20 @@ Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item clicked_control_point = 0; clicked_trackview = &clicked_regionview->get_time_axis_view(); clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(clicked_trackview); - ret = button_press_handler (item, event, AudioRegionViewName); + ret = button_press_handler (item, event, RegionViewName); break; case GDK_BUTTON_RELEASE: - ret = button_release_handler (item, event, AudioRegionViewName); + ret = button_release_handler (item, event, RegionViewName); break; case GDK_MOTION_NOTIFY: - ret = motion_handler (item, event, AudioRegionViewName); + ret = motion_handler (item, event, RegionViewName); break; case GDK_ENTER_NOTIFY: - ret = enter_handler (item, event, AudioRegionViewName); + ret = enter_handler (item, event, RegionViewName); break; case GDK_LEAVE_NOTIFY: - ret = leave_handler (item, event, AudioRegionViewName); + ret = leave_handler (item, event, RegionViewName); break; default: diff --git a/gtk2_ardour/editor_export_audio.cc b/gtk2_ardour/editor_export_audio.cc index 7339536e42..46a704b435 100644 --- a/gtk2_ardour/editor_export_audio.cc +++ b/gtk2_ardour/editor_export_audio.cc @@ -31,7 +31,7 @@ #include "selection.h" #include "time_axis_view.h" #include "audio_time_axis.h" -#include "regionview.h" +#include "audio_region_view.h" #include <pbd/pthread_utils.h> #include <ardour/types.h> @@ -92,12 +92,12 @@ Editor::export_region () return; } - ExportDialog* dialog = new ExportRegionDialog (*this, &clicked_regionview->region); + ExportDialog* dialog = new ExportRegionDialog (*this, &clicked_regionview->region()); dialog->connect_to_session (session); dialog->set_range ( - clicked_regionview->region.first_frame(), - clicked_regionview->region.last_frame()); + clicked_regionview->region().first_frame(), + clicked_regionview->region().last_frame()); dialog->start_export(); } @@ -123,24 +123,26 @@ Editor::export_range_markers () } int -Editor::write_region_selection (AudioRegionSelection& regions) +Editor::write_region_selection (RegionSelection& regions) { - for (AudioRegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) { - if (write_region ("", (*i)->region) == false) { - return -1; - } + for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) { + AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*i); + if (arv) + if (write_region ("", arv->audio_region()) == false) + return -1; } + return 0; } void Editor::bounce_region_selection () { - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { - AudioRegion& region ((*i)->region); - AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&(*i)->get_time_axis_view()); - AudioTrack* track = dynamic_cast<AudioTrack*>(&(atv->route())); + Region& region ((*i)->region()); + RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view()); + Track* track = dynamic_cast<Track*>(rtv->route().get()); InterThreadInfo itt; @@ -287,7 +289,7 @@ Editor::write_audio_selection (TimeSelection& ts) if (atv->is_audio_track()) { - Playlist* playlist = atv->get_diskstream()->playlist(); + AudioPlaylist* playlist = dynamic_cast<AudioPlaylist*>(atv->get_diskstream()->playlist()); if (playlist && write_audio_range (*playlist, atv->get_diskstream()->n_channels(), ts) == 0) { ret = -1; @@ -300,7 +302,7 @@ Editor::write_audio_selection (TimeSelection& ts) } bool -Editor::write_audio_range (Playlist& playlist, uint32_t channels, list<AudioRange>& range) +Editor::write_audio_range (AudioPlaylist& playlist, uint32_t channels, list<AudioRange>& range) { AudioFileSource* fs; const jack_nframes_t chunk_size = 4096; @@ -435,7 +437,7 @@ Editor::write_selection () { if (!selection->time.empty()) { write_audio_selection (selection->time); - } else if (!selection->audio_regions.empty()) { - write_region_selection (selection->audio_regions); + } else if (!selection->regions.empty()) { + write_region_selection (selection->regions); } } diff --git a/gtk2_ardour/editor_items.h b/gtk2_ardour/editor_items.h index 4f6010ec2c..7f3a0d3fcc 100644 --- a/gtk2_ardour/editor_items.h +++ b/gtk2_ardour/editor_items.h @@ -23,8 +23,8 @@ enum ItemType { TempoMarkerItem, MeterBarItem, TempoBarItem, - AudioRegionViewNameHighlight, - AudioRegionViewName, + RegionViewNameHighlight, + RegionViewName, StartSelectionTrimItem, EndSelectionTrimItem, AutomationTrackItem, diff --git a/gtk2_ardour/editor_keyboard.cc b/gtk2_ardour/editor_keyboard.cc index b665f8b0a6..a0368b23b0 100644 --- a/gtk2_ardour/editor_keyboard.cc +++ b/gtk2_ardour/editor_keyboard.cc @@ -23,7 +23,7 @@ #include <pbd/memento_command.h> #include "editor.h" -#include "regionview.h" +#include "region_view.h" #include "selection.h" #include "i18n.h" @@ -82,10 +82,10 @@ Editor::kbd_do_split (GdkEvent* ev) jack_nframes_t where = event_frame (ev); if (entered_regionview) { - if (selection->audio_regions.find (entered_regionview) != selection->audio_regions.end()) { - split_regions_at (where, selection->audio_regions); + if (selection->regions.find (entered_regionview) != selection->regions.end()) { + split_regions_at (where, selection->regions); } else { - AudioRegionSelection s; + RegionSelection s; s.add (entered_regionview); split_regions_at (where, s); } @@ -103,11 +103,11 @@ Editor::kbd_mute_unmute_region () { if (entered_regionview) { begin_reversible_command (_("mute region")); - XMLNode &before = entered_regionview->region.playlist()->get_state(); + XMLNode &before = entered_regionview->region().playlist()->get_state(); - entered_regionview->region.set_muted (!entered_regionview->region.muted()); + entered_regionview->region().set_muted (!entered_regionview->region().muted()); - XMLNode &after = entered_regionview->region.playlist()->get_state(); + XMLNode &after = entered_regionview->region().playlist()->get_state(); session->add_command (new MementoCommand<ARDOUR::Playlist>(*(entered_regionview->region.playlist()), before, after)); commit_reversible_command(); } @@ -126,7 +126,7 @@ Editor::kbd_do_set_sync_position (GdkEvent* ev) snap_to (where); if (entered_regionview) { - set_a_regions_sync_position (entered_regionview->region, where); + set_a_regions_sync_position (entered_regionview->region(), where); } } diff --git a/gtk2_ardour/editor_keys.cc b/gtk2_ardour/editor_keys.cc index baa158cbf8..1bcaafd279 100644 --- a/gtk2_ardour/editor_keys.cc +++ b/gtk2_ardour/editor_keys.cc @@ -30,7 +30,7 @@ #include "ardour_ui.h" #include "editor.h" #include "time_axis_view.h" -#include "regionview.h" +#include "region_view.h" #include "selection.h" #include "i18n.h" @@ -66,7 +66,7 @@ Editor::keyboard_selection_begin () void Editor::keyboard_duplicate_region () { - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } @@ -74,9 +74,9 @@ Editor::keyboard_duplicate_region () bool was_floating; if (get_prefix (prefix, was_floating) == 0) { - duplicate_some_regions (selection->audio_regions, prefix); + duplicate_some_regions (selection->regions, prefix); } else { - duplicate_some_regions (selection->audio_regions, 1); + duplicate_some_regions (selection->regions, 1); } } diff --git a/gtk2_ardour/editor_markers.cc b/gtk2_ardour/editor_markers.cc index c4d8f3143f..ccc1415888 100644 --- a/gtk2_ardour/editor_markers.cc +++ b/gtk2_ardour/editor_markers.cc @@ -717,9 +717,9 @@ Editor::marker_menu_set_from_selection () } } else { - if (!selection->audio_regions.empty()) { - l->set_start (selection->audio_regions.start()); - l->set_end (selection->audio_regions.end_frame()); + if (!selection->regions.empty()) { + l->set_start (selection->regions.start()); + l->set_end (selection->regions.end_frame()); } } } diff --git a/gtk2_ardour/editor_mixer.cc b/gtk2_ardour/editor_mixer.cc index a55b6f2066..246dbdc647 100644 --- a/gtk2_ardour/editor_mixer.cc +++ b/gtk2_ardour/editor_mixer.cc @@ -131,7 +131,7 @@ Editor::set_selected_mixer_strip (TimeAxisView& view) /* might be nothing to do */ - if (¤t_mixer_strip->route() == &at->route()) { + if (current_mixer_strip->route() == at->route()) { return; } @@ -221,7 +221,7 @@ Editor::current_mixer_strip_hidden () AudioTimeAxisView* tmp; if ((tmp = dynamic_cast<AudioTimeAxisView*>(*i)) != 0) { - if (&(tmp->route()) == &(current_mixer_strip->route())) { + if (tmp->route() == current_mixer_strip->route()) { (*i)->set_selected (false); break; } @@ -270,8 +270,6 @@ Editor::session_going_away () group_model->clear (); edit_cursor_clock.set_session (0); - selection_start_clock.set_session (0); - selection_end_clock.set_session (0); zoom_range_clock.set_session (0); nudge_clock.set_session (0); diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index c7199984a8..f7abe7fdea 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -18,6 +18,7 @@ $Id$ */ +#include <cassert> #include <cstdlib> #include <stdint.h> #include <cmath> @@ -33,7 +34,7 @@ #include "editor.h" #include "time_axis_view.h" #include "audio_time_axis.h" -#include "regionview.h" +#include "audio_region_view.h" #include "marker.h" #include "streamview.h" #include "region_gain_line.h" @@ -183,7 +184,7 @@ Editor::set_mouse_mode (MouseMode m, bool force) show the object (region) selection. */ - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { (*i)->set_should_show_selection (true); } for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { @@ -320,8 +321,8 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it commit = (c1 || c2); break; - case AudioRegionViewNameHighlight: - case AudioRegionViewName: + case RegionViewNameHighlight: + case RegionViewName: c1 = set_selected_track_from_click (press, op, true, true); c2 = set_selected_regionview_from_click (press, op, true); commit = (c1 || c2); @@ -522,12 +523,12 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp } break; - case AudioRegionViewNameHighlight: + case RegionViewNameHighlight: start_trim (item, event); return true; break; - case AudioRegionViewName: + case RegionViewName: /* rename happens on edit clicks */ start_trim (clicked_regionview->get_name_highlight(), event); return true; @@ -693,12 +694,12 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp switch (item_type) { - case AudioRegionViewNameHighlight: + case RegionViewNameHighlight: start_trim (item, event); return true; break; - case AudioRegionViewName: + case RegionViewName: start_trim (clicked_regionview->get_name_highlight(), event); return true; break; @@ -854,7 +855,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT edit_meter_marker (item); break; - case AudioRegionViewName: + case RegionViewName: if (clicked_regionview->name_active()) { return mouse_rename_region (item, event); } @@ -889,8 +890,8 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT break; case RegionItem: - case AudioRegionViewNameHighlight: - case AudioRegionViewName: + case RegionViewNameHighlight: + case RegionViewName: popup_track_context_menu (1, event->button.time, item_type, false, where); break; @@ -1048,9 +1049,13 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT break; case MouseGain: + // Gain only makes sense for audio regions + if ( ! dynamic_cast<AudioRegionView*>(clicked_regionview)) + break; + switch (item_type) { case RegionItem: - clicked_regionview->add_gain_point_event (item, event); + dynamic_cast<AudioRegionView*>(clicked_regionview)->add_gain_point_event (item, event); return true; break; @@ -1204,7 +1209,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ } break; - case AudioRegionViewNameHighlight: + case RegionViewNameHighlight: if (is_drawable() && mouse_mode == MouseObject) { track_canvas.get_window()->set_cursor (*trimmer_cursor); } @@ -1231,11 +1236,11 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ } break; - case AudioRegionViewName: + case RegionViewName: /* when the name is not an active item, the entire name highlight is for trimming */ - if (!reinterpret_cast<AudioRegionView *> (item->get_data ("regionview"))->name_active()) { + if (!reinterpret_cast<RegionView *> (item->get_data ("regionview"))->name_active()) { if (mouse_mode == MouseObject && is_drawable()) { track_canvas.get_window()->set_cursor (*trimmer_cursor); } @@ -1340,7 +1345,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ ControlPoint* cp; Marker *marker; Location *loc; - AudioRegionView* rv; + RegionView* rv; bool is_start; switch (item_type) { @@ -1362,7 +1367,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ hide_verbose_canvas_cursor (); break; - case AudioRegionViewNameHighlight: + case RegionViewNameHighlight: case StartSelectionTrimItem: case EndSelectionTrimItem: case EditCursorItem: @@ -1393,9 +1398,9 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ } break; - case AudioRegionViewName: + case RegionViewName: /* see enter_handler() for notes */ - if (!reinterpret_cast<AudioRegionView *> (item->get_data ("regionview"))->name_active()) { + if (!reinterpret_cast<RegionView *> (item->get_data ("regionview"))->name_active()) { if (is_drawable() && mouse_mode == MouseObject) { track_canvas.get_window()->set_cursor (*current_canvas_cursor); } @@ -1430,7 +1435,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ case FadeInHandleItem: case FadeOutHandleItem: - rv = static_cast<AudioRegionView*>(item->get_data ("regionview")); + rv = static_cast<RegionView*>(item->get_data ("regionview")); { ArdourCanvas::SimpleRect *rect = dynamic_cast<ArdourCanvas::SimpleRect *> (item); if (rect) { @@ -1525,7 +1530,7 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item case PanAutomationControlPointItem: case TempoMarkerItem: case MeterMarkerItem: - case AudioRegionViewNameHighlight: + case RegionViewNameHighlight: case StartSelectionTrimItem: case EndSelectionTrimItem: case SelectionItem: @@ -1746,7 +1751,7 @@ Editor::start_fade_in_grab (ArdourCanvas::Item* item, GdkEvent* event) AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data); - drag_info.pointer_frame_offset = drag_info.grab_frame - ((jack_nframes_t) arv->region.fade_in().back()->when + arv->region.position()); + drag_info.pointer_frame_offset = drag_info.grab_frame - ((jack_nframes_t) arv->audio_region().fade_in().back()->when + arv->region().position()); } void @@ -1767,17 +1772,17 @@ Editor::fade_in_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) snap_to (pos); } - if (pos < (arv->region.position() + 64)) { + if (pos < (arv->region().position() + 64)) { fade_length = 64; // this should be a minimum defined somewhere - } else if (pos > arv->region.last_frame()) { - fade_length = arv->region.length(); + } else if (pos > arv->region().last_frame()) { + fade_length = arv->region().length(); } else { - fade_length = pos - arv->region.position(); + fade_length = pos - arv->region().position(); } arv->reset_fade_in_shape_width (fade_length); - show_verbose_duration_cursor (arv->region.position(), arv->region.position() + fade_length, 10); + show_verbose_duration_cursor (arv->region().position(), arv->region().position() + fade_length, 10); drag_info.first_move = false; } @@ -1802,23 +1807,23 @@ Editor::fade_in_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* even snap_to (pos); } - if (pos < (arv->region.position() + 64)) { + if (pos < (arv->region().position() + 64)) { fade_length = 64; // this should be a minimum defined somewhere } - else if (pos > arv->region.last_frame()) { - fade_length = arv->region.length(); + else if (pos > arv->region().last_frame()) { + fade_length = arv->region().length(); } else { - fade_length = pos - arv->region.position(); + fade_length = pos - arv->region().position(); } begin_reversible_command (_("change fade in length")); - XMLNode &before = arv->region.get_state(); + XMLNode &before = arv->audio_region().get_state(); - arv->region.set_fade_in_length (fade_length); + arv->audio_region().set_fade_in_length (fade_length); - XMLNode &after = arv->region.get_state(); - session->add_command(new MementoCommand<ARDOUR::AudioRegion>(arv->region, + XMLNode &after = arv->audio_region().get_state(); + session->add_command(new MementoCommand<ARDOUR::AudioRegion>(arv->audio_regio(), before, after)); commit_reversible_command (); @@ -1841,7 +1846,7 @@ Editor::start_fade_out_grab (ArdourCanvas::Item* item, GdkEvent* event) AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data); - drag_info.pointer_frame_offset = drag_info.grab_frame - (arv->region.length() - (jack_nframes_t) arv->region.fade_out().back()->when + arv->region.position()); + drag_info.pointer_frame_offset = drag_info.grab_frame - (arv->region().length() - (jack_nframes_t) arv->audio_region().fade_out().back()->when + arv->region().position()); } void @@ -1862,19 +1867,19 @@ Editor::fade_out_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event snap_to (pos); } - if (pos > (arv->region.last_frame() - 64)) { + if (pos > (arv->region().last_frame() - 64)) { fade_length = 64; // this should really be a minimum fade defined somewhere } - else if (pos < arv->region.position()) { - fade_length = arv->region.length(); + else if (pos < arv->region().position()) { + fade_length = arv->region().length(); } else { - fade_length = arv->region.last_frame() - pos; + fade_length = arv->region().last_frame() - pos; } arv->reset_fade_out_shape_width (fade_length); - show_verbose_duration_cursor (arv->region.last_frame() - fade_length, arv->region.last_frame(), 10); + show_verbose_duration_cursor (arv->region().last_frame() - fade_length, arv->region().last_frame(), 10); drag_info.first_move = false; } @@ -1899,23 +1904,23 @@ Editor::fade_out_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* eve snap_to (pos); } - if (pos > (arv->region.last_frame() - 64)) { + if (pos > (arv->region().last_frame() - 64)) { fade_length = 64; // this should really be a minimum fade defined somewhere } - else if (pos < arv->region.position()) { - fade_length = arv->region.length(); + else if (pos < arv->region().position()) { + fade_length = arv->region().length(); } else { - fade_length = arv->region.last_frame() - pos; + fade_length = arv->region().last_frame() - pos; } begin_reversible_command (_("change fade out length")); - XMLNode &before = arv->region.get_state(); + XMLNode &before = arv->region().get_state(); - arv->region.set_fade_out_length (fade_length); + arv->audio_region().set_fade_out_length (fade_length); - XMLNode &after = arv->region.get_state(); - session->add_command(new MementoCommand<ARDOUR::AudioRegion>(arv->region, before, after)); + XMLNode &after = arv->region().get_state(); + session->add_command(new MementoCommand<ARDOUR::AudioRegion>(arv->region(), before, after)); commit_reversible_command (); fade_out_drag_motion_callback (item, event); @@ -2038,7 +2043,7 @@ Editor::start_marker_grab (ArdourCanvas::Item* item, GdkEvent* event) drag_info.copied_location = new Location (*location); drag_info.pointer_frame_offset = drag_info.grab_frame - (is_start ? location->start() : location->end()); - + update_marker_drag_item (location); if (location->is_mark()) { @@ -2097,31 +2102,39 @@ Editor::marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) move_both = true; } - if (is_start) { // start marker + if (copy_location->is_mark()) { + /* just move it */ - if (move_both) { - copy_location->set_start (newframe); - copy_location->set_end (newframe + f_delta); - } else if (newframe < copy_location->end()) { - copy_location->set_start (newframe); - } else { - snap_to (next, 1, true); - copy_location->set_end (next); - copy_location->set_start (newframe); - } + copy_location->set_start (newframe); - } else { // end marker + } else { - if (move_both) { - copy_location->set_end (newframe); - copy_location->set_start (newframe - f_delta); - } else if (newframe > copy_location->start()) { - copy_location->set_end (newframe); + if (is_start) { // start-of-range marker - } else if (newframe > 0) { - snap_to (next, -1, true); - copy_location->set_start (next); - copy_location->set_end (newframe); + if (move_both) { + copy_location->set_start (newframe); + copy_location->set_end (newframe + f_delta); + } else if (newframe < copy_location->end()) { + copy_location->set_start (newframe); + } else { + snap_to (next, 1, true); + copy_location->set_end (next); + copy_location->set_start (newframe); + } + + } else { // end marker + + if (move_both) { + copy_location->set_end (newframe); + copy_location->set_start (newframe - f_delta); + } else if (newframe > copy_location->start()) { + copy_location->set_end (newframe); + + } else if (newframe > 0) { + snap_to (next, -1, true); + copy_location->set_start (next); + copy_location->set_end (newframe); + } } } @@ -2154,7 +2167,11 @@ Editor::marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event Location * location = find_location_from_marker (marker, is_start); if (location) { - location->set (drag_info.copied_location->start(), drag_info.copied_location->end()); + if (location->is_mark()) { + location->set_start (drag_info.copied_location->start()); + } else { + location->set (drag_info.copied_location->start(), drag_info.copied_location->end()); + } } XMLNode &after = session->locations()->get_state(); @@ -2553,7 +2570,8 @@ Editor::start_line_grab_from_regionview (ArdourCanvas::Item* item, GdkEvent* eve { switch (mouse_mode) { case MouseGain: - start_line_grab (clicked_regionview->get_gain_line(), event); + assert(dynamic_cast<AudioRegionView*>(clicked_regionview)); + start_line_grab (dynamic_cast<AudioRegionView*>(clicked_regionview)->get_gain_line(), event); break; default: break; @@ -2647,7 +2665,7 @@ Editor::line_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event) void Editor::start_region_grab (ArdourCanvas::Item* item, GdkEvent* event) { - if (selection->audio_regions.empty() || clicked_regionview == 0) { + if (selection->regions.empty() || clicked_regionview == 0) { return; } @@ -2661,13 +2679,13 @@ Editor::start_region_grab (ArdourCanvas::Item* item, GdkEvent* event) double speed = 1.0; TimeAxisView* tvp = clicked_trackview; - AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp); + RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp); if (tv && tv->is_audio_track()) { speed = tv->get_diskstream()->speed(); } - drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed); + drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region().position() / speed); drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position; drag_info.last_trackview = &clicked_regionview->get_time_axis_view(); // we want a move threshold @@ -2681,7 +2699,7 @@ Editor::start_region_grab (ArdourCanvas::Item* item, GdkEvent* event) void Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event) { - if (selection->audio_regions.empty() || clicked_regionview == 0) { + if (selection->regions.empty() || clicked_regionview == 0) { return; } @@ -2692,7 +2710,7 @@ Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event) start_grab(event); TimeAxisView* tv = &clicked_regionview->get_time_axis_view(); - AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(tv); + RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*>(tv); double speed = 1.0; if (atv && atv->is_audio_track()) { @@ -2700,7 +2718,7 @@ Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event) } drag_info.last_trackview = &clicked_regionview->get_time_axis_view(); - drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed); + drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region().position() / speed); drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position; // we want a move threshold drag_info.want_move_threshold = true; @@ -2711,7 +2729,7 @@ Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event) void Editor::start_region_brush_grab (ArdourCanvas::Item* item, GdkEvent* event) { - if (selection->audio_regions.empty() || clicked_regionview == 0) { + if (selection->regions.empty() || clicked_regionview == 0) { return; } @@ -2725,13 +2743,13 @@ Editor::start_region_brush_grab (ArdourCanvas::Item* item, GdkEvent* event) double speed = 1.0; TimeAxisView* tvp = clicked_trackview; - AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp); + RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp); if (tv && tv->is_audio_track()) { speed = tv->get_diskstream()->speed(); } - drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed); + drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region().position() / speed); drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position; drag_info.last_trackview = &clicked_regionview->get_time_axis_view(); // we want a move threshold @@ -2746,7 +2764,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) { double x_delta; double y_delta = 0; - AudioRegionView *rv = reinterpret_cast<AudioRegionView*> (drag_info.data); + RegionView* rv = reinterpret_cast<RegionView*> (drag_info.data); jack_nframes_t pending_region_position = 0; int32_t pointer_y_span = 0, canvas_pointer_y_span = 0, original_pointer_order; int32_t visible_y_high = 0, visible_y_low = 512; //high meaning higher numbered.. not the height on the screen @@ -2766,18 +2784,18 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) /* duplicate the region(s) */ - vector<AudioRegionView*> new_regionviews; + vector<RegionView*> new_regionviews; set<Playlist*> affected_playlists; pair<set<Playlist*>::iterator,bool> insert_result; - for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) { - AudioRegionView* rv; + for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { + RegionView* rv; rv = (*i); - Playlist* to_playlist = rv->region.playlist(); - AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&rv->get_time_axis_view()); + Playlist* to_playlist = rv->region().playlist(); + RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*>(&rv->get_time_axis_view()); insert_result = affected_playlists.insert (to_playlist); if (insert_result.second) { @@ -2786,18 +2804,21 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) latest_regionview = 0; - sigc::connection c = atv->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); - - /* create a new region with the same name. - */ + sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); - AudioRegion* newregion = new AudioRegion (rv->region); + /* create a new region with the same name. */ + // FIXME: ew. need a (virtual) Region::duplicate() or something? + Region* newregion = NULL; + if (dynamic_cast<AudioRegion*>(&rv->region())) + newregion = new AudioRegion (dynamic_cast<AudioRegion&>(rv->region())); + assert(newregion); + /* if the original region was locked, we don't care */ newregion->set_locked (false); - to_playlist->add_region (*newregion, (jack_nframes_t) (rv->region.position() * atv->get_diskstream()->speed())); + to_playlist->add_region (*newregion, (jack_nframes_t) (rv->region().position() * atv->get_diskstream()->speed())); c.disconnect (); @@ -2909,16 +2930,15 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) } } - for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) { - AudioRegionView* rv2; - rv2 = (*i); + for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { + RegionView* rv2 = (*i); double ix1, ix2, iy1, iy2; int32_t n = 0; rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2); rv2->get_canvas_group()->i2w (ix1, iy1); TimeAxisView* tvp2 = trackview_by_y_position (iy1); - AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2); + RouteTimeAxisView* atv2 = dynamic_cast<RouteTimeAxisView*>(tvp2); if (atv2->order != original_pointer_order) { /* this isn't the pointer track */ @@ -3013,8 +3033,8 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) pending_region_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset; - sync_offset = rv->region.sync_offset (sync_dir); - sync_frame = rv->region.adjust_to_sync (pending_region_position); + sync_offset = rv->region().sync_offset (sync_dir); + sync_frame = rv->region().adjust_to_sync (pending_region_position); /* we snap if the snap modifier is not enabled. */ @@ -3033,7 +3053,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) pending_region_position = 0; } - if (pending_region_position > max_frames - rv->region.length()) { + if (pending_region_position > max_frames - rv->region().length()) { pending_region_position = drag_info.last_frame_position; } @@ -3075,14 +3095,11 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) } if (x_delta < 0) { - for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) { + for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { - AudioRegionView* rv2; - rv2 = (*i); + RegionView* rv2 = (*i); - /* if any regionview is at zero, we need to know so we can - stop further leftward motion. - */ + // If any regionview is at zero, we need to know so we can stop further leftward motion. double ix1, ix2, iy1, iy2; rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2); @@ -3100,12 +3117,11 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) ************************************************************/ pair<set<Playlist*>::iterator,bool> insert_result; - const list<AudioRegionView*>& layered_regions = selection->audio_regions.by_layer(); + const list<RegionView*>& layered_regions = selection->regions.by_layer(); - for (list<AudioRegionView*>::const_iterator i = layered_regions.begin(); i != layered_regions.end(); ++i) { + for (list<RegionView*>::const_iterator i = layered_regions.begin(); i != layered_regions.end(); ++i) { - AudioRegionView* rv; - rv = (*i); + RegionView* rv = (*i); double ix1, ix2, iy1, iy2; int32_t temp_pointer_y_span = pointer_y_span; @@ -3186,8 +3202,8 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) if (-x_delta > ix1) { x_delta = -ix1; } - } else if ((x_delta > 0) &&(rv->region.last_frame() > max_frames - x_delta)) { - x_delta = max_frames - rv->region.last_frame(); + } else if ((x_delta > 0) &&(rv->region().last_frame() > max_frames - x_delta)) { + x_delta = max_frames - rv->region().last_frame(); } if (drag_info.first_move) { @@ -3212,7 +3228,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&rv->get_time_axis_view()); if (atv && atv->is_audio_track()) { - AudioPlaylist* pl = atv->get_diskstream()->playlist(); + AudioPlaylist* pl = dynamic_cast<AudioPlaylist*>(atv->get_diskstream()->playlist()); if (pl) { /* only freeze and capture state once */ @@ -3248,11 +3264,11 @@ void Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event) { jack_nframes_t where; - AudioRegionView* rv = reinterpret_cast<AudioRegionView *> (drag_info.data); + RegionView* rv = reinterpret_cast<RegionView *> (drag_info.data); pair<set<Playlist*>::iterator,bool> insert_result; bool nocommit = true; double speed; - AudioTimeAxisView* atv; + RouteTimeAxisView* atv; bool regionview_y_movement; bool regionview_x_movement; @@ -3286,7 +3302,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event speed = atv->get_diskstream()->speed(); } - regionview_x_movement = (drag_info.last_frame_position != (jack_nframes_t) (rv->region.position()/speed)); + regionview_x_movement = (drag_info.last_frame_position != (jack_nframes_t) (rv->region().position()/speed)); regionview_y_movement = (drag_info.last_trackview != &rv->get_time_axis_view()); //printf ("last_frame: %s position is %lu %g\n", rv->get_time_axis_view().name().c_str(), drag_info.last_frame_position, speed); @@ -3296,13 +3312,13 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event /* motion between tracks */ - list<AudioRegionView*> new_selection; + list<RegionView*> new_selection; /* moved to a different audio track. */ - for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ) { + for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ) { - AudioRegionView* rv2 = (*i); + RegionView* rv2 = (*i); /* the region that used to be in the old playlist is not moved to the new one - we make a copy of it. as a result, @@ -3319,7 +3335,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event /* first, freeze the target tracks */ - for (list<AudioRegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) { + for (list<RegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) { Playlist* from_playlist; Playlist* to_playlist; @@ -3331,7 +3347,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event TimeAxisView* tvp2 = trackview_by_y_position (iy1); AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2); - from_playlist = (*i)->region.playlist(); + from_playlist = (*i)->region().playlist(); to_playlist = atv2->playlist(); /* the from_playlist was frozen in the "first_move" case @@ -3354,7 +3370,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event /* now do it again with the actual operations */ - for (list<AudioRegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) { + for (list<RegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) { Playlist* from_playlist; Playlist* to_playlist; @@ -3366,17 +3382,17 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event TimeAxisView* tvp2 = trackview_by_y_position (iy1); AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2); - from_playlist = (*i)->region.playlist(); + from_playlist = (*i)->region().playlist(); to_playlist = atv2->playlist(); latest_regionview = 0; where = (jack_nframes_t) (unit_to_frame (ix1) * speed); - Region* new_region = createRegion ((*i)->region); + Region* new_region = createRegion ((*i)->region()); - from_playlist->remove_region (&((*i)->region)); + from_playlist->remove_region (&((*i)->region())); - sigc::connection c = atv2->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); + sigc::connection c = atv2->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); to_playlist->add_region (*new_region, where); c.disconnect (); @@ -3389,11 +3405,11 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event /* motion within a single track */ - for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) { + for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { rv = (*i); - if (rv->region.locked()) { + if (rv->region().locked()) { continue; } @@ -3415,14 +3431,14 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event } else { - where = rv->region.position(); + where = rv->region().position(); } rv->get_time_axis_view().reveal_dependent_views (*rv); /* no need to add an undo here, we did that when we added this playlist to motion_frozen playlists */ - rv->region.set_position (where, (void *) this); + rv->region().set_position (where, (void *) this); } } @@ -3456,15 +3472,15 @@ Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event) if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) { - align_region (rv.region, SyncPoint, (jack_nframes_t) (edit_cursor->current_frame * speed)); + align_region (rv.region(), SyncPoint, (jack_nframes_t) (edit_cursor->current_frame * speed)); } else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) { - align_region (rv.region, End, (jack_nframes_t) (edit_cursor->current_frame * speed)); + align_region (rv.region(), End, (jack_nframes_t) (edit_cursor->current_frame * speed)); } else { - align_region (rv.region, Start, (jack_nframes_t) (edit_cursor->current_frame * speed)); + align_region (rv.region(), Start, (jack_nframes_t) (edit_cursor->current_frame * speed)); } } } @@ -3581,7 +3597,7 @@ Editor::show_verbose_duration_cursor (jack_nframes_t start, jack_nframes_t end, } void -Editor::collect_new_region_view (AudioRegionView* rv) +Editor::collect_new_region_view (RegionView* rv) { latest_regionview = rv; } @@ -3614,7 +3630,7 @@ Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event) */ latest_regionview = 0; - sigc::connection c = clicked_audio_trackview->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); + sigc::connection c = clicked_audio_trackview->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); /* A selection grab currently creates two undo/redo operations, one for creating the new region and another for moving it. @@ -3650,7 +3666,7 @@ Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event) start_grab (event); drag_info.last_trackview = clicked_trackview; - drag_info.last_frame_position = latest_regionview->region.position(); + drag_info.last_frame_position = latest_regionview->region().position(); drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position; show_verbose_time_cursor (drag_info.last_frame_position, 10); @@ -3891,9 +3907,9 @@ Editor::start_trim (ArdourCanvas::Item* item, GdkEvent* event) speed = tv->get_diskstream()->speed(); } - jack_nframes_t region_start = (jack_nframes_t) (clicked_regionview->region.position() / speed); - jack_nframes_t region_end = (jack_nframes_t) (clicked_regionview->region.last_frame() / speed); - jack_nframes_t region_length = (jack_nframes_t) (clicked_regionview->region.length() / speed); + jack_nframes_t region_start = (jack_nframes_t) (clicked_regionview->region().position() / speed); + jack_nframes_t region_end = (jack_nframes_t) (clicked_regionview->region().last_frame() / speed); + jack_nframes_t region_length = (jack_nframes_t) (clicked_regionview->region().length() / speed); motion_frozen_playlists.clear(); @@ -3933,7 +3949,7 @@ Editor::start_trim (ArdourCanvas::Item* item, GdkEvent* event) void Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) { - AudioRegionView* rv = clicked_regionview; + RegionView* rv = clicked_regionview; jack_nframes_t frame_delta = 0; bool left_direction; bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()); @@ -3945,7 +3961,7 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) double speed = 1.0; TimeAxisView* tvp = clicked_trackview; - AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp); + RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp); pair<set<Playlist*>::iterator,bool> insert_result; if (tv && tv->is_audio_track()) { @@ -3984,11 +4000,14 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) begin_reversible_command (trim_type); - for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) { - (*i)->region.freeze (); - (*i)->temporarily_hide_envelope (); + for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { + (*i)->region().freeze (); + + AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i); + if (arv) + arv->temporarily_hide_envelope (); - Playlist * pl = (*i)->region.playlist(); + Playlist * pl = (*i)->region().playlist(); insert_result = motion_frozen_playlists.insert (pl); if (insert_result.second) { session->add_command(new MementoUndoCommand<Playlist>(*pl, pl->get_state())); @@ -4004,20 +4023,20 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) switch (trim_op) { case StartTrim: - if ((left_direction == false) && (drag_info.current_pointer_frame <= rv->region.first_frame()/speed)) { + if ((left_direction == false) && (drag_info.current_pointer_frame <= rv->region().first_frame()/speed)) { break; } else { - for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) { + for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { single_start_trim (**i, frame_delta, left_direction, obey_snap); } break; } case EndTrim: - if ((left_direction == true) && (drag_info.current_pointer_frame > (jack_nframes_t) (rv->region.last_frame()/speed))) { + if ((left_direction == true) && (drag_info.current_pointer_frame > (jack_nframes_t) (rv->region().last_frame()/speed))) { break; } else { - for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) { + for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { single_end_trim (**i, frame_delta, left_direction, obey_snap); } break; @@ -4031,8 +4050,8 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) swap_direction = true; } - for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); - i != selection->audio_regions.by_layer().end(); ++i) + for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); + i != selection->regions.by_layer().end(); ++i) { single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap); } @@ -4042,10 +4061,10 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) switch (trim_op) { case StartTrim: - show_verbose_time_cursor((jack_nframes_t) (rv->region.position()/speed), 10); + show_verbose_time_cursor((jack_nframes_t) (rv->region().position()/speed), 10); break; case EndTrim: - show_verbose_time_cursor((jack_nframes_t) (rv->region.last_frame()/speed), 10); + show_verbose_time_cursor((jack_nframes_t) (rv->region().last_frame()/speed), 10); break; case ContentsTrim: show_verbose_time_cursor(drag_info.current_pointer_frame, 10); @@ -4057,9 +4076,9 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) } void -Editor::single_contents_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool swap_direction, bool obey_snap) +Editor::single_contents_trim (RegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool swap_direction, bool obey_snap) { - Region& region (rv.region); + Region& region (rv.region()); if (region.locked()) { return; @@ -4069,7 +4088,7 @@ Editor::single_contents_trim (AudioRegionView& rv, jack_nframes_t frame_delta, b double speed = 1.0; TimeAxisView* tvp = clicked_trackview; - AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp); + RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp); if (tv && tv->is_audio_track()) { speed = tv->get_diskstream()->speed(); @@ -4097,9 +4116,9 @@ Editor::single_contents_trim (AudioRegionView& rv, jack_nframes_t frame_delta, b } void -Editor::single_start_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap) +Editor::single_start_trim (RegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap) { - Region& region (rv.region); + Region& region (rv.region()); if (region.locked()) { return; @@ -4131,9 +4150,9 @@ Editor::single_start_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool } void -Editor::single_end_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap) +Editor::single_end_trim (RegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap) { - Region& region (rv.region); + Region& region (rv.region()); if (region.locked()) { return; @@ -4172,8 +4191,8 @@ Editor::trim_finished_callback (ArdourCanvas::Item* item, GdkEvent* event) thaw_region_after_trim (*clicked_regionview); } else { - for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); - i != selection->audio_regions.by_layer().end(); ++i) + for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); + i != selection->regions.by_layer().end(); ++i) { thaw_region_after_trim (**i); } @@ -4196,7 +4215,7 @@ Editor::trim_finished_callback (ArdourCanvas::Item* item, GdkEvent* event) void Editor::point_trim (GdkEvent* event) { - AudioRegionView* rv = clicked_regionview; + RegionView* rv = clicked_regionview; jack_nframes_t new_bound = drag_info.current_pointer_frame; if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) { @@ -4211,13 +4230,13 @@ Editor::point_trim (GdkEvent* event) if (rv->get_selected()) { - for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); - i != selection->audio_regions.by_layer().end(); ++i) + for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); + i != selection->regions.by_layer().end(); ++i) { - if (!(*i)->region.locked()) { + if (!(*i)->region().locked()) { Playlist *pl = (*i)->region.playlist(); XMLNode &before = pl->get_state(); - (*i)->region.trim_front (new_bound, this); + (*i)->region().trim_front (new_bound, this); XMLNode &after = pl->get_state(); session->add_command(new MementoCommand<Playlist>(*pl, before, after)); } @@ -4225,10 +4244,10 @@ Editor::point_trim (GdkEvent* event) } else { - if (!rv->region.locked()) { - Playlist *pl = rv->region.playlist(); + if (!rv->region().locked()) { + Playlist *pl = rv->region().playlist(); XMLNode &before = pl->get_state(); - rv->region.trim_front (new_bound, this); + rv->region().trim_front (new_bound, this); XMLNode &after = pl->get_state(); session->add_command(new MementoCommand<Playlist>(*pl, before, after)); } @@ -4243,12 +4262,12 @@ Editor::point_trim (GdkEvent* event) if (rv->get_selected()) { - for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) + for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { - if (!(*i)->region.locked()) { - Playlist *pl = (*i)->region.playlist(); + if (!(*i)->region().locked()) { + Playlist *pl = (*i)->region().playlist(); XMLNode &before = pl->get_state(); - (*i)->region.trim_end (new_bound, this); + (*i)->region().trim_end (new_bound, this); XMLNode &after = pl->get_state(); session->add_command(new MementoCommand<Playlist>(*pl, before, after)); } @@ -4256,10 +4275,10 @@ Editor::point_trim (GdkEvent* event) } else { - if (!rv->region.locked()) { - Playlist *pl = rv->region.playlist(); + if (!rv->region().locked()) { + Playlist *pl = rv->region().playlist(); XMLNode &before = pl->get_state(); - rv->region.trim_end (new_bound, this); + rv->region().trim_end (new_bound, this); XMLNode &after = pl->get_state(); session->add_command (new MementoCommand<Playlist>(*pl, before, after)); } @@ -4274,9 +4293,9 @@ Editor::point_trim (GdkEvent* event) } void -Editor::thaw_region_after_trim (AudioRegionView& rv) +Editor::thaw_region_after_trim (RegionView& rv) { - Region& region (rv.region); + Region& region (rv.region()); if (region.locked()) { return; @@ -4286,7 +4305,9 @@ Editor::thaw_region_after_trim (AudioRegionView& rv) XMLNode &after = region.playlist()->get_state(); session->add_command (new MementoRedoCommand<Playlist>(*(region.playlist()), after)); - rv.unhide_envelope (); + AudioRegionView* arv = dynamic_cast<AudioRegionView*>(&rv); + if (arv) + arv->unhide_envelope (); } void @@ -4679,7 +4700,7 @@ Editor::end_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event) } } else { - selection->clear_audio_regions(); + selection->clear_regions(); selection->clear_points (); selection->clear_lines (); } @@ -4696,7 +4717,7 @@ Editor::mouse_rename_region (ArdourCanvas::Item* item, GdkEvent* event) ArdourPrompter prompter (false); prompter.set_prompt (_("Name for region:")); - prompter.set_initial_text (clicked_regionview->region.name()); + prompter.set_initial_text (clicked_regionview->region().name()); prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT); prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false); prompter.show_all (); @@ -4705,7 +4726,7 @@ Editor::mouse_rename_region (ArdourCanvas::Item* item, GdkEvent* event) string str; prompter.get_result(str); if (str.length()) { - clicked_regionview->region.set_name (str); + clicked_regionview->region().set_name (str); } break; } @@ -4727,7 +4748,7 @@ Editor::start_time_fx (ArdourCanvas::Item* item, GdkEvent* event) void Editor::time_fx_motion (ArdourCanvas::Item *item, GdkEvent* event) { - AudioRegionView* rv = clicked_regionview; + RegionView* rv = clicked_regionview; if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) { snap_to (drag_info.current_pointer_frame); @@ -4737,8 +4758,8 @@ Editor::time_fx_motion (ArdourCanvas::Item *item, GdkEvent* event) return; } - if (drag_info.current_pointer_frame > rv->region.position()) { - rv->get_time_axis_view().show_timestretch (rv->region.position(), drag_info.current_pointer_frame); + if (drag_info.current_pointer_frame > rv->region().position()) { + rv->get_time_axis_view().show_timestretch (rv->region().position(), drag_info.current_pointer_frame); } drag_info.last_pointer_frame = drag_info.current_pointer_frame; @@ -4756,21 +4777,25 @@ Editor::end_time_fx (ArdourCanvas::Item* item, GdkEvent* event) return; } - jack_nframes_t newlen = drag_info.last_pointer_frame - clicked_regionview->region.position(); - float percentage = (float) ((double) newlen - (double) clicked_regionview->region.length()) / ((double) newlen) * 100.0f; + jack_nframes_t newlen = drag_info.last_pointer_frame - clicked_regionview->region().position(); + float percentage = (float) ((double) newlen - (double) clicked_regionview->region().length()) / ((double) newlen) * 100.0f; begin_reversible_command (_("timestretch")); - if (run_timestretch (selection->audio_regions, percentage) == 0) { + if (run_timestretch (selection->regions, percentage) == 0) { session->commit_reversible_command (); } } void -Editor::mouse_brush_insert_region (AudioRegionView* rv, jack_nframes_t pos) +Editor::mouse_brush_insert_region (RegionView* rv, jack_nframes_t pos) { /* no brushing without a useful snap setting */ + // FIXME + AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv); + assert(arv); + switch (snap_mode) { case SnapMagnetic: return; /* can't work because it allows region to be placed anywhere */ @@ -4790,11 +4815,11 @@ Editor::mouse_brush_insert_region (AudioRegionView* rv, jack_nframes_t pos) /* don't brush a copy over the original */ - if (pos == rv->region.position()) { + if (pos == rv->region().position()) { return; } - AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&rv->get_time_axis_view()); + RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*>(&arv->get_time_axis_view()); if (atv == 0 || !atv->is_audio_track()) { return; @@ -4804,7 +4829,7 @@ Editor::mouse_brush_insert_region (AudioRegionView* rv, jack_nframes_t pos) double speed = atv->get_diskstream()->speed(); XMLNode &before = playlist->get_state(); - playlist->add_region (*(new AudioRegion (rv->region)), (jack_nframes_t) (pos * speed)); + playlist->add_region (*(new AudioRegion (arv->audio_region)), (jack_nframes_t) (pos * speed)); XMLNode &after = playlist->get_state(); session->add_command(new MementoCommand<Playlist>(*playlist, before, after)); diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index e9fcc028e6..d98be4f088 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -52,7 +52,7 @@ #include "audio_time_axis.h" #include "automation_time_axis.h" #include "streamview.h" -#include "regionview.h" +#include "audio_region_view.h" #include "rgb_macros.h" #include "selection_templates.h" #include "selection.h" @@ -187,29 +187,31 @@ Editor::split_region () void Editor::split_region_at (jack_nframes_t where) { - split_regions_at (where, selection->audio_regions); + split_regions_at (where, selection->regions); } void -Editor::split_regions_at (jack_nframes_t where, AudioRegionSelection& regions) +Editor::split_regions_at (jack_nframes_t where, RegionSelection& regions) { begin_reversible_command (_("split")); snap_to (where); - for (AudioRegionSelection::iterator a = regions.begin(); a != regions.end(); ) { + for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) { - AudioRegionSelection::iterator tmp; + RegionSelection::iterator tmp; tmp = a; ++tmp; - Playlist* pl = (*a)->region.playlist(); + Playlist* pl = (*a)->region().playlist(); - _new_regionviews_show_envelope = (*a)->envelope_visible(); + AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*a); + if (arv) + _new_regionviews_show_envelope = arv->envelope_visible(); if (pl) { XMLNode &before = pl->get_state(); - pl->split_region ((*a)->region, where); + pl->split_region ((*a)->region(), where); XMLNode &after = pl->get_state(); session->add_command(new MementoCommand<Playlist>(*pl, before, after)); } @@ -232,7 +234,7 @@ Editor::remove_clicked_region () begin_reversible_command (_("remove region")); XMLNode &before = playlist->get_state(); - playlist->remove_region (&clicked_regionview->region); + playlist->remove_region (&clicked_regionview->region()); XMLNode &after = playlist->get_state(); session->add_command(new MementoCommand<Playlist>(*playlist, before, after)); commit_reversible_command (); @@ -241,7 +243,7 @@ Editor::remove_clicked_region () void Editor::destroy_clicked_region () { - int32_t selected = selection->audio_regions.size(); + int32_t selected = selection->regions.size(); if (!session || clicked_regionview == 0 && selected == 0) { return; @@ -273,29 +275,29 @@ Do you really want to destroy %1 ?"), if (selected > 0) { list<Region*> r; - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - r.push_back (&(*i)->region); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + r.push_back (&(*i)->region()); } session->destroy_regions (r); } else if (clicked_regionview) { - session->destroy_region (&clicked_regionview->region); + session->destroy_region (&clicked_regionview->region()); } } -AudioRegion * +Region * Editor::select_region_for_operation (int dir, TimeAxisView **tv) { - AudioRegionView* rv; - AudioRegion *region; + RegionView* rv; + Region *region; jack_nframes_t start = 0; if (selection->time.start () == selection->time.end_frame ()) { /* no current selection-> is there a selected regionview? */ - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return 0; } @@ -303,26 +305,26 @@ Editor::select_region_for_operation (int dir, TimeAxisView **tv) region = 0; - if (!selection->audio_regions.empty()) { + if (!selection->regions.empty()) { - rv = *(selection->audio_regions.begin()); + rv = *(selection->regions.begin()); (*tv) = &rv->get_time_axis_view(); - region = &rv->region; + region = &rv->region(); } else if (!selection->tracks.empty()) { (*tv) = selection->tracks.front(); - AudioTimeAxisView* atv; + RouteTimeAxisView* rtv; - if ((atv = dynamic_cast<AudioTimeAxisView*> (*tv)) != 0) { + if ((rtv = dynamic_cast<RouteTimeAxisView*> (*tv)) != 0) { Playlist *pl; - if ((pl = atv->playlist()) == 0) { + if ((pl = rtv->playlist()) == 0) { return 0; } - region = dynamic_cast<AudioRegion*> (pl->top_region_at (start)); + region = pl->top_region_at (start); } } @@ -394,12 +396,12 @@ Editor::nudge_forward (bool next) if (!session) return; - if (!selection->audio_regions.empty()) { + if (!selection->regions.empty()) { begin_reversible_command (_("nudge forward")); - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - AudioRegion& r ((*i)->region); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + Region& r ((*i)->region()); distance = get_nudge_distance (r.position(), next_distance); @@ -429,12 +431,12 @@ Editor::nudge_backward (bool next) if (!session) return; - if (!selection->audio_regions.empty()) { + if (!selection->regions.empty()) { begin_reversible_command (_("nudge forward")); - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - AudioRegion& r ((*i)->region); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + Region& r ((*i)->region()); distance = get_nudge_distance (r.position(), next_distance); @@ -474,14 +476,14 @@ Editor::nudge_forward_capture_offset () if (!session) return; - if (!selection->audio_regions.empty()) { + if (!selection->regions.empty()) { begin_reversible_command (_("nudge forward")); distance = session->worst_output_latency(); - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - AudioRegion& r ((*i)->region); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + Region& r ((*i)->region()); XMLNode &before = r.playlist()->get_state(); r.set_position (r.position() + distance, this); @@ -501,14 +503,14 @@ Editor::nudge_backward_capture_offset () if (!session) return; - if (!selection->audio_regions.empty()) { + if (!selection->regions.empty()) { begin_reversible_command (_("nudge forward")); distance = session->worst_output_latency(); - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - AudioRegion& r ((*i)->region); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + Region& r ((*i)->region()); XMLNode &before = r.playlist()->get_state(); @@ -789,8 +791,8 @@ Editor::cursor_to_selection_start (Cursor *cursor) jack_nframes_t pos = 0; switch (mouse_mode) { case MouseObject: - if (!selection->audio_regions.empty()) { - pos = selection->audio_regions.start(); + if (!selection->regions.empty()) { + pos = selection->regions.start(); } break; @@ -818,8 +820,8 @@ Editor::cursor_to_selection_end (Cursor *cursor) switch (mouse_mode) { case MouseObject: - if (!selection->audio_regions.empty()) { - pos = selection->audio_regions.end_frame(); + if (!selection->regions.empty()) { + pos = selection->regions.end_frame(); } break; @@ -1319,12 +1321,12 @@ Editor::add_location_from_playhead_cursor () void Editor::add_location_from_audio_region () { - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } - AudioRegionView* rv = *(selection->audio_regions.begin()); - Region& region = rv->region; + RegionView* rv = *(selection->regions.begin()); + Region& region = rv->region(); Location *location = new Location (region.position(), region.last_frame(), region.name()); session->begin_reversible_command (_("add marker")); @@ -1452,12 +1454,12 @@ Editor::select_all_within (jack_nframes_t start, jack_nframes_t end, double top, void Editor::set_selection_from_audio_region () { - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } - AudioRegionView* rv = *(selection->audio_regions.begin()); - Region& region = rv->region; + RegionView* rv = *(selection->regions.begin()); + Region& region = rv->region(); begin_reversible_command (_("set selection from region")); selection->set (0, region.position(), region.last_frame()); @@ -1840,13 +1842,13 @@ Editor::insert_region_list_drag (AudioRegion& region, int x, int y) void Editor::insert_region_list_selection (float times) { - AudioTimeAxisView *tv = 0; + RouteTimeAxisView *tv = 0; Playlist *playlist; if (clicked_audio_trackview != 0) { tv = clicked_audio_trackview; } else if (!selection->tracks.empty()) { - if ((tv = dynamic_cast<AudioTimeAxisView*>(selection->tracks.front())) == 0) { + if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) { return; } } else { @@ -1941,23 +1943,23 @@ Editor::play_selection () void Editor::play_selected_region () { - if (!selection->audio_regions.empty()) { - AudioRegionView *rv = *(selection->audio_regions.begin()); + if (!selection->regions.empty()) { + RegionView *rv = *(selection->regions.begin()); - session->request_bounded_roll (rv->region.position(), rv->region.last_frame()); + session->request_bounded_roll (rv->region().position(), rv->region().last_frame()); } } void Editor::loop_selected_region () { - if (!selection->audio_regions.empty()) { - AudioRegionView *rv = *(selection->audio_regions.begin()); + if (!selection->regions.empty()) { + RegionView *rv = *(selection->regions.begin()); Location* tll; if ((tll = transport_loop_location()) != 0) { - tll->set (rv->region.position(), rv->region.last_frame()); + tll->set (rv->region().position(), rv->region().last_frame()); // enable looping, reposition and start rolling @@ -2000,10 +2002,10 @@ void Editor::toggle_region_mute () { if (clicked_regionview) { - clicked_regionview->region.set_muted (!clicked_regionview->region.muted()); - } else if (!selection->audio_regions.empty()) { - bool yn = ! (*selection->audio_regions.begin())->region.muted(); - selection->foreach_audio_region (&AudioRegion::set_muted, yn); + clicked_regionview->region().set_muted (!clicked_regionview->region().muted()); + } else if (!selection->regions.empty()) { + bool yn = ! (*selection->regions.begin())->region().muted(); + selection->foreach_region (&Region::set_muted, yn); } } @@ -2011,35 +2013,35 @@ void Editor::toggle_region_opaque () { if (clicked_regionview) { - clicked_regionview->region.set_opaque (!clicked_regionview->region.opaque()); - } else if (!selection->audio_regions.empty()) { - bool yn = ! (*selection->audio_regions.begin())->region.opaque(); - selection->foreach_audio_region (&Region::set_opaque, yn); + clicked_regionview->region().set_opaque (!clicked_regionview->region().opaque()); + } else if (!selection->regions.empty()) { + bool yn = ! (*selection->regions.begin())->region().opaque(); + selection->foreach_region (&Region::set_opaque, yn); } } void Editor::raise_region () { - selection->foreach_audio_region (&Region::raise); + selection->foreach_region (&Region::raise); } void Editor::raise_region_to_top () { - selection->foreach_audio_region (&Region::raise_to_top); + selection->foreach_region (&Region::raise_to_top); } void Editor::lower_region () { - selection->foreach_audio_region (&Region::lower); + selection->foreach_region (&Region::lower); } void Editor::lower_region_to_bottom () { - selection->foreach_audio_region (&Region::lower_to_bottom); + selection->foreach_region (&Region::lower_to_bottom); } void @@ -2060,7 +2062,7 @@ Editor::rename_region () Button ok_button (_("OK")); Button cancel_button (_("Cancel")); - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } @@ -2091,7 +2093,7 @@ Editor::rename_region () Main::run (); if (region_renamed) { - (*selection->audio_regions.begin())->region.set_name (entry.get_text()); + (*selection->regions.begin())->region().set_name (entry.get_text()); redisplay_regions (); } } @@ -2105,7 +2107,7 @@ Editor::rename_region_finished (bool status) } void -Editor::audition_playlist_region_via_route (AudioRegion& region, Route& route) +Editor::audition_playlist_region_via_route (Region& region, Route& route) { if (session->is_auditioning()) { session->cancel_audition (); @@ -2126,14 +2128,14 @@ Editor::audition_playlist_region_via_route (AudioRegion& region, Route& route) void Editor::audition_selected_region () { - if (!selection->audio_regions.empty()) { - AudioRegionView* rv = *(selection->audio_regions.begin()); - session->audition_region (rv->region); + if (!selection->regions.empty()) { + RegionView* rv = *(selection->regions.begin()); + session->audition_region (rv->region()); } } void -Editor::audition_playlist_region_standalone (AudioRegion& region) +Editor::audition_playlist_region_standalone (Region& region) { session->audition_region (region); } @@ -2183,7 +2185,6 @@ Editor::region_from_selection () jack_nframes_t selection_cnt = end - start + 1; for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { - AudioRegion *region; AudioRegion *current; Region* current_r; @@ -2200,7 +2201,9 @@ Editor::region_from_selection () continue; } - if ((current = dynamic_cast<AudioRegion*> (current_r)) != 0) { + current = dynamic_cast<AudioRegion*> (current_r); + // FIXME: audio only + if (current != 0) { internal_start = start - current->position(); session->region_name (new_name, current->name(), true); region = new AudioRegion (*current, internal_start, selection_cnt, new_name); @@ -2250,11 +2253,13 @@ Editor::split_multichannel_region () { vector<AudioRegion*> v; - if (!clicked_regionview || clicked_regionview->region.n_channels() < 2) { + AudioRegionView* clicked_arv = dynamic_cast<AudioRegionView*>(clicked_regionview); + + if (!clicked_arv || clicked_arv->audio_region().n_channels() < 2) { return; } - clicked_regionview->region.separate_by_channel (*session, v); + clicked_arv->audio_region().separate_by_channel (*session, v); /* nothing else to do, really */ } @@ -2440,7 +2445,7 @@ Editor::region_fill_track () { jack_nframes_t end; - if (!session || selection->audio_regions.empty()) { + if (!session || selection->regions.empty()) { return; } @@ -2448,9 +2453,15 @@ Editor::region_fill_track () begin_reversible_command (_("region fill")); - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + + Region& region ((*i)->region()); + + // FIXME + AudioRegion* const ar = dynamic_cast<AudioRegion*>(®ion); + if (!ar) + continue; - AudioRegion& region ((*i)->region); Playlist* pl = region.playlist(); if (end <= region.last_frame()) { @@ -2464,7 +2475,7 @@ Editor::region_fill_track () } XMLNode &before = pl->get_state(); - pl->add_region (*(new AudioRegion (region)), region.last_frame(), times); + pl->add_region (*(new AudioRegion (*ar)), ar->last_frame(), times); session->add_command (new MementoCommand<Playlist>(*pl, before, pl->get_state())); } @@ -2544,12 +2555,12 @@ Editor::set_region_sync_from_edit_cursor () return; } - if (!clicked_regionview->region.covers (edit_cursor->current_frame)) { + if (!clicked_regionview->region().covers (edit_cursor->current_frame)) { error << _("Place the edit cursor at the desired sync point") << endmsg; return; } - Region& region (clicked_regionview->region); + Region& region (clicked_regionview->region()); begin_reversible_command (_("set sync from edit cursor")); XMLNode &before = region.playlist()->get_state(); region.set_sync_position (edit_cursor->current_frame); @@ -2562,7 +2573,7 @@ void Editor::remove_region_sync () { if (clicked_regionview) { - Region& region (clicked_regionview->region); + Region& region (clicked_regionview->region()); begin_reversible_command (_("remove sync")); XMLNode &before = region.playlist()->get_state(); region.clear_sync_position (); @@ -2575,15 +2586,15 @@ Editor::remove_region_sync () void Editor::naturalize () { - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } begin_reversible_command (_("naturalize")); - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - XMLNode &before = (*i)->region.get_state(); - (*i)->region.move_to_natural_position (this); - XMLNode &after = (*i)->region.get_state(); - session->add_command (new MementoCommand<AudioRegion>((*i)->region, before, after)); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + XMLNode &before = (*i)->region().get_state(); + (*i)->region().move_to_natural_position (this); + XMLNode &after = (*i)->region().get_state(); + session->add_command (new MementoCommand<AudioRegion>((*i)->region(), before, after)); } commit_reversible_command (); } @@ -2602,14 +2613,14 @@ Editor::align_relative (RegionPoint what) struct RegionSortByTime { bool operator() (const AudioRegionView* a, const AudioRegionView* b) { - return a->region.position() < b->region.position(); + return a->region().position() < b->region().position(); } }; void Editor::align_selection_relative (RegionPoint point, jack_nframes_t position) { - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } @@ -2617,9 +2628,9 @@ Editor::align_selection_relative (RegionPoint point, jack_nframes_t position) jack_nframes_t pos = 0; int dir; - list<AudioRegionView*> sorted; - selection->audio_regions.by_position (sorted); - Region& r ((*sorted.begin())->region); + list<RegionView*> sorted; + selection->regions.by_position (sorted); + Region& r ((*sorted.begin())->region()); switch (point) { case Start: @@ -2645,9 +2656,9 @@ Editor::align_selection_relative (RegionPoint point, jack_nframes_t position) begin_reversible_command (_("align selection (relative)")); - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { - Region& region ((*i)->region); + Region& region ((*i)->region()); XMLNode &before = region.playlist()->get_state(); @@ -2668,14 +2679,14 @@ Editor::align_selection_relative (RegionPoint point, jack_nframes_t position) void Editor::align_selection (RegionPoint point, jack_nframes_t position) { - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } begin_reversible_command (_("align selection")); - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - align_region_internal ((*i)->region, point, position); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + align_region_internal ((*i)->region(), point, position); } commit_reversible_command (); @@ -2721,7 +2732,7 @@ Editor::trim_region_to_edit_cursor () return; } - Region& region (clicked_regionview->region); + Region& region (clicked_regionview->region()); float speed = 1.0f; AudioTimeAxisView *atav; @@ -2747,7 +2758,7 @@ Editor::trim_region_from_edit_cursor () return; } - Region& region (clicked_regionview->region); + Region& region (clicked_regionview->region()); float speed = 1.0f; AudioTimeAxisView *atav; @@ -2920,16 +2931,16 @@ Editor::cut_copy (CutCopyOp op) switch (current_mouse_mode()) { case MouseObject: - if (!selection->audio_regions.empty() || !selection->points.empty()) { + if (!selection->regions.empty() || !selection->points.empty()) { begin_reversible_command (opname + _(" objects")); - if (!selection->audio_regions.empty()) { + if (!selection->regions.empty()) { cut_copy_regions (op); if (op == Cut) { - selection->clear_audio_regions (); + selection->clear_regions (); } } @@ -2986,11 +2997,11 @@ Editor::cut_copy_regions (CutCopyOp op) set<Playlist*> freezelist; pair<set<Playlist*>::iterator,bool> insert_result; - for (AudioRegionSelection::iterator x = selection->audio_regions.begin(); x != selection->audio_regions.end(); ++x) { - first_position = min ((*x)->region.position(), first_position); + for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) { + first_position = min ((*x)->region().position(), first_position); if (op == Cut || op == Clear) { - AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region.playlist()); + AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region().playlist()); if (pl) { insert_result = freezelist.insert (pl); if (insert_result.second) { @@ -3001,11 +3012,11 @@ Editor::cut_copy_regions (CutCopyOp op) } } - for (AudioRegionSelection::iterator x = selection->audio_regions.begin(); x != selection->audio_regions.end(); ) { + for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) { - AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region.playlist()); + AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region().playlist()); AudioPlaylist* npl; - AudioRegionSelection::iterator tmp; + RegionSelection::iterator tmp; tmp = x; ++tmp; @@ -3022,18 +3033,24 @@ Editor::cut_copy_regions (CutCopyOp op) npl = pi->second; } + // FIXME + AudioRegion* const ar = dynamic_cast<AudioRegion*>(&(*x)->region()); switch (op) { case Cut: - npl->add_region (*(new AudioRegion ((*x)->region)), (*x)->region.position() - first_position); - pl->remove_region (&((*x)->region)); + if (!ar) break; + + npl->add_region (*(new AudioRegion (*ar)), (*x)->region().position() - first_position); + pl->remove_region (&((*x)->region())); break; case Copy: - npl->add_region (*(new AudioRegion ((*x)->region)), (*x)->region.position() - first_position); + if (!ar) break; + + npl->add_region (*(new AudioRegion (*ar)), (*x)->region().position() - first_position); break; case Clear: - pl->remove_region (&((*x)->region)); + pl->remove_region (&((*x)->region())); break; } } @@ -3179,24 +3196,24 @@ Editor::paste_named_selection (float times) } void -Editor::duplicate_some_regions (AudioRegionSelection& regions, float times) +Editor::duplicate_some_regions (RegionSelection& regions, float times) { Playlist *playlist; - AudioRegionSelection sel = regions; // clear (below) will clear the argument list + RegionSelection sel = regions; // clear (below) will clear the argument list begin_reversible_command (_("duplicate region")); - selection->clear_audio_regions (); + selection->clear_regions (); - for (AudioRegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) { + for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) { - Region& r ((*i)->region); + Region& r ((*i)->region()); TimeAxisView& tv = (*i)->get_time_axis_view(); AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv); - sigc::connection c = atv->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); + sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); - playlist = (*i)->region.playlist(); + playlist = (*i)->region().playlist(); XMLNode &before = playlist->get_state(); playlist->duplicate (r, r.last_frame(), times); session->add_command(new MementoCommand<Playlist>(*playlist, before, playlist->get_state())); @@ -3369,7 +3386,7 @@ Editor::normalize_region () return; } - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } @@ -3378,11 +3395,13 @@ Editor::normalize_region () track_canvas.get_window()->set_cursor (*wait_cursor); gdk_flush (); - for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ++r) { - XMLNode &before = (*r)->region.get_state(); - (*r)->region.normalize_to (0.0f); - XMLNode &after = (*r)->region.get_state(); - session->add_command (new MementoCommand<AudioRegion>((*r)->region, before, after)); + for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) { + AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r); + if (!arv) + continue; + XMLNode &before = arv->region().get_state(); + arv->audio_region().normalize_to (0.0f); + session->add_command (new MementoCommand<Region>(arv->region, arv->region().get_state()); } commit_reversible_command (); @@ -3397,17 +3416,19 @@ Editor::denormalize_region () return; } - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } begin_reversible_command ("denormalize"); - for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ++r) { - XMLNode &before = (*r)->region.get_state(); - (*r)->region.set_scale_amplitude (1.0f); - XMLNode &after = (*r)->region.get_state(); - session->add_command (new MementoCommand<AudioRegion>((*r)->region, before, after)); + for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) { + AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r); + if (!arv) + continue; + XMLNode &before = arv->region().get_state(); + arv->audio_region().set_scale_amplitude (1.0f); + session->add_command (new MementoCommand<Region>(arv->region, before, arv->region().get_state()); } commit_reversible_command (); @@ -3428,7 +3449,7 @@ Editor::reverse_region () void Editor::apply_filter (AudioFilter& filter, string command) { - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } @@ -3437,20 +3458,22 @@ Editor::apply_filter (AudioFilter& filter, string command) track_canvas.get_window()->set_cursor (*wait_cursor); gdk_flush (); - for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ) { + for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) { + AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r); + if (!arv) + continue; - AudioRegion& region ((*r)->region); - Playlist* playlist = region.playlist(); + Playlist* playlist = arv->region().playlist(); - AudioRegionSelection::iterator tmp; + RegionSelection::iterator tmp; tmp = r; ++tmp; - if (region.apply (filter) == 0) { + if (arv->audio_region().apply (filter) == 0) { XMLNode &before = playlist->get_state(); - playlist->replace_region (region, *(filter.results.front()), region.position()); + playlist->replace_region (arv->region(), *(filter.results.front()), arv->region()position()); XMLNode &after = playlist->get_state(); session->add_command(new MementoCommand<Playlist>(*playlist, before, after)); } else { @@ -3461,7 +3484,7 @@ Editor::apply_filter (AudioFilter& filter, string command) } commit_reversible_command (); - selection->audio_regions.clear (); + selection->regions.clear (); out: track_canvas.get_window()->set_cursor (*current_canvas_cursor); @@ -3470,8 +3493,8 @@ Editor::apply_filter (AudioFilter& filter, string command) void Editor::region_selection_op (void (Region::*pmf)(void)) { - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - ((*i)->region.*pmf)(); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + ((*i)->region().*pmf)(); } } @@ -3479,16 +3502,16 @@ Editor::region_selection_op (void (Region::*pmf)(void)) void Editor::region_selection_op (void (Region::*pmf)(void*), void *arg) { - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - ((*i)->region.*pmf)(arg); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + ((*i)->region().*pmf)(arg); } } void Editor::region_selection_op (void (Region::*pmf)(bool), bool yn) { - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - ((*i)->region.*pmf)(yn); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + ((*i)->region().*pmf)(yn); } } @@ -3505,20 +3528,20 @@ Editor::external_edit_region () void Editor::brush (jack_nframes_t pos) { - AudioRegionSelection sel; + RegionSelection sel; snap_to (pos); - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { /* XXX get selection from region list */ } else { - sel = selection->audio_regions; + sel = selection->regions; } if (sel.empty()) { return; } - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { mouse_brush_insert_region ((*i), pos); } } @@ -3526,18 +3549,19 @@ Editor::brush (jack_nframes_t pos) void Editor::toggle_gain_envelope_visibility () { - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - (*i)->set_envelope_visible (!(*i)->envelope_visible()); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i); + if (arv) + arv->set_envelope_visible (!arv->envelope_visible()); } } void Editor::toggle_gain_envelope_active () { - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - AudioRegion* ar = dynamic_cast<AudioRegion*>(&(*i)->region); - if (ar) { - ar->set_envelope_active (true); - } + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i); + if (arv) + arv->audio_region().set_envelope_active (true); } } diff --git a/gtk2_ardour/editor_route_list.cc b/gtk2_ardour/editor_route_list.cc index 2e036f5001..c93cf9aba2 100644 --- a/gtk2_ardour/editor_route_list.cc +++ b/gtk2_ardour/editor_route_list.cc @@ -39,21 +39,16 @@ using namespace PBD; using namespace Gtk; void -Editor::handle_new_route_p (Route* route) -{ - ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_new_route_p), route)); - handle_new_route (*route); -} - -void -Editor::handle_new_route (Route& route) +Editor::handle_new_route (boost::shared_ptr<Route> route) { + ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_new_route), route)); + TimeAxisView *tv; AudioTimeAxisView *atv; TreeModel::Row parent; TreeModel::Row row; - if (route.hidden()) { + if (route->hidden()) { return; } @@ -75,7 +70,7 @@ Editor::handle_new_route (Route& route) } - if (dynamic_cast<AudioTrack*>(&route) != 0) { + if (dynamic_cast<AudioTrack*>(route.get()) != 0) { TreeModel::iterator iter = route_display_model->get_iter ("1"); // audio tracks parent = *iter; } else { @@ -89,7 +84,7 @@ Editor::handle_new_route (Route& route) row = *(route_display_model->append ()); #endif - row[route_display_columns.text] = route.name(); + row[route_display_columns.text] = route->name(); row[route_display_columns.visible] = tv->marked_for_display(); row[route_display_columns.tv] = tv; @@ -99,14 +94,14 @@ Editor::handle_new_route (Route& route) if ((atv = dynamic_cast<AudioTimeAxisView*> (tv)) != 0) { /* added a new fresh one at the end */ - if (atv->route().order_key(N_("editor")) == -1) { - atv->route().set_order_key (N_("editor"), route_display_model->children().size()-1); + if (atv->route()->order_key(N_("editor")) == -1) { + atv->route()->set_order_key (N_("editor"), route_display_model->children().size()-1); } } ignore_route_list_reorder = false; - route.gui_changed.connect (mem_fun(*this, &Editor::handle_gui_changes)); + route->gui_changed.connect (mem_fun(*this, &Editor::handle_gui_changes)); tv->GoingAway.connect (bind (mem_fun(*this, &Editor::remove_route), tv)); @@ -188,7 +183,7 @@ Editor::hide_track_in_display (TimeAxisView& tv) AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv); - if (atv && current_mixer_strip && &(atv->route()) == &(current_mixer_strip->route())) { + if (atv && current_mixer_strip && (atv->route() == current_mixer_strip->route())) { // this will hide the mixer strip set_selected_mixer_strip (tv); } @@ -244,7 +239,7 @@ Editor::redisplay_route_list () */ if ((at = dynamic_cast<AudioTimeAxisView*> (tv)) != 0) { - at->route().set_order_key (N_("editor"), order); + at->route()->set_order_key (N_("editor"), order); ++order; } } @@ -263,6 +258,10 @@ Editor::redisplay_route_list () } + /* make sure the cursors stay on top of every newly added track */ + + cursor_group->raise_to_top (); + reset_scrolling_region (); } @@ -473,7 +472,7 @@ Editor::route_list_selection_filter (const Glib::RefPtr<TreeModel>& model, const } struct EditorOrderRouteSorter { - bool operator() (Route* a, Route* b) { + bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) { /* use of ">" forces the correct sort order */ return a->order_key ("editor") < b->order_key ("editor"); } @@ -482,17 +481,18 @@ struct EditorOrderRouteSorter { void Editor::initial_route_list_display () { - Session::RouteList routes = session->get_routes(); + boost::shared_ptr<Session::RouteList> routes = session->get_routes(); + Session::RouteList r (*routes); EditorOrderRouteSorter sorter; - routes.sort (sorter); + r.sort (sorter); no_route_list_redisplay = true; route_display_model->clear (); - for (Session::RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { - handle_new_route (**i); + for (Session::RouteList::iterator i = r.begin(); i != r.end(); ++i) { + handle_new_route (*i); } no_route_list_redisplay = false; diff --git a/gtk2_ardour/editor_timefx.cc b/gtk2_ardour/editor_timefx.cc index 27fa6c9651..3fe0023d07 100644 --- a/gtk2_ardour/editor_timefx.cc +++ b/gtk2_ardour/editor_timefx.cc @@ -29,7 +29,7 @@ #include "editor.h" #include "audio_time_axis.h" -#include "regionview.h" +#include "audio_region_view.h" #include "region_selection.h" #include <ardour/session.h> @@ -101,7 +101,7 @@ Editor::TimeStretchDialog::delete_timestretch_in_progress (GdkEventAny* ev) } int -Editor::run_timestretch (AudioRegionSelection& regions, float fraction) +Editor::run_timestretch (RegionSelection& regions, float fraction) { pthread_t thread; @@ -158,39 +158,42 @@ Editor::run_timestretch (AudioRegionSelection& regions, float fraction) void Editor::do_timestretch (TimeStretchDialog& dialog) { - AudioTrack* at; + Track* t; Playlist* playlist; - AudioRegion* new_region; + Region* new_region; - for (AudioRegionSelection::iterator i = dialog.regions.begin(); i != dialog.regions.end(); ) { + for (RegionSelection::iterator i = dialog.regions.begin(); i != dialog.regions.end(); ) { + AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*i); + if (!arv) + continue; - AudioRegion& aregion ((*i)->region); - TimeAxisView* tv = &(*i)->get_time_axis_view(); - AudioTimeAxisView* atv; - AudioRegionSelection::iterator tmp; + AudioRegion& region (arv->audio_region()); + TimeAxisView* tv = &(arv->get_time_axis_view()); + RouteTimeAxisView* rtv; + RegionSelection::iterator tmp; - cerr << "stretch " << aregion.name() << endl; + cerr << "stretch " << region.name() << endl; tmp = i; ++tmp; - if ((atv = dynamic_cast<AudioTimeAxisView*> (tv)) == 0) { + if ((rtv = dynamic_cast<RouteTimeAxisView*> (tv)) == 0) { i = tmp; continue; } - if ((at = dynamic_cast<AudioTrack*> (&atv->route())) == 0) { + if ((t = dynamic_cast<Track*> (rtv->route().get())) == 0) { i = tmp; continue; } - if ((playlist = at->disk_stream().playlist()) == 0) { + if ((playlist = t->diskstream().playlist()) == 0) { i = tmp; continue; } - dialog.request.region = &aregion; + dialog.request.region = ®ion; if (!dialog.request.running) { /* we were cancelled */ @@ -205,7 +208,7 @@ Editor::do_timestretch (TimeStretchDialog& dialog) } XMLNode &before = playlist->get_state(); - playlist->replace_region (aregion, *new_region, aregion.position()); + playlist->replace_region (region, *new_region, region.position()); XMLNode &after = playlist->get_state(); session->add_command (new MementoCommand<Playlist>(*playlist, before, after)); diff --git a/gtk2_ardour/export_dialog.cc b/gtk2_ardour/export_dialog.cc index bcf8cd85ad..b5a4757090 100644 --- a/gtk2_ardour/export_dialog.cc +++ b/gtk2_ardour/export_dialog.cc @@ -1082,11 +1082,11 @@ ExportDialog::fill_lists () track_list->clear(); master_list->clear(); - Session::RouteList routes = session->get_routes (); + boost::shared_ptr<Session::RouteList> routes = session->get_routes (); - for (Session::RouteList::iterator ri = routes.begin(); ri != routes.end(); ++ri) { - - Route* route = (*ri); + for (Session::RouteList::iterator ri = routes->begin(); ri != routes->end(); ++ri) { + + boost::shared_ptr<Route> route = (*ri); if (route->hidden()) { continue; diff --git a/gtk2_ardour/export_region_dialog.cc b/gtk2_ardour/export_region_dialog.cc index 97bf7c22b1..1964fabbfe 100644 --- a/gtk2_ardour/export_region_dialog.cc +++ b/gtk2_ardour/export_region_dialog.cc @@ -18,6 +18,8 @@ */ +#include <cassert> + #include <pbd/pthread_utils.h> #include <ardour/audioregion.h> @@ -26,11 +28,13 @@ #include "i18n.h" -ExportRegionDialog::ExportRegionDialog (PublicEditor& editor, ARDOUR::AudioRegion* region) +ExportRegionDialog::ExportRegionDialog (PublicEditor& editor, ARDOUR::Region* region) : ExportDialog(editor) { - audio_region = region; - + // FIXME + ARDOUR::AudioRegion* audio_region = dynamic_cast<ARDOUR::AudioRegion*>(region); + assert(audio_region); + do_not_allow_track_and_master_selection(); do_not_allow_channel_count_selection(); } diff --git a/gtk2_ardour/export_region_dialog.h b/gtk2_ardour/export_region_dialog.h index 00464eb5b3..e8afe97d6b 100644 --- a/gtk2_ardour/export_region_dialog.h +++ b/gtk2_ardour/export_region_dialog.h @@ -27,7 +27,7 @@ class ExportRegionDialog : public ExportDialog { public: - ExportRegionDialog (PublicEditor&, ARDOUR::AudioRegion*); + ExportRegionDialog (PublicEditor&, ARDOUR::Region*); static void* _export_region_thread (void *); void export_region (); diff --git a/gtk2_ardour/fft_graph.cc b/gtk2_ardour/fft_graph.cc index c2d81abf3c..367dc54b7c 100644 --- a/gtk2_ardour/fft_graph.cc +++ b/gtk2_ardour/fft_graph.cc @@ -234,11 +234,11 @@ FFTGraph::draw_scales(Glib::RefPtr<Gdk::Window> window) while (_logScale[logscale_pos] < position_on_scale) logscale_pos++; - int coord = v_margin + 1.0 + position_on_scale; + int coord = (int)(v_margin + 1.0 + position_on_scale); int SR = 44100; - int rate_at_pos = (double)(SR/2) * (double)logscale_pos / (double)_dataSize; + int rate_at_pos = (int)((double)(SR/2) * (double)logscale_pos / (double)_dataSize); char buf[32]; snprintf(buf,32,"%dhz",rate_at_pos); @@ -384,7 +384,7 @@ FFTGraph::on_size_request(Gtk::Requisition* requisition) } void -FFTGraph::on_size_allocate(Gtk::Allocation alloc) +FFTGraph::on_size_allocate(Gtk::Allocation & alloc) { width = alloc.get_width(); height = alloc.get_height(); diff --git a/gtk2_ardour/fft_graph.h b/gtk2_ardour/fft_graph.h index 80c78180a6..73636b989d 100644 --- a/gtk2_ardour/fft_graph.h +++ b/gtk2_ardour/fft_graph.h @@ -51,7 +51,7 @@ class FFTGraph : public Gtk::DrawingArea bool on_expose_event (GdkEventExpose* event); void on_size_request(Gtk::Requisition* requisition); - void on_size_allocate(Gtk::Allocation alloc); + void on_size_allocate(Gtk::Allocation & alloc); FFTResult *prepareResult(Gdk::Color color, std::string trackname); private: diff --git a/gtk2_ardour/fft_result.cc b/gtk2_ardour/fft_result.cc index 9a55b59cb5..f5acef92ed 100644 --- a/gtk2_ardour/fft_result.cc +++ b/gtk2_ardour/fft_result.cc @@ -20,9 +20,9 @@ #include <fft_result.h> #include <fft_graph.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> +#include <cstdlib> +#include <string> +#include <cmath> #include <iostream> diff --git a/gtk2_ardour/gain_automation_time_axis.cc b/gtk2_ardour/gain_automation_time_axis.cc index 3e3d02bfc4..c86c1390f3 100644 --- a/gtk2_ardour/gain_automation_time_axis.cc +++ b/gtk2_ardour/gain_automation_time_axis.cc @@ -32,7 +32,9 @@ using namespace ARDOUR; using namespace PBD; using namespace Gtk; -GainAutomationTimeAxisView::GainAutomationTimeAxisView (Session& s, Route& r, PublicEditor& e, TimeAxisView& parent, ArdourCanvas::Canvas& canvas, const string & n, ARDOUR::Curve& c) +GainAutomationTimeAxisView::GainAutomationTimeAxisView (Session& s, boost::shared_ptr<Route> r, + PublicEditor& e, TimeAxisView& parent, + ArdourCanvas::Canvas& canvas, const string & n, ARDOUR::Curve& c) : AxisView (s), AutomationTimeAxisView (s, r, e, parent, canvas, n, X_("gain"), ""), @@ -74,6 +76,6 @@ void GainAutomationTimeAxisView::set_automation_state (AutoState state) { if (!ignore_state_request) { - route.set_gain_automation_state (state); + route->set_gain_automation_state (state); } } diff --git a/gtk2_ardour/gain_automation_time_axis.h b/gtk2_ardour/gain_automation_time_axis.h index 50f1cba3f9..dc6d5bd28e 100644 --- a/gtk2_ardour/gain_automation_time_axis.h +++ b/gtk2_ardour/gain_automation_time_axis.h @@ -13,7 +13,7 @@ class GainAutomationTimeAxisView : public AutomationTimeAxisView { public: GainAutomationTimeAxisView (ARDOUR::Session&, - ARDOUR::Route&, + boost::shared_ptr<ARDOUR::Route>, PublicEditor&, TimeAxisView& parent_axis, ArdourCanvas::Canvas& canvas, diff --git a/gtk2_ardour/gain_meter.cc b/gtk2_ardour/gain_meter.cc index b7746c4b19..5fa8c462bc 100644 --- a/gtk2_ardour/gain_meter.cc +++ b/gtk2_ardour/gain_meter.cc @@ -79,7 +79,7 @@ GainMeter::setup_slider_pix () return 0; } -GainMeter::GainMeter (IO& io, Session& s) +GainMeter::GainMeter (boost::shared_ptr<IO> io, Session& s) : _io (io), _session (s), gain_slider (0), @@ -99,18 +99,13 @@ GainMeter::GainMeter (IO& io, Session& s) gain_slider = manage (new VSliderController (slider, rail, &gain_adjustment, - & _io.midi_gain_control(), + _io->gain_control(), false)); gain_slider->signal_button_press_event().connect (mem_fun(*this, &GainMeter::start_gain_touch)); gain_slider->signal_button_release_event().connect (mem_fun(*this, &GainMeter::end_gain_touch)); gain_slider->set_name ("MixerGainMeter"); - if (_session.midi_port()) { - _io.set_midi_to_gain_function (slider_position_to_gain); - _io.set_gain_to_midi_function (gain_to_slider_position); - } - gain_display.set_print_func (_gain_printer, this); gain_display_box.set_spacing (2); @@ -157,7 +152,7 @@ GainMeter::GainMeter (IO& io, Session& s) Route* r; - if ((r = dynamic_cast<Route*> (&_io)) != 0) { + if ((r = dynamic_cast<Route*> (_io.get())) != 0) { /* if we don't have a route (if we're the click), pack some route-dependent stuff. @@ -170,13 +165,13 @@ GainMeter::GainMeter (IO& io, Session& s) using namespace Menu_Helpers; gain_astate_menu.items().push_back (MenuElem (_("Off"), - bind (mem_fun (&_io, &IO::set_gain_automation_state), (AutoState) Off))); + bind (mem_fun (*_io, &IO::set_gain_automation_state), (AutoState) Off))); gain_astate_menu.items().push_back (MenuElem (_("Play"), - bind (mem_fun (&_io, &IO::set_gain_automation_state), (AutoState) Play))); + bind (mem_fun (*_io, &IO::set_gain_automation_state), (AutoState) Play))); gain_astate_menu.items().push_back (MenuElem (_("Write"), - bind (mem_fun (&_io, &IO::set_gain_automation_state), (AutoState) Write))); + bind (mem_fun (*_io, &IO::set_gain_automation_state), (AutoState) Write))); gain_astate_menu.items().push_back (MenuElem (_("Touch"), - bind (mem_fun (&_io, &IO::set_gain_automation_state), (AutoState) Touch))); + bind (mem_fun (*_io, &IO::set_gain_automation_state), (AutoState) Touch))); gain_astyle_menu.items().push_back (MenuElem (_("Trim"))); gain_astyle_menu.items().push_back (MenuElem (_("Abs"))); @@ -200,7 +195,7 @@ GainMeter::GainMeter (IO& io, Session& s) pack_start (gain_display_box, Gtk::PACK_SHRINK); pack_start (hbox, Gtk::PACK_SHRINK); - _io.gain_changed.connect (mem_fun(*this, &GainMeter::gain_changed)); + _io->gain_changed.connect (mem_fun(*this, &GainMeter::gain_changed)); meter_metric_area.signal_expose_event().connect (mem_fun(*this, &GainMeter::meter_metrics_expose)); gain_adjustment.signal_value_changed().connect (mem_fun(*this, &GainMeter::gain_adjusted)); @@ -328,7 +323,7 @@ GainMeter::update_meters () for (n = 0, i = meters.begin(); i != meters.end(); ++i, ++n) { if ((*i).packed) { - peak = _io.peak_input_power (n); + peak = _io->peak_input_power (n); (*i).meter->set (log_meter (peak), peak); @@ -387,14 +382,14 @@ GainMeter::hide_all_meters () void GainMeter::setup_meters () { - uint32_t nmeters = _io.n_outputs(); + uint32_t nmeters = _io->n_outputs(); guint16 width; hide_all_meters (); Route* r; - if ((r = dynamic_cast<Route*> (&_io)) != 0) { + if ((r = dynamic_cast<Route*> (_io.get())) != 0) { switch (r->meter_point()) { case MeterPreFader: @@ -408,7 +403,7 @@ GainMeter::setup_meters () } else { - nmeters = _io.n_outputs(); + nmeters = _io->n_outputs(); } @@ -456,7 +451,7 @@ GainMeter::peak_button_release (GdkEventButton* ev) ResetAllPeakDisplays (); } else if (ev->button == 1 && Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) { Route* r; - if ((r = dynamic_cast<Route*> (&_io)) != 0) { + if ((r = dynamic_cast<Route*> (_io.get())) != 0) { ResetGroupPeakDisplays (r->mix_group()); } } else { @@ -477,7 +472,7 @@ void GainMeter::reset_group_peak_display (RouteGroup* group) { Route* r; - if ((r = dynamic_cast<Route*> (&_io)) != 0) { + if ((r = dynamic_cast<Route*> (_io.get())) != 0) { if (group == r->mix_group()) { reset_peak_display (); } @@ -546,14 +541,14 @@ void GainMeter::gain_adjusted () { if (!ignore_toggle) { - _io.set_gain (slider_position_to_gain (gain_adjustment.get_value()), this); + _io->set_gain (slider_position_to_gain (gain_adjustment.get_value()), this); } } void GainMeter::effective_gain_display () { - gfloat value = gain_to_slider_position (_io.effective_gain()); + gfloat value = gain_to_slider_position (_io->effective_gain()); if (gain_adjustment.get_value() != value) { ignore_toggle = true; @@ -583,7 +578,7 @@ GainMeter::set_fader_name (const char * name) void GainMeter::update_gain_sensitive () { - static_cast<Gtkmm2ext::SliderController*>(gain_slider)->set_sensitive (!(_io.gain_automation_state() & Play)); + static_cast<Gtkmm2ext::SliderController*>(gain_slider)->set_sensitive (!(_io->gain_automation_state() & Play)); } @@ -614,7 +609,7 @@ GainMeter::meter_press(GdkEventButton* ev) wait_for_release = false; - if ((_route = dynamic_cast<Route*>(&_io)) == 0) { + if ((_route = dynamic_cast<Route*>(_io.get())) == 0) { return FALSE; } @@ -676,7 +671,7 @@ GainMeter::meter_release(GdkEventButton* ev) if(!ignore_toggle){ if (wait_for_release){ wait_for_release = false; - set_meter_point (*(dynamic_cast<Route*>(&_io)), old_meter_point); + set_meter_point (*(dynamic_cast<Route*>(_io.get())), old_meter_point); } } return true; @@ -705,7 +700,7 @@ GainMeter::meter_point_clicked () { Route* r; - if ((r = dynamic_cast<Route*> (&_io)) != 0) { + if ((r = dynamic_cast<Route*> (_io.get())) != 0) { } } @@ -713,14 +708,14 @@ GainMeter::meter_point_clicked () gint GainMeter::start_gain_touch (GdkEventButton* ev) { - _io.start_gain_touch (); + _io->start_gain_touch (); return FALSE; } gint GainMeter::end_gain_touch (GdkEventButton* ev) { - _io.end_gain_touch (); + _io->end_gain_touch (); return FALSE; } @@ -824,10 +819,10 @@ GainMeter::gain_automation_style_changed () // Route* _route = dynamic_cast<Route*>(&_io); switch (_width) { case Wide: - gain_automation_style_button.set_label (astyle_string(_io.gain_automation_curve().automation_style())); + gain_automation_style_button.set_label (astyle_string(_io->gain_automation_curve().automation_style())); break; case Narrow: - gain_automation_style_button.set_label (short_astyle_string(_io.gain_automation_curve().automation_style())); + gain_automation_style_button.set_label (short_astyle_string(_io->gain_automation_curve().automation_style())); break; } } @@ -842,14 +837,14 @@ GainMeter::gain_automation_state_changed () switch (_width) { case Wide: - gain_automation_state_button.set_label (astate_string(_io.gain_automation_curve().automation_state())); + gain_automation_state_button.set_label (astate_string(_io->gain_automation_curve().automation_state())); break; case Narrow: - gain_automation_state_button.set_label (short_astate_string(_io.gain_automation_curve().automation_state())); + gain_automation_state_button.set_label (short_astate_string(_io->gain_automation_curve().automation_state())); break; } - x = (_io.gain_automation_state() != Off); + x = (_io->gain_automation_state() != Off); if (gain_automation_state_button.get_active() != x) { ignore_toggle = true; diff --git a/gtk2_ardour/gain_meter.h b/gtk2_ardour/gain_meter.h index ddf93b579f..1dfc088248 100644 --- a/gtk2_ardour/gain_meter.h +++ b/gtk2_ardour/gain_meter.h @@ -34,8 +34,8 @@ #include <ardour/types.h> -#include <gtkmm2ext/slider_controller.h> #include <gtkmm2ext/click_box.h> +#include <gtkmm2ext/slider_controller.h> #include "enums.h" @@ -56,7 +56,7 @@ namespace Gtk { class GainMeter : public Gtk::VBox { public: - GainMeter (ARDOUR::IO&, ARDOUR::Session&); + GainMeter (boost::shared_ptr<ARDOUR::IO>, ARDOUR::Session&); ~GainMeter (); void update_gain_sensitive (); @@ -75,7 +75,7 @@ class GainMeter : public Gtk::VBox private: friend class MixerStrip; - ARDOUR::IO& _io; + boost::shared_ptr<ARDOUR::IO> _io; ARDOUR::Session& _session; bool ignore_toggle; diff --git a/gtk2_ardour/io_selector.cc b/gtk2_ardour/io_selector.cc index b0ecd05077..f754435112 100644 --- a/gtk2_ardour/io_selector.cc +++ b/gtk2_ardour/io_selector.cc @@ -52,7 +52,7 @@ using namespace ARDOUR; using namespace PBD; using namespace Gtkmm2ext; -IOSelectorWindow::IOSelectorWindow (Session& sess, IO& ior, bool input, bool can_cancel) +IOSelectorWindow::IOSelectorWindow (Session& sess, boost::shared_ptr<IO> ior, bool input, bool can_cancel) : ArdourDialog ("i/o selector"), _selector (sess, ior, input), ok_button (can_cancel ? _("OK"): _("Close")), @@ -65,9 +65,9 @@ IOSelectorWindow::IOSelectorWindow (Session& sess, IO& ior, bool input, bool can string title; if (input) { - title = string_compose(_("%1 input"), ior.name()); + title = string_compose(_("%1 input"), ior->name()); } else { - title = string_compose(_("%1 output"), ior.name()); + title = string_compose(_("%1 output"), ior->name()); } ok_button.set_name ("IOSelectorButton"); @@ -135,7 +135,7 @@ IOSelectorWindow::on_map () The IO Selector "widget" *************************/ -IOSelector::IOSelector (Session& sess, IO& ior, bool input) +IOSelector::IOSelector (Session& sess, boost::shared_ptr<IO> ior, bool input) : session (sess), io (ior), for_input (input), @@ -184,14 +184,14 @@ IOSelector::IOSelector (Session& sess, IO& ior, bool input) port_button_box.pack_start (add_port_button, false, false); if (for_input) { - if (io.input_maximum() < 0 || io.input_maximum() > (int) io.n_inputs()) { + if (io->input_maximum() < 0 || io->input_maximum() > (int) io->n_inputs()) { add_port_button.set_sensitive (true); } else { add_port_button.set_sensitive (false); } } else { - if (io.output_maximum() < 0 || io.output_maximum() > (int) io.n_outputs()) { + if (io->output_maximum() < 0 || io->output_maximum() > (int) io->n_outputs()) { add_port_button.set_sensitive (true); } else { add_port_button.set_sensitive (false); @@ -202,14 +202,14 @@ IOSelector::IOSelector (Session& sess, IO& ior, bool input) port_button_box.pack_start (remove_port_button, false, false); if (for_input) { - if (io.input_minimum() < 0 || io.input_minimum() < (int) io.n_inputs()) { + if (io->input_minimum() < 0 || io->input_minimum() < (int) io->n_inputs()) { remove_port_button.set_sensitive (true); } else { remove_port_button.set_sensitive (false); } } else { - if (io.output_minimum() < 0 || io.output_minimum() < (int) io.n_outputs()) { + if (io->output_minimum() < 0 || io->output_minimum() < (int) io->n_outputs()) { remove_port_button.set_sensitive (true); } else { remove_port_button.set_sensitive (false); @@ -241,12 +241,12 @@ IOSelector::IOSelector (Session& sess, IO& ior, bool input) remove_port_button.signal_clicked().connect (mem_fun(*this, &IOSelector::remove_port)); if (for_input) { - io.input_changed.connect (mem_fun(*this, &IOSelector::ports_changed)); + io->input_changed.connect (mem_fun(*this, &IOSelector::ports_changed)); } else { - io.output_changed.connect (mem_fun(*this, &IOSelector::ports_changed)); + io->output_changed.connect (mem_fun(*this, &IOSelector::ports_changed)); } - io.name_changed.connect (mem_fun(*this, &IOSelector::name_changed)); + io->name_changed.connect (mem_fun(*this, &IOSelector::name_changed)); } IOSelector::~IOSelector () @@ -265,9 +265,9 @@ void IOSelector::clear_connections () { if (for_input) { - io.disconnect_inputs (this); + io->disconnect_inputs (this); } else { - io.disconnect_outputs (this); + io->disconnect_outputs (this); } } @@ -374,9 +374,9 @@ IOSelector::display_ports () uint32_t limit; if (for_input) { - limit = io.n_inputs(); + limit = io->n_inputs(); } else { - limit = io.n_outputs(); + limit = io->n_outputs(); } for (slist<TreeView *>::iterator i = port_displays.begin(); i != port_displays.end(); ) { @@ -401,9 +401,9 @@ IOSelector::display_ports () string really_short_name; if (for_input) { - port = io.input (n); + port = io->input (n); } else { - port = io.output (n); + port = io->output (n); } /* we know there is '/' because we put it there */ @@ -443,7 +443,7 @@ IOSelector::display_ports () if (for_input) { - if (io.input_maximum() == 1) { + if (io->input_maximum() == 1) { selected_port = port; selected_port_tview = tview; } else { @@ -454,7 +454,7 @@ IOSelector::display_ports () } else { - if (io.output_maximum() == 1) { + if (io->output_maximum() == 1) { selected_port = port; selected_port_tview = tview; } else { @@ -516,12 +516,12 @@ IOSelector::port_selection_changed (GdkEventButton *ev, TreeView* treeview) ustring other_port_name = (*i)[port_display_columns.full_name]; if (for_input) { - if ((status = io.connect_input (selected_port, other_port_name, this)) == 0) { + if ((status = io->connect_input (selected_port, other_port_name, this)) == 0) { Port *p = session.engine().get_port_by_name (other_port_name); p->enable_metering(); } } else { - status = io.connect_output (selected_port, other_port_name, this); + status = io->connect_output (selected_port, other_port_name, this); } if (status == 0) { @@ -548,7 +548,7 @@ IOSelector::add_port () if (for_input) { try { - io.add_input_port ("", this); + io->add_input_port ("", this); } catch (AudioEngine::PortRegistrationFailure& err) { @@ -556,18 +556,18 @@ IOSelector::add_port () msg.run (); } - if (io.input_maximum() >= 0 && io.input_maximum() <= (int) io.n_inputs()) { + if (io->input_maximum() >= 0 && io->input_maximum() <= (int) io->n_inputs()) { add_port_button.set_sensitive (false); } - if (io.input_minimum() < (int) io.n_inputs()) { + if (io->input_minimum() < (int) io->n_inputs()) { remove_port_button.set_sensitive (true); } } else { try { - io.add_output_port ("", this); + io->add_output_port ("", this); } catch (AudioEngine::PortRegistrationFailure& err) { @@ -575,7 +575,7 @@ IOSelector::add_port () msg.run (); } - if (io.output_maximum() >= 0 && io.output_maximum() <= (int) io.n_outputs()) { + if (io->output_maximum() >= 0 && io->output_maximum() <= (int) io->n_outputs()) { add_port_button.set_sensitive (false); } } @@ -589,15 +589,15 @@ IOSelector::remove_port () // always remove last port if (for_input) { - if ((nports = io.n_inputs()) > 0) { - io.remove_input_port (io.input(nports-1), this); + if ((nports = io->n_inputs()) > 0) { + io->remove_input_port (io->input(nports-1), this); } - if (io.input_minimum() == (int) io.n_inputs()) { + if (io->input_minimum() == (int) io->n_inputs()) { remove_port_button.set_sensitive (false); } } else { - if ((nports = io.n_outputs()) > 0) { - io.remove_output_port (io.output(nports-1), this); + if ((nports = io->n_outputs()) > 0) { + io->remove_output_port (io->output(nports-1), this); } } } @@ -606,9 +606,9 @@ gint IOSelector::remove_port_when_idle (Port *port) { if (for_input) { - io.remove_input_port (port, this); + io->remove_input_port (port, this); } else { - io.remove_output_port (port, this); + io->remove_output_port (port, this); } return FALSE; @@ -651,9 +651,9 @@ IOSelector::connection_button_release (GdkEventButton *ev, TreeView *treeview) if (for_input) { Port *p = session.engine().get_port_by_name (connected_port_name); p->disable_metering(); - io.disconnect_input (port, connected_port_name, this); + io->disconnect_input (port, connected_port_name, this); } else { - io.disconnect_output (port, connected_port_name, this); + io->disconnect_output (port, connected_port_name, this); } } @@ -749,17 +749,17 @@ IOSelector::redisplay () display_ports (); if (for_input) { - if (io.input_maximum() != 0) { + if (io->input_maximum() != 0) { rescan (); } } else { - if (io.output_maximum() != 0) { + if (io->output_maximum() != 0) { rescan(); } } } -PortInsertUI::PortInsertUI (Session& sess, PortInsert& pi) +PortInsertUI::PortInsertUI (Session& sess, boost::shared_ptr<PortInsert> pi) : input_selector (sess, pi, true), output_selector (sess, pi, false) { @@ -786,9 +786,9 @@ PortInsertUI::finished(IOSelector::Result r) } -PortInsertWindow::PortInsertWindow (Session& sess, PortInsert& pi, bool can_cancel) +PortInsertWindow::PortInsertWindow (Session& sess, boost::shared_ptr<PortInsert> pi, bool can_cancel) : ArdourDialog ("port insert dialog"), - _portinsertui(sess, pi), + _portinsertui (sess, pi), ok_button (can_cancel ? _("OK"): _("Close")), cancel_button (_("Cancel")), rescan_button (_("Rescan")) @@ -796,7 +796,7 @@ PortInsertWindow::PortInsertWindow (Session& sess, PortInsert& pi, bool can_canc set_name ("IOSelectorWindow"); string title = _("ardour: "); - title += pi.name(); + title += pi->name(); set_title (title); ok_button.set_name ("IOSelectorButton"); @@ -823,7 +823,7 @@ PortInsertWindow::PortInsertWindow (Session& sess, PortInsert& pi, bool can_canc rescan_button.signal_clicked().connect (mem_fun(*this, &PortInsertWindow::rescan)); signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), reinterpret_cast<Window *> (this))); - pi.GoingAway.connect (mem_fun(*this, &PortInsertWindow::plugin_going_away)); + pi->GoingAway.connect (mem_fun(*this, &PortInsertWindow::plugin_going_away)); } void diff --git a/gtk2_ardour/io_selector.h b/gtk2_ardour/io_selector.h index 44518e6759..993d4aa1ad 100644 --- a/gtk2_ardour/io_selector.h +++ b/gtk2_ardour/io_selector.h @@ -53,7 +53,7 @@ namespace ARDOUR { class IOSelector : public Gtk::VBox { public: - IOSelector (ARDOUR::Session&, ARDOUR::IO&, bool for_input); + IOSelector (ARDOUR::Session&, boost::shared_ptr<ARDOUR::IO>, bool for_input); ~IOSelector (); void redisplay (); @@ -67,9 +67,9 @@ class IOSelector : public Gtk::VBox { protected: ARDOUR::Session& session; - + private: - ARDOUR::IO& io; + boost::shared_ptr<ARDOUR::IO> io; bool for_input; ARDOUR::Port *selected_port; @@ -135,7 +135,7 @@ class IOSelector : public Gtk::VBox { class IOSelectorWindow : public ArdourDialog { public: - IOSelectorWindow (ARDOUR::Session&, ARDOUR::IO&, bool for_input, bool can_cancel=false); + IOSelectorWindow (ARDOUR::Session&, boost::shared_ptr<ARDOUR::IO>, bool for_input, bool can_cancel=false); ~IOSelectorWindow (); IOSelector& selector() { return _selector; } @@ -162,7 +162,7 @@ class IOSelectorWindow : public ArdourDialog class PortInsertUI : public Gtk::VBox { public: - PortInsertUI (ARDOUR::Session&, ARDOUR::PortInsert&); + PortInsertUI (ARDOUR::Session&, boost::shared_ptr<ARDOUR::PortInsert>); void redisplay (); void finished (IOSelector::Result); @@ -178,7 +178,7 @@ class PortInsertUI : public Gtk::VBox class PortInsertWindow : public ArdourDialog { public: - PortInsertWindow (ARDOUR::Session&, ARDOUR::PortInsert&, bool can_cancel=false); + PortInsertWindow (ARDOUR::Session&, boost::shared_ptr<ARDOUR::PortInsert>, bool can_cancel=false); protected: void on_map (); diff --git a/gtk2_ardour/keyboard.h b/gtk2_ardour/keyboard.h index 06ed4c800d..c13b06afe5 100644 --- a/gtk2_ardour/keyboard.h +++ b/gtk2_ardour/keyboard.h @@ -28,7 +28,7 @@ #include <gtk/gtk.h> #include <ardour/types.h> -#include <ardour/stateful.h> +#include <pbd/stateful.h> #include "selection.h" diff --git a/gtk2_ardour/main.cc b/gtk2_ardour/main.cc index 778355c858..047bb130a4 100644 --- a/gtk2_ardour/main.cc +++ b/gtk2_ardour/main.cc @@ -446,7 +446,7 @@ int main (int argc, char *argv[]) try { engine = new ARDOUR::AudioEngine (jack_client_name); - ARDOUR::init (*engine, use_vst, try_hw_optimization); + ARDOUR::init (use_vst, try_hw_optimization); ui->set_engine (*engine); } catch (AudioEngine::NoBackendAvailable& err) { gui_jack_error (); diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc index 47d884be5e..4f3dc720d9 100644 --- a/gtk2_ardour/mixer_strip.cc +++ b/gtk2_ardour/mixer_strip.cc @@ -27,10 +27,10 @@ #include <gtkmm2ext/gtk_ui.h> #include <gtkmm2ext/utils.h> #include <gtkmm2ext/choice.h> -#include <gtkmm2ext/slider_controller.h> #include <gtkmm2ext/stop_signal.h> -#include <gtkmm2ext/bindable_button.h> #include <gtkmm2ext/doi.h> +#include <gtkmm2ext/slider_controller.h> +#include <gtkmm2ext/bindable_button.h> #include <ardour/ardour.h> #include <ardour/session.h> @@ -52,7 +52,6 @@ #include "keyboard.h" #include "plugin_selector.h" #include "public_editor.h" - #include "plugin_ui.h" #include "send_ui.h" #include "io_selector.h" @@ -81,7 +80,7 @@ speed_printer (char buf[32], Gtk::Adjustment& adj, void* arg) } #endif -MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, Route& rt, bool in_mixer) +MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt, bool in_mixer) : AxisView(sess), RouteUI (rt, sess, _("Mute"), _("Solo"), _("Record")), _mixer(mx), @@ -126,12 +125,12 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, Route& rt, bool in_mixer) output_button.set_name ("MixerIOButton"); output_label.set_name ("MixerIOButtonLabel"); - _route.meter_change.connect (mem_fun(*this, &MixerStrip::meter_changed)); + _route->meter_change.connect (mem_fun(*this, &MixerStrip::meter_changed)); meter_point_button.add (meter_point_label); meter_point_button.set_name ("MixerStripMeterPreButton"); meter_point_label.set_name ("MixerStripMeterPreButton"); - switch (_route.meter_point()) { + switch (_route->meter_point()) { case MeterInput: meter_point_label.set_text (_("input")); break; @@ -159,9 +158,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, Route& rt, bool in_mixer) /* XXX what is this meant to do? */ //meter_point_button.signal_button_release_event().connect (mem_fun (gpm, &GainMeter::meter_release), false); - rec_enable_button->set_name ("MixerRecordEnableButton"); - rec_enable_button->unset_flags (Gtk::CAN_FOCUS); - solo_button->set_name ("MixerSoloButton"); mute_button->set_name ("MixerMuteButton"); @@ -191,7 +187,11 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, Route& rt, bool in_mixer) if (is_audio_track()) { - AudioTrack* at = dynamic_cast<AudioTrack*>(&_route); + rec_enable_button->set_name ("MixerRecordEnableButton"); + rec_enable_button->unset_flags (Gtk::CAN_FOCUS); + rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press)); + + AudioTrack* at = audio_track(); at->FreezeChange.connect (mem_fun(*this, &MixerStrip::map_frozen)); @@ -217,10 +217,10 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, Route& rt, bool in_mixer) Gtkmm2ext::set_size_request_to_display_given_text (name_button, "longest label", 2, 2); name_label.set_name ("MixerNameButtonLabel"); - if (_route.phase_invert()) { + if (_route->phase_invert()) { name_label.set_text (X_("Ø ") + name_label.get_text()); } else { - name_label.set_text (_route.name()); + name_label.set_text (_route->name()); } group_button.add (group_label); @@ -229,9 +229,9 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, Route& rt, bool in_mixer) comment_button.set_name ("MixerCommentButton"); - ARDOUR_UI::instance()->tooltips().set_tip (comment_button, _route.comment()=="" ? + ARDOUR_UI::instance()->tooltips().set_tip (comment_button, _route->comment()=="" ? _("Click to Add/Edit Comments"): - _route.comment()); + _route->comment()); comment_button.signal_clicked().connect (mem_fun(*this, &MixerStrip::comment_button_clicked)); @@ -281,27 +281,26 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, Route& rt, bool in_mixer) _session.engine().Stopped.connect (mem_fun(*this, &MixerStrip::engine_stopped)); _session.engine().Running.connect (mem_fun(*this, &MixerStrip::engine_running)); - _route.input_changed.connect (mem_fun(*this, &MixerStrip::input_changed)); - _route.output_changed.connect (mem_fun(*this, &MixerStrip::output_changed)); - _route.mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)); - _route.solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)); - _route.solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)); - _route.mix_group_changed.connect (mem_fun(*this, &MixerStrip::mix_group_changed)); - _route.panner().Changed.connect (mem_fun(*this, &MixerStrip::connect_to_pan)); + _route->input_changed.connect (mem_fun(*this, &MixerStrip::input_changed)); + _route->output_changed.connect (mem_fun(*this, &MixerStrip::output_changed)); + _route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)); + _route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)); + _route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)); + _route->mix_group_changed.connect (mem_fun(*this, &MixerStrip::mix_group_changed)); + _route->panner().Changed.connect (mem_fun(*this, &MixerStrip::connect_to_pan)); if (is_audio_track()) { - audio_track()->diskstream_changed.connect (mem_fun(*this, &MixerStrip::diskstream_changed)); - get_diskstream()->speed_changed.connect (mem_fun(*this, &MixerStrip::speed_changed)); + audio_track()->DiskstreamChanged.connect (mem_fun(*this, &MixerStrip::diskstream_changed)); + get_diskstream()->SpeedChanged.connect (mem_fun(*this, &MixerStrip::speed_changed)); } - _route.name_changed.connect (mem_fun(*this, &RouteUI::name_changed)); - _route.comment_changed.connect (mem_fun(*this, &MixerStrip::comment_changed)); - _route.gui_changed.connect (mem_fun(*this, &MixerStrip::route_gui_changed)); + _route->name_changed.connect (mem_fun(*this, &RouteUI::name_changed)); + _route->comment_changed.connect (mem_fun(*this, &MixerStrip::comment_changed)); + _route->gui_changed.connect (mem_fun(*this, &MixerStrip::route_gui_changed)); input_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::input_press), false); output_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::output_press), false); - rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press)); solo_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::solo_press), false); solo_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::solo_release), false); mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press), false); @@ -414,20 +413,22 @@ MixerStrip::set_width (Width w) set_size_request (-1, -1); xml_node->add_property ("strip_width", "wide"); - rec_enable_button->set_label (_("record")); + if (rec_enable_button) { + rec_enable_button->set_label (_("record")); + } mute_button->set_label (_("mute")); solo_button->set_label (_("solo")); - if (_route.comment() == "") { + if (_route->comment() == "") { comment_button.set_label (_("comments")); } else { comment_button.set_label (_("*comments*")); } - gpm.gain_automation_style_button.set_label (gpm.astyle_string(_route.gain_automation_curve().automation_style())); - gpm.gain_automation_state_button.set_label (gpm.astate_string(_route.gain_automation_curve().automation_state())); - panners.pan_automation_style_button.set_label (panners.astyle_string(_route.panner().automation_style())); - panners.pan_automation_state_button.set_label (panners.astate_string(_route.panner().automation_state())); + gpm.gain_automation_style_button.set_label (gpm.astyle_string(_route->gain_automation_curve().automation_style())); + gpm.gain_automation_state_button.set_label (gpm.astate_string(_route->gain_automation_curve().automation_state())); + panners.pan_automation_style_button.set_label (panners.astyle_string(_route->panner().automation_style())); + panners.pan_automation_state_button.set_label (panners.astate_string(_route->panner().automation_state())); Gtkmm2ext::set_size_request_to_display_given_text (name_button, "long", 2, 2); break; @@ -435,20 +436,22 @@ MixerStrip::set_width (Width w) set_size_request (50, -1); xml_node->add_property ("strip_width", "narrow"); - rec_enable_button->set_label (_("Rec")); + if (rec_enable_button) { + rec_enable_button->set_label (_("Rec")); + } mute_button->set_label (_("M")); solo_button->set_label (_("S")); - if (_route.comment() == "") { + if (_route->comment() == "") { comment_button.set_label (_("Cmt")); } else { comment_button.set_label (_("*Cmt*")); } - gpm.gain_automation_style_button.set_label (gpm.short_astyle_string(_route.gain_automation_curve().automation_style())); - gpm.gain_automation_state_button.set_label (gpm.short_astate_string(_route.gain_automation_curve().automation_state())); - panners.pan_automation_style_button.set_label (panners.short_astyle_string(_route.panner().automation_style())); - panners.pan_automation_state_button.set_label (panners.short_astate_string(_route.panner().automation_state())); + gpm.gain_automation_style_button.set_label (gpm.short_astyle_string(_route->gain_automation_curve().automation_style())); + gpm.gain_automation_state_button.set_label (gpm.short_astate_string(_route->gain_automation_curve().automation_state())); + panners.pan_automation_style_button.set_label (panners.short_astyle_string(_route->panner().automation_style())); + panners.pan_automation_state_button.set_label (panners.short_astate_string(_route->panner().automation_state())); Gtkmm2ext::set_size_request_to_display_given_text (name_button, "longest label", 2, 2); break; } @@ -555,11 +558,6 @@ MixerStrip::input_press (GdkEventButton *ev) case 1: -#if ADVANCED_ROUTE_DISKSTREAM_CONNECTIVITY - if (is_audio_track()) { - citems.push_back (MenuElem (_("Track"), mem_fun(*this, &MixerStrip::select_stream_input))); - } -#endif citems.push_back (MenuElem (_("Edit"), mem_fun(*this, &MixerStrip::edit_input_configuration))); citems.push_back (SeparatorElem()); citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input))); @@ -581,7 +579,7 @@ MixerStrip::connection_input_chosen (ARDOUR::Connection *c) if (!ignore_toggle) { try { - _route.use_input_connection (*c, this); + _route->use_input_connection (*c, this); } catch (AudioEngine::PortRegistrationFailure& err) { @@ -597,7 +595,7 @@ MixerStrip::connection_output_chosen (ARDOUR::Connection *c) if (!ignore_toggle) { try { - _route.use_output_connection (*c, this); + _route->use_output_connection (*c, this); } catch (AudioEngine::PortRegistrationFailure& err) { @@ -618,11 +616,11 @@ MixerStrip::add_connection_to_input_menu (ARDOUR::Connection* c) MenuList& citems = input_menu.items(); - if (c->nports() == _route.n_inputs()) { + if (c->nports() == _route->n_inputs()) { citems.push_back (CheckMenuElem (c->name(), bind (mem_fun(*this, &MixerStrip::connection_input_chosen), c))); - ARDOUR::Connection *current = _route.input_connection(); + ARDOUR::Connection *current = _route->input_connection(); if (current == c) { ignore_toggle = true; @@ -641,12 +639,12 @@ MixerStrip::add_connection_to_output_menu (ARDOUR::Connection* c) return; } - if (c->nports() == _route.n_outputs()) { + if (c->nports() == _route->n_outputs()) { MenuList& citems = output_menu.items(); citems.push_back (CheckMenuElem (c->name(), bind (mem_fun(*this, &MixerStrip::connection_output_chosen), c))); - ARDOUR::Connection *current = _route.output_connection(); + ARDOUR::Connection *current = _route->output_connection(); if (current == c) { ignore_toggle = true; @@ -657,42 +655,6 @@ MixerStrip::add_connection_to_output_menu (ARDOUR::Connection* c) } void -MixerStrip::select_stream_input () -{ - using namespace Menu_Helpers; - - Menu *stream_menu = manage (new Menu); - MenuList& items = stream_menu->items(); - stream_menu->set_name ("ArdourContextMenu"); - - Session::AudioDiskstreamList streams = _session.audio_disk_streams(); - - for (Session::AudioDiskstreamList::iterator i = streams.begin(); i != streams.end(); ++i) { - - if (!(*i)->hidden()) { - - items.push_back (CheckMenuElem ((*i)->name(), bind (mem_fun(*this, &MixerStrip::stream_input_chosen), *i))); - - if (get_diskstream() == *i) { - ignore_toggle = true; - static_cast<CheckMenuItem *> (&items.back())->set_active (true); - ignore_toggle = false; - } - } - } - - stream_menu->popup (1, 0); -} - -void -MixerStrip::stream_input_chosen (AudioDiskstream *stream) -{ - if (is_audio_track()) { - audio_track()->set_diskstream (*stream, this); - } -} - -void MixerStrip::update_diskstream_display () { if (is_audio_track()) { @@ -724,8 +686,8 @@ MixerStrip::connect_to_pan () panstate_connection.disconnect (); panstyle_connection.disconnect (); - if (!_route.panner().empty()) { - StreamPanner* sp = _route.panner().front(); + if (!_route->panner().empty()) { + StreamPanner* sp = _route->panner().front(); panstate_connection = sp->automation().automation_state_changed.connect (mem_fun(panners, &PannerUI::pan_automation_state_changed)); panstyle_connection = sp->automation().automation_style_changed.connect (mem_fun(panners, &PannerUI::pan_automation_style_changed)); @@ -739,7 +701,7 @@ MixerStrip::update_input_display () { ARDOUR::Connection *c; - if ((c = _route.input_connection()) != 0) { + if ((c = _route->input_connection()) != 0) { input_label.set_text (c->name()); } else { switch (_width) { @@ -759,7 +721,7 @@ MixerStrip::update_output_display () { ARDOUR::Connection *c; - if ((c = _route.output_connection()) != 0) { + if ((c = _route->output_connection()) != 0) { output_label.set_text (c->name()); } else { switch (_width) { @@ -782,7 +744,7 @@ MixerStrip::fast_update () } void -MixerStrip::diskstream_changed (void *src) +MixerStrip::diskstream_changed () { Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_diskstream_display)); } @@ -810,8 +772,8 @@ MixerStrip::comment_button_clicked () if (comment_window->is_visible()) { string str = comment_area->get_buffer()->get_text(); - if (_route.comment() != str) { - _route.set_comment (str, this); + if (_route->comment() != str) { + _route->set_comment (str, this); switch (_width) { @@ -855,7 +817,7 @@ void MixerStrip::setup_comment_editor () { string title; - title = _route.name(); + title = _route->name(); title += _(": comment editor"); comment_window = new ArdourDialog (title, false); @@ -867,7 +829,7 @@ MixerStrip::setup_comment_editor () comment_area->set_size_request (110, 178); comment_area->set_wrap_mode (WRAP_WORD); comment_area->set_editable (true); - comment_area->get_buffer()->set_text (_route.comment()); + comment_area->get_buffer()->set_text (_route->comment()); comment_area->show (); comment_window->get_vbox()->pack_start (*comment_area); @@ -882,7 +844,7 @@ MixerStrip::comment_changed (void *src) if (src != this) { ignore_comment_edit = true; if (comment_area) { - comment_area->get_buffer()->set_text (_route.comment()); + comment_area->get_buffer()->set_text (_route->comment()); } ignore_comment_edit = false; } @@ -891,7 +853,7 @@ MixerStrip::comment_changed (void *src) void MixerStrip::set_mix_group (RouteGroup *rg) { - _route.set_mix_group (rg, this); + _route->set_mix_group (rg, this); } void @@ -903,7 +865,7 @@ MixerStrip::add_mix_group_to_menu (RouteGroup *rg, RadioMenuItem::Group* group) items.push_back (RadioMenuElem (*group, rg->name(), bind (mem_fun(*this, &MixerStrip::set_mix_group), rg))); - if (_route.mix_group() == rg) { + if (_route->mix_group() == rg) { static_cast<RadioMenuItem*>(&items.back())->set_active (); } } @@ -943,7 +905,7 @@ MixerStrip::mix_group_changed (void *ignored) { ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::mix_group_changed), ignored)); - RouteGroup *rg = _route.mix_group(); + RouteGroup *rg = _route->mix_group(); if (rg) { group_label.set_text (rg->name()); @@ -999,11 +961,11 @@ MixerStrip::build_route_ops_menu () items.push_back (SeparatorElem()); items.push_back (CheckMenuElem (_("Active"), mem_fun (*this, &RouteUI::toggle_route_active))); route_active_menu_item = dynamic_cast<CheckMenuItem *> (&items.back()); - route_active_menu_item->set_active (_route.active()); + route_active_menu_item->set_active (_route->active()); items.push_back (SeparatorElem()); items.push_back (CheckMenuElem (_("Invert Polarity"), mem_fun (*this, &RouteUI::toggle_polarity))); polarity_menu_item = dynamic_cast<CheckMenuItem *> (&items.back()); - polarity_menu_item->set_active (_route.phase_invert()); + polarity_menu_item->set_active (_route->phase_invert()); build_remote_control_menu (); @@ -1093,10 +1055,10 @@ MixerStrip::name_changed (void *src) RouteUI::name_changed (src); break; case Narrow: - name_label.set_text (PBD::short_version (_route.name(), 5)); + name_label.set_text (PBD::short_version (_route->name(), 5)); break; } - if (_route.phase_invert()) { + if (_route->phase_invert()) { name_label.set_text (X_("Ø ") + name_label.get_text()); } } @@ -1135,7 +1097,7 @@ MixerStrip::map_frozen () { ENSURE_GUI_THREAD (mem_fun(*this, &MixerStrip::map_frozen)); - AudioTrack* at = dynamic_cast<AudioTrack*>(&_route); + AudioTrack* at = audio_track(); if (at) { switch (at->freeze_state()) { @@ -1151,11 +1113,11 @@ MixerStrip::map_frozen () break; } } - _route.foreach_redirect (this, &MixerStrip::hide_redirect_editor); + _route->foreach_redirect (this, &MixerStrip::hide_redirect_editor); } void -MixerStrip::hide_redirect_editor (Redirect* redirect) +MixerStrip::hide_redirect_editor (boost::shared_ptr<Redirect> redirect) { void* gui = redirect->get_gui (); @@ -1170,7 +1132,7 @@ MixerStrip::route_active_changed () RouteUI::route_active_changed (); if (is_audio_track()) { - if (_route.active()) { + if (_route->active()) { set_name ("AudioTrackStripBase"); gpm.set_meter_strip_name ("AudioTrackStripBase"); } else { @@ -1178,8 +1140,8 @@ MixerStrip::route_active_changed () gpm.set_meter_strip_name ("AudioTrackStripBaseInactive"); } gpm.set_fader_name ("AudioTrackFader"); - } else { - if (_route.active()) { + } else { // FIXME: assumed audio bus + if (_route->active()) { set_name ("AudioBusStripBase"); gpm.set_meter_strip_name ("AudioBusStripBase"); } else { @@ -1193,14 +1155,16 @@ MixerStrip::route_active_changed () RouteGroup* MixerStrip::mix_group() const { - return _route.mix_group(); + return _route->mix_group(); } void MixerStrip::engine_stopped () { input_button.set_sensitive (false); - rec_enable_button->set_sensitive (false); + if (rec_enable_button) { + rec_enable_button->set_sensitive (false); + } output_button.set_sensitive (false); } @@ -1208,7 +1172,9 @@ void MixerStrip::engine_running () { input_button.set_sensitive (true); - rec_enable_button->set_sensitive (true); + if (rec_enable_button) { + rec_enable_button->set_sensitive (true); + } output_button.set_sensitive (true); } @@ -1218,7 +1184,7 @@ MixerStrip::meter_changed (void *src) ENSURE_GUI_THREAD (bind (mem_fun(*this, &MixerStrip::meter_changed), src)); - switch (_route.meter_point()) { + switch (_route->meter_point()) { case MeterInput: meter_point_label.set_text (_("input")); break; diff --git a/gtk2_ardour/mixer_strip.h b/gtk2_ardour/mixer_strip.h index 0cc8fed8e3..21db0d14ca 100644 --- a/gtk2_ardour/mixer_strip.h +++ b/gtk2_ardour/mixer_strip.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,8 +14,6 @@ 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_mixer_strip__ @@ -37,14 +35,15 @@ #include <gtkmm/adjustment.h> #include <gtkmm2ext/auto_spin.h> -#include <gtkmm2ext/slider_controller.h> #include <gtkmm2ext/click_box.h> +#include <gtkmm2ext/slider_controller.h> + +#include <pbd/stateful.h> #include <ardour/types.h> #include <ardour/ardour.h> #include <ardour/io.h> #include <ardour/insert.h> -#include <ardour/stateful.h> #include <ardour/redirect.h> #include <pbd/fastlog.h> @@ -83,7 +82,7 @@ class Mixer_UI; class MixerStrip : public RouteUI, public Gtk::EventBox { public: - MixerStrip (Mixer_UI&, ARDOUR::Session&, ARDOUR::Route &, bool in_mixer = true); + MixerStrip (Mixer_UI&, ARDOUR::Session&, boost::shared_ptr<ARDOUR::Route>, bool in_mixer = true); ~MixerStrip (); void set_width (Width); @@ -170,15 +169,13 @@ class MixerStrip : public RouteUI, public Gtk::EventBox Gtk::Menu output_menu; void add_connection_to_output_menu (ARDOUR::Connection *); - void stream_input_chosen (ARDOUR::AudioDiskstream*); - void select_stream_input (); void connection_input_chosen (ARDOUR::Connection *); void connection_output_chosen (ARDOUR::Connection *); void edit_input_configuration (); void edit_output_configuration (); - void diskstream_changed (void *src); + void diskstream_changed (); Gtk::Menu *send_action_menu; void build_send_action_menu (); @@ -238,7 +235,7 @@ class MixerStrip : public RouteUI, public Gtk::EventBox void name_changed (void *src); void update_speed_display (); void map_frozen (); - void hide_redirect_editor (ARDOUR::Redirect* redirect); + void hide_redirect_editor (boost::shared_ptr<ARDOUR::Redirect> redirect); bool ignore_speed_adjustment; diff --git a/gtk2_ardour/mixer_ui.cc b/gtk2_ardour/mixer_ui.cc index 983903d6dd..c2eb588b2f 100644 --- a/gtk2_ardour/mixer_ui.cc +++ b/gtk2_ardour/mixer_ui.cc @@ -251,7 +251,7 @@ Mixer_UI::show_window () } void -Mixer_UI::add_strip (Route* route) +Mixer_UI::add_strip (boost::shared_ptr<Route> route) { ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::add_strip), route)); @@ -261,7 +261,7 @@ Mixer_UI::add_strip (Route* route) return; } - strip = new MixerStrip (*this, *session, *route); + strip = new MixerStrip (*this, *session, route); strips.push_back (strip); strip->set_width (_strip_width); @@ -310,7 +310,7 @@ void Mixer_UI::follow_strip_selection () { for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) { - (*i)->set_selected (_selection.selected (&(*i)->route())); + (*i)->set_selected (_selection.selected ((*i)->route())); } } @@ -324,13 +324,13 @@ Mixer_UI::strip_button_release_event (GdkEventButton *ev, MixerStrip *strip) at the same time. */ - if (_selection.selected (&strip->route())) { - _selection.remove (&strip->route()); + if (_selection.selected (strip->route())) { + _selection.remove (strip->route()); } else { if (Keyboard::modifier_state_equals (ev->state, Keyboard::Shift)) { - _selection.add (&strip->route()); + _selection.add (strip->route()); } else { - _selection.set (&strip->route()); + _selection.set (strip->route()); } } } @@ -444,7 +444,7 @@ Mixer_UI::set_all_strips_visibility (bool yn) continue; } - if (strip->route().master() || strip->route().control()) { + if (strip->route()->master() || strip->route()->control()) { continue; } @@ -472,11 +472,11 @@ Mixer_UI::set_all_audio_visibility (int tracks, bool yn) continue; } - if (strip->route().master() || strip->route().control()) { + if (strip->route()->master() || strip->route()->control()) { continue; } - AudioTrack* at = dynamic_cast<AudioTrack*> (&strip->route()); + AudioTrack* at = strip->audio_track(); switch (tracks) { case 0: @@ -570,11 +570,11 @@ Mixer_UI::redisplay_track_list () if (visible) { strip->set_marked_for_display (true); - strip->route().set_order_key (N_("signal"), order); + strip->route()->set_order_key (N_("signal"), order); if (strip->packed()) { - if (strip->route().master() || strip->route().control()) { + if (strip->route()->master() || strip->route()->control()) { out_packer.reorder_child (*strip, -1); } else { strip_packer.reorder_child (*strip, -1); /* put at end */ @@ -582,7 +582,7 @@ Mixer_UI::redisplay_track_list () } else { - if (strip->route().master() || strip->route().control()) { + if (strip->route()->master() || strip->route()->control()) { out_packer.pack_start (*strip, false, false); } else { strip_packer.pack_start (*strip, false, false); @@ -593,7 +593,7 @@ Mixer_UI::redisplay_track_list () } else { - if (strip->route().master() || strip->route().control()) { + if (strip->route()->master() || strip->route()->control()) { /* do nothing, these cannot be hidden */ } else { strip_packer.remove (*strip); @@ -604,7 +604,7 @@ Mixer_UI::redisplay_track_list () } struct SignalOrderRouteSorter { - bool operator() (Route* a, Route* b) { + bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) { /* use of ">" forces the correct sort order */ return a->order_key ("signal") < b->order_key ("signal"); } @@ -613,16 +613,17 @@ struct SignalOrderRouteSorter { void Mixer_UI::initial_track_display () { - Session::RouteList routes = session->get_routes(); + boost::shared_ptr<Session::RouteList> routes = session->get_routes(); + Session::RouteList copy (*routes); SignalOrderRouteSorter sorter; - routes.sort (sorter); + copy.sort (sorter); no_track_list_redisplay = true; track_model->clear (); - for (Session::RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + for (Session::RouteList::iterator i = copy.begin(); i != copy.end(); ++i) { add_strip (*i); } @@ -670,7 +671,7 @@ Mixer_UI::track_display_button_press (GdkEventButton* ev) MixerStrip* strip = (*iter)[track_columns.strip]; if (strip) { - if (!strip->route().master() && !strip->route().control()) { + if (!strip->route()->master() && !strip->route()->control()) { bool visible = (*iter)[track_columns.visible]; (*iter)[track_columns.visible] = !visible; } @@ -715,7 +716,7 @@ Mixer_UI::strip_name_changed (void* src, MixerStrip* mx) for (i = rows.begin(); i != rows.end(); ++i) { if ((*i)[track_columns.strip] == mx) { - (*i)[track_columns.text] = mx->route().name(); + (*i)[track_columns.text] = mx->route()->name(); return; } } diff --git a/gtk2_ardour/mixer_ui.h b/gtk2_ardour/mixer_ui.h index 5108df6014..6fe4120427 100644 --- a/gtk2_ardour/mixer_ui.h +++ b/gtk2_ardour/mixer_ui.h @@ -33,8 +33,9 @@ #include <gtkmm/menu.h> #include <gtkmm/treeview.h> +#include <pbd/stateful.h> + #include <ardour/ardour.h> -#include <ardour/stateful.h> #include <ardour/io.h> #include "keyboard_target.h" @@ -110,7 +111,7 @@ class Mixer_UI : public Gtk::Window bool strip_scroller_button_release (GdkEventButton*); - void add_strip (ARDOUR::Route*); + void add_strip (boost::shared_ptr<ARDOUR::Route>); void remove_strip (MixerStrip *); void hide_all_strips (bool with_select); @@ -193,7 +194,7 @@ class Mixer_UI : public Gtk::Window } Gtk::TreeModelColumn<bool> visible; Gtk::TreeModelColumn<Glib::ustring> text; - Gtk::TreeModelColumn<ARDOUR::Route*> route; + Gtk::TreeModelColumn<boost::shared_ptr<ARDOUR::Route> > route; Gtk::TreeModelColumn<MixerStrip*> strip; }; diff --git a/gtk2_ardour/option_editor.cc b/gtk2_ardour/option_editor.cc index d4c2715742..b7fc7e746e 100644 --- a/gtk2_ardour/option_editor.cc +++ b/gtk2_ardour/option_editor.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2001 Paul Davis + Copyright (C) 2001-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,6 +20,7 @@ #include <pbd/whitespace.h> +#include <ardour/audio_library.h> #include <ardour/session.h> #include <ardour/audioengine.h> #include <ardour/configuration.h> @@ -59,9 +60,7 @@ OptionEditor::OptionEditor (ARDOUR_UI& uip, PublicEditor& ed, Mixer_UI& mixui) /* Paths */ path_table (11, 2), - sfdb_path_columns(), - sfdb_paths(ListStore::create(sfdb_path_columns)), - sfdb_path_view(sfdb_paths), + sfdb_path_view(), /* Fades */ @@ -163,7 +162,6 @@ OptionEditor::set_session (Session *s) return; } - click_path_entry.set_sensitive (true); click_emphasis_path_entry.set_sensitive (true); session_raid_entry.set_sensitive (true); @@ -251,13 +249,19 @@ OptionEditor::setup_path_options() path_table.attach(*label, 0, 1, 2, 3, FILL|EXPAND, FILL); path_table.attach(sfdb_path_view, 1, 3, 2, 3, Gtk::FILL|Gtk::EXPAND, FILL); - sfdb_path_view.append_column(_("Paths"), sfdb_path_columns.paths); - sfdb_path_view.set_size_request(-1, 100); + sfdb_path_view.set_paths(Library->get_paths()); + sfdb_path_view.PathsUpdated.connect (mem_fun(*this, &OptionEditor::sfdb_paths_changed)); path_table.show_all(); } void +OptionEditor::sfdb_paths_changed () +{ + Library->set_paths (sfdb_path_view.get_paths()); +} + +void OptionEditor::add_session_paths () { click_path_entry.set_sensitive (true); diff --git a/gtk2_ardour/option_editor.h b/gtk2_ardour/option_editor.h index b9690b02e2..1331d3126e 100644 --- a/gtk2_ardour/option_editor.h +++ b/gtk2_ardour/option_editor.h @@ -33,6 +33,8 @@ #include <gtkmm/radiobutton.h> #include <gtkmm/comboboxtext.h> +#include <gtkmm2ext/pathlist.h> + #include <ardour/session.h> #include "ardour_dialog.h" @@ -70,24 +72,16 @@ class OptionEditor : public Gtk::Dialog /* paths */ - Gtk::Table path_table; - Gtk::Entry session_raid_entry; - - struct SoundFilePathColumns : public Gtk::TreeModel::ColumnRecord { - public: - SoundFilePathColumns() { add (paths); } - Gtk::TreeModelColumn<std::string> paths; - - }; + Gtk::Table path_table; + Gtk::Entry session_raid_entry; - SoundFilePathColumns sfdb_path_columns; - Glib::RefPtr<Gtk::ListStore> sfdb_paths; - Gtk::TreeView sfdb_path_view; + Gtkmm2ext::PathList sfdb_path_view; void setup_path_options(); void add_session_paths (); void remove_session_paths (); void raid_path_changed (); + void sfdb_paths_changed (); /* fades */ diff --git a/gtk2_ardour/pan_automation_time_axis.cc b/gtk2_ardour/pan_automation_time_axis.cc index 73d0f7f1aa..3169f65059 100644 --- a/gtk2_ardour/pan_automation_time_axis.cc +++ b/gtk2_ardour/pan_automation_time_axis.cc @@ -28,6 +28,7 @@ #include "pan_automation_time_axis.h" #include "automation_line.h" #include "canvas_impl.h" +#include "route_ui.h" #include "i18n.h" @@ -35,11 +36,15 @@ using namespace ARDOUR; using namespace PBD; using namespace Gtk; -PanAutomationTimeAxisView::PanAutomationTimeAxisView (Session& s, Route& r, PublicEditor& e, TimeAxisView& parent, Canvas& canvas, std::string n) +PanAutomationTimeAxisView::PanAutomationTimeAxisView (Session& s, boost::shared_ptr<Route> r, PublicEditor& e, + TimeAxisView& parent, Canvas& canvas, std::string n) : AxisView (s), AutomationTimeAxisView (s, r, e, parent, canvas, n, X_("pan"), "") { + multiline_selector.set_name ("PanAutomationLineSelector"); + + controls_table.attach (multiline_selector, 1, 5, 1, 2, Gtk::EXPAND, Gtk::EXPAND); } PanAutomationTimeAxisView::~PanAutomationTimeAxisView () @@ -54,14 +59,19 @@ PanAutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkEv return; } + int line_index = 0; + if (lines.size() > 1) { + line_index = multiline_selector.get_active_row_number(); - Gtkmm2ext::PopUp* msg = new Gtkmm2ext::PopUp (Gtk::WIN_POS_MOUSE, 5000, true); - - msg->set_text (_("You can't graphically edit panning of more than stream")); - msg->touch (); + if (line_index < 0 || line_index >= (int)lines.size()) { + Gtkmm2ext::PopUp* msg = new Gtkmm2ext::PopUp (Gtk::WIN_POS_MOUSE, 5000, true); - return; + msg->set_text (_("You need to select which line to edit")); + msg->touch (); + + return; + } } double x = 0; @@ -76,7 +86,7 @@ PanAutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkEv lines.front()->view_to_model_y (y); - AutomationList& alist (lines.front()->the_list()); + AutomationList& alist (lines[line_index]->the_list()); _session.begin_reversible_command (_("add pan automation event")); XMLNode &before = alist.get_state(); @@ -88,9 +98,56 @@ PanAutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkEv } void +PanAutomationTimeAxisView::clear_lines () +{ + AutomationTimeAxisView::clear_lines(); + multiline_selector.clear(); +} + +void +PanAutomationTimeAxisView::add_line (AutomationLine& line) +{ + char buf[32]; + snprintf(buf,32,"Line %u",lines.size()+1); + multiline_selector.append_text(buf); + + if (lines.empty()) { + multiline_selector.set_active(0); + } + + if (lines.size() + 1 > 1 && (height_style != Small && height_style != Smaller)) { + multiline_selector.show(); + } else { + multiline_selector.hide(); + + } + + AutomationTimeAxisView::add_line(line); +} + +void +PanAutomationTimeAxisView::set_height (TimeAxisView::TrackHeight th) +{ + AutomationTimeAxisView::set_height(th); + + switch (th) { + case Largest: + case Large: + case Larger: + case Normal: + if (lines.size() > 1) { + multiline_selector.show(); + break; + } + default: + multiline_selector.hide(); + } +} + +void PanAutomationTimeAxisView::set_automation_state (AutoState state) { if (!ignore_state_request) { - route.panner().set_automation_state (state); + route->panner().set_automation_state (state); } } diff --git a/gtk2_ardour/pan_automation_time_axis.h b/gtk2_ardour/pan_automation_time_axis.h index b35ee67735..ca4a4db8e7 100644 --- a/gtk2_ardour/pan_automation_time_axis.h +++ b/gtk2_ardour/pan_automation_time_axis.h @@ -4,27 +4,36 @@ #include "canvas.h" #include "automation_time_axis.h" +#include <gtkmm/comboboxtext.h> + namespace ARDOUR { class Redirect; } class PanAutomationTimeAxisView : public AutomationTimeAxisView { - public: - PanAutomationTimeAxisView (ARDOUR::Session&, - ARDOUR::Route&, - PublicEditor&, - TimeAxisView& parent_axis, - ArdourCanvas::Canvas& canvas, - std::string name); - - ~PanAutomationTimeAxisView(); - - void add_automation_event (ArdourCanvas::Item *item, GdkEvent *event, jack_nframes_t, double); - - private: - void automation_changed (); - void set_automation_state (ARDOUR::AutoState); + public: + PanAutomationTimeAxisView (ARDOUR::Session&, + boost::shared_ptr<ARDOUR::Route>, + PublicEditor&, + TimeAxisView& parent_axis, + ArdourCanvas::Canvas& canvas, + std::string name); + + ~PanAutomationTimeAxisView(); + + void add_automation_event (ArdourCanvas::Item *item, GdkEvent *event, jack_nframes_t, double); + + void clear_lines (); + void add_line (AutomationLine&); + void set_height (TimeAxisView::TrackHeight); + + protected: + Gtk::ComboBoxText multiline_selector; + + private: + void automation_changed (); + void set_automation_state (ARDOUR::AutoState); }; #endif /* __ardour_gtk_pan_automation_time_axis_h__ */ diff --git a/gtk2_ardour/panner_ui.cc b/gtk2_ardour/panner_ui.cc index 63a19867a8..ccce2ec9f1 100644 --- a/gtk2_ardour/panner_ui.cc +++ b/gtk2_ardour/panner_ui.cc @@ -14,8 +14,6 @@ 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 <limits.h> @@ -47,7 +45,7 @@ using namespace Gtk; using namespace sigc; -PannerUI::PannerUI (IO& io, Session& s) +PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s) : _io (io), _session (s), hAdjustment(0.0, 0.0, 0.0), @@ -87,13 +85,13 @@ PannerUI::PannerUI (IO& io, Session& s) using namespace Menu_Helpers; pan_astate_menu.items().push_back (MenuElem (_("Off"), - bind (mem_fun (_io.panner(), &Panner::set_automation_state), (AutoState) Off))); + bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Off))); pan_astate_menu.items().push_back (MenuElem (_("Play"), - bind (mem_fun (_io.panner(), &Panner::set_automation_state), (AutoState) Play))); + bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Play))); pan_astate_menu.items().push_back (MenuElem (_("Write"), - bind (mem_fun (_io.panner(), &Panner::set_automation_state), (AutoState) Write))); + bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Write))); pan_astate_menu.items().push_back (MenuElem (_("Touch"), - bind (mem_fun (_io.panner(), &Panner::set_automation_state), (AutoState) Touch))); + bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Touch))); pan_astyle_menu.items().push_back (MenuElem (_("Trim"))); pan_astyle_menu.items().push_back (MenuElem (_("Abs"))); @@ -143,9 +141,9 @@ PannerUI::PannerUI (IO& io, Session& s) set_width(Narrow); - _io.panner().Changed.connect (mem_fun(*this, &PannerUI::panner_changed)); - _io.panner().LinkStateChanged.connect (mem_fun(*this, &PannerUI::update_pan_linkage)); - _io.panner().StateChanged.connect (mem_fun(*this, &PannerUI::update_pan_state)); + _io->panner().Changed.connect (mem_fun(*this, &PannerUI::panner_changed)); + _io->panner().LinkStateChanged.connect (mem_fun(*this, &PannerUI::update_pan_linkage)); + _io->panner().StateChanged.connect (mem_fun(*this, &PannerUI::update_pan_state)); pan_changed (0); update_pan_sensitive (); @@ -165,7 +163,7 @@ PannerUI::panning_link_button_release (GdkEventButton* ev) { cerr << "link release\n"; if (!ignore_toggle) { - _io.panner().set_linked (!_io.panner().linked()); + _io->panner().set_linked (!_io->panner().linked()); } return true; } @@ -173,12 +171,12 @@ PannerUI::panning_link_button_release (GdkEventButton* ev) void PannerUI::panning_link_direction_clicked() { - switch (_io.panner().link_direction()) { + switch (_io->panner().link_direction()) { case Panner::SameDirection: - _io.panner().set_link_direction (Panner::OppositeDirection); + _io->panner().set_link_direction (Panner::OppositeDirection); break; default: - _io.panner().set_link_direction (Panner::SameDirection); + _io->panner().set_link_direction (Panner::SameDirection); break; } } @@ -188,7 +186,7 @@ PannerUI::update_pan_linkage () { ENSURE_GUI_THREAD(mem_fun(*this, &PannerUI::update_pan_linkage)); - bool x = _io.panner().linked(); + bool x = _io->panner().linked(); bool bx = panning_link_button.get_active(); if (x != bx) { @@ -200,7 +198,7 @@ PannerUI::update_pan_linkage () panning_link_direction_button.set_sensitive (x); - switch (_io.panner().link_direction()) { + switch (_io->panner().link_direction()) { case Panner::SameDirection: panning_link_direction_button.set_image (*(manage (new Image (get_xpm ("forwardblarrow.xpm"))))); break; @@ -278,7 +276,7 @@ PannerUI::update_pan_state () void PannerUI::setup_pan () { - uint32_t nouts = _io.n_outputs (); + uint32_t nouts = _io->n_outputs (); if (nouts == 0 || nouts == 1) { @@ -292,7 +290,7 @@ PannerUI::setup_pan () } else if (nouts == 2) { vector<Adjustment*>::size_type asz; - uint32_t npans = _io.panner().size(); + uint32_t npans = _io->panner().size(); while (!pan_adjustments.empty()) { delete pan_bars.back(); @@ -308,34 +306,26 @@ PannerUI::setup_pan () /* initialize adjustment with current value of panner */ - _io.panner()[asz]->get_position (x); + _io->panner()[asz]->get_position (x); pan_adjustments.push_back (new Adjustment (x, 0, 1.0, 0.05, 0.1)); pan_adjustments.back()->signal_value_changed().connect (bind (mem_fun(*this, &PannerUI::pan_adjustment_changed), (uint32_t) asz)); - _io.panner()[asz]->Changed.connect (bind (mem_fun(*this, &PannerUI::pan_value_changed), (uint32_t) asz)); + _io->panner()[asz]->Changed.connect (bind (mem_fun(*this, &PannerUI::pan_value_changed), (uint32_t) asz)); bc = new BarController (*pan_adjustments[asz], - &_io.panner()[asz]->midi_control(), + _io->panner()[asz]->control(), bind (mem_fun(*this, &PannerUI::pan_printer), pan_adjustments[asz])); - if (_session.midi_port()) { - _io.panner()[asz]->reset_midi_control (_session.midi_port(), true); - } - bc->set_name ("PanSlider"); bc->set_shadow_type (Gtk::SHADOW_NONE); bc->set_style (BarController::Line); - bc->StartGesture.connect (bind (mem_fun (_io, &IO::start_pan_touch), (uint32_t) asz)); - bc->StopGesture.connect (bind (mem_fun (_io, &IO::end_pan_touch), (uint32_t) asz)); + bc->StartGesture.connect (bind (mem_fun (*_io, &IO::start_pan_touch), (uint32_t) asz)); + bc->StopGesture.connect (bind (mem_fun (*_io, &IO::end_pan_touch), (uint32_t) asz)); char buf[64]; -#ifdef __APPLE__ - snprintf (buf, sizeof (buf), _("panner for channel %lu"), asz + 1); -#else - snprintf (buf, sizeof (buf), _("panner for channel %u"), asz + 1); -#endif + snprintf (buf, sizeof (buf), _("panner for channel %zu"), asz + 1); ARDOUR_UI::instance()->tooltips().set_tip (bc->event_widget(), buf); bc->event_widget().signal_button_release_event().connect @@ -379,13 +369,13 @@ PannerUI::setup_pan () } if (panner == 0) { - panner = new Panner2d (_io.panner(), w, 61); + panner = new Panner2d (_io->panner(), w, 61); panner->set_name ("MixerPanZone"); panner->show (); } update_pan_sensitive (); - panner->reset (_io.n_inputs()); + panner->reset (_io->n_inputs()); panner->set_size_request (w, 61); /* and finally, add it to the panner frame */ @@ -428,7 +418,7 @@ PannerUI::build_pan_menu (uint32_t which) /* set state first, connect second */ - (dynamic_cast<CheckMenuItem*> (&items.back()))->set_active (_io.panner()[which]->muted()); + (dynamic_cast<CheckMenuItem*> (&items.back()))->set_active (_io->panner()[which]->muted()); (dynamic_cast<CheckMenuItem*> (&items.back()))->signal_toggled().connect (bind (mem_fun(*this, &PannerUI::pan_mute), which)); @@ -437,7 +427,7 @@ PannerUI::build_pan_menu (uint32_t which) /* set state first, connect second */ - bypass_menu_item->set_active (_io.panner().bypassed()); + bypass_menu_item->set_active (_io->panner().bypassed()); bypass_menu_item->signal_toggled().connect (mem_fun(*this, &PannerUI::pan_bypass_toggle)); items.push_back (MenuElem (_("Reset"), mem_fun(*this, &PannerUI::pan_reset))); @@ -448,15 +438,15 @@ PannerUI::build_pan_menu (uint32_t which) void PannerUI::pan_mute (uint32_t which) { - StreamPanner* sp = _io.panner()[which]; + StreamPanner* sp = _io->panner()[which]; sp->set_muted (!sp->muted()); } void PannerUI::pan_bypass_toggle () { - if (bypass_menu_item && (_io.panner().bypassed() != bypass_menu_item->get_active())) { - _io.panner().set_bypassed (!_io.panner().bypassed()); + if (bypass_menu_item && (_io->panner().bypassed() != bypass_menu_item->get_active())) { + _io->panner().set_bypassed (!_io->panner().bypassed()); } } @@ -468,11 +458,11 @@ PannerUI::pan_reset () void PannerUI::effective_pan_display () { - if (_io.panner().empty()) { + if (_io->panner().empty()) { return; } - switch (_io.n_outputs()) { + switch (_io->n_outputs()) { case 0: case 1: /* relax */ @@ -495,7 +485,7 @@ PannerUI::pan_changed (void *src) return; } - switch (_io.panner().size()) { + switch (_io->panner().size()) { case 0: panning_link_direction_button.set_sensitive (false); panning_link_button.set_sensitive (false); @@ -509,7 +499,7 @@ PannerUI::pan_changed (void *src) panning_link_button.set_sensitive (true); } - uint32_t nouts = _io.n_outputs(); + uint32_t nouts = _io->n_outputs(); switch (nouts) { case 0: @@ -530,11 +520,11 @@ PannerUI::pan_changed (void *src) void PannerUI::pan_adjustment_changed (uint32_t which) { - if (!in_pan_update && which < _io.panner().size()) { + if (!in_pan_update && which < _io->panner().size()) { float xpos; float val = pan_adjustments[which]->get_value (); - _io.panner()[which]->get_position (xpos); + _io->panner()[which]->get_position (xpos); /* add a kinda-sorta detent for the middle */ @@ -551,7 +541,7 @@ PannerUI::pan_adjustment_changed (uint32_t which) if (!Panner::equivalent (val, xpos)) { - _io.panner()[which]->set_position (val); + _io->panner()[which]->set_position (val); /* XXX the panner objects have no access to the session, so do this here. ick. @@ -566,11 +556,11 @@ PannerUI::pan_value_changed (uint32_t which) { ENSURE_GUI_THREAD (bind (mem_fun(*this, &PannerUI::pan_value_changed), which)); - if (_io.n_outputs() > 1 && which < _io.panner().size()) { + if (_io->n_outputs() > 1 && which < _io->panner().size()) { float xpos; float val = pan_adjustments[which]->get_value (); - _io.panner()[which]->get_position (xpos); + _io->panner()[which]->get_position (xpos); if (!Panner::equivalent (val, xpos)) { in_pan_update = true; @@ -596,14 +586,14 @@ PannerUI::update_pan_bars (bool only_if_aplay) float xpos, val; if (only_if_aplay) { - AutomationList& alist (_io.panner()[n]->automation()); + AutomationList& alist (_io->panner()[n]->automation()); if (!alist.automation_playback()) { continue; } } - _io.panner()[n]->get_effective_position (xpos); + _io->panner()[n]->get_effective_position (xpos); val = (*i)->get_value (); if (!Panner::equivalent (val, xpos)) { @@ -634,9 +624,9 @@ PannerUI::pan_printer (char *buf, uint32_t len, Adjustment* adj) void PannerUI::update_pan_sensitive () { - bool sensitive = !(_io.panner().automation_state() & Play); + bool sensitive = !(_io->panner().automation_state() & Play); - switch (_io.n_outputs()) { + switch (_io->n_outputs()) { case 0: case 1: break; @@ -697,10 +687,10 @@ PannerUI::pan_automation_style_changed () switch (_width) { case Wide: - pan_automation_style_button.set_label (astyle_string(_io.panner().automation_style())); + pan_automation_style_button.set_label (astyle_string(_io->panner().automation_style())); break; case Narrow: - pan_automation_style_button.set_label (short_astyle_string(_io.panner().automation_style())); + pan_automation_style_button.set_label (short_astyle_string(_io->panner().automation_style())); break; } } @@ -714,10 +704,10 @@ PannerUI::pan_automation_state_changed () switch (_width) { case Wide: - pan_automation_state_button.set_label (astate_string(_io.panner().automation_state())); + pan_automation_state_button.set_label (astate_string(_io->panner().automation_state())); break; case Narrow: - pan_automation_state_button.set_label (short_astate_string(_io.panner().automation_state())); + pan_automation_state_button.set_label (short_astate_string(_io->panner().automation_state())); break; } @@ -726,11 +716,11 @@ PannerUI::pan_automation_state_changed () here. */ - if (_io.panner().empty()) { + if (_io->panner().empty()) { return; } - x = (_io.panner().front()->automation().automation_state() != Off); + x = (_io->panner().front()->automation().automation_state() != Off); if (pan_automation_state_button.get_active() != x) { ignore_toggle = true; diff --git a/gtk2_ardour/panner_ui.h b/gtk2_ardour/panner_ui.h index 80b14465cf..7658978233 100644 --- a/gtk2_ardour/panner_ui.h +++ b/gtk2_ardour/panner_ui.h @@ -31,8 +31,8 @@ #include <gtkmm/togglebutton.h> #include <gtkmm/button.h> -#include <gtkmm2ext/slider_controller.h> #include <gtkmm2ext/click_box.h> +#include <gtkmm2ext/slider_controller.h> #include "enums.h" @@ -55,7 +55,7 @@ namespace Gtk { class PannerUI : public Gtk::HBox { public: - PannerUI (ARDOUR::IO&, ARDOUR::Session&); + PannerUI (boost::shared_ptr<ARDOUR::IO>, ARDOUR::Session&); ~PannerUI (); void pan_changed (void *); @@ -72,7 +72,7 @@ class PannerUI : public Gtk::HBox private: friend class MixerStrip; - ARDOUR::IO& _io; + boost::shared_ptr<ARDOUR::IO> _io; ARDOUR::Session& _session; bool ignore_toggle; diff --git a/gtk2_ardour/pixmaps/tool_audition.xpm b/gtk2_ardour/pixmaps/tool_audition.xpm new file mode 100644 index 0000000000..d6f2ccd127 --- /dev/null +++ b/gtk2_ardour/pixmaps/tool_audition.xpm @@ -0,0 +1,19 @@ +/* XPM */ +static char * tool_audition_xpm[] = { +"16 12 4 1", +" c None", +". c #000000", +"+ c #ECECEC", +"@ c #FFFFFF", +" .. ", +" .+. . ", +" .++. .@. ", +"....+@+... .@. ", +".+++@@+..@. .@.", +".+@@@@+. .@. .@.", +".+@@@@+. .@. .@.", +".+++@@+..@. .@.", +"....+@+... .@. ", +" .++. .@. ", +" .+. . ", +" .. "}; diff --git a/gtk2_ardour/pixmaps/tool_gain.xpm b/gtk2_ardour/pixmaps/tool_gain.xpm new file mode 100644 index 0000000000..480426fab8 --- /dev/null +++ b/gtk2_ardour/pixmaps/tool_gain.xpm @@ -0,0 +1,18 @@ +/* XPM */ +static char * tool_gain_xpm[] = { +"16 12 3 1", +" c None", +". c #000000", +"+ c #FFFFFF", +"... ", +".++.. ", +"...++. ", +" ..+. ", +" .+. ", +" .+. ", +" .+. ", +" .+. ", +" .+.. ", +" .++.....", +" ..++++.", +" ....."}; diff --git a/gtk2_ardour/pixmaps/tool_object.xpm b/gtk2_ardour/pixmaps/tool_object.xpm new file mode 100644 index 0000000000..3d18ab8af7 --- /dev/null +++ b/gtk2_ardour/pixmaps/tool_object.xpm @@ -0,0 +1,18 @@ +/* XPM */ +static char * tool_object_xpm[] = { +"16 12 3 1", +" c None", +". c #000000", +"+ c #FFFFFF", +" ... ", +" .+. ", +" .+. ", +" .+. ", +" .+..... ", +" .+.+.+... ", +" ...+.+.+.+. ", +" .+.+++++++. ", +" .+++++++++. ", +" ..+++++++.. ", +" ...+++++. ", +" .+++++. "}; diff --git a/gtk2_ardour/pixmaps/tool_range.xpm b/gtk2_ardour/pixmaps/tool_range.xpm new file mode 100644 index 0000000000..75ee865ca2 --- /dev/null +++ b/gtk2_ardour/pixmaps/tool_range.xpm @@ -0,0 +1,18 @@ +/* XPM */ +static char * tool_range_xpm[] = { +"16 12 3 1", +" c None", +". c #000000", +"+ c #FFFFFF", +"... ...", +".+. .. .. .+.", +".+. .+. .+. .+.", +".+..+. .+..+.", +".+.++......++.+.", +".++++++++++++++.", +".+.++......++.+.", +".+..+. .+..+.", +".+. .+. .+. .+.", +".+. .. .. .+.", +".+. .+.", +"... ..."}; diff --git a/gtk2_ardour/pixmaps/tool_stretch.xpm b/gtk2_ardour/pixmaps/tool_stretch.xpm new file mode 100644 index 0000000000..77943cd7d4 --- /dev/null +++ b/gtk2_ardour/pixmaps/tool_stretch.xpm @@ -0,0 +1,18 @@ +/* XPM */ +static char * tool_stretch_xpm[] = { +"16 12 3 1", +" c None", +". c #000000", +"+ c #FFFFFF", +" .. .. ", +" .+. .+. ", +".++..........++.", +"++++++++++++++++", +".++..........++.", +" .+. .+. ", +" .. .. ", +" + + + + ", +" ++ +++ + + +++ ", +"++++++++++++++++", +" ++ + ++ + + ", +" + + + + "}; diff --git a/gtk2_ardour/pixmaps/tool_zoom.xpm b/gtk2_ardour/pixmaps/tool_zoom.xpm new file mode 100644 index 0000000000..581363f3f4 --- /dev/null +++ b/gtk2_ardour/pixmaps/tool_zoom.xpm @@ -0,0 +1,29 @@ +/* XPM */ +static char * tool_zoom_xpm[] = { +"16 12 14 1", +" c None", +". c #000000", +"+ c #474747", +"@ c #E7E7E7", +"# c #F6F6F6", +"$ c #DCDCDC", +"% c #FFFFFF", +"& c #DFDFDF", +"* c #D7D7D7", +"= c #D6D6D6", +"- c #040404", +"; c #070707", +"> c #060606", +", c #050505", +" ... ", +" +.@#$.+ ", +" .%%%%%. ", +" .&%%%%%*. ", +" .#%%%%%#. ", +" .$%%%%%&. ", +" .%%%%%.+ ", +" +.*#=... ", +" ...+... ", +" -.; ", +" >.- ", +" ,. "}; diff --git a/gtk2_ardour/pixmaps/zoom_full.xpm b/gtk2_ardour/pixmaps/zoom_full.xpm new file mode 100644 index 0000000000..5564074875 --- /dev/null +++ b/gtk2_ardour/pixmaps/zoom_full.xpm @@ -0,0 +1,30 @@ +/* XPM */ +static char * zoom_full_xpm[] = { +"12 12 15 1", +" c None", +". c #000000", +"+ c #474747", +"@ c #E7E7E7", +"# c #F6F6F6", +"$ c #DCDCDC", +"% c #ACACAC", +"& c #FFFFFF", +"* c #DFDFDF", +"= c #D7D7D7", +"- c #D6D6D6", +"; c #040404", +"> c #070707", +", c #060606", +"' c #050505", +" ... ", +" +.@#$.+ ", +" .%&&&%. ", +".*..&..=. ", +".#.&&&.#. ", +".$..&..*. ", +" .%&&&%.+ ", +" +.=#-... ", +" ...+... ", +" ;.> ", +" ,.;", +" '."}; diff --git a/gtk2_ardour/pixmaps/zoom_in.xpm b/gtk2_ardour/pixmaps/zoom_in.xpm new file mode 100644 index 0000000000..1f8d4e8273 --- /dev/null +++ b/gtk2_ardour/pixmaps/zoom_in.xpm @@ -0,0 +1,29 @@ +/* XPM */ +static char * zoom_in_xpm[] = { +"12 12 14 1", +" c None", +". c #000000", +"+ c #474747", +"@ c #E7E7E7", +"# c #F6F6F6", +"$ c #DCDCDC", +"% c #FFFFFF", +"& c #DFDFDF", +"* c #D7D7D7", +"= c #D6D6D6", +"- c #040404", +"; c #070707", +"> c #060606", +", c #050505", +" ... ", +" +.@#$.+ ", +" .%%.%%. ", +".&%%.%%*. ", +".#.....#. ", +".$%%.%%&. ", +" .%%.%%.+ ", +" +.*#=... ", +" ...+... ", +" -.; ", +" >.-", +" ,."}; diff --git a/gtk2_ardour/pixmaps/zoom_out.xpm b/gtk2_ardour/pixmaps/zoom_out.xpm new file mode 100644 index 0000000000..ea50d145ad --- /dev/null +++ b/gtk2_ardour/pixmaps/zoom_out.xpm @@ -0,0 +1,29 @@ +/* XPM */ +static char * zoom_out_xpm[] = { +"12 12 14 1", +" c None", +". c #000000", +"+ c #474747", +"@ c #E7E7E7", +"# c #F6F6F6", +"$ c #DCDCDC", +"% c #FFFFFF", +"& c #DFDFDF", +"* c #D7D7D7", +"= c #D6D6D6", +"- c #040404", +"; c #070707", +"> c #060606", +", c #050505", +" ... ", +" +.@#$.+ ", +" .%%%%%. ", +".&%%%%%*. ", +".#.....#. ", +".$%%%%%&. ", +" .%%%%%.+ ", +" +.*#=... ", +" ...+... ", +" -.; ", +" >.-", +" ,."}; diff --git a/gtk2_ardour/playlist_selector.cc b/gtk2_ardour/playlist_selector.cc index f1a975d5dc..8eaac7cb9d 100644 --- a/gtk2_ardour/playlist_selector.cc +++ b/gtk2_ardour/playlist_selector.cc @@ -90,13 +90,13 @@ void PlaylistSelector::show_for (RouteUI* ruix) { vector<const char*> item; - AudioDiskstream* this_ds; + Diskstream* this_ds; string str; rui = ruix; str = _("ardour: playlist for "); - str += rui->route().name(); + str += rui->route()->name(); set_title (str); @@ -116,7 +116,7 @@ PlaylistSelector::show_for (RouteUI* ruix) for (DSPL_Map::iterator x = dspl_map.begin(); x != dspl_map.end(); ++x) { - AudioDiskstream* ds = session->diskstream_by_id (x->first); + Diskstream* ds = session->diskstream_by_id (x->first); if (ds == 0) { continue; @@ -189,7 +189,7 @@ PlaylistSelector::add_playlist_to_map (Playlist *pl) if ((x = dspl_map.find (apl->get_orig_diskstream_id())) == dspl_map.end()) { - pair<ARDOUR::id_t,list<Playlist*>*> newp (apl->get_orig_diskstream_id(), new list<Playlist*>); + pair<PBD::ID,list<Playlist*>*> newp (apl->get_orig_diskstream_id(), new list<Playlist*>); x = dspl_map.insert (dspl_map.end(), newp); } @@ -223,7 +223,7 @@ PlaylistSelector::selection_changed () TreeModel::iterator iter = tree.get_selection()->get_selected(); - if (!iter) { + if (!iter || rui == 0) { /* nothing selected */ return; } @@ -233,7 +233,7 @@ PlaylistSelector::selection_changed () AudioTrack* at; AudioPlaylist* apl; - if ((at = dynamic_cast<AudioTrack*> (&rui->route())) == 0) { + if ((at = rui->audio_track()) == 0) { /* eh? */ return; } @@ -243,7 +243,7 @@ PlaylistSelector::selection_changed () return; } - at->disk_stream().use_playlist (apl); + at->diskstream().use_playlist (apl); hide (); } diff --git a/gtk2_ardour/playlist_selector.h b/gtk2_ardour/playlist_selector.h index 863d6cc7f3..2829ba54bb 100644 --- a/gtk2_ardour/playlist_selector.h +++ b/gtk2_ardour/playlist_selector.h @@ -46,7 +46,7 @@ class PlaylistSelector : public ArdourDialog void show_for (RouteUI*); private: - typedef std::map<ARDOUR::id_t,std::list<ARDOUR::Playlist*>*> DSPL_Map; + typedef std::map<PBD::ID,std::list<ARDOUR::Playlist*>*> DSPL_Map; ARDOUR::Session* session; Gtk::ScrolledWindow scroller; diff --git a/gtk2_ardour/plugin_selector.cc b/gtk2_ardour/plugin_selector.cc index 16796df160..e0a62b177f 100644 --- a/gtk2_ardour/plugin_selector.cc +++ b/gtk2_ardour/plugin_selector.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -48,8 +48,8 @@ PluginSelector::PluginSelector (PluginManager *mgr) manager = mgr; session = 0; - o_selected_plug = -1; - i_selected_plug = 0; + + current_selection = PluginInfo::LADSPA; lmodel = Gtk::ListStore::create(lcols); ladspa_display.set_model (lmodel); @@ -91,6 +91,25 @@ PluginSelector::PluginSelector (PluginManager *mgr) column->set_sort_column(i); } #endif + +#ifdef HAVE_COREAUDIO + aumodel = ListStore::create(aucols); + au_display.set_model (aumodel); + au_display.append_column (_("Available plugins"), aucols.name); + au_display.append_column (_("# Inputs"), aucols.ins); + au_display.append_column (_("# Outputs"), aucols.outs); + au_display.set_headers_visible (true); + au_display.set_reorderable (false); + auscroller.set_border_width(10); + auscroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + auscroller.add(au_display); + + for (int i = 0; i <=2; i++) { + Gtk::TreeView::Column* column = au_display.get_column(i); + column->set_sort_column(i); + } +#endif + ascroller.set_border_width(10); ascroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); ascroller.add(added_list); @@ -124,35 +143,51 @@ PluginSelector::PluginSelector (PluginManager *mgr) using namespace Gtk::Notebook_Helpers; notebook.pages().push_back (TabElem (lscroller, _("LADSPA"))); + #ifdef VST_SUPPORT if (Config->get_use_vst()) { notebook.pages().push_back (TabElem (vscroller, _("VST"))); } #endif +#ifdef HAVE_COREAUDIO + notebook.pages().push_back (TabElem (auscroller, _("AudioUnit"))); +#endif + table->set_name("PluginSelectorTable"); ladspa_display.set_name("PluginSelectorDisplay"); //ladspa_display.set_name("PluginSelectorList"); added_list.set_name("PluginSelectorList"); ladspa_display.signal_button_press_event().connect_notify (mem_fun(*this, &PluginSelector::row_clicked)); + ladspa_display.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::ladspa_display_selection_changed)); + #ifdef VST_SUPPORT if (Config->get_use_vst()) { vst_display.signal_button_press_event().connect_notify (mem_fun(*this, &PluginSelector::row_clicked)); vst_display.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::vst_display_selection_changed)); } #endif - + +#ifdef HAVE_COREAUDIO + au_display.signal_button_press_event().connect_notify (mem_fun(*this, &PluginSelector::row_clicked)); + au_display.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::au_display_selection_changed)); +#endif + btn_update->signal_clicked().connect (mem_fun(*this, &PluginSelector::btn_update_clicked)); btn_add->signal_clicked().connect(mem_fun(*this, &PluginSelector::btn_add_clicked)); btn_remove->signal_clicked().connect(mem_fun(*this, &PluginSelector::btn_remove_clicked)); - ladspa_display.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::ladspa_display_selection_changed)); added_list.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::added_list_selection_changed)); input_refiller (); + #ifdef VST_SUPPORT vst_refiller (); #endif + +#ifdef HAVE_COREAUDIO + au_refiller (); +#endif } void @@ -189,13 +224,11 @@ void PluginSelector::input_refiller () { guint row; - list<PluginInfo *> &plugs = manager->ladspa_plugin_info (); - list<PluginInfo *>::iterator i; + PluginInfoList &plugs = manager->ladspa_plugin_info (); + PluginInfoList::iterator i; char ibuf[16], obuf[16]; lmodel->clear(); -#ifdef VST_SUPPORT - vmodel->clear(); -#endif + // Insert into GTK list for (row = 0, i=plugs.begin(); i != plugs.end(); ++i, ++row) { snprintf (ibuf, sizeof(ibuf)-1, "%d", (*i)->n_inputs); @@ -224,9 +257,10 @@ void PluginSelector::vst_refiller () { guint row; - list<PluginInfo *> &plugs = manager->vst_plugin_info (); - list<PluginInfo *>::iterator i; + PluginInfoList &plugs = manager->vst_plugin_info (); + PluginInfoList::iterator i; char ibuf[16], obuf[16]; + vmodel->clear(); // Insert into GTK list for (row = 0, i=plugs.begin(); i != plugs.end(); ++i, ++row) { @@ -242,18 +276,75 @@ PluginSelector::vst_refiller () } vmodel->set_sort_column (0, Gtk::SORT_ASCENDING); } -#endif void -PluginSelector::use_plugin (PluginInfo* pi) +PluginSelector::vst_display_selection_changed() { - list<PluginInfo *>::iterator i; + if (vst_display.get_selection()->count_selected_rows() != 0) { + btn_add->set_sensitive (true); + } else { + btn_add->set_sensitive (false); + } + + current_selection = PluginInfo::VST; +} + +#endif //VST_SUPPORT - if (pi == 0 || session == 0) { +#ifdef HAVE_COREAUDIO + +void +PluginSelector::_au_refiller (void *arg) +{ + ((PluginSelector *) arg)->au_refiller (); +} + +void +PluginSelector::au_refiller () +{ + guint row; + PluginInfoList plugs (AUPluginInfo::discover ()); + PluginInfoList::iterator i; + char ibuf[16], obuf[16]; + aumodel->clear(); + + // Insert into GTK list + for (row = 0, i=plugs.begin(); i != plugs.end(); ++i, ++row) { + + snprintf (ibuf, sizeof(ibuf)-1, "%d", (*i)->n_inputs); + snprintf (obuf, sizeof(obuf)-1, "%d", (*i)->n_outputs); + + Gtk::TreeModel::Row newrow = *(aumodel->append()); + newrow[aucols.name] = (*i)->name.c_str(); + newrow[aucols.ins] = ibuf; + newrow[aucols.outs] = obuf; + newrow[aucols.plugin] = *i; + } + aumodel->set_sort_column (0, Gtk::SORT_ASCENDING); +} + +void +PluginSelector::au_display_selection_changed() +{ + if (au_display.get_selection()->count_selected_rows() != 0) { + btn_add->set_sensitive (true); + } else { + btn_add->set_sensitive (false); + } + + current_selection = PluginInfo::AudioUnit; +} + +#endif //HAVE_COREAUDIO + +void +PluginSelector::use_plugin (PluginInfoPtr pi) +{ + if (session == 0) { return; } - Plugin *plugin = manager->load (*session, pi); + PluginPtr plugin = pi->load (*session); if (plugin) { PluginCreated (plugin); @@ -263,46 +354,54 @@ PluginSelector::use_plugin (PluginInfo* pi) void PluginSelector::btn_add_clicked() { - bool vst = notebook.get_current_page(); // 0 = LADSPA, 1 = VST std::string name; - ARDOUR::PluginInfo *pi; + PluginInfoPtr pi; Gtk::TreeModel::Row newrow = *(amodel->append()); - if (vst) { + Gtk::TreeModel::Row row; + + switch (current_selection) { + case PluginInfo::LADSPA: + row = *(ladspa_display.get_selection()->get_selected()); + name = row[lcols.name]; + pi = row[lcols.plugin]; + break; + case PluginInfo::VST: #ifdef VST_SUPPORT - Gtk::TreeModel::Row row = *(vst_display.get_selection()->get_selected()); - name = row[vcols.name]; - pi = row[vcols.plugin]; - added_plugins.push_back (row[vcols.plugin]); + row = *(vst_display.get_selection()->get_selected()); + name = row[vcols.name]; + pi = row[vcols.plugin]; #endif - } else { - Gtk::TreeModel::Row row = *(ladspa_display.get_selection()->get_selected()); - name = row[lcols.name]; - pi = row[lcols.plugin]; - added_plugins.push_back (row[lcols.plugin]); + break; + case PluginInfo::AudioUnit: +#ifdef HAVE_COREAUDIO + row = *(au_display.get_selection()->get_selected()); + name = row[aucols.name]; + pi = row[aucols.plugin]; +#endif + break; + default: + error << "Programming error. Unknown plugin selected." << endmsg; + return; } + newrow[acols.text] = name; newrow[acols.plugin] = pi; if (!amodel->children().empty()) { - set_response_sensitive (RESPONSE_APPLY, true); + set_response_sensitive (RESPONSE_APPLY, true); } } void PluginSelector::btn_remove_clicked() { - list<PluginInfo*>::iterator i; Gtk::TreeModel::iterator iter = added_list.get_selection()->get_selected(); - for (i = added_plugins.begin(); (*i) != (*iter)[acols.plugin]; ++i); - - added_plugins.erase(i); + amodel->erase(iter); if (amodel->children().empty()) { - set_response_sensitive (RESPONSE_APPLY, false); + set_response_sensitive (RESPONSE_APPLY, false); } - - } void @@ -313,28 +412,21 @@ PluginSelector::btn_update_clicked() #ifdef VST_SUPPORT vst_refiller (); #endif -} - -#ifdef VST_SUPPORT -void -PluginSelector::vst_display_selection_changed() -{ - if (vst_display.get_selection()->count_selected_rows() != 0) { - btn_add->set_sensitive (true); - } else { - btn_add->set_sensitive (false); - } -} +#ifdef HAVE_COREAUDIO + au_refiller (); #endif +} void PluginSelector::ladspa_display_selection_changed() { - if (ladspa_display.get_selection()->count_selected_rows() != 0) { - btn_add->set_sensitive (true); - } else { - btn_add->set_sensitive (false); - } + if (ladspa_display.get_selection()->count_selected_rows() != 0) { + btn_add->set_sensitive (true); + } else { + btn_add->set_sensitive (false); + } + + current_selection = PluginInfo::LADSPA; } void @@ -351,14 +443,14 @@ int PluginSelector::run () { ResponseType r; - list<PluginInfo*>::iterator i; + TreeModel::Children::iterator i; r = (ResponseType) Dialog::run (); switch (r) { case RESPONSE_APPLY: - for (i = added_plugins.begin(); i != added_plugins.end(); ++i){ - use_plugin (*i); + for (i = amodel->children().begin(); i != amodel->children().end(); ++i) { + use_plugin ((*i)[acols.plugin]); } break; @@ -375,7 +467,5 @@ void PluginSelector::cleanup () { hide(); - added_plugins.clear(); amodel->clear(); } - diff --git a/gtk2_ardour/plugin_selector.h b/gtk2_ardour/plugin_selector.h index 125ce1b80a..583506972a 100644 --- a/gtk2_ardour/plugin_selector.h +++ b/gtk2_ardour/plugin_selector.h @@ -25,17 +25,18 @@ #include <gtkmm/treeview.h> #include <gtkmm2ext/selector.h> +#include <ardour/plugin.h> + namespace ARDOUR { class Session; class PluginManager; - class Plugin; } class PluginSelector : public ArdourDialog { public: PluginSelector (ARDOUR::PluginManager *); - sigc::signal<void,ARDOUR::Plugin *> PluginCreated; + sigc::signal<void,boost::shared_ptr<ARDOUR::Plugin> > PluginCreated; int run (); // XXX should we try not to overload the non-virtual Gtk::Dialog::run() ? @@ -44,9 +45,12 @@ class PluginSelector : public ArdourDialog private: ARDOUR::Session* session; Gtk::Notebook notebook; - Gtk::ScrolledWindow lscroller; - Gtk::ScrolledWindow vscroller; - Gtk::ScrolledWindow ascroller; + Gtk::ScrolledWindow lscroller; // ladspa + Gtk::ScrolledWindow vscroller; // vst + Gtk::ScrolledWindow auscroller; // AudioUnit + Gtk::ScrolledWindow ascroller; // Added plugins + + ARDOUR::PluginInfo::Type current_selection; // page 1 struct LadspaColumns : public Gtk::TreeModel::ColumnRecord { @@ -61,7 +65,7 @@ class PluginSelector : public ArdourDialog Gtk::TreeModelColumn<std::string> type; Gtk::TreeModelColumn<std::string> ins; Gtk::TreeModelColumn<std::string> outs; - Gtk::TreeModelColumn<ARDOUR::PluginInfo *> plugin; + Gtk::TreeModelColumn<ARDOUR::PluginInfoPtr> plugin; }; LadspaColumns lcols; Glib::RefPtr<Gtk::ListStore> lmodel; @@ -76,7 +80,7 @@ class PluginSelector : public ArdourDialog add (plugin); } Gtk::TreeModelColumn<std::string> text; - Gtk::TreeModelColumn<ARDOUR::PluginInfo *> plugin; + Gtk::TreeModelColumn<ARDOUR::PluginInfoPtr> plugin; }; AddedColumns acols; Glib::RefPtr<Gtk::ListStore> amodel; @@ -95,7 +99,7 @@ class PluginSelector : public ArdourDialog Gtk::TreeModelColumn<std::string> name; Gtk::TreeModelColumn<std::string> ins; Gtk::TreeModelColumn<std::string> outs; - Gtk::TreeModelColumn<ARDOUR::PluginInfo *> plugin; + Gtk::TreeModelColumn<ARDOUR::PluginInfoPtr> plugin; }; VstColumns vcols; Glib::RefPtr<Gtk::ListStore> vmodel; @@ -104,16 +108,32 @@ class PluginSelector : public ArdourDialog static void _vst_refiller (void *); void vst_refiller (); void vst_display_selection_changed(); -#endif - - ARDOUR::PluginInfo* i_selected_plug; +#endif // VST_SUPPORT - // We need an integer for the output side because - // the name isn't promised to be unique. - gint o_selected_plug; +#ifdef HAVE_COREAUDIO + // page 3 + struct AUColumns : public Gtk::TreeModel::ColumnRecord { + AUColumns () { + add (name); + add (ins); + add (outs); + add (plugin); + } + Gtk::TreeModelColumn<std::string> name; + Gtk::TreeModelColumn<std::string> ins; + Gtk::TreeModelColumn<std::string> outs; + Gtk::TreeModelColumn<ARDOUR::PluginInfoPtr> plugin; + }; + AUColumns aucols; + Glib::RefPtr<Gtk::ListStore> aumodel; + Glib::RefPtr<Gtk::TreeSelection> auselection; + Gtk::TreeView au_display; + static void _au_refiller (void *); + void au_refiller (); + void au_display_selection_changed(); +#endif //HAVE_COREAUDIO ARDOUR::PluginManager *manager; - list<ARDOUR::PluginInfo*> added_plugins; static void _input_refiller (void *); @@ -125,8 +145,9 @@ class PluginSelector : public ArdourDialog void added_list_selection_changed(); void ladspa_display_selection_changed(); void btn_apply_clicked(); - void use_plugin (ARDOUR::PluginInfo*); + void use_plugin (ARDOUR::PluginInfoPtr); void cleanup (); }; #endif // __ardour_plugin_selector_h__ + diff --git a/gtk2_ardour/plugin_ui.cc b/gtk2_ardour/plugin_ui.cc index 749ab9d4ac..5e5263b9ad 100644 --- a/gtk2_ardour/plugin_ui.cc +++ b/gtk2_ardour/plugin_ui.cc @@ -29,10 +29,10 @@ #include <gtkmm2ext/click_box.h> #include <gtkmm2ext/fastmeter.h> -#include <gtkmm2ext/slider_controller.h> #include <gtkmm2ext/barcontroller.h> #include <gtkmm2ext/utils.h> #include <gtkmm2ext/doi.h> +#include <gtkmm2ext/slider_controller.h> #include <midi++/manager.h> @@ -61,19 +61,19 @@ using namespace Gtkmm2ext; using namespace Gtk; using namespace sigc; -PluginUIWindow::PluginUIWindow (AudioEngine &engine, PluginInsert& insert, bool scrollable) +PluginUIWindow::PluginUIWindow (AudioEngine &engine, boost::shared_ptr<PluginInsert> insert, bool scrollable) : ArdourDialog ("plugin ui") { - if (insert.plugin().has_editor()) { + if (insert->plugin()->has_editor()) { #ifdef VST_SUPPORT - VSTPlugin* vp; + boost::shared_ptr<VSTPlugin> vp; - if ((vp = dynamic_cast<VSTPlugin*> (&insert.plugin())) != 0) { + if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (insert->plugin())) != 0) { - VSTPluginUI* vpu = new VSTPluginUI (insert, *vp); + VSTPluginUI* vpu = new VSTPluginUI (insert, vp); _pluginui = vpu; get_vbox()->add (*vpu); @@ -104,7 +104,7 @@ PluginUIWindow::PluginUIWindow (AudioEngine &engine, PluginInsert& insert, bool add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK); signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), reinterpret_cast<Window*> (this))); - insert.GoingAway.connect (mem_fun(*this, &PluginUIWindow::plugin_going_away)); + insert->GoingAway.connect (mem_fun(*this, &PluginUIWindow::plugin_going_away)); if (scrollable) { gint h = _pluginui->get_preferred_height (); @@ -117,7 +117,7 @@ PluginUIWindow::~PluginUIWindow () { } -PluginUI::PluginUI (AudioEngine &engine, PluginInsert& pi, bool scrollable) +PluginUI::PluginUI (AudioEngine &engine, boost::shared_ptr<PluginInsert> pi, bool scrollable) : PlugUIBase (pi), engine(engine), button_table (initial_button_rows, initial_button_cols), @@ -165,8 +165,8 @@ PluginUI::PluginUI (AudioEngine &engine, PluginInsert& pi, bool scrollable) pack_start (hpacker, false, false); } - insert.active_changed.connect (mem_fun(*this, &PluginUI::redirect_active_changed)); - bypass_button.set_active (!insert.active()); + insert->active_changed.connect (mem_fun(*this, &PluginUI::redirect_active_changed)); + bypass_button.set_active (!insert->active()); build (engine); } @@ -233,13 +233,13 @@ PluginUI::build (AudioEngine &engine) /* find all ports. build control elements for all appropriate control ports */ - for (i = 0; i < plugin.parameter_count(); ++i) { + for (i = 0; i < plugin->parameter_count(); ++i) { - if (plugin.parameter_is_control (i)) { + if (plugin->parameter_is_control (i)) { /* Don't show latency control ports */ - if (plugin.describe_parameter (i) == X_("latency")) { + if (plugin->describe_parameter (i) == X_("latency")) { continue; } @@ -263,7 +263,7 @@ PluginUI::build (AudioEngine &engine) } } - if ((cui = build_control_ui (engine, i, plugin.get_nth_midi_control (i))) == 0) { + if ((cui = build_control_ui (engine, i, plugin->get_nth_control (i))) == 0) { error << string_compose(_("Plugin Editor: could not build control element for port %1"), i) << endmsg; continue; } @@ -326,8 +326,8 @@ PluginUI::build (AudioEngine &engine) } } - n_ins = plugin.get_info().n_inputs; - n_outs = plugin.get_info().n_outputs; + n_ins = plugin->get_info()->n_inputs; + n_outs = plugin->get_info()->n_outputs; if (box->children().empty()) { hpacker.remove (*frame); @@ -387,7 +387,7 @@ PluginUI::automation_state_changed (ControlUI* cui) { /* update button label */ - switch (insert.get_port_automation_state (cui->port_index) & (Off|Play|Touch|Write)) { + switch (insert->get_port_automation_state (cui->port_index) & (Off|Play|Touch|Write)) { case Off: cui->automate_button.set_label (_("Off")); break; @@ -415,17 +415,17 @@ static void integer_printer (char buf[32], Adjustment &adj, void *arg) void PluginUI::print_parameter (char *buf, uint32_t len, uint32_t param) { - plugin.print_parameter (param, buf, len); + plugin->print_parameter (param, buf, len); } PluginUI::ControlUI* -PluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, MIDI::Controllable* mcontrol) +PluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, PBD::Controllable* mcontrol) { ControlUI* control_ui; Plugin::ParameterDescriptor desc; - plugin.get_parameter_descriptor (port_index, desc); + plugin->get_parameter_descriptor (port_index, desc); control_ui = manage (new ControlUI ()); control_ui->adjustment = 0; @@ -439,11 +439,11 @@ PluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, MIDI::Contr control_ui->set_spacing (5); - if (plugin.parameter_is_input (port_index)) { + if (plugin->parameter_is_input (port_index)) { - LadspaPlugin* lp; + boost::shared_ptr<LadspaPlugin> lp; - if ((lp = dynamic_cast<LadspaPlugin*>(&plugin)) != 0) { + if ((lp = boost::dynamic_pointer_cast<LadspaPlugin>(plugin)) != 0) { lrdf_defaults* defaults = lrdf_get_scale_values(lp->unique_id(), port_index); @@ -453,7 +453,7 @@ PluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, MIDI::Contr //control_ui->combo->set_value_in_list(true, false); set_popdown_strings (*control_ui->combo, setup_scale_values(port_index, control_ui)); control_ui->combo->signal_changed().connect (bind (mem_fun(*this, &PluginUI::control_combo_changed), control_ui)); - plugin.ParameterChanged.connect (bind (mem_fun (*this, &PluginUI::parameter_changed), control_ui)); + plugin->ParameterChanged.connect (bind (mem_fun (*this, &PluginUI::parameter_changed), control_ui)); control_ui->pack_start(control_ui->label, true, true); control_ui->pack_start(*control_ui->combo, false, true); @@ -478,7 +478,7 @@ PluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, MIDI::Contr control_ui->button->signal_clicked().connect (bind (mem_fun(*this, &PluginUI::control_port_toggled), control_ui)); - if(plugin.get_parameter (port_index) == 1){ + if(plugin->get_parameter (port_index) == 1){ control_ui->button->set_active(true); } @@ -516,7 +516,7 @@ PluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, MIDI::Contr } else { sigc::slot<void,char*,uint32_t> pslot = sigc::bind (mem_fun(*this, &PluginUI::print_parameter), (uint32_t) port_index); - control_ui->control = new BarController (*control_ui->adjustment, mcontrol, pslot); + control_ui->control = new BarController (*control_ui->adjustment, *mcontrol, pslot); // should really match the height of the text in the automation button+label control_ui->control->set_size_request (200, 22); control_ui->control->set_name (X_("PluginSlider")); @@ -529,9 +529,9 @@ PluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, MIDI::Contr } if (control_ui->logarithmic) { - control_ui->adjustment->set_value(log(plugin.get_parameter(port_index))); + control_ui->adjustment->set_value(log(plugin->get_parameter(port_index))); } else{ - control_ui->adjustment->set_value(plugin.get_parameter(port_index)); + control_ui->adjustment->set_value(plugin->get_parameter(port_index)); } /* XXX memory leak: SliderController not destroyed by ControlUI @@ -552,11 +552,11 @@ PluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, MIDI::Contr automation_state_changed (control_ui); - plugin.ParameterChanged.connect (bind (mem_fun(*this, &PluginUI::parameter_changed), control_ui)); - insert.automation_list (port_index).automation_state_changed.connect + plugin->ParameterChanged.connect (bind (mem_fun(*this, &PluginUI::parameter_changed), control_ui)); + insert->automation_list (port_index).automation_state_changed.connect (bind (mem_fun(*this, &PluginUI::automation_state_changed), control_ui)); - } else if (plugin.parameter_is_output (port_index)) { + } else if (plugin->parameter_is_output (port_index)) { control_ui->display = manage (new EventBox); control_ui->display->set_name ("ParameterValueDisplay"); @@ -603,20 +603,20 @@ PluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, MIDI::Contr output_controls.push_back (control_ui); } - plugin.ParameterChanged.connect (bind (mem_fun(*this, &PluginUI::parameter_changed), control_ui)); + plugin->ParameterChanged.connect (bind (mem_fun(*this, &PluginUI::parameter_changed), control_ui)); return control_ui; } void PluginUI::start_touch (PluginUI::ControlUI* cui) { - insert.automation_list (cui->port_index).start_touch (); + insert->automation_list (cui->port_index).start_touch (); } void PluginUI::stop_touch (PluginUI::ControlUI* cui) { - insert.automation_list (cui->port_index).stop_touch (); + insert->automation_list (cui->port_index).stop_touch (); } void @@ -647,7 +647,7 @@ PluginUI::astate_clicked (ControlUI* cui, uint32_t port) void PluginUI::set_automation_state (AutoState state, ControlUI* cui) { - insert.set_port_automation_state (cui->port_index, state); + insert->set_port_automation_state (cui->port_index, state); } void @@ -663,7 +663,7 @@ PluginUI::control_adjustment_changed (ControlUI* cui) value = exp(value); } - insert.set_parameter (cui->port_index, (float) value); + insert->set_parameter (cui->port_index, (float) value); } void @@ -684,7 +684,7 @@ PluginUI::update_control_display (ControlUI* cui) cui->update_pending = false; - float val = plugin.get_parameter (cui->port_index); + float val = plugin->get_parameter (cui->port_index); cui->ignore_change++; if (cui->combo) { @@ -718,7 +718,7 @@ void PluginUI::control_port_toggled (ControlUI* cui) { if (!cui->ignore_change) { - insert.set_parameter (cui->port_index, cui->button->get_active()); + insert->set_parameter (cui->port_index, cui->button->get_active()); } } @@ -728,7 +728,7 @@ PluginUI::control_combo_changed (ControlUI* cui) if (!cui->ignore_change) { string value = cui->combo->get_active_text(); std::map<string,float> mapping = *cui->combo_map; - insert.set_parameter (cui->port_index, mapping[value]); + insert->set_parameter (cui->port_index, mapping[value]); } } @@ -774,7 +774,7 @@ void PluginUI::output_update () { for (vector<ControlUI*>::iterator i = output_controls.begin(); i != output_controls.end(); ++i) { - float val = plugin.get_parameter ((*i)->port_index); + float val = plugin->get_parameter ((*i)->port_index); char buf[32]; snprintf (buf, sizeof(buf), "%.2f", val); (*i)->display_label->set_text (buf); @@ -808,7 +808,7 @@ vector<string> PluginUI::setup_scale_values(guint32 port_index, ControlUI* cui) { vector<string> enums; - LadspaPlugin* lp = dynamic_cast<LadspaPlugin*> (&plugin); + boost::shared_ptr<LadspaPlugin> lp = boost::dynamic_pointer_cast<LadspaPlugin> (plugin); cui->combo_map = new std::map<string, float>; lrdf_defaults* defaults = lrdf_get_scale_values(lp->unique_id(), port_index); @@ -827,14 +827,14 @@ PluginUI::setup_scale_values(guint32 port_index, ControlUI* cui) return enums; } -PlugUIBase::PlugUIBase (PluginInsert& pi) +PlugUIBase::PlugUIBase (boost::shared_ptr<PluginInsert> pi) : insert (pi), - plugin (insert.plugin()), + plugin (insert->plugin()), save_button(_("Add")), bypass_button (_("Bypass")) { //combo.set_use_arrows_always(true); - set_popdown_strings (combo, plugin.get_presets()); + set_popdown_strings (combo, plugin->get_presets()); combo.set_size_request (100, -1); combo.set_active_text (""); combo.signal_changed().connect(mem_fun(*this, &PlugUIBase::setting_selected)); @@ -850,7 +850,7 @@ void PlugUIBase::setting_selected() { if (combo.get_active_text().length() > 0) { - if (!plugin.load_preset(combo.get_active_text())) { + if (!plugin->load_preset(combo.get_active_text())) { warning << string_compose(_("Plugin preset %1 not found"), combo.get_active_text()) << endmsg; } } @@ -875,8 +875,8 @@ PlugUIBase::save_plugin_setting () prompter.get_result(name); if (name.length()) { - if(plugin.save_preset(name)){ - set_popdown_strings (combo, plugin.get_presets()); + if(plugin->save_preset(name)){ + set_popdown_strings (combo, plugin->get_presets()); combo.set_active_text (name); } } @@ -889,8 +889,8 @@ PlugUIBase::bypass_toggled () { bool x; - if ((x = bypass_button.get_active()) == insert.active()) { - insert.set_active (!x, this); + if ((x = bypass_button.get_active()) == insert->active()) { + insert->set_active (!x, this); } } diff --git a/gtk2_ardour/plugin_ui.h b/gtk2_ardour/plugin_ui.h index e5800e8ece..570a224b66 100644 --- a/gtk2_ardour/plugin_ui.h +++ b/gtk2_ardour/plugin_ui.h @@ -52,7 +52,7 @@ namespace ARDOUR { class Redirect; } -namespace MIDI { +namespace PBD { class Controllable; } @@ -67,7 +67,7 @@ namespace Gtkmm2ext { class PlugUIBase : public virtual sigc::trackable { public: - PlugUIBase (ARDOUR::PluginInsert&); + PlugUIBase (boost::shared_ptr<ARDOUR::PluginInsert>); virtual ~PlugUIBase() {} virtual gint get_preferred_height () = 0; @@ -75,8 +75,8 @@ class PlugUIBase : public virtual sigc::trackable virtual bool stop_updating(GdkEventAny*) = 0; protected: - ARDOUR::PluginInsert& insert; - ARDOUR::Plugin& plugin; + boost::shared_ptr<ARDOUR::PluginInsert> insert; + boost::shared_ptr<ARDOUR::Plugin> plugin; Gtk::ComboBoxText combo; Gtk::Button save_button; Gtk::ToggleButton bypass_button; @@ -89,7 +89,7 @@ class PlugUIBase : public virtual sigc::trackable class PluginUI : public PlugUIBase, public Gtk::VBox { public: - PluginUI (ARDOUR::AudioEngine &, ARDOUR::PluginInsert& plug, bool scrollable=false); + PluginUI (ARDOUR::AudioEngine &, boost::shared_ptr<ARDOUR::PluginInsert> plug, bool scrollable=false); ~PluginUI (); gint get_preferred_height () { return prefheight; } @@ -174,7 +174,7 @@ class PluginUI : public PlugUIBase, public Gtk::VBox void output_update(); void build (ARDOUR::AudioEngine &); - ControlUI* build_control_ui (ARDOUR::AudioEngine &, guint32 port_index, MIDI::Controllable *); + ControlUI* build_control_ui (ARDOUR::AudioEngine &, guint32 port_index, PBD::Controllable *); std::vector<string> setup_scale_values(guint32 port_index, ControlUI* cui); void control_adjustment_changed (ControlUI* cui); void parameter_changed (uint32_t, float, ControlUI* cui); @@ -196,7 +196,7 @@ class PluginUI : public PlugUIBase, public Gtk::VBox class PluginUIWindow : public ArdourDialog { public: - PluginUIWindow (ARDOUR::AudioEngine &, ARDOUR::PluginInsert& insert, bool scrollable=false); + PluginUIWindow (ARDOUR::AudioEngine &, boost::shared_ptr<ARDOUR::PluginInsert> insert, bool scrollable=false); ~PluginUIWindow (); PlugUIBase& pluginui() { return *_pluginui; } @@ -213,7 +213,7 @@ class PluginUIWindow : public ArdourDialog class VSTPluginUI : public PlugUIBase, public Gtk::VBox { public: - VSTPluginUI (ARDOUR::PluginInsert&, ARDOUR::VSTPlugin&); + VSTPluginUI (boost::shared_ptr<ARDOUR::PluginInsert>, boost::shared_ptr<ARDOUR::VSTPlugin>); ~VSTPluginUI (); gint get_preferred_height (); @@ -223,7 +223,7 @@ class VSTPluginUI : public PlugUIBase, public Gtk::VBox int package (Gtk::Window&); private: - ARDOUR::VSTPlugin& vst; + boost::shared_ptr<ARDOUR::VSTPlugin> vst; Gtk::Socket socket; Gtk::HBox preset_box; Gtk::VBox vpacker; diff --git a/gtk2_ardour/po/SConscript b/gtk2_ardour/po/SConscript index 868f123988..d7e957b3eb 100644 --- a/gtk2_ardour/po/SConscript +++ b/gtk2_ardour/po/SConscript @@ -27,7 +27,7 @@ print "Updating pot file: " domain = gtkardour['DOMAIN'] potfile = gtkardour['POTFILE'] -poaction = Action('intltool-update -p -g=' + domain) +poaction = env.Action('intltool-update -p -g=' + domain) Execute(poaction) diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h index 4c12b99d7c..f70e4c20bd 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -39,7 +39,7 @@ class AutomationLine; class ControlPoint; class SelectionRect; class CrossfadeView; -class AudioTimeAxisView; +class RouteTimeAxisView; class AudioRegionView; class TempoMarker; class MeterMarker; @@ -145,10 +145,10 @@ class PublicEditor : public Gtk::Window, public Stateful { virtual bool canvas_fade_in_handle_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*) = 0; virtual bool canvas_fade_out_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*) = 0; virtual bool canvas_fade_out_handle_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*) = 0; - virtual bool canvas_region_view_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*) = 0; - virtual bool canvas_region_view_name_highlight_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*) = 0; - virtual bool canvas_region_view_name_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*) = 0; - virtual bool canvas_stream_view_event (GdkEvent* event,ArdourCanvas::Item*, AudioTimeAxisView*) = 0; + virtual bool canvas_region_view_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*) = 0; + virtual bool canvas_region_view_name_highlight_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*) = 0; + virtual bool canvas_region_view_name_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*) = 0; + virtual bool canvas_stream_view_event (GdkEvent* event,ArdourCanvas::Item*, RouteTimeAxisView*) = 0; virtual bool canvas_marker_event (GdkEvent* event,ArdourCanvas::Item*, Marker*) = 0; virtual bool canvas_zoom_rect_event (GdkEvent* event,ArdourCanvas::Item*) = 0; virtual bool canvas_tempo_marker_event (GdkEvent* event,ArdourCanvas::Item*, TempoMarker*) = 0; diff --git a/gtk2_ardour/redirect_automation_line.cc b/gtk2_ardour/redirect_automation_line.cc index 8971e8ff10..1ea5013295 100644 --- a/gtk2_ardour/redirect_automation_line.cc +++ b/gtk2_ardour/redirect_automation_line.cc @@ -55,7 +55,7 @@ RedirectAutomationLine::RedirectAutomationLine (const string & name, Redirect& r /*NOTREACHED*/ } - pi->plugin().get_parameter_descriptor (_port, desc); + pi->plugin()->get_parameter_descriptor (_port, desc); upper = desc.upper; lower = desc.lower; diff --git a/gtk2_ardour/redirect_automation_time_axis.cc b/gtk2_ardour/redirect_automation_time_axis.cc index e3ce4b08c6..e527fd1d5e 100644 --- a/gtk2_ardour/redirect_automation_time_axis.cc +++ b/gtk2_ardour/redirect_automation_time_axis.cc @@ -33,7 +33,8 @@ using namespace ARDOUR; using namespace PBD; using namespace Gtk; -RedirectAutomationTimeAxisView::RedirectAutomationTimeAxisView (Session& s, Route& r, PublicEditor& e, TimeAxisView& parent, Canvas& canvas, std::string n, +RedirectAutomationTimeAxisView::RedirectAutomationTimeAxisView (Session& s, boost::shared_ptr<Route> r, + PublicEditor& e, TimeAxisView& parent, Canvas& canvas, std::string n, uint32_t prt, Redirect& rd, string state_name) : AxisView (s), diff --git a/gtk2_ardour/redirect_automation_time_axis.h b/gtk2_ardour/redirect_automation_time_axis.h index b8d94b2a3e..6976dc2358 100644 --- a/gtk2_ardour/redirect_automation_time_axis.h +++ b/gtk2_ardour/redirect_automation_time_axis.h @@ -14,7 +14,7 @@ class RedirectAutomationTimeAxisView : public AutomationTimeAxisView { public: RedirectAutomationTimeAxisView (ARDOUR::Session&, - ARDOUR::Route&, + boost::shared_ptr<ARDOUR::Route>, PublicEditor&, TimeAxisView& parent, ArdourCanvas::Canvas& canvas, diff --git a/gtk2_ardour/redirect_box.cc b/gtk2_ardour/redirect_box.cc index f5cb9522e0..74198265d9 100644 --- a/gtk2_ardour/redirect_box.cc +++ b/gtk2_ardour/redirect_box.cc @@ -76,7 +76,7 @@ bool RedirectBox::get_colors = true; Gdk::Color* RedirectBox::active_redirect_color; Gdk::Color* RedirectBox::inactive_redirect_color; -RedirectBox::RedirectBox (Placement pcmnt, Session& sess, Route& rt, PluginSelector &plugsel, +RedirectBox::RedirectBox (Placement pcmnt, Session& sess, boost::shared_ptr<Route> rt, PluginSelector &plugsel, RouteRedirectSelection & rsel, bool owner_is_mixer) : _route(rt), _session(sess), @@ -132,7 +132,7 @@ RedirectBox::RedirectBox (Placement pcmnt, Session& sess, Route& rt, PluginSelec pack_start (redirect_eventbox, true, true); - _route.redirects_changed.connect (mem_fun(*this, &RedirectBox::redisplay_redirects)); + _route->redirects_changed.connect (mem_fun(*this, &RedirectBox::redisplay_redirects)); redirect_eventbox.signal_enter_notify_event().connect (bind (sigc::ptr_fun (RedirectBox::enter_box), this)); @@ -161,10 +161,10 @@ RedirectBox::object_drop (string type, uint32_t cnt, void** ptr) /* do something with the dropped redirects */ - list<Redirect*> redirects; - + list<boost::shared_ptr<Redirect> > redirects; + for (uint32_t n = 0; n < cnt; ++n) { - redirects.push_back ((Redirect*) ptr[n]); + redirects.push_back (boost::shared_ptr<Redirect> ((Redirect*) ptr[n])); } paste_redirect_list (redirects); @@ -189,21 +189,21 @@ RedirectBox::set_width (Width w) } void -RedirectBox::remove_redirect_gui (Redirect *redirect) +RedirectBox::remove_redirect_gui (boost::shared_ptr<Redirect> redirect) { - Insert *insert = 0; - Send *send = 0; - PortInsert *port_insert = 0; + boost::shared_ptr<Insert> insert; + boost::shared_ptr<Send> send; + boost::shared_ptr<PortInsert> port_insert; - if ((insert = dynamic_cast<Insert *> (redirect)) != 0) { + if ((insert = boost::dynamic_pointer_cast<Insert> (redirect)) != 0) { - if ((port_insert = dynamic_cast<PortInsert *> (insert)) != 0) { + if ((port_insert = boost::dynamic_pointer_cast<PortInsert> (insert)) != 0) { PortInsertUI *io_selector = reinterpret_cast<PortInsertUI *> (port_insert->get_gui()); port_insert->set_gui (0); delete io_selector; } - } else if ((send = dynamic_cast<Send *> (insert)) != 0) { + } else if ((send = boost::dynamic_pointer_cast<Send> (insert)) != 0) { SendUIWindow *sui = reinterpret_cast<SendUIWindow*> (send->get_gui()); send->set_gui (0); delete sui; @@ -268,7 +268,7 @@ RedirectBox::redirect_button_press_event (GdkEventButton *ev) TreeViewColumn* column; int cellx; int celly; - Redirect* redirect = 0; + boost::shared_ptr<Redirect> redirect; int ret = false; bool selected = false; @@ -353,32 +353,32 @@ RedirectBox::choose_plugin () } void -RedirectBox::insert_plugin_chosen (Plugin *plugin) +RedirectBox::insert_plugin_chosen (boost::shared_ptr<Plugin> plugin) { if (plugin) { - Redirect *redirect = new PluginInsert (_session, *plugin, _placement); + boost::shared_ptr<Redirect> redirect (new PluginInsert (_session, plugin, _placement)); redirect->active_changed.connect (mem_fun(*this, &RedirectBox::show_redirect_active)); uint32_t err_streams; - if (_route.add_redirect (redirect, this, &err_streams)) { + if (_route->add_redirect (redirect, this, &err_streams)) { wierd_plugin_dialog (*plugin, err_streams, _route); - delete redirect; + // XXX SHAREDPTR delete plugin here .. do we even need to care? } } } void -RedirectBox::wierd_plugin_dialog (Plugin& p, uint32_t streams, IO& io) +RedirectBox::wierd_plugin_dialog (Plugin& p, uint32_t streams, boost::shared_ptr<IO> io) { ArdourDialog dialog ("wierd plugin dialog"); Label label; /* i hate this kind of code */ - if (streams > p.get_info().n_inputs) { + if (streams > p.get_info()->n_inputs) { label.set_text (string_compose (_( "You attempted to add a plugin (%1).\n" "The plugin has %2 inputs\n" @@ -388,9 +388,9 @@ RedirectBox::wierd_plugin_dialog (Plugin& p, uint32_t streams, IO& io) "This makes no sense - you are throwing away\n" "part of the signal."), p.name(), - p.get_info().n_inputs, + p.get_info()->n_inputs, streams)); - } else if (streams < p.get_info().n_inputs) { + } else if (streams < p.get_info()->n_inputs) { label.set_text (string_compose (_( "You attempted to add a plugin (%1).\n" "The plugin has %2 inputs\n" @@ -401,7 +401,7 @@ RedirectBox::wierd_plugin_dialog (Plugin& p, uint32_t streams, IO& io) "side-chain inputs. A future version of Ardour will\n" "support this type of configuration."), p.name(), - p.get_info().n_inputs, + p.get_info()->n_inputs, streams)); } else { label.set_text (string_compose (_( @@ -415,10 +415,10 @@ RedirectBox::wierd_plugin_dialog (Plugin& p, uint32_t streams, IO& io) "\n" "Ardour does not understand what to do in such situations.\n"), p.name(), - p.get_info().n_inputs, - p.get_info().n_outputs, - io.n_inputs(), - io.n_outputs(), + p.get_info()->n_inputs, + p.get_info()->n_outputs, + io->n_inputs(), + io->n_outputs(), streams)); } @@ -436,36 +436,36 @@ RedirectBox::wierd_plugin_dialog (Plugin& p, uint32_t streams, IO& io) void RedirectBox::choose_insert () { - Redirect *redirect = new PortInsert (_session, _placement); + boost::shared_ptr<Redirect> redirect (new PortInsert (_session, _placement)); redirect->active_changed.connect (mem_fun(*this, &RedirectBox::show_redirect_active)); - _route.add_redirect (redirect, this); + _route->add_redirect (redirect, this); } void RedirectBox::choose_send () { - Send *send = new Send (_session, _placement); + boost::shared_ptr<Send> send (new Send (_session, _placement)); /* XXX need redirect lock on route */ - send->ensure_io (0, _route.max_redirect_outs(), false, this); + send->ensure_io (0, _route->max_redirect_outs(), false, this); - IOSelectorWindow *ios = new IOSelectorWindow (_session, *send, false, true); + IOSelectorWindow *ios = new IOSelectorWindow (_session, send, false, true); ios->show_all (); - ios->selector().Finished.connect (bind (mem_fun(*this, &RedirectBox::send_io_finished), static_cast<Redirect*>(send), ios)); + ios->selector().Finished.connect (bind (mem_fun(*this, &RedirectBox::send_io_finished), boost::static_pointer_cast<Redirect>(send), ios)); } void -RedirectBox::send_io_finished (IOSelector::Result r, Redirect* redirect, IOSelectorWindow* ios) +RedirectBox::send_io_finished (IOSelector::Result r, boost::shared_ptr<Redirect> redirect, IOSelectorWindow* ios) { switch (r) { case IOSelector::Cancelled: - delete redirect; + // delete redirect; XXX SHAREDPTR HOW TO DESTROY THE REDIRECT ? do we even need to think about it? break; case IOSelector::Accepted: - _route.add_redirect (redirect, this); + _route->add_redirect (redirect, this); break; } @@ -488,7 +488,8 @@ RedirectBox::redisplay_redirects (void *src) redirect_active_connections.clear (); redirect_name_connections.clear (); - _route.foreach_redirect (this, &RedirectBox::add_redirect_to_display); + void (RedirectBox::*pmf)(boost::shared_ptr<Redirect>) = &RedirectBox::add_redirect_to_display; + _route->foreach_redirect (this, pmf); switch (_placement) { case PreFader: @@ -501,33 +502,33 @@ RedirectBox::redisplay_redirects (void *src) } void -RedirectBox::add_redirect_to_display (Redirect *redirect) +RedirectBox::add_redirect_to_display (boost::shared_ptr<Redirect> redirect) { if (redirect->placement() != _placement) { return; } Gtk::TreeModel::Row row = *(model->append()); - row[columns.text] = redirect_name (*redirect); + row[columns.text] = redirect_name (redirect); row[columns.redirect] = redirect; - show_redirect_active (redirect, this); + show_redirect_active (redirect.get(), this); redirect_active_connections.push_back (redirect->active_changed.connect (mem_fun(*this, &RedirectBox::show_redirect_active))); redirect_name_connections.push_back (redirect->name_changed.connect (bind (mem_fun(*this, &RedirectBox::show_redirect_name), redirect))); } string -RedirectBox::redirect_name (Redirect& redirect) +RedirectBox::redirect_name (boost::shared_ptr<Redirect> redirect) { - Send *send; + boost::shared_ptr<Send> send; string name_display; - if (!redirect.active()) { + if (!redirect->active()) { name_display = " ("; } - if ((send = dynamic_cast<Send *> (&redirect)) != 0) { + if ((send = boost::dynamic_pointer_cast<Send> (redirect)) != 0) { name_display += '>'; @@ -550,16 +551,16 @@ RedirectBox::redirect_name (Redirect& redirect) switch (_width) { case Wide: - name_display += redirect.name(); + name_display += redirect->name(); break; case Narrow: - name_display += PBD::short_version (redirect.name(), 5); + name_display += PBD::short_version (redirect->name(), 5); break; } } - if (!redirect.active()) { + if (!redirect->active()) { name_display += ')'; } @@ -581,34 +582,36 @@ RedirectBox::build_redirect_tooltip (EventBox& box, string start) } void -RedirectBox::show_redirect_name (void* src, Redirect *redirect) +RedirectBox::show_redirect_name (void* src, boost::shared_ptr<Redirect> redirect) { ENSURE_GUI_THREAD(bind (mem_fun(*this, &RedirectBox::show_redirect_name), src, redirect)); - - show_redirect_active (redirect, src); + show_redirect_active (redirect.get(), src); } void -RedirectBox::show_redirect_active (Redirect *redirect, void *src) +RedirectBox::show_redirect_active (Redirect* redirect, void *src) { ENSURE_GUI_THREAD(bind (mem_fun(*this, &RedirectBox::show_redirect_active), redirect, src)); Gtk::TreeModel::Children children = model->children(); Gtk::TreeModel::Children::iterator iter = children.begin(); - while( iter != children.end()) - { - if ((*iter)[columns.redirect] == redirect) - break; - iter++; - } + while (iter != children.end()) { - (*iter)[columns.text] = redirect_name (*redirect); + boost::shared_ptr<Redirect> r = (*iter)[columns.redirect]; - if (redirect->active()) { - (*iter)[columns.color] = *active_redirect_color; - } else { - (*iter)[columns.color] = *inactive_redirect_color; + if (r.get() == redirect) { + (*iter)[columns.text] = redirect_name (r); + + if (redirect->active()) { + (*iter)[columns.color] = *active_redirect_color; + } else { + (*iter)[columns.color] = *inactive_redirect_color; + } + break; + } + + iter++; } } @@ -627,12 +630,12 @@ RedirectBox::compute_redirect_sort_keys () Gtk::TreeModel::Children children = model->children(); for (Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) { - Redirect *redirect = (*iter)[columns.redirect]; - redirect->set_sort_key (sort_key); + boost::shared_ptr<Redirect> r = (*iter)[columns.redirect]; + r->set_sort_key (sort_key); sort_key++; } - if (_route.sort_redirects ()) { + if (_route->sort_redirects ()) { redisplay_redirects (0); @@ -661,7 +664,7 @@ outputs do not work correctly.")); void RedirectBox::rename_redirects () { - vector<Redirect*> to_be_renamed; + vector<boost::shared_ptr<Redirect> > to_be_renamed; get_selected_redirects (to_be_renamed); @@ -669,7 +672,7 @@ RedirectBox::rename_redirects () return; } - for (vector<Redirect*>::iterator i = to_be_renamed.begin(); i != to_be_renamed.end(); ++i) { + for (vector<boost::shared_ptr<Redirect> >::iterator i = to_be_renamed.begin(); i != to_be_renamed.end(); ++i) { rename_redirect (*i); } } @@ -677,7 +680,7 @@ RedirectBox::rename_redirects () void RedirectBox::cut_redirects () { - vector<Redirect*> to_be_removed; + vector<boost::shared_ptr<Redirect> > to_be_removed; get_selected_redirects (to_be_removed); @@ -692,7 +695,7 @@ RedirectBox::cut_redirects () _rr_selection.set (to_be_removed); - for (vector<Redirect*>::iterator i = to_be_removed.begin(); i != to_be_removed.end(); ++i) { + for (vector<boost::shared_ptr<Redirect> >::iterator i = to_be_removed.begin(); i != to_be_removed.end(); ++i) { void* gui = (*i)->get_gui (); @@ -700,7 +703,7 @@ RedirectBox::cut_redirects () static_cast<Gtk::Widget*>(gui)->hide (); } - if (_route.remove_redirect (*i, this)) { + if (_route->remove_redirect (*i, this)) { /* removal failed */ _rr_selection.remove (*i); } @@ -711,8 +714,8 @@ RedirectBox::cut_redirects () void RedirectBox::copy_redirects () { - vector<Redirect*> to_be_copied; - vector<Redirect*> copies; + vector<boost::shared_ptr<Redirect> > to_be_copied; + vector<boost::shared_ptr<Redirect> > copies; get_selected_redirects (to_be_copied); @@ -720,29 +723,24 @@ RedirectBox::copy_redirects () return; } - for (vector<Redirect*>::iterator i = to_be_copied.begin(); i != to_be_copied.end(); ++i) { - copies.push_back (Redirect::clone (**i)); + for (vector<boost::shared_ptr<Redirect> >::iterator i = to_be_copied.begin(); i != to_be_copied.end(); ++i) { + copies.push_back (Redirect::clone (*i)); } _rr_selection.set (copies); } gint -RedirectBox::idle_delete_redirect (Redirect *redirect) +RedirectBox::idle_delete_redirect (boost::shared_ptr<Redirect> redirect) { /* NOT copied to _mixer.selection() */ - if (_route.remove_redirect (redirect, this)) { - /* removal failed */ - return FALSE; - } - - delete redirect; + _route->remove_redirect (redirect, this); return FALSE; } void -RedirectBox::rename_redirect (Redirect* redirect) +RedirectBox::rename_redirect (boost::shared_ptr<Redirect> redirect) { ArdourPrompter name_prompter (true); string result; @@ -767,7 +765,7 @@ RedirectBox::rename_redirect (Redirect* redirect) } void -RedirectBox::cut_redirect (Redirect *redirect) +RedirectBox::cut_redirect (boost::shared_ptr<Redirect> redirect) { /* this essentially transfers ownership of the redirect of the redirect from the route to the mixer @@ -782,15 +780,15 @@ RedirectBox::cut_redirect (Redirect *redirect) static_cast<Gtk::Widget*>(gui)->hide (); } - if (_route.remove_redirect (redirect, this)) { + if (_route->remove_redirect (redirect, this)) { _rr_selection.remove (redirect); } } void -RedirectBox::copy_redirect (Redirect *redirect) +RedirectBox::copy_redirect (boost::shared_ptr<Redirect> redirect) { - Redirect* copy = Redirect::clone (*redirect); + boost::shared_ptr<Redirect> copy = Redirect::clone (redirect); _rr_selection.add (copy); } @@ -805,22 +803,19 @@ RedirectBox::paste_redirects () } void -RedirectBox::paste_redirect_list (list<Redirect*>& redirects) +RedirectBox::paste_redirect_list (list<boost::shared_ptr<Redirect> >& redirects) { - list<Redirect*> copies; + list<boost::shared_ptr<Redirect> > copies; - for (list<Redirect*>::iterator i = redirects.begin(); i != redirects.end(); ++i) { + for (list<boost::shared_ptr<Redirect> >::iterator i = redirects.begin(); i != redirects.end(); ++i) { - Redirect* copy = Redirect::clone (**i); + boost::shared_ptr<Redirect> copy = Redirect::clone (*i); copy->set_placement (_placement, this); copies.push_back (copy); } - if (_route.add_redirects (copies, this)) { - for (list<Redirect*>::iterator i = copies.begin(); i != copies.end(); ++i) { - delete *i; - } + if (_route->add_redirects (copies, this)) { string msg = _( "Copying the set of redirects on the clipboard failed,\n\ @@ -832,19 +827,19 @@ could not match the configuration of this track."); } void -RedirectBox::activate_redirect (Redirect *r) +RedirectBox::activate_redirect (boost::shared_ptr<Redirect> r) { r->set_active (true, 0); } void -RedirectBox::deactivate_redirect (Redirect *r) +RedirectBox::deactivate_redirect (boost::shared_ptr<Redirect> r) { r->set_active (false, 0); } void -RedirectBox::get_selected_redirects (vector<Redirect*>& redirects) +RedirectBox::get_selected_redirects (vector<boost::shared_ptr<Redirect> >& redirects) { vector<Gtk::TreeModel::Path> pathlist = redirect_display.get_selection()->get_selected_rows(); @@ -853,12 +848,12 @@ RedirectBox::get_selected_redirects (vector<Redirect*>& redirects) } void -RedirectBox::for_selected_redirects (void (RedirectBox::*pmf)(Redirect*)) +RedirectBox::for_selected_redirects (void (RedirectBox::*pmf)(boost::shared_ptr<Redirect>)) { vector<Gtk::TreeModel::Path> pathlist = redirect_display.get_selection()->get_selected_rows(); for (vector<Gtk::TreeModel::Path>::iterator iter = pathlist.begin(); iter != pathlist.end(); ++iter) { - Redirect* redirect = (*(model->get_iter(*iter)))[columns.redirect]; + boost::shared_ptr<Redirect> redirect = (*(model->get_iter(*iter)))[columns.redirect]; (this->*pmf)(redirect); } } @@ -869,7 +864,7 @@ RedirectBox::clone_redirects () RouteSelection& routes (_rr_selection.routes); if (!routes.empty()) { - if (_route.copy_redirects (*routes.front(), _placement)) { + if (_route->copy_redirects (*routes.front(), _placement)) { string msg = _( "Copying the set of redirects on the clipboard failed,\n\ probably because the I/O configuration of the plugins\n\ @@ -883,7 +878,7 @@ could not match the configuration of this track."); void RedirectBox::all_redirects_active (bool state) { - _route.all_redirects_active (state); + _route->all_redirects_active (state); } void @@ -892,7 +887,7 @@ RedirectBox::clear_redirects() string prompt; vector<string> choices; - if (dynamic_cast<AudioTrack*>(&_route) != 0) { + if (boost::dynamic_pointer_cast<AudioTrack>(_route) != 0) { prompt = _("Do you really want to remove all redirects from this track?\n" "(this cannot be undone)"); } else { @@ -906,23 +901,23 @@ RedirectBox::clear_redirects() Gtkmm2ext::Choice prompter (prompt, choices); if (prompter.run () == 1) { - _route.clear_redirects (this); + _route->clear_redirects (this); } } void -RedirectBox::edit_redirect (Redirect* redirect) +RedirectBox::edit_redirect (boost::shared_ptr<Redirect> redirect) { - Insert *insert; + boost::shared_ptr<Insert> insert; - if (dynamic_cast<AudioTrack*>(&_route) != 0) { + if (boost::dynamic_pointer_cast<AudioTrack>(_route) != 0) { - if (dynamic_cast<AudioTrack*> (&_route)->freeze_state() == AudioTrack::Frozen) { + if (boost::dynamic_pointer_cast<AudioTrack> (_route)->freeze_state() == AudioTrack::Frozen) { return; } } - if ((insert = dynamic_cast<Insert *> (redirect)) == 0) { + if ((insert = boost::dynamic_pointer_cast<Insert> (redirect)) == 0) { /* its a send */ @@ -930,7 +925,7 @@ RedirectBox::edit_redirect (Redirect* redirect) return; } - Send *send = dynamic_cast<Send*> (redirect); + boost::shared_ptr<Send> send = boost::dynamic_pointer_cast<Send> (redirect); SendUIWindow *send_ui; @@ -939,7 +934,7 @@ RedirectBox::edit_redirect (Redirect* redirect) string title; title = string_compose(_("ardour: %1"), send->name()); - send_ui = new SendUIWindow (*send, _session); + send_ui = new SendUIWindow (send, _session); send_ui->set_title (title); send->set_gui (send_ui); @@ -957,17 +952,17 @@ RedirectBox::edit_redirect (Redirect* redirect) /* its an insert */ - PluginInsert *plugin_insert; - PortInsert *port_insert; + boost::shared_ptr<PluginInsert> plugin_insert; + boost::shared_ptr<PortInsert> port_insert; - if ((plugin_insert = dynamic_cast<PluginInsert *> (insert)) != 0) { + if ((plugin_insert = boost::dynamic_pointer_cast<PluginInsert> (insert)) != 0) { PluginUIWindow *plugin_ui; if (plugin_insert->get_gui() == 0) { string title; - string maker = plugin_insert->plugin().maker(); + string maker = plugin_insert->plugin()->maker(); string::size_type email_pos; if ((email_pos = maker.find_first_of ('<')) != string::npos) { @@ -979,9 +974,9 @@ RedirectBox::edit_redirect (Redirect* redirect) maker += " ..."; } - title = string_compose(_("ardour: %1: %2 (by %3)"), _route.name(), plugin_insert->name(), maker); + title = string_compose(_("ardour: %1: %2 (by %3)"), _route->name(), plugin_insert->name(), maker); - plugin_ui = new PluginUIWindow (_session.engine(), *plugin_insert); + plugin_ui = new PluginUIWindow (_session.engine(), plugin_insert); if (_owner_is_mixer) { ARDOUR_UI::instance()->the_mixer()->ensure_float (*plugin_ui); } else { @@ -1000,7 +995,7 @@ RedirectBox::edit_redirect (Redirect* redirect) plugin_ui->show_all (); } - } else if ((port_insert = dynamic_cast<PortInsert *> (insert)) != 0) { + } else if ((port_insert = boost::dynamic_pointer_cast<PortInsert> (insert)) != 0) { if (!_session.engine().connected()) { MessageDialog msg ( _("Not connected to JACK - no I/O changes are possible")); @@ -1011,7 +1006,7 @@ RedirectBox::edit_redirect (Redirect* redirect) PortInsertWindow *io_selector; if (port_insert->get_gui() == 0) { - io_selector = new PortInsertWindow (_session, *port_insert); + io_selector = new PortInsertWindow (_session, port_insert); port_insert->set_gui (io_selector); } else { diff --git a/gtk2_ardour/redirect_box.h b/gtk2_ardour/redirect_box.h index bc162fac17..51c17cad51 100644 --- a/gtk2_ardour/redirect_box.h +++ b/gtk2_ardour/redirect_box.h @@ -33,11 +33,12 @@ #include <gtkmm2ext/click_box.h> #include <gtkmm2ext/dndtreeview.h> +#include <pbd/stateful.h> + #include <ardour/types.h> #include <ardour/ardour.h> #include <ardour/io.h> #include <ardour/insert.h> -#include <ardour/stateful.h> #include <ardour/redirect.h> #include <pbd/fastlog.h> @@ -64,7 +65,8 @@ namespace ARDOUR { class RedirectBox : public Gtk::HBox { public: - RedirectBox (ARDOUR::Placement, ARDOUR::Session&, ARDOUR::Route &, PluginSelector &, RouteRedirectSelection &, bool owner_is_mixer = false); + RedirectBox (ARDOUR::Placement, ARDOUR::Session&, + boost::shared_ptr<ARDOUR::Route>, PluginSelector &, RouteRedirectSelection &, bool owner_is_mixer = false); ~RedirectBox (); void set_width (Width); @@ -77,8 +79,8 @@ class RedirectBox : public Gtk::HBox void select_all_inserts (); void select_all_sends (); - sigc::signal<void,ARDOUR::Redirect *> RedirectSelected; - sigc::signal<void,ARDOUR::Redirect *> RedirectUnselected; + sigc::signal<void,boost::shared_ptr<ARDOUR::Redirect> > RedirectSelected; + sigc::signal<void,boost::shared_ptr<ARDOUR::Redirect> > RedirectUnselected; static void register_actions(); @@ -86,7 +88,7 @@ class RedirectBox : public Gtk::HBox void set_stuff_from_route (); private: - ARDOUR::Route & _route; + boost::shared_ptr<ARDOUR::Route> _route; ARDOUR::Session & _session; bool _owner_is_mixer; @@ -102,7 +104,7 @@ class RedirectBox : public Gtk::HBox add (color); } Gtk::TreeModelColumn<std::string> text; - Gtk::TreeModelColumn<ARDOUR::Redirect*> redirect; + Gtk::TreeModelColumn<boost::shared_ptr<ARDOUR::Redirect> > redirect; Gtk::TreeModelColumn<Gdk::Color> color; }; @@ -137,24 +139,29 @@ class RedirectBox : public Gtk::HBox void show_redirect_menu (gint arg); void choose_send (); - void send_io_finished (IOSelector::Result, ARDOUR::Redirect*, IOSelectorWindow*); + void send_io_finished (IOSelector::Result, boost::shared_ptr<ARDOUR::Redirect>, IOSelectorWindow*); void choose_insert (); void choose_plugin (); - void insert_plugin_chosen (ARDOUR::Plugin *); + void insert_plugin_chosen (boost::shared_ptr<ARDOUR::Plugin>); bool no_redirect_redisplay; bool ignore_delete; bool redirect_button_press_event (GdkEventButton *); void redisplay_redirects (void* src); - void show_redirect_active (ARDOUR::Redirect *, void *); - void show_redirect_name (void*, ARDOUR::Redirect *); - void add_redirect_to_display (ARDOUR::Redirect *); + void add_redirect_to_display (boost::shared_ptr<ARDOUR::Redirect>); void row_deleted (const Gtk::TreeModel::Path& path); + void show_redirect_name (void*, boost::shared_ptr<ARDOUR::Redirect>); + + /* these are handlers for Redirect signals, so they take Redirect* + directly, rather than shared_ptr<Redirect> + */ + + void show_redirect_active (ARDOUR::Redirect*, void *); - string redirect_name (ARDOUR::Redirect&); + string redirect_name (boost::shared_ptr<ARDOUR::Redirect>); - void remove_redirect_gui (ARDOUR::Redirect *); + void remove_redirect_gui (boost::shared_ptr<ARDOUR::Redirect>); void redirects_reordered (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator&, int*); void compute_redirect_sort_keys (); @@ -173,23 +180,23 @@ class RedirectBox : public Gtk::HBox void clone_redirects (); void rename_redirects (); - void for_selected_redirects (void (RedirectBox::*pmf)(ARDOUR::Redirect*)); - void get_selected_redirects (vector<ARDOUR::Redirect*>&); + void for_selected_redirects (void (RedirectBox::*pmf)(boost::shared_ptr<ARDOUR::Redirect>)); + void get_selected_redirects (vector<boost::shared_ptr<ARDOUR::Redirect> >&); static Glib::RefPtr<Gtk::Action> paste_action; - void paste_redirect_list (std::list<ARDOUR::Redirect*>& redirects); + void paste_redirect_list (std::list<boost::shared_ptr<ARDOUR::Redirect> >& redirects); - void activate_redirect (ARDOUR::Redirect*); - void deactivate_redirect (ARDOUR::Redirect*); - void cut_redirect (ARDOUR::Redirect*); - void copy_redirect (ARDOUR::Redirect*); - void edit_redirect (ARDOUR::Redirect*); - void hide_redirect_editor (ARDOUR::Redirect*); - void rename_redirect (ARDOUR::Redirect*); + void activate_redirect (boost::shared_ptr<ARDOUR::Redirect>); + void deactivate_redirect (boost::shared_ptr<ARDOUR::Redirect>); + void cut_redirect (boost::shared_ptr<ARDOUR::Redirect>); + void copy_redirect (boost::shared_ptr<ARDOUR::Redirect>); + void edit_redirect (boost::shared_ptr<ARDOUR::Redirect>); + void hide_redirect_editor (boost::shared_ptr<ARDOUR::Redirect>); + void rename_redirect (boost::shared_ptr<ARDOUR::Redirect>); - gint idle_delete_redirect (ARDOUR::Redirect *); + gint idle_delete_redirect (boost::shared_ptr<ARDOUR::Redirect>); - void wierd_plugin_dialog (ARDOUR::Plugin& p, uint32_t streams, ARDOUR::IO& io); + void wierd_plugin_dialog (ARDOUR::Plugin& p, uint32_t streams, boost::shared_ptr<ARDOUR::IO> io); static RedirectBox* _current_redirect_box; static bool enter_box (GdkEventCrossing*, RedirectBox*); diff --git a/gtk2_ardour/redirect_selection.h b/gtk2_ardour/redirect_selection.h index 3695f85c60..5bcd77cfe4 100644 --- a/gtk2_ardour/redirect_selection.h +++ b/gtk2_ardour/redirect_selection.h @@ -2,11 +2,12 @@ #define __ardour_gtk_redirect_selection_h__ #include <list> +#include <boost/shared_ptr.hpp> namespace ARDOUR { class Redirect; } -struct RedirectSelection : list<ARDOUR::Redirect*> {}; +struct RedirectSelection : list<boost::shared_ptr<ARDOUR::Redirect> > {}; #endif /* __ardour_gtk_redirect_selection_h__ */ diff --git a/gtk2_ardour/region_editor.h b/gtk2_ardour/region_editor.h index 65b0bbaa94..70590b0db5 100644 --- a/gtk2_ardour/region_editor.h +++ b/gtk2_ardour/region_editor.h @@ -15,172 +15,29 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ + $Id: /local/undo/gtk2_ardour/region_editor.h 5 2006-05-31T02:48:48.738745Z paul $ */ #ifndef __gtk_ardour_region_edit_h__ #define __gtk_ardour_region_edit_h__ -#include <map> - -#include <gtkmm/label.h> -#include <gtkmm/entry.h> -#include <gtkmm/box.h> -#include <gtkmm/togglebutton.h> -#include <gtkmm/button.h> -#include <gtkmm/arrow.h> -#include <gtkmm/frame.h> -#include <gtkmm/table.h> -#include <gtkmm/alignment.h> -#include <gtkmm/adjustment.h> -#include <gtkmm/separator.h> -#include <gtkmm/spinbutton.h> - -#include <libgnomecanvas/libgnomecanvas.h> -#include <sigc++/signal.h> - -#include "audio_clock.h" #include "ardour_dialog.h" -namespace ARDOUR { - class AudioRegion; - class Session; -} - -class AudioRegionView; +namespace ARDOUR { class Session; } -class AudioRegionEditor : public ArdourDialog +/** Just a useless stub for now... */ +class RegionEditor : public ArdourDialog { public: - AudioRegionEditor (ARDOUR::Session&, ARDOUR::AudioRegion&, AudioRegionView& rv); - ~AudioRegionEditor (); - - private: - ARDOUR::Session& _session; - ARDOUR::AudioRegion& _region; - AudioRegionView& _region_view; - - void connect_editor_events (); - - Gtk::Label name_label; - Gtk::Entry name_entry; - Gtk::HBox name_hbox; - - Gtk::HBox top_row_hbox; - Gtk::HBox top_row_button_hbox; - - Gtk::ToggleButton lock_button; - Gtk::ToggleButton mute_button; - Gtk::ToggleButton opaque_button; - Gtk::ToggleButton envelope_active_button; - Gtk::ToggleButton envelope_view_button; - - Gtk::Button raise_button; - Gtk::Arrow raise_arrow; - Gtk::Button lower_button; - Gtk::Arrow lower_arrow; - Gtk::Frame layer_frame; - Gtk::Label layer_value_label; - Gtk::Label layer_label; - Gtk::HBox layer_hbox; - - Gtk::ToggleButton audition_button; - - Gtk::HBox lower_hbox; - - Gtk::Table time_table; - - Gtk::Label start_label; - Gtk::Label end_label; - Gtk::Label length_label; - Gtk::Alignment start_alignment; - Gtk::Alignment end_alignment; - Gtk::Alignment length_alignment; - - AudioClock start_clock; - AudioClock end_clock; - AudioClock length_clock; - AudioClock sync_offset_clock; - - Gtk::Table envelope_loop_table; - Gtk::Button loop_button; - Gtk::Label loop_label; - Gtk::Label envelope_label; - - Gtk::Table fade_in_table; - Gtk::Label fade_in_label; - Gtk::Alignment fade_in_label_align; - Gtk::Label fade_in_active_button_label; - Gtk::ToggleButton fade_in_active_button; - Gtk::Label fade_in_length_label; - - Gtk::Adjustment fade_in_length_adjustment; - Gtk::SpinButton fade_in_length_spinner; - - Gtk::Table fade_out_table; - Gtk::Label fade_out_label; - Gtk::Alignment fade_out_label_align; - Gtk::Label fade_out_active_button_label; - Gtk::ToggleButton fade_out_active_button; - Gtk::Label fade_out_length_label; - - Gtk::Adjustment fade_out_length_adjustment; - Gtk::SpinButton fade_out_length_spinner; - - Gtk::HSeparator sep3; - Gtk::VSeparator sep1; - Gtk::VSeparator sep2; - - void region_changed (ARDOUR::Change); - void bounds_changed (ARDOUR::Change); - void name_changed (); - void opacity_changed (); - void mute_changed (); - void envelope_active_changed (); - void lock_changed (); - void layer_changed (); - - void fade_in_length_adjustment_changed (); - void fade_out_length_adjustment_changed (); - void fade_in_changed (); - void fade_out_changed (); - void audition_state_changed (bool); - - void activation (); - - void name_entry_changed (); - void start_clock_changed (); - void end_clock_changed (); - void length_clock_changed (); - - gint envelope_active_button_press (GdkEventButton *); - gint envelope_active_button_release (GdkEventButton *); - - void audition_button_toggled (); - void envelope_view_button_toggled (); - void lock_button_clicked (); - void mute_button_clicked (); - void opaque_button_clicked (); - void raise_button_clicked (); - void lower_button_clicked (); - - void fade_in_active_toggled (); - void fade_out_active_toggled (); - void fade_in_active_changed (); - void fade_out_active_changed (); - - void fade_in_realized (); - void fade_out_realized (); - - void start_editing_fade_in (); - void start_editing_fade_out (); - void stop_editing_fade_in (); - void stop_editing_fade_out (); + RegionEditor(ARDOUR::Session& s) + : ArdourDialog ("region editor") + , _session(s) + {} - gint bpressed (GdkEventButton* ev, Gtk::SpinButton* but, void (AudioRegionEditor::*pmf)()); - gint breleased (GdkEventButton* ev, Gtk::SpinButton* but, void (AudioRegionEditor::*pmf)()); + virtual ~RegionEditor () {} - bool spin_arrow_grab; + protected: + ARDOUR::Session& _session; }; #endif /* __gtk_ardour_region_edit_h__ */ diff --git a/gtk2_ardour/region_gain_line.cc b/gtk2_ardour/region_gain_line.cc index ebcf65cedd..920d2cdca9 100644 --- a/gtk2_ardour/region_gain_line.cc +++ b/gtk2_ardour/region_gain_line.cc @@ -3,7 +3,7 @@ #include <pbd/memento_command.h> #include "region_gain_line.h" -#include "regionview.h" +#include "audio_region_view.h" #include "utils.h" #include "time_axis_view.h" @@ -47,8 +47,8 @@ void AudioRegionGainLine::start_drag (ControlPoint* cp, float fraction) { AutomationLine::start_drag(cp,fraction); - if (!rv.region.envelope_active()) { - trackview.session().add_command(new MementoUndoCommand<AudioRegion>(rv.region, rv.region.get_state())); + if (!rv.audio_region().envelope_active()) { + trackview.session().add_command(new MementoUndoCommand<AudioRegion>(rv.audio_region(), rv.audio_region().get_state())); rv.region.set_envelope_active(false); } } @@ -64,11 +64,11 @@ AudioRegionGainLine::remove_point (ControlPoint& cp) trackview.editor.current_session()->begin_reversible_command (_("remove control point")); XMLNode &before = get_state(); - if (!rv.region.envelope_active()) { - XMLNode &before = rv.region.get_state(); - rv.region.set_envelope_active(true); - XMLNode &after = rv.region.get_state(); - trackview.session().add_command(new MementoCommand<AudioRegion>(rv.region, before, after)); + if (!rv.audio_region().envelope_active()) { + XMLNode &before = rv.audio_region().get_state(); + rv.audio_region().set_envelope_active(true); + XMLNode &after = rv.audio_region().get_state(); + trackview.session().add_command(new MementoCommand<AudioRegion>(rv.audio_region(), before, after)); } alist.erase (mr.start, mr.end); @@ -81,9 +81,9 @@ AudioRegionGainLine::remove_point (ControlPoint& cp) void AudioRegionGainLine::end_drag (ControlPoint* cp) { - if (!rv.region.envelope_active()) { - rv.region.set_envelope_active(true); - trackview.session().add_command(new MementoRedoCommand<AudioRegion>(rv.region, rv.region.get_state())); + if (!rv.audio_region().envelope_active()) { + rv.audio_region().set_envelope_active(true); + trackview.session().add_command(new MementoRedoCommand<AudioRegion>(rv.audio_region(), rv.audio_region().get_state())); } AutomationLine::end_drag(cp); } diff --git a/gtk2_ardour/region_selection.cc b/gtk2_ardour/region_selection.cc index 751584cab7..f8c9f384a9 100644 --- a/gtk2_ardour/region_selection.cc +++ b/gtk2_ardour/region_selection.cc @@ -1,8 +1,26 @@ +/* + Copyright (C) 2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + #include <algorithm> -#include <ardour/audioregion.h> +#include <ardour/region.h> -#include "regionview.h" +#include "region_view.h" #include "region_selection.h" using namespace ARDOUR; @@ -11,7 +29,7 @@ using namespace sigc; bool -AudioRegionComparator::operator() (const AudioRegionView* a, const AudioRegionView* b) const +RegionComparator::operator() (const RegionView* a, const RegionView* b) const { if (a == b) { return false; @@ -20,16 +38,16 @@ AudioRegionComparator::operator() (const AudioRegionView* a, const AudioRegionVi } } -AudioRegionSelection::AudioRegionSelection () +RegionSelection::RegionSelection () { _current_start = 0; _current_end = 0; } -AudioRegionSelection::AudioRegionSelection (const AudioRegionSelection& other) +RegionSelection::RegionSelection (const RegionSelection& other) { - for (AudioRegionSelection::const_iterator i = other.begin(); i != other.end(); ++i) { + for (RegionSelection::const_iterator i = other.begin(); i != other.end(); ++i) { add (*i, false); } _current_start = other._current_start; @@ -38,14 +56,14 @@ AudioRegionSelection::AudioRegionSelection (const AudioRegionSelection& other) -AudioRegionSelection& -AudioRegionSelection::operator= (const AudioRegionSelection& other) +RegionSelection& +RegionSelection::operator= (const RegionSelection& other) { if (this != &other) { clear_all(); - for (AudioRegionSelection::const_iterator i = other.begin(); i != other.end(); ++i) { + for (RegionSelection::const_iterator i = other.begin(); i != other.end(); ++i) { add (*i, false); } @@ -57,13 +75,13 @@ AudioRegionSelection::operator= (const AudioRegionSelection& other) } void -AudioRegionSelection::clear_all() +RegionSelection::clear_all() { clear(); _bylayer.clear(); } -bool AudioRegionSelection::contains (AudioRegionView* rv) +bool RegionSelection::contains (RegionView* rv) { if (this->find (rv) != end()) { return true; @@ -75,21 +93,21 @@ bool AudioRegionSelection::contains (AudioRegionView* rv) } void -AudioRegionSelection::add (AudioRegionView* rv, bool dosort) +RegionSelection::add (RegionView* rv, bool dosort) { if (this->find (rv) != end()) { /* we already have it */ return; } - rv->AudioRegionViewGoingAway.connect (mem_fun(*this, &AudioRegionSelection::remove_it)); + rv->RegionViewGoingAway.connect (mem_fun(*this, &RegionSelection::remove_it)); - if (rv->region.first_frame() < _current_start || empty()) { - _current_start = rv->region.first_frame(); + if (rv->region().first_frame() < _current_start || empty()) { + _current_start = rv->region().first_frame(); } - if (rv->region.last_frame() > _current_end || empty()) { - _current_end = rv->region.last_frame(); + if (rv->region().last_frame() > _current_end || empty()) { + _current_end = rv->region().last_frame(); } insert (rv); @@ -100,15 +118,15 @@ AudioRegionSelection::add (AudioRegionView* rv, bool dosort) } void -AudioRegionSelection::remove_it (AudioRegionView *rv) +RegionSelection::remove_it (RegionView *rv) { remove (rv); } bool -AudioRegionSelection::remove (AudioRegionView* rv) +RegionSelection::remove (RegionView* rv) { - AudioRegionSelection::iterator i; + RegionSelection::iterator i; if ((i = this->find (rv)) != end()) { @@ -124,7 +142,7 @@ AudioRegionSelection::remove (AudioRegionView* rv) } else { - AudioRegion& region ((*i)->region); + Region& region ((*i)->region()); if (region.first_frame() == _current_start) { @@ -165,15 +183,15 @@ AudioRegionSelection::remove (AudioRegionView* rv) } void -AudioRegionSelection::add_to_layer (AudioRegionView * rv) +RegionSelection::add_to_layer (RegionView * rv) { // insert it into layer sorted position - list<AudioRegionView*>::iterator i; + list<RegionView*>::iterator i; for (i = _bylayer.begin(); i != _bylayer.end(); ++i) { - if (rv->region.layer() < (*i)->region.layer()) { + if (rv->region().layer() < (*i)->region().layer()) { _bylayer.insert(i, rv); return; } @@ -184,16 +202,16 @@ AudioRegionSelection::add_to_layer (AudioRegionView * rv) } struct RegionSortByTime { - bool operator() (const AudioRegionView* a, const AudioRegionView* b) { - return a->region.position() < b->region.position(); + bool operator() (const RegionView* a, const RegionView* b) { + return a->region().position() < b->region().position(); } }; void -AudioRegionSelection::by_position (list<AudioRegionView*>& foo) const +RegionSelection::by_position (list<RegionView*>& foo) const { - list<AudioRegionView*>::const_iterator i; + list<RegionView*>::const_iterator i; RegionSortByTime sorter; for (i = _bylayer.begin(); i != _bylayer.end(); ++i) { diff --git a/gtk2_ardour/region_selection.h b/gtk2_ardour/region_selection.h index 0c2b7be025..2192442cb0 100644 --- a/gtk2_ardour/region_selection.h +++ b/gtk2_ardour/region_selection.h @@ -1,3 +1,21 @@ +/* + Copyright (C) 2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + #ifndef __ardour_gtk_region_selection_h__ #define __ardour_gtk_region_selection_h__ @@ -9,23 +27,23 @@ using std::list; using std::set; -class AudioRegionView; +class RegionView; -struct AudioRegionComparator { - bool operator() (const AudioRegionView* a, const AudioRegionView* b) const; +struct RegionComparator { + bool operator() (const RegionView* a, const RegionView* b) const; }; -class AudioRegionSelection : public set<AudioRegionView*, AudioRegionComparator>, public sigc::trackable +class RegionSelection : public set<RegionView*, RegionComparator>, public sigc::trackable { public: - AudioRegionSelection(); - AudioRegionSelection (const AudioRegionSelection&); + RegionSelection(); + RegionSelection (const RegionSelection&); - AudioRegionSelection& operator= (const AudioRegionSelection&); + RegionSelection& operator= (const RegionSelection&); - void add (AudioRegionView*, bool dosort = true); - bool remove (AudioRegionView*); - bool contains (AudioRegionView*); + void add (RegionView*, bool dosort = true); + bool remove (RegionView*); + bool contains (RegionView*); void clear_all(); @@ -39,18 +57,18 @@ class AudioRegionSelection : public set<AudioRegionView*, AudioRegionComparator> return _current_end; } - const list<AudioRegionView *> & by_layer() const { return _bylayer; } - void by_position (list<AudioRegionView*>&) const; + const list<RegionView *> & by_layer() const { return _bylayer; } + void by_position (list<RegionView*>&) const; private: - void remove_it (AudioRegionView*); + void remove_it (RegionView*); - void add_to_layer (AudioRegionView *); + void add_to_layer (RegionView *); jack_nframes_t _current_start; jack_nframes_t _current_end; - list<AudioRegionView *> _bylayer; + list<RegionView *> _bylayer; }; #endif /* __ardour_gtk_region_selection_h__ */ diff --git a/gtk2_ardour/region_view.cc b/gtk2_ardour/region_view.cc new file mode 100644 index 0000000000..ebec4261ac --- /dev/null +++ b/gtk2_ardour/region_view.cc @@ -0,0 +1,494 @@ +/* + Copyright (C) 2001-2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: regionview.cc 691 2006-07-23 12:03:19Z drobilla $ +*/ + +#include <cmath> +#include <cassert> +#include <algorithm> + +#include <gtkmm.h> + +#include <gtkmm2ext/gtk_ui.h> + +#include <ardour/playlist.h> +#include <ardour/audioregion.h> +#include <ardour/audiosource.h> +#include <ardour/audio_diskstream.h> + +#include "streamview.h" +#include "region_view.h" +#include "route_time_axis.h" +#include "simplerect.h" +#include "simpleline.h" +#include "waveview.h" +#include "public_editor.h" +#include "region_editor.h" +#include "ghostregion.h" +#include "route_time_axis.h" +#include "utils.h" +#include "rgb_macros.h" +#include "gui_thread.h" + +#include "i18n.h" + +using namespace sigc; +using namespace ARDOUR; +using namespace PBD; +using namespace Editing; +using namespace ArdourCanvas; + +static const int32_t sync_mark_width = 9; + +sigc::signal<void,RegionView*> RegionView::RegionViewGoingAway; + +RegionView::RegionView (ArdourCanvas::Group* parent, + TimeAxisView& tv, + ARDOUR::Region& r, + double spu, + Gdk::Color& basic_color) + : TimeAxisViewItem (r.name(), *parent, tv, spu, basic_color, r.position(), r.length(), + TimeAxisViewItem::Visibility (TimeAxisViewItem::ShowNameText| + TimeAxisViewItem::ShowNameHighlight| + TimeAxisViewItem::ShowFrame)) + , _region (r) + , sync_mark(0) + , no_wave_msg(0) + , editor(0) + , current_visible_sync_position(0.0) + , valid(false) + , _pixel_width(1.0) + , _height(1.0) + , in_destructor(false) + , wait_for_data(false) +{ +} + +RegionView::RegionView (ArdourCanvas::Group* parent, + TimeAxisView& tv, + ARDOUR::Region& r, + double spu, + Gdk::Color& basic_color, + TimeAxisViewItem::Visibility visibility) + : TimeAxisViewItem (r.name(), *parent, tv, spu, basic_color, r.position(), r.length(), visibility) + , _region (r) + , sync_mark(0) + , no_wave_msg(0) + , editor(0) + , current_visible_sync_position(0.0) + , valid(false) + , _pixel_width(1.0) + , _height(1.0) + , in_destructor(false) + , wait_for_data(false) +{ +} + +void +RegionView::init (Gdk::Color& basic_color, bool wfd) +{ + editor = 0; + valid = true; + in_destructor = false; + _height = 0; + wait_for_data = wfd; + + compute_colors (basic_color); + + name_highlight->set_data ("regionview", this); + name_text->set_data ("regionview", this); + + /* an equilateral triangle */ + ArdourCanvas::Points shape; + shape.push_back (Gnome::Art::Point (-((sync_mark_width-1)/2), 1)); + shape.push_back (Gnome::Art::Point ((sync_mark_width - 1)/2, 1)); + shape.push_back (Gnome::Art::Point (0, sync_mark_width - 1)); + shape.push_back (Gnome::Art::Point (-((sync_mark_width-1)/2), 1)); + + sync_mark = new ArdourCanvas::Polygon (*group); + sync_mark->property_points() = shape; + sync_mark->property_fill_color_rgba() = fill_color; + sync_mark->hide(); + + reset_width_dependent_items ((double) _region.length() / samples_per_unit); + + set_height (trackview.height); + + region_muted (); + region_sync_changed (); + region_resized (BoundsChanged); + region_locked (); + + _region.StateChanged.connect (mem_fun(*this, &RegionView::region_changed)); + + group->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_region_view_event), group, this)); + name_highlight->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_region_view_name_highlight_event), name_highlight, this)); + + set_colors (); + + ColorChanged.connect (mem_fun (*this, &RegionView::color_handler)); + + /* XXX sync mark drag? */ +} + +RegionView::~RegionView () +{ + in_destructor = true; + + RegionViewGoingAway (this); /* EMIT_SIGNAL */ + + for (vector<GhostRegion*>::iterator g = ghosts.begin(); g != ghosts.end(); ++g) { + delete *g; + } + + if (editor) { + delete editor; + } +} + +gint +RegionView::_lock_toggle (ArdourCanvas::Item* item, GdkEvent* ev, void* arg) +{ + switch (ev->type) { + case GDK_BUTTON_RELEASE: + static_cast<RegionView*>(arg)->lock_toggle (); + return TRUE; + break; + default: + break; + } + return FALSE; +} + +void +RegionView::lock_toggle () +{ + _region.set_locked (!_region.locked()); +} + +void +RegionView::region_changed (Change what_changed) +{ + ENSURE_GUI_THREAD (bind (mem_fun(*this, &RegionView::region_changed), what_changed)); + + if (what_changed & BoundsChanged) { + region_resized (what_changed); + region_sync_changed (); + } + if (what_changed & Region::MuteChanged) { + region_muted (); + } + if (what_changed & Region::OpacityChanged) { + region_opacity (); + } + if (what_changed & ARDOUR::NameChanged) { + region_renamed (); + } + if (what_changed & Region::SyncOffsetChanged) { + region_sync_changed (); + } + if (what_changed & Region::LayerChanged) { + region_layered (); + } + if (what_changed & Region::LockChanged) { + region_locked (); + } +} + +void +RegionView::region_locked () +{ + /* name will show locked status */ + region_renamed (); +} + +void +RegionView::region_resized (Change what_changed) +{ + double unit_length; + + if (what_changed & ARDOUR::PositionChanged) { + set_position (_region.position(), 0); + } + + if (what_changed & Change (StartChanged|LengthChanged)) { + + set_duration (_region.length(), 0); + + unit_length = _region.length() / samples_per_unit; + + reset_width_dependent_items (unit_length); + + for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { + + (*i)->set_duration (unit_length); + + } + } +} + +void +RegionView::reset_width_dependent_items (double pixel_width) +{ + TimeAxisViewItem::reset_width_dependent_items (pixel_width); + _pixel_width = pixel_width; +} + +void +RegionView::region_layered () +{ + RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*>(&get_time_axis_view()); + assert(rtv); + rtv->view()->region_layered (this); +} + +void +RegionView::region_muted () +{ + set_frame_color (); + region_renamed (); +} + +void +RegionView::region_opacity () +{ + set_frame_color (); +} + +void +RegionView::raise () +{ + _region.raise (); +} + +void +RegionView::raise_to_top () +{ + _region.raise_to_top (); +} + +void +RegionView::lower () +{ + _region.lower (); +} + +void +RegionView::lower_to_bottom () +{ + _region.lower_to_bottom (); +} + +bool +RegionView::set_position (jack_nframes_t pos, void* src, double* ignored) +{ + double delta; + bool ret; + + if (!(ret = TimeAxisViewItem::set_position (pos, this, &delta))) { + return false; + } + + if (ignored) { + *ignored = delta; + } + + if (delta) { + for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { + (*i)->group->move (delta, 0.0); + } + } + + return ret; +} + +void +RegionView::set_samples_per_unit (gdouble spu) +{ + TimeAxisViewItem::set_samples_per_unit (spu); + + for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { + (*i)->set_samples_per_unit (spu); + (*i)->set_duration (_region.length() / samples_per_unit); + } + + region_sync_changed (); +} + +bool +RegionView::set_duration (jack_nframes_t frames, void *src) +{ + if (!TimeAxisViewItem::set_duration (frames, src)) { + return false; + } + + for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { + (*i)->set_duration (_region.length() / samples_per_unit); + } + + return true; +} + +void +RegionView::compute_colors (Gdk::Color& basic_color) +{ + TimeAxisViewItem::compute_colors (basic_color); +} + +void +RegionView::set_colors () +{ + TimeAxisViewItem::set_colors (); + + if (sync_mark) { + sync_mark->property_fill_color_rgba() = fill_color; + } +} + +void +RegionView::set_frame_color () +{ + if (_region.opaque()) { + fill_opacity = 180; + } else { + fill_opacity = 100; + } + + TimeAxisViewItem::set_frame_color (); +} + +void +RegionView::hide_region_editor() +{ + if (editor) { + editor->hide_all (); + } +} + +void +RegionView::region_renamed () +{ + string str; + + if (_region.locked()) { + str += '>'; + str += _region.name(); + str += '<'; + } else { + str = _region.name(); + } + + if (_region.speed_mismatch (trackview.session().frame_rate())) { + str = string ("*") + str; + } + + if (_region.muted()) { + str = string ("!") + str; + } + + set_item_name (str, this); + set_name_text (str); +} + +void +RegionView::region_sync_changed () +{ + if (sync_mark == 0) { + return; + } + + int sync_dir; + jack_nframes_t sync_offset; + + sync_offset = _region.sync_offset (sync_dir); + + /* this has to handle both a genuine change of position, a change of samples_per_unit, + and a change in the bounds of the _region. + */ + + if (sync_offset == 0) { + + /* no sync mark - its the start of the region */ + + sync_mark->hide(); + + } else { + + if ((sync_dir < 0) || ((sync_dir > 0) && (sync_offset > _region.length()))) { + + /* no sync mark - its out of the bounds of the region */ + + sync_mark->hide(); + + } else { + + /* lets do it */ + + Points points; + + //points = sync_mark->property_points().get_value(); + + double offset = sync_offset / samples_per_unit; + points.push_back (Gnome::Art::Point (offset - ((sync_mark_width-1)/2), 1)); + points.push_back (Gnome::Art::Point (offset + ((sync_mark_width-1)/2), 1)); + points.push_back (Gnome::Art::Point (offset, sync_mark_width - 1)); + points.push_back (Gnome::Art::Point (offset - ((sync_mark_width-1)/2), 1)); + sync_mark->property_points().set_value (points); + sync_mark->show(); + + } + } +} + +void +RegionView::move (double x_delta, double y_delta) +{ + if (_region.locked() || (x_delta == 0 && y_delta == 0)) { + return; + } + + get_canvas_group()->move (x_delta, y_delta); + + /* note: ghosts never leave their tracks so y_delta for them is always zero */ + + for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { + (*i)->group->move (x_delta, 0.0); + } +} + +void +RegionView::remove_ghost (GhostRegion* ghost) +{ + if (in_destructor) { + return; + } + + for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { + if (*i == ghost) { + ghosts.erase (i); + break; + } + } +} + +uint32_t +RegionView::get_fill_color () +{ + return fill_color; +} + diff --git a/gtk2_ardour/region_view.h b/gtk2_ardour/region_view.h new file mode 100644 index 0000000000..fdc69ea70e --- /dev/null +++ b/gtk2_ardour/region_view.h @@ -0,0 +1,140 @@ +/* + Copyright (C) 2001-2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __gtk_ardour_region_view_h__ +#define __gtk_ardour_region_view_h__ + +#include <vector> + +#include <libgnomecanvasmm.h> +#include <libgnomecanvasmm/polygon.h> +#include <sigc++/signal.h> +#include <ardour/region.h> + +#include "time_axis_view_item.h" +#include "automation_line.h" +#include "enums.h" +#include "waveview.h" +#include "canvas.h" +#include "color.h" + +class TimeAxisView; +class RegionEditor; +class GhostRegion; +class AutomationTimeAxisView; + +class RegionView : public TimeAxisViewItem +{ + public: + RegionView (ArdourCanvas::Group* parent, + TimeAxisView& time_view, + ARDOUR::Region& region, + double samples_per_unit, + Gdk::Color& basic_color); + + ~RegionView (); + + virtual void init (Gdk::Color& base_color, bool wait_for_data); + + ARDOUR::Region& region() const { return _region; } + + bool is_valid() const { return valid; } + void set_valid (bool yn) { valid = yn; } + + virtual void set_height (double) = 0; + virtual void set_samples_per_unit (double); + virtual bool set_duration (jack_nframes_t, void*); + + void move (double xdelta, double ydelta); + + void raise (); + void raise_to_top (); + void lower (); + void lower_to_bottom (); + + bool set_position(jack_nframes_t pos, void* src, double* delta = 0); + + virtual void show_region_editor () = 0; + virtual void hide_region_editor(); + + virtual void region_changed (ARDOUR::Change); + + virtual GhostRegion* add_ghost (AutomationTimeAxisView&) = 0; + void remove_ghost (GhostRegion*); + + uint32_t get_fill_color (); + + virtual void entered () {} + virtual void exited () {} + + static sigc::signal<void,RegionView*> RegionViewGoingAway; + sigc::signal<void> GoingAway; + + protected: + + /** Allows derived types to specify their visibility requirements + * to the TimeAxisViewItem parent class + */ + RegionView (ArdourCanvas::Group *, + TimeAxisView&, + ARDOUR::Region&, + double samples_per_unit, + Gdk::Color& basic_color, + TimeAxisViewItem::Visibility); + + virtual void region_resized (ARDOUR::Change); + void region_moved (void *); + virtual void region_muted (); + void region_locked (); + void region_opacity (); + void region_layered (); + void region_renamed (); + void region_sync_changed (); + + static gint _lock_toggle (ArdourCanvas::Item*, GdkEvent*, void*); + void lock_toggle (); + + virtual void set_colors (); + virtual void compute_colors (Gdk::Color&); + virtual void set_frame_color (); + virtual void reset_width_dependent_items (double pixel_width); + + virtual void color_handler (ColorID, uint32_t) {} + + ARDOUR::Region& _region; + + ArdourCanvas::Polygon* sync_mark; ///< polgyon for sync position + ArdourCanvas::Text* no_wave_msg; + + RegionEditor* editor; + + vector<ControlPoint *> control_points; + double current_visible_sync_position; + + bool valid; ///< see StreamView::redisplay_diskstream() + double _pixel_width; + double _height; + bool in_destructor; + + bool wait_for_data; + sigc::connection data_ready_connection; + + vector<GhostRegion*> ghosts; +}; + +#endif /* __gtk_ardour_region_view_h__ */ diff --git a/gtk2_ardour/route_params_ui.cc b/gtk2_ardour/route_params_ui.cc index d6ec7eab6c..8b47a17511 100644 --- a/gtk2_ardour/route_params_ui.cc +++ b/gtk2_ardour/route_params_ui.cc @@ -59,14 +59,10 @@ using namespace sigc; RouteParams_UI::RouteParams_UI (AudioEngine& eng) : ArdourDialog ("track/bus inspector"), engine (eng), - _route(0), track_menu(0) { pre_redirect_box = 0; post_redirect_box = 0; - _route = 0; - _pre_redirect = 0; - _post_redirect = 0; _input_iosel = 0; _output_iosel = 0; _active_pre_view = 0; @@ -163,7 +159,7 @@ RouteParams_UI::~RouteParams_UI () } void -RouteParams_UI::add_route (Route* route) +RouteParams_UI::add_route (boost::shared_ptr<Route> route) { ENSURE_GUI_THREAD(bind (mem_fun(*this, &RouteParams_UI::add_route), route)); @@ -183,22 +179,22 @@ RouteParams_UI::add_route (Route* route) void -RouteParams_UI::route_name_changed (void *src, Route *route) +RouteParams_UI::route_name_changed (void *src, boost::shared_ptr<Route> route) { ENSURE_GUI_THREAD(bind (mem_fun(*this, &RouteParams_UI::route_name_changed), src, route)); bool found = false ; TreeModel::Children rows = route_display_model->children(); for(TreeModel::Children::iterator iter = rows.begin(); iter != rows.end(); ++iter) { - if((*iter)[route_display_columns.route] == route) { + boost::shared_ptr<Route> r =(*iter)[route_display_columns.route]; + if (r == route) { (*iter)[route_display_columns.text] = route->name() ; found = true ; break; } } - if(!found) - { + if(!found) { error << _("route display list item for renamed route not found!") << endmsg; } @@ -217,8 +213,8 @@ RouteParams_UI::setup_redirect_boxes() cleanup_redirect_boxes(); // construct new redirect boxes - pre_redirect_box = new RedirectBox(PreFader, *session, *_route, *_plugin_selector, _rr_selection); - post_redirect_box = new RedirectBox(PostFader, *session, *_route, *_plugin_selector, _rr_selection); + pre_redirect_box = new RedirectBox(PreFader, *session, _route, *_plugin_selector, _rr_selection); + post_redirect_box = new RedirectBox(PostFader, *session, _route, *_plugin_selector, _rr_selection); pre_redir_hpane.pack1 (*pre_redirect_box); post_redir_hpane.pack1 (*post_redirect_box); @@ -256,13 +252,13 @@ RouteParams_UI::setup_io_frames() cleanup_io_frames(); // input - _input_iosel = new IOSelector (*session, *_route, true); + _input_iosel = new IOSelector (*session, _route, true); _input_iosel->redisplay (); input_frame.add (*_input_iosel); input_frame.show_all(); // output - _output_iosel = new IOSelector (*session, *_route, false); + _output_iosel = new IOSelector (*session, _route, false); _output_iosel->redisplay (); output_frame.add (*_output_iosel); output_frame.show_all(); @@ -322,36 +318,31 @@ RouteParams_UI::cleanup_post_view (bool stopupdate) void -RouteParams_UI::route_removed (Route *route) +RouteParams_UI::route_removed (boost::shared_ptr<Route> route) { ENSURE_GUI_THREAD(bind (mem_fun(*this, &RouteParams_UI::route_removed), route)); - /* - route_select_list.freeze (); - route_select_list.clear (); - session->foreach_route (this, &RouteParams_UI::add_route); - route_select_list.thaw (); - */ TreeModel::Children rows = route_display_model->children(); TreeModel::Children::iterator ri; for(TreeModel::Children::iterator iter = rows.begin(); iter != rows.end(); ++iter) { - if((*iter)[route_display_columns.route] == route) { + boost::shared_ptr<Route> r =(*iter)[route_display_columns.route]; + + if (r == route) { route_display_model->erase(iter); break; } } - if (route == _route) - { + if (route == _route) { cleanup_io_frames(); cleanup_pre_view(); cleanup_post_view(); cleanup_redirect_boxes(); - _route = 0; - _pre_redirect = 0; - _post_redirect = 0; + _route.reset ((Route*) 0); + _pre_redirect.reset ((Redirect*) 0); + _post_redirect.reset ((Redirect*) 0); update_title(); } } @@ -390,9 +381,9 @@ RouteParams_UI::session_gone () cleanup_post_view(); cleanup_redirect_boxes(); - _route = 0; - _pre_redirect = 0; - _post_redirect = 0; + _route.reset ((Route*) 0); + _pre_redirect.reset ((Redirect*) 0); + _post_redirect.reset ((Redirect*) 0); update_title(); ArdourDialog::session_gone(); @@ -406,7 +397,7 @@ RouteParams_UI::route_selected() TreeModel::iterator iter = selection->get_selected(); // only used with Gtk::SELECTION_SINGLE if(iter) { //If anything is selected - Route* route = (*iter)[route_display_columns.route] ; + boost::shared_ptr<Route> route = (*iter)[route_display_columns.route] ; if (_route == route) { // do nothing @@ -447,9 +438,9 @@ RouteParams_UI::route_selected() cleanup_post_view(); cleanup_redirect_boxes(); - _route = 0; - _pre_redirect = 0; - _post_redirect = 0; + _route.reset ((Route*) 0); + _pre_redirect.reset ((Redirect*) 0); + _post_redirect.reset ((Redirect *) 0); track_input_label.set_text(_("NO TRACK")); update_title(); } @@ -468,7 +459,7 @@ RouteParams_UI::route_selected() // cleanup_post_view(); // cleanup_redirect_boxes(); -// _route = 0; +// _route.reset ((Route*)0); // _pre_redirect = 0; // _post_redirect = 0; // track_input_label.set_text(_("NO TRACK")); @@ -495,8 +486,8 @@ RouteParams_UI::redirects_changed (void *src) cleanup_pre_view(); cleanup_post_view(); - _pre_redirect = 0; - _post_redirect = 0; + _pre_redirect.reset ((Redirect*) 0); + _post_redirect.reset ((Redirect*) 0); //update_title(); } @@ -520,24 +511,24 @@ RouteParams_UI::show_track_menu() void -RouteParams_UI::redirect_selected (ARDOUR::Redirect *redirect, ARDOUR::Placement place) +RouteParams_UI::redirect_selected (boost::shared_ptr<ARDOUR::Redirect> redirect, ARDOUR::Placement place) { - Insert *insert; + boost::shared_ptr<Insert> insert; if ((place == PreFader && _pre_redirect == redirect) || (place == PostFader && _post_redirect == redirect)){ return; } - if ((insert = dynamic_cast<Insert *> (redirect)) == 0) { - - Send *send; + if ((insert = boost::dynamic_pointer_cast<Insert> (redirect)) == 0) { - if ((send = dynamic_cast<Send *> (redirect)) != 0) { + boost::shared_ptr<Send> send; + + if ((send = boost::dynamic_pointer_cast<Send> (redirect)) != 0) { /* its a send */ - SendUI *send_ui = new SendUI (*send, *session); + SendUI *send_ui = new SendUI (send, *session); if (place == PreFader) { cleanup_pre_view(); @@ -560,16 +551,16 @@ RouteParams_UI::redirect_selected (ARDOUR::Redirect *redirect, ARDOUR::Placement } else { /* its an insert, though we don't know what kind yet. */ - PluginInsert *plugin_insert; - PortInsert *port_insert; + boost::shared_ptr<PluginInsert> plugin_insert; + boost::shared_ptr<PortInsert> port_insert; - if ((plugin_insert = dynamic_cast<PluginInsert *> (insert)) != 0) { + if ((plugin_insert = boost::dynamic_pointer_cast<PluginInsert> (insert)) != 0) { - PluginUI *plugin_ui = new PluginUI (session->engine(), *plugin_insert, true); + PluginUI *plugin_ui = new PluginUI (session->engine(), plugin_insert, true); if (place == PreFader) { cleanup_pre_view(); - _pre_plugin_conn = plugin_insert->plugin().GoingAway.connect (bind (mem_fun(*this, &RouteParams_UI::plugin_going_away), PreFader)); + _pre_plugin_conn = plugin_insert->plugin()->GoingAway.connect (bind (mem_fun(*this, &RouteParams_UI::plugin_going_away), PreFader)); plugin_ui->start_updating (0); _active_pre_view = plugin_ui; pre_redir_hpane.pack2 (*_active_pre_view); @@ -577,16 +568,16 @@ RouteParams_UI::redirect_selected (ARDOUR::Redirect *redirect, ARDOUR::Placement } else { cleanup_post_view(); - _post_plugin_conn = plugin_insert->plugin().GoingAway.connect (bind (mem_fun(*this, &RouteParams_UI::plugin_going_away), PostFader)); + _post_plugin_conn = plugin_insert->plugin()->GoingAway.connect (bind (mem_fun(*this, &RouteParams_UI::plugin_going_away), PostFader)); plugin_ui->start_updating (0); _active_post_view = plugin_ui; post_redir_hpane.pack2 (*_active_post_view); post_redir_hpane.show_all(); } - } else if ((port_insert = dynamic_cast<PortInsert *> (insert)) != 0) { + } else if ((port_insert = boost::dynamic_pointer_cast<PortInsert> (insert)) != 0) { - PortInsertUI *portinsert_ui = new PortInsertUI (*session, *port_insert); + PortInsertUI *portinsert_ui = new PortInsertUI (*session, port_insert); if (place == PreFader) { cleanup_pre_view(); @@ -610,8 +601,7 @@ RouteParams_UI::redirect_selected (ARDOUR::Redirect *redirect, ARDOUR::Placement if (place == PreFader) { _pre_redirect = redirect; - } - else { + } else { _post_redirect = redirect; } @@ -620,23 +610,6 @@ RouteParams_UI::redirect_selected (ARDOUR::Redirect *redirect, ARDOUR::Placement } void -RouteParams_UI::redirect_unselected (ARDOUR::Redirect *redirect) -{ - // not called anymore - - if (redirect == _pre_redirect) { - cleanup_pre_view(); - _pre_redirect = 0; - } - else if (redirect == _post_redirect) { - cleanup_post_view(); - _post_redirect = 0; - } -} - - - -void RouteParams_UI::plugin_going_away (Plugin *plugin, Placement place) { ENSURE_GUI_THREAD(bind (mem_fun(*this, &RouteParams_UI::plugin_going_away), plugin, place)); @@ -645,11 +618,11 @@ RouteParams_UI::plugin_going_away (Plugin *plugin, Placement place) if (place == PreFader) { cleanup_pre_view (false); - _pre_redirect = 0; + _pre_redirect.reset ((Redirect*) 0); } else { cleanup_post_view (false); - _post_redirect = 0; + _post_redirect.reset ((Redirect*) 0); } } @@ -661,13 +634,13 @@ RouteParams_UI::redirect_going_away (ARDOUR::Redirect *plugin) printf ("redirect going away\n"); // delete the current view without calling finish - if (plugin == _pre_redirect) { + if (plugin == _pre_redirect.get()) { cleanup_pre_view (false); - _pre_redirect = 0; + _pre_redirect.reset ((Redirect*) 0); } - else if (plugin == _post_redirect) { + else if (plugin == _post_redirect.get()) { cleanup_post_view (false); - _post_redirect = 0; + _post_redirect.reset ((Redirect*) 0); } } diff --git a/gtk2_ardour/route_params_ui.h b/gtk2_ardour/route_params_ui.h index 96b2041db4..5f487d6e5c 100644 --- a/gtk2_ardour/route_params_ui.h +++ b/gtk2_ardour/route_params_ui.h @@ -33,8 +33,9 @@ #include <gtkmm/togglebutton.h> #include <gtkmm/treeview.h> +#include <pbd/stateful.h> + #include <ardour/ardour.h> -#include <ardour/stateful.h> #include <ardour/io.h> #include <ardour/redirect.h> @@ -120,14 +121,14 @@ class RouteParams_UI : public ArdourDialog PluginSelector *_plugin_selector; RouteRedirectSelection _rr_selection; - ARDOUR::Route *_route; + boost::shared_ptr<ARDOUR::Route> _route; sigc::connection _route_conn; sigc::connection _route_ds_conn; - ARDOUR::Redirect * _pre_redirect; + boost::shared_ptr<ARDOUR::Redirect> _pre_redirect; sigc::connection _pre_plugin_conn; - ARDOUR::Redirect * _post_redirect; + boost::shared_ptr<ARDOUR::Redirect> _post_redirect; sigc::connection _post_plugin_conn; @@ -150,7 +151,7 @@ class RouteParams_UI : public ArdourDialog add(route); } Gtk::TreeModelColumn<Glib::ustring> text; - Gtk::TreeModelColumn<ARDOUR::Route*> route; + Gtk::TreeModelColumn<boost::shared_ptr<ARDOUR::Route> > route; }; RouteDisplayModelColumns route_display_columns ; @@ -158,10 +159,10 @@ class RouteParams_UI : public ArdourDialog Glib::RefPtr<Gtk::ListStore> route_display_model; - void add_route (ARDOUR::Route*); + void add_route (boost::shared_ptr<ARDOUR::Route>); - void route_name_changed (void *src, ARDOUR::Route *route); - void route_removed (ARDOUR::Route *route); + void route_name_changed (void *src, boost::shared_ptr<ARDOUR::Route> route); + void route_removed (boost::shared_ptr<ARDOUR::Route> route); void route_selected(); @@ -179,8 +180,7 @@ class RouteParams_UI : public ArdourDialog void setup_redirect_boxes(); void cleanup_redirect_boxes(); - void redirect_selected (ARDOUR::Redirect *, ARDOUR::Placement); - void redirect_unselected (ARDOUR::Redirect *); + void redirect_selected (boost::shared_ptr<ARDOUR::Redirect>, ARDOUR::Placement); void plugin_going_away (ARDOUR::Plugin *foo, ARDOUR::Placement); void redirect_going_away (ARDOUR::Redirect *foo); diff --git a/gtk2_ardour/route_redirect_selection.cc b/gtk2_ardour/route_redirect_selection.cc index 6d315e0aae..76f202dd92 100644 --- a/gtk2_ardour/route_redirect_selection.cc +++ b/gtk2_ardour/route_redirect_selection.cc @@ -61,17 +61,6 @@ RouteRedirectSelection::clear () void RouteRedirectSelection::clear_redirects () { - for (RedirectSelection::iterator i = redirects.begin(); i != redirects.end(); ) { - RedirectSelection::iterator tmp; - - tmp = i; - ++tmp; - - delete *i; - - i = tmp; - } - redirects.clear (); RedirectsChanged (); } @@ -84,29 +73,32 @@ RouteRedirectSelection::clear_routes () } void -RouteRedirectSelection::add (Redirect* r) +RouteRedirectSelection::add (boost::shared_ptr<Redirect> r) { if (find (redirects.begin(), redirects.end(), r) == redirects.end()) { redirects.push_back (r); - - void (RouteRedirectSelection::*pmf)(Redirect*) = &RouteRedirectSelection::remove; - r->GoingAway.connect (mem_fun(*this, pmf)); + + // XXX SHAREDPTR FIXME + // void (RouteRedirectSelection::*pmf)(Redirect*) = &RouteRedirectSelection::remove; + // r->GoingAway.connect (mem_fun(*this, pmf)); RedirectsChanged(); } } void -RouteRedirectSelection::add (const vector<Redirect*>& rlist) +RouteRedirectSelection::add (const vector<boost::shared_ptr<Redirect> >& rlist) { bool changed = false; - for (vector<Redirect*>::const_iterator i = rlist.begin(); i != rlist.end(); ++i) { + for (vector<boost::shared_ptr<Redirect> >::const_iterator i = rlist.begin(); i != rlist.end(); ++i) { if (find (redirects.begin(), redirects.end(), *i) == redirects.end()) { redirects.push_back (*i); - void (RouteRedirectSelection::*pmf)(Redirect*) = &RouteRedirectSelection::remove; - (*i)->GoingAway.connect (mem_fun(*this, pmf)); + // XXX SHAREDPTR FIXME + + //void (RouteRedirectSelection::*pmf)(Redirect*) = &RouteRedirectSelection::remove; + // (*i)->GoingAway.connect (mem_fun(*this, pmf)); changed = true; } } @@ -117,9 +109,9 @@ RouteRedirectSelection::add (const vector<Redirect*>& rlist) } void -RouteRedirectSelection::remove (Redirect* r) +RouteRedirectSelection::remove (boost::shared_ptr<Redirect> r) { - list<Redirect*>::iterator i; + list<boost::shared_ptr<Redirect> >::iterator i; if ((i = find (redirects.begin(), redirects.end(), r)) != redirects.end()) { redirects.erase (i); RedirectsChanged (); @@ -127,36 +119,37 @@ RouteRedirectSelection::remove (Redirect* r) } void -RouteRedirectSelection::set (Redirect *r) +RouteRedirectSelection::set (boost::shared_ptr<Redirect> r) { clear_redirects (); add (r); } void -RouteRedirectSelection::set (const vector<Redirect*>& rlist) +RouteRedirectSelection::set (const vector<boost::shared_ptr<Redirect> >& rlist) { clear_redirects (); add (rlist); } void -RouteRedirectSelection::add (Route* r) +RouteRedirectSelection::add (boost::shared_ptr<Route> r) { if (find (routes.begin(), routes.end(), r) == routes.end()) { routes.push_back (r); - void (RouteRedirectSelection::*pmf)(Route*) = &RouteRedirectSelection::remove; - r->GoingAway.connect (bind (mem_fun(*this, pmf), r)); + // XXX SHAREDPTR FIXME + // void (RouteRedirectSelection::*pmf)(Route*) = &RouteRedirectSelection::remove; + // r->GoingAway.connect (bind (mem_fun(*this, pmf), r)); RoutesChanged(); } } void -RouteRedirectSelection::remove (Route* r) +RouteRedirectSelection::remove (boost::shared_ptr<Route> r) { - list<Route*>::iterator i; + list<boost::shared_ptr<Route> >::iterator i; if ((i = find (routes.begin(), routes.end(), r)) != routes.end()) { routes.erase (i); RoutesChanged (); @@ -164,16 +157,16 @@ RouteRedirectSelection::remove (Route* r) } void -RouteRedirectSelection::set (Route *r) +RouteRedirectSelection::set (boost::shared_ptr<Route> r) { clear_routes (); add (r); } bool -RouteRedirectSelection::selected (Route* ms) +RouteRedirectSelection::selected (boost::shared_ptr<Route> r) { - return find (routes.begin(), routes.end(), ms) != routes.end(); + return find (routes.begin(), routes.end(), r) != routes.end(); } bool diff --git a/gtk2_ardour/route_redirect_selection.h b/gtk2_ardour/route_redirect_selection.h index 9e2b866171..60d301e762 100644 --- a/gtk2_ardour/route_redirect_selection.h +++ b/gtk2_ardour/route_redirect_selection.h @@ -43,20 +43,20 @@ class RouteRedirectSelection : public sigc::trackable void clear (); bool empty(); - void set (ARDOUR::Redirect*); - void set (const std::vector<ARDOUR::Redirect*>&); - void add (ARDOUR::Redirect*); - void add (const std::vector<ARDOUR::Redirect*>&); - void remove (ARDOUR::Redirect*); + void set (boost::shared_ptr<ARDOUR::Redirect>); + void set (const std::vector<boost::shared_ptr<ARDOUR::Redirect> >&); + void add (boost::shared_ptr<ARDOUR::Redirect>); + void add (const std::vector<boost::shared_ptr<ARDOUR::Redirect> >&); + void remove (boost::shared_ptr<ARDOUR::Redirect>); - void set (ARDOUR::Route*); - void add (ARDOUR::Route*); - void remove (ARDOUR::Route*); + void set (boost::shared_ptr<ARDOUR::Route>); + void add (boost::shared_ptr<ARDOUR::Route>); + void remove (boost::shared_ptr<ARDOUR::Route>); void clear_redirects (); void clear_routes (); - bool selected (ARDOUR::Route*); + bool selected (boost::shared_ptr<ARDOUR::Route>); }; bool operator==(const RouteRedirectSelection& a, const RouteRedirectSelection& b); diff --git a/gtk2_ardour/route_selection.h b/gtk2_ardour/route_selection.h index 50797deed3..8d5673a2ef 100644 --- a/gtk2_ardour/route_selection.h +++ b/gtk2_ardour/route_selection.h @@ -1,12 +1,14 @@ #ifndef __ardour_gtk_route_selection_h__ #define __ardour_gtk_route_selection_h__ + +#include <boost/shared_ptr.hpp> #include <list> namespace ARDOUR { class Route; } -struct RouteSelection : list<ARDOUR::Route*> {}; +struct RouteSelection : std::list<boost::shared_ptr<ARDOUR::Route> > {}; #endif /* __ardour_gtk_route_selection_h__ */ diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc new file mode 100644 index 0000000000..8dca7be480 --- /dev/null +++ b/gtk2_ardour/route_time_axis.cc @@ -0,0 +1,1601 @@ +/* + Copyright (C) 2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <cstdlib> +#include <cmath> +#include <cassert> + +#include <algorithm> +#include <string> +#include <vector> + +#include <sigc++/bind.h> + +#include <pbd/error.h> +#include <pbd/stl_delete.h> +#include <pbd/whitespace.h> + +#include <gtkmm/menu.h> +#include <gtkmm/menuitem.h> +#include <gtkmm2ext/gtk_ui.h> +#include <gtkmm2ext/selector.h> +#include <gtkmm2ext/stop_signal.h> +#include <gtkmm2ext/bindable_button.h> +#include <gtkmm2ext/utils.h> + +#include <ardour/playlist.h> +#include <ardour/diskstream.h> +#include <ardour/insert.h> +#include <ardour/ladspa_plugin.h> +#include <ardour/location.h> +#include <ardour/panner.h> +#include <ardour/playlist.h> +#include <ardour/session.h> +#include <ardour/session_playlist.h> +#include <ardour/utils.h> + +#include "ardour_ui.h" +#include "route_time_axis.h" +#include "automation_time_axis.h" +#include "redirect_automation_time_axis.h" +#include "redirect_automation_line.h" +#include "canvas_impl.h" +#include "crossfade_view.h" +#include "enums.h" +#include "gui_thread.h" +#include "keyboard.h" +#include "playlist_selector.h" +#include "plugin_selector.h" +#include "plugin_ui.h" +#include "point_selection.h" +#include "prompter.h" +#include "public_editor.h" +#include "region_view.h" +#include "rgb_macros.h" +#include "selection.h" +#include "simplerect.h" +#include "streamview.h" +#include "utils.h" + +#include <ardour/track.h> + +#include "i18n.h" + +using namespace ARDOUR; +using namespace PBD; +using namespace Gtk; +using namespace Editing; + + +RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::shared_ptr<Route> rt, Canvas& canvas) + : AxisView(sess), + RouteUI(rt, sess, _("m"), _("s"), _("r")), // mute, solo, and record + TimeAxisView(sess,ed,(TimeAxisView*) 0, canvas), + parent_canvas (canvas), + button_table (3, 3), + edit_group_button (_("g")), // group + playlist_button (_("p")), + size_button (_("h")), // height + automation_button (_("a")), + visual_button (_("v")) + +{ + _has_state = true; + playlist_menu = 0; + playlist_action_menu = 0; + automation_action_menu = 0; + _view = 0; + timestretch_rect = 0; + no_redraw = false; + + ignore_toggle = false; + + mute_button->set_active (false); + solo_button->set_active (false); + + mute_button->set_name ("TrackMuteButton"); + solo_button->set_name ("SoloButton"); + edit_group_button.set_name ("TrackGroupButton"); + playlist_button.set_name ("TrackPlaylistButton"); + automation_button.set_name ("TrackAutomationButton"); + size_button.set_name ("TrackSizeButton"); + visual_button.set_name ("TrackVisualButton"); + hide_button.set_name ("TrackRemoveButton"); + + hide_button.add (*(manage (new Image (get_xpm("small_x.xpm"))))); + + solo_button->signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false); + mute_button->signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false); + playlist_button.signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false); + automation_button.signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false); + size_button.signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false); + visual_button.signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false); + hide_button.signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false); + + solo_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::solo_press), false); + solo_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::solo_release), false); + mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press), false); + mute_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::mute_release), false); + edit_group_button.signal_button_release_event().connect (mem_fun(*this, &RouteTimeAxisView::edit_click), false); + playlist_button.signal_clicked().connect (mem_fun(*this, &RouteTimeAxisView::playlist_click)); + automation_button.signal_clicked().connect (mem_fun(*this, &RouteTimeAxisView::automation_click)); + size_button.signal_button_release_event().connect (mem_fun(*this, &RouteTimeAxisView::size_click), false); + visual_button.signal_clicked().connect (mem_fun(*this, &RouteTimeAxisView::visual_click)); + hide_button.signal_clicked().connect (mem_fun(*this, &RouteTimeAxisView::hide_click)); + + if (is_track()) { + rec_enable_button->set_active (false); + rec_enable_button->set_name ("TrackRecordEnableButton"); + rec_enable_button->signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false); + rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press)); + controls_table.attach (*rec_enable_button, 5, 6, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); + ARDOUR_UI::instance()->tooltips().set_tip(*rec_enable_button, _("Record")); + } + + controls_table.attach (*mute_button, 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); + controls_table.attach (*solo_button, 7, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::FILL|Gtk::EXPAND, 0, 0); + + controls_table.attach (edit_group_button, 6, 7, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); + + ARDOUR_UI::instance()->tooltips().set_tip(*solo_button,_("Solo")); + ARDOUR_UI::instance()->tooltips().set_tip(*mute_button,_("Mute")); + ARDOUR_UI::instance()->tooltips().set_tip(edit_group_button,_("Edit Group")); + ARDOUR_UI::instance()->tooltips().set_tip(size_button,_("Display Height")); + ARDOUR_UI::instance()->tooltips().set_tip(playlist_button,_("Playlist")); + ARDOUR_UI::instance()->tooltips().set_tip(automation_button, _("Automation")); + ARDOUR_UI::instance()->tooltips().set_tip(visual_button, _("Visual options")); + ARDOUR_UI::instance()->tooltips().set_tip(hide_button, _("Hide this track")); + + label_view (); + + controls_table.attach (hide_button, 0, 1, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + controls_table.attach (visual_button, 1, 2, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + controls_table.attach (size_button, 2, 3, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + controls_table.attach (automation_button, 3, 4, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + + if (is_track() && track()->mode() == ARDOUR::Normal) { + controls_table.attach (playlist_button, 5, 6, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + } + + /* remove focus from the buttons */ + + automation_button.unset_flags (Gtk::CAN_FOCUS); + solo_button->unset_flags (Gtk::CAN_FOCUS); + mute_button->unset_flags (Gtk::CAN_FOCUS); + edit_group_button.unset_flags (Gtk::CAN_FOCUS); + size_button.unset_flags (Gtk::CAN_FOCUS); + playlist_button.unset_flags (Gtk::CAN_FOCUS); + hide_button.unset_flags (Gtk::CAN_FOCUS); + visual_button.unset_flags (Gtk::CAN_FOCUS); + + /* map current state of the route */ + + update_diskstream_display (); + solo_changed(0); + mute_changed(0); + //redirects_changed (0); + //reset_redirect_automation_curves (); + y_position = -1; + + _route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)); + _route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)); + _route->redirects_changed.connect (mem_fun(*this, &RouteTimeAxisView::redirects_changed)); + _route->name_changed.connect (mem_fun(*this, &RouteTimeAxisView::route_name_changed)); + _route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)); + + if (is_track()) { + + track()->FreezeChange.connect (mem_fun(*this, &RouteTimeAxisView::map_frozen)); + track()->DiskstreamChanged.connect (mem_fun(*this, &RouteTimeAxisView::diskstream_changed)); + get_diskstream()->SpeedChanged.connect (mem_fun(*this, &RouteTimeAxisView::speed_changed)); + + /* ask for notifications of any new RegionViews */ + // FIXME: _view is NULL, but it would be nice to attach this here :/ + //_view->RegionViewAdded.connect (mem_fun(*this, &RouteTimeAxisView::region_view_added)); + //_view->attach (); + + /* pick up the correct freeze state */ + map_frozen (); + + } + + editor.ZoomChanged.connect (mem_fun(*this, &RouteTimeAxisView::reset_samples_per_unit)); + ColorChanged.connect (mem_fun (*this, &RouteTimeAxisView::color_handler)); +} + +RouteTimeAxisView::~RouteTimeAxisView () +{ + GoingAway (); /* EMIT_SIGNAL */ + + vector_delete (&redirect_automation_curves); + + for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { + delete *i; + } + + if (playlist_menu) { + delete playlist_menu; + playlist_menu = 0; + } + + if (playlist_action_menu) { + delete playlist_action_menu; + playlist_action_menu = 0; + } + + if (_view) { + delete _view; + _view = 0; + } +} + +void +RouteTimeAxisView::set_playlist (Playlist *newplaylist) +{ + Playlist *pl = playlist(); + assert(pl); + + modified_connection.disconnect (); + state_changed_connection.disconnect (); + + state_changed_connection = pl->StateChanged.connect (mem_fun(*this, &RouteTimeAxisView::playlist_state_changed)); + modified_connection = pl->Modified.connect (mem_fun(*this, &RouteTimeAxisView::playlist_modified)); +} + +void +RouteTimeAxisView::playlist_modified () +{ +} + +gint +RouteTimeAxisView::edit_click (GdkEventButton *ev) +{ + if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) { + _route->set_edit_group (0, this); + return FALSE; + } + + using namespace Menu_Helpers; + + MenuList& items = edit_group_menu.items (); + RadioMenuItem::Group group; + + items.clear (); + items.push_back (RadioMenuElem (group, _("No group"), + bind (mem_fun(*this, &RouteTimeAxisView::set_edit_group_from_menu), (RouteGroup *) 0))); + + if (_route->edit_group() == 0) { + static_cast<RadioMenuItem*>(&items.back())->set_active (); + } + + _session.foreach_edit_group (bind (mem_fun (*this, &RouteTimeAxisView::add_edit_group_menu_item), &group)); + edit_group_menu.popup (ev->button, ev->time); + + return FALSE; +} + +void +RouteTimeAxisView::add_edit_group_menu_item (RouteGroup *eg, RadioMenuItem::Group* group) +{ + using namespace Menu_Helpers; + + MenuList &items = edit_group_menu.items(); + + cerr << "adding edit group " << eg->name() << endl; + + items.push_back (RadioMenuElem (*group, eg->name(), bind (mem_fun(*this, &RouteTimeAxisView::set_edit_group_from_menu), eg))); + if (_route->edit_group() == eg) { + static_cast<RadioMenuItem*>(&items.back())->set_active (); + } +} + +void +RouteTimeAxisView::set_edit_group_from_menu (RouteGroup *eg) + +{ + _route->set_edit_group (eg, this); +} + +void +RouteTimeAxisView::playlist_state_changed (Change ignored) +{ + // ENSURE_GUI_THREAD (bind (mem_fun(*this, &RouteTimeAxisView::playlist_state_changed), ignored)); + // why are we here ? +} + +void +RouteTimeAxisView::playlist_changed () + +{ + label_view (); + + if (is_track()) { + set_playlist (dynamic_cast<Playlist*>(get_diskstream()->playlist())); + } +} + +void +RouteTimeAxisView::label_view () +{ + string x = _route->name(); + + if (x != name_entry.get_text()) { + name_entry.set_text (x); + } + + ARDOUR_UI::instance()->tooltips().set_tip (name_entry, x); +} + +void +RouteTimeAxisView::route_name_changed (void *src) +{ + editor.route_name_changed (this); + label_view (); +} + +void +RouteTimeAxisView::take_name_changed (void *src) + +{ + if (src != this) { + label_view (); + } +} + +void +RouteTimeAxisView::playlist_click () +{ + // always build a new action menu + + if (playlist_action_menu == 0) { + playlist_action_menu = new Menu; + playlist_action_menu->set_name ("ArdourContextMenu"); + } + + build_playlist_menu(playlist_action_menu); + + playlist_action_menu->popup (1, 0); +} + +void +RouteTimeAxisView::automation_click () +{ + if (automation_action_menu == 0) { + /* this seems odd, but the automation action + menu is built as part of the display menu. + */ + build_display_menu (); + } + automation_action_menu->popup (1, 0); +} + +void +RouteTimeAxisView::build_automation_action_menu () +{ + using namespace Menu_Helpers; + + automation_action_menu = manage (new Menu); + MenuList& automation_items = automation_action_menu->items(); + automation_action_menu->set_name ("ArdourContextMenu"); + + automation_items.push_back (MenuElem (_("Show all automation"), + mem_fun(*this, &RouteTimeAxisView::show_all_automation))); + + automation_items.push_back (MenuElem (_("Show existing automation"), + mem_fun(*this, &RouteTimeAxisView::show_existing_automation))); + + automation_items.push_back (MenuElem (_("Hide all automation"), + mem_fun(*this, &RouteTimeAxisView::hide_all_automation))); + + automation_items.push_back (MenuElem (_("Plugins"), subplugin_menu)); +} + +void +RouteTimeAxisView::build_display_menu () +{ + using namespace Menu_Helpers; + + /* get the size menu ready */ + + build_size_menu (); + + /* prepare it */ + + TimeAxisView::build_display_menu (); + + /* now fill it with our stuff */ + + MenuList& items = display_menu->items(); + display_menu->set_name ("ArdourContextMenu"); + + items.push_back (MenuElem (_("Height"), *size_menu)); + items.push_back (MenuElem (_("Color"), mem_fun(*this, &RouteTimeAxisView::select_track_color))); + + items.push_back (SeparatorElem()); + + build_remote_control_menu (); + items.push_back (MenuElem (_("Remote Control ID"), *remote_control_menu)); + + build_automation_action_menu (); + items.push_back (MenuElem (_("Automation"), *automation_action_menu)); + + // Hook for derived classes to add type specific stuff + items.push_back (SeparatorElem()); + append_extra_display_menu_items (); + items.push_back (SeparatorElem()); + + if (is_track()) { + + Menu* alignment_menu = manage (new Menu); + MenuList& alignment_items = alignment_menu->items(); + alignment_menu->set_name ("ArdourContextMenu"); + + RadioMenuItem::Group align_group; + + alignment_items.push_back (RadioMenuElem (align_group, _("Align with existing material"), + bind (mem_fun(*this, &RouteTimeAxisView::set_align_style), ExistingMaterial))); + align_existing_item = dynamic_cast<RadioMenuItem*>(&alignment_items.back()); + if (get_diskstream()->alignment_style() == ExistingMaterial) + align_existing_item->set_active(); + + alignment_items.push_back (RadioMenuElem (align_group, _("Align with capture time"), + bind (mem_fun(*this, &RouteTimeAxisView::set_align_style), CaptureTime))); + align_capture_item = dynamic_cast<RadioMenuItem*>(&alignment_items.back()); + if (get_diskstream()->alignment_style() == CaptureTime) + align_capture_item->set_active(); + + items.push_back (MenuElem (_("Alignment"), *alignment_menu)); + + get_diskstream()->AlignmentStyleChanged.connect ( + mem_fun(*this, &RouteTimeAxisView::align_style_changed)); + } + + items.push_back (SeparatorElem()); + items.push_back (CheckMenuElem (_("Active"), mem_fun(*this, &RouteUI::toggle_route_active))); + route_active_menu_item = dynamic_cast<CheckMenuItem *> (&items.back()); + route_active_menu_item->set_active (_route->active()); + + items.push_back (SeparatorElem()); + items.push_back (MenuElem (_("Remove"), mem_fun(*this, &RouteUI::remove_this_route))); +} + + +void +RouteTimeAxisView::show_timestretch (jack_nframes_t start, jack_nframes_t end) +{ + double x1; + double x2; + double y2; + + TimeAxisView::show_timestretch (start, end); + + hide_timestretch (); + +#if 0 + if (ts.empty()) { + return; + } + + + /* check that the time selection was made in our route, or our edit group. + remember that edit_group() == 0 implies the route is *not* in a edit group. + */ + + if (!(ts.track == this || (ts.group != 0 && ts.group == _route->edit_group()))) { + /* this doesn't apply to us */ + return; + } + + /* ignore it if our edit group is not active */ + + if ((ts.track != this) && _route->edit_group() && !_route->edit_group()->is_active()) { + return; + } +#endif + + if (timestretch_rect == 0) { + timestretch_rect = new SimpleRect (*canvas_display); + timestretch_rect->property_x1() = 0.0; + timestretch_rect->property_y1() = 0.0; + timestretch_rect->property_x2() = 0.0; + timestretch_rect->property_y2() = 0.0; + timestretch_rect->property_fill_color_rgba() = color_map[cTimeStretchFill]; + timestretch_rect->property_outline_color_rgba() = color_map[cTimeStretchOutline]; + } + + timestretch_rect->show (); + timestretch_rect->raise_to_top (); + + x1 = start / editor.get_current_zoom(); + x2 = (end - 1) / editor.get_current_zoom(); + y2 = height - 2; + + timestretch_rect->property_x1() = x1; + timestretch_rect->property_y1() = 1.0; + timestretch_rect->property_x2() = x2; + timestretch_rect->property_y2() = y2; +} + +void +RouteTimeAxisView::hide_timestretch () +{ + TimeAxisView::hide_timestretch (); + + if (timestretch_rect) { + timestretch_rect->hide (); + } +} + +void +RouteTimeAxisView::show_selection (TimeSelection& ts) +{ + +#if 0 + /* ignore it if our edit group is not active or if the selection was started + in some other track or edit group (remember that edit_group() == 0 means + that the track is not in an edit group). + */ + + if (((ts.track != this && !is_child (ts.track)) && _route->edit_group() && !_route->edit_group()->is_active()) || + (!(ts.track == this || is_child (ts.track) || (ts.group != 0 && ts.group == _route->edit_group())))) { + hide_selection (); + return; + } +#endif + + TimeAxisView::show_selection (ts); +} + +void +RouteTimeAxisView::set_height (TrackHeight h) +{ + bool height_changed = (height == 0) || (h != height_style); + + TimeAxisView::set_height (h); + + ensure_xml_node (); + + _view->set_height ((double) height); + + switch (height_style) { + case Largest: + xml_node->add_property ("track_height", "largest"); + break; + + case Large: + xml_node->add_property ("track_height", "large"); + break; + + case Larger: + xml_node->add_property ("track_height", "larger"); + break; + + case Normal: + xml_node->add_property ("track_height", "normal"); + break; + + case Smaller: + xml_node->add_property ("track_height", "smaller"); + break; + + case Small: + xml_node->add_property ("track_height", "small"); + break; + } + + switch (height_style) { + case Largest: + case Large: + case Larger: + case Normal: + show_name_entry (); + hide_name_label (); + + mute_button->show_all(); + solo_button->show_all(); + if (rec_enable_button) + rec_enable_button->show_all(); + + edit_group_button.show_all(); + hide_button.show_all(); + visual_button.show_all(); + size_button.show_all(); + automation_button.show_all(); + + if (is_track() && track()->mode() == ARDOUR::Normal) { + playlist_button.show_all(); + } + break; + + case Smaller: + show_name_entry (); + hide_name_label (); + + mute_button->show_all(); + solo_button->show_all(); + if (rec_enable_button) + rec_enable_button->show_all(); + + edit_group_button.hide (); + hide_button.hide (); + visual_button.hide (); + size_button.hide (); + automation_button.hide (); + + if (is_track() && track()->mode() == ARDOUR::Normal) { + playlist_button.hide (); + } + break; + + case Small: + hide_name_entry (); + show_name_label (); + + mute_button->hide(); + solo_button->hide(); + if (rec_enable_button) + rec_enable_button->hide(); + + edit_group_button.hide (); + hide_button.hide (); + visual_button.hide (); + size_button.hide (); + automation_button.hide (); + playlist_button.hide (); + name_label.set_text (_route->name()); + break; + } + + if (height_changed) { + /* only emit the signal if the height really changed */ + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ + } +} + +void +RouteTimeAxisView::select_track_color () +{ + if (RouteUI::choose_color ()) { + + if (_view) { + _view->apply_color (_color, StreamView::RegionColor); + } + } +} + +void +RouteTimeAxisView::reset_samples_per_unit () +{ + set_samples_per_unit (editor.get_current_zoom()); +} + +void +RouteTimeAxisView::set_samples_per_unit (double spu) +{ + double speed = 1.0; + + if (get_diskstream() != 0) { + speed = get_diskstream()->speed(); + } + + if (_view) { + _view->set_samples_per_unit (spu * speed); + } + + TimeAxisView::set_samples_per_unit (spu * speed); +} + +void +RouteTimeAxisView::align_style_changed () +{ + switch (get_diskstream()->alignment_style()) { + case ExistingMaterial: + if (!align_existing_item->get_active()) { + align_existing_item->set_active(); + } + break; + case CaptureTime: + if (!align_capture_item->get_active()) { + align_capture_item->set_active(); + } + break; + } +} + +void +RouteTimeAxisView::set_align_style (AlignStyle style) +{ + get_diskstream()->set_align_style (style); +} + +void +RouteTimeAxisView::rename_current_playlist () +{ + ArdourPrompter prompter (true); + string name; + + Diskstream *const ds = get_diskstream(); + if (!ds || ds->destructive()) + return; + + Playlist *const pl = ds->playlist(); + if (!pl) + return; + + prompter.set_prompt (_("Name for playlist")); + prompter.set_initial_text (pl->name()); + prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT); + prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false); + + switch (prompter.run ()) { + case Gtk::RESPONSE_ACCEPT: + prompter.get_result (name); + if (name.length()) { + pl->set_name (name); + } + break; + + default: + break; + } +} + +void +RouteTimeAxisView::use_copy_playlist (bool prompt) +{ + string name; + + Diskstream *const ds = get_diskstream(); + if (!ds || ds->destructive()) + return; + + Playlist *const pl = ds->playlist(); + if (!pl) + return; + + name = Playlist::bump_name (pl->name(), _session); + + if (prompt) { + + ArdourPrompter prompter (true); + + prompter.set_prompt (_("Name for Playlist")); + prompter.set_initial_text (name); + prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT); + prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false); + prompter.show_all (); + + switch (prompter.run ()) { + case Gtk::RESPONSE_ACCEPT: + prompter.get_result (name); + break; + + default: + return; + } + } + + if (name.length()) { + ds->use_copy_playlist (); + pl->set_name (name); + } +} + +void +RouteTimeAxisView::use_new_playlist (bool prompt) +{ + string name; + + Diskstream *const ds = get_diskstream(); + if (!ds || ds->destructive()) + return; + + Playlist *const pl = ds->playlist(); + if (!pl) + return; + + name = Playlist::bump_name (pl->name(), _session); + + if (prompt) { + + ArdourPrompter prompter (true); + + prompter.set_prompt (_("Name for Playlist")); + prompter.set_initial_text (name); + prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT); + prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false); + + switch (prompter.run ()) { + case Gtk::RESPONSE_ACCEPT: + prompter.get_result (name); + break; + + default: + return; + } + } + + if (name.length()) { + ds->use_new_playlist (); + pl->set_name (name); + } +} + +void +RouteTimeAxisView::clear_playlist () +{ + Diskstream *const ds = get_diskstream(); + if (!ds || ds->destructive()) + return; + + Playlist *const pl = ds->playlist(); + if (!pl) + return; + + editor.clear_playlist (*pl); +} + +void +RouteTimeAxisView::speed_changed () +{ + Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &RouteTimeAxisView::reset_samples_per_unit)); +} + +void +RouteTimeAxisView::diskstream_changed () +{ + Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &RouteTimeAxisView::update_diskstream_display)); +} + +void +RouteTimeAxisView::update_diskstream_display () +{ + if (!get_diskstream()) // bus + return; + + set_playlist (get_diskstream()->playlist()); + map_frozen (); +} + +void +RouteTimeAxisView::selection_click (GdkEventButton* ev) +{ + PublicEditor::TrackViewList* tracks = editor.get_valid_views (this, _route->edit_group()); + + switch (Keyboard::selection_type (ev->state)) { + case Selection::Toggle: + /* XXX this is not right */ + editor.get_selection().add (*tracks); + break; + + case Selection::Set: + editor.get_selection().set (*tracks); + break; + + case Selection::Extend: + /* not defined yet */ + break; + } + + delete tracks; +} + +void +RouteTimeAxisView::set_selected_points (PointSelection& points) +{ + for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) { + (*i)->set_selected_points (points); + } +} + +void +RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions) +{ + _view->set_selected_regionviews (regions); +} + +void +RouteTimeAxisView::get_selectables (jack_nframes_t start, jack_nframes_t end, double top, double bot, list<Selectable*>& results) +{ + double speed = 1.0; + + if (get_diskstream() != 0) { + speed = get_diskstream()->speed(); + } + + jack_nframes_t start_adjusted = session_frame_to_track_frame(start, speed); + jack_nframes_t end_adjusted = session_frame_to_track_frame(end, speed); + + if (_view && ((top < 0.0 && bot < 0.0)) || touched (top, bot)) { + _view->get_selectables (start_adjusted, end_adjusted, results); + } + + /* pick up visible automation tracks */ + + for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) { + if (!(*i)->hidden()) { + (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results); + } + } +} + +void +RouteTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& results) +{ + if (_view) { + _view->get_inverted_selectables (sel, results); + } + + for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) { + if (!(*i)->hidden()) { + (*i)->get_inverted_selectables (sel, results); + } + } + + return; +} + +RouteGroup* +RouteTimeAxisView::edit_group() const +{ + return _route->edit_group(); +} + +string +RouteTimeAxisView::name() const +{ + return _route->name(); +} + +Playlist * +RouteTimeAxisView::playlist () const +{ + Diskstream *ds; + + if ((ds = get_diskstream()) != 0) { + return ds->playlist(); + } else { + return 0; + } +} + +void +RouteTimeAxisView::name_entry_changed () +{ + string x; + + x = name_entry.get_text (); + + if (x == _route->name()) { + return; + } + + if (x.length() == 0) { + name_entry.set_text (_route->name()); + return; + } + + strip_whitespace_edges(x); + + if (_session.route_name_unique (x)) { + _route->set_name (x, this); + } else { + ARDOUR_UI::instance()->popup_error (_("a track already exists with that name")); + name_entry.set_text (_route->name()); + } +} + +void +RouteTimeAxisView::visual_click () +{ + popup_display_menu (0); +} + +void +RouteTimeAxisView::hide_click () +{ + editor.hide_track_in_display (*this); +} + +Region* +RouteTimeAxisView::find_next_region (jack_nframes_t pos, RegionPoint point, int32_t dir) +{ + Diskstream *stream; + Playlist *playlist; + + if ((stream = get_diskstream()) != 0 && (playlist = stream->playlist()) != 0) { + return playlist->find_next_region (pos, point, dir); + } + + return 0; +} + +bool +RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) +{ + Playlist* what_we_got; + Diskstream* ds = get_diskstream(); + Playlist* playlist; + bool ret = false; + + if (ds == 0) { + /* route is a bus, not a track */ + return false; + } + + playlist = ds->playlist(); + + + TimeSelection time (selection.time); + float speed = ds->speed(); + if (speed != 1.0f) { + for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) { + (*i).start = session_frame_to_track_frame((*i).start, speed); + (*i).end = session_frame_to_track_frame((*i).end, speed); + } + } + + switch (op) { + case Cut: + _session.add_undo (playlist->get_memento()); + if ((what_we_got = playlist->cut (time)) != 0) { + editor.get_cut_buffer().add (what_we_got); + _session.add_redo_no_execute (playlist->get_memento()); + ret = true; + } + break; + case Copy: + if ((what_we_got = playlist->copy (time)) != 0) { + editor.get_cut_buffer().add (what_we_got); + } + break; + + case Clear: + _session.add_undo (playlist->get_memento()); + if ((what_we_got = playlist->cut (time)) != 0) { + _session.add_redo_no_execute (playlist->get_memento()); + what_we_got->unref (); + ret = true; + } + break; + } + + return ret; +} + +bool +RouteTimeAxisView::paste (jack_nframes_t pos, float times, Selection& selection, size_t nth) +{ + if (!is_track()) { + return false; + } + + Playlist* playlist = get_diskstream()->playlist(); + PlaylistSelection::iterator p; + + for (p = selection.playlists.begin(); p != selection.playlists.end() && nth; ++p, --nth); + + if (p == selection.playlists.end()) { + return false; + } + + if (get_diskstream()->speed() != 1.0f) + pos = session_frame_to_track_frame(pos, get_diskstream()->speed() ); + + _session.add_undo (playlist->get_memento()); + playlist->paste (**p, pos, times); + _session.add_redo_no_execute (playlist->get_memento()); + + return true; +} + + +list<TimeAxisView*> +RouteTimeAxisView::get_child_list() +{ + + list<TimeAxisView*>redirect_children; + + for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) { + if (!(*i)->hidden()) { + redirect_children.push_back(*i); + } + } + return redirect_children; +} + + +void +RouteTimeAxisView::build_playlist_menu (Gtk::Menu * menu) +{ + using namespace Menu_Helpers; + + if (!menu || !is_track()) { + return; + } + + MenuList& playlist_items = menu->items(); + menu->set_name ("ArdourContextMenu"); + playlist_items.clear(); + + if (playlist_menu) { + delete playlist_menu; + } + playlist_menu = new Menu; + playlist_menu->set_name ("ArdourContextMenu"); + + playlist_items.push_back (MenuElem (string_compose (_("Current: %1"), get_diskstream()->playlist()->name()))); + playlist_items.push_back (SeparatorElem()); + + playlist_items.push_back (MenuElem (_("Rename"), mem_fun(*this, &RouteTimeAxisView::rename_current_playlist))); + playlist_items.push_back (SeparatorElem()); + + playlist_items.push_back (MenuElem (_("New"), mem_fun(editor, &PublicEditor::new_playlists))); + playlist_items.push_back (MenuElem (_("New Copy"), mem_fun(editor, &PublicEditor::copy_playlists))); + playlist_items.push_back (SeparatorElem()); + playlist_items.push_back (MenuElem (_("Clear Current"), mem_fun(editor, &PublicEditor::clear_playlists))); + playlist_items.push_back (SeparatorElem()); + playlist_items.push_back (MenuElem(_("Select"), mem_fun(*this, &RouteTimeAxisView::show_playlist_selector))); + +} + +void +RouteTimeAxisView::show_playlist_selector () +{ + editor.playlist_selector().show_for (this); +} + +void +RouteTimeAxisView::map_frozen () +{ + if (!is_track()) { + return; + } + + ENSURE_GUI_THREAD (mem_fun(*this, &RouteTimeAxisView::map_frozen)); + + switch (track()->freeze_state()) { + case Track::Frozen: + playlist_button.set_sensitive (false); + rec_enable_button->set_sensitive (false); + break; + default: + playlist_button.set_sensitive (true); + rec_enable_button->set_sensitive (true); + break; + } +} + +void +RouteTimeAxisView::color_handler (ColorID id, uint32_t val) +{ + switch (id) { + case cTimeStretchOutline: + timestretch_rect->property_outline_color_rgba() = val; + break; + case cTimeStretchFill: + timestretch_rect->property_fill_color_rgba() = val; + break; + default: + break; + } +} + +bool +RouteTimeAxisView::select_me (GdkEventButton* ev) +{ + editor.get_selection().add (this); + return false; +} + +void +RouteTimeAxisView::show_all_automation () +{ + no_redraw = true; + + for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { + for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { + if ((*ii)->view == 0) { + add_redirect_automation_curve ((*i)->redirect, (*ii)->what); + } + + (*ii)->menu_item->set_active (true); + } + } + + no_redraw = false; + + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ +} + +void +RouteTimeAxisView::show_existing_automation () +{ + no_redraw = true; + + for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { + for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { + if ((*ii)->view != 0) { + (*ii)->menu_item->set_active (true); + } + } + } + + no_redraw = false; + + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ +} + +void +RouteTimeAxisView::hide_all_automation () +{ + no_redraw = true; + + for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { + for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { + (*ii)->menu_item->set_active (false); + } + } + + no_redraw = false; + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ +} + + +void +RouteTimeAxisView::region_view_added (RegionView* rv) +{ + for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) { + AutomationTimeAxisView* atv; + + if ((atv = dynamic_cast<AutomationTimeAxisView*> (*i)) != 0) { + rv->add_ghost (*atv); + } + } +} + +void +RouteTimeAxisView::add_ghost_to_redirect (RegionView* rv, AutomationTimeAxisView* atv) +{ + rv->add_ghost (*atv); +} + +RouteTimeAxisView::RedirectAutomationInfo::~RedirectAutomationInfo () +{ + for (vector<RedirectAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) { + delete *i; + } +} + + +RouteTimeAxisView::RedirectAutomationNode::~RedirectAutomationNode () +{ + parent.remove_ran (this); + + if (view) { + delete view; + } +} + +void +RouteTimeAxisView::remove_ran (RedirectAutomationNode* ran) +{ + if (ran->view) { + remove_child (ran->view); + } +} + +RouteTimeAxisView::RedirectAutomationNode* +RouteTimeAxisView::find_redirect_automation_node (boost::shared_ptr<Redirect> redirect, uint32_t what) +{ + for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { + + if ((*i)->redirect == redirect) { + + for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { + if ((*ii)->what == what) { + return *ii; + } + } + } + } + + return 0; +} + +// FIXME: duplicated in midi_time_axis.cc +static string +legalize_for_xml_node (string str) +{ + string::size_type pos; + string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+=:"; + string legal; + + legal = str; + pos = 0; + + while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) { + legal.replace (pos, 1, "_"); + pos += 1; + } + + return legal; +} + + +void +RouteTimeAxisView::add_redirect_automation_curve (boost::shared_ptr<Redirect> redirect, uint32_t what) +{ + RedirectAutomationLine* ral; + string name; + RedirectAutomationNode* ran; + + if ((ran = find_redirect_automation_node (redirect, what)) == 0) { + fatal << _("programming error: ") + << string_compose (X_("redirect automation curve for %1:%2 not registered with audio track!"), + redirect->name(), what) + << endmsg; + /*NOTREACHED*/ + return; + } + + if (ran->view) { + return; + } + + name = redirect->describe_parameter (what); + + /* create a string that is a legal XML node name that can be used to refer to this redirect+port combination */ + + char state_name[256]; + snprintf (state_name, sizeof (state_name), "Redirect-%s-%" PRIu32, legalize_for_xml_node (redirect->name()).c_str(), what); + + ran->view = new RedirectAutomationTimeAxisView (_session, _route, editor, *this, parent_canvas, name, what, *redirect, state_name); + + ral = new RedirectAutomationLine (name, + *redirect, what, _session, *ran->view, + *ran->view->canvas_display, redirect->automation_list (what)); + + ral->set_line_color (color_map[cRedirectAutomationLine]); + ral->queue_reset (); + + ran->view->add_line (*ral); + + ran->view->Hiding.connect (bind (mem_fun(*this, &RouteTimeAxisView::redirect_automation_track_hidden), ran, redirect)); + + if (!ran->view->marked_for_display()) { + ran->view->hide (); + } else { + ran->menu_item->set_active (true); + } + + add_child (ran->view); + + _view->foreach_regionview (bind (mem_fun(*this, &RouteTimeAxisView::add_ghost_to_redirect), ran->view)); + + redirect->mark_automation_visible (what, true); +} + +void +RouteTimeAxisView::redirect_automation_track_hidden (RouteTimeAxisView::RedirectAutomationNode* ran, boost::shared_ptr<Redirect> r) +{ + if (!_hidden) { + ran->menu_item->set_active (false); + } + + r->mark_automation_visible (ran->what, false); + + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ +} + +void +RouteTimeAxisView::add_existing_redirect_automation_curves (boost::shared_ptr<Redirect> redirect) +{ + set<uint32_t> s; + RedirectAutomationLine *ral; + + redirect->what_has_visible_automation (s); + + for (set<uint32_t>::iterator i = s.begin(); i != s.end(); ++i) { + + if ((ral = find_redirect_automation_curve (redirect, *i)) != 0) { + ral->queue_reset (); + } else { + add_redirect_automation_curve (redirect, (*i)); + } + } +} + +void +RouteTimeAxisView::add_redirect_to_subplugin_menu (boost::shared_ptr<Redirect> r) +{ + using namespace Menu_Helpers; + RedirectAutomationInfo *rai; + list<RedirectAutomationInfo*>::iterator x; + + const std::set<uint32_t>& automatable = r->what_can_be_automated (); + std::set<uint32_t> has_visible_automation; + + r->what_has_visible_automation(has_visible_automation); + + if (automatable.empty()) { + return; + } + + for (x = redirect_automation.begin(); x != redirect_automation.end(); ++x) { + if ((*x)->redirect == r) { + break; + } + } + + if (x == redirect_automation.end()) { + + rai = new RedirectAutomationInfo (r); + redirect_automation.push_back (rai); + + } else { + + rai = *x; + + } + + /* any older menu was deleted at the top of redirects_changed() + when we cleared the subplugin menu. + */ + + rai->menu = manage (new Menu); + MenuList& items = rai->menu->items(); + rai->menu->set_name ("ArdourContextMenu"); + + items.clear (); + + for (std::set<uint32_t>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) { + + RedirectAutomationNode* ran; + CheckMenuItem* mitem; + + string name = r->describe_parameter (*i); + + items.push_back (CheckMenuElem (name)); + mitem = dynamic_cast<CheckMenuItem*> (&items.back()); + + if (has_visible_automation.find((*i)) != has_visible_automation.end()) { + mitem->set_active(true); + } + + if ((ran = find_redirect_automation_node (r, *i)) == 0) { + + /* new item */ + + ran = new RedirectAutomationNode (*i, mitem, *this); + + rai->lines.push_back (ran); + + } else { + + ran->menu_item = mitem; + + } + + mitem->signal_toggled().connect (bind (mem_fun(*this, &RouteTimeAxisView::redirect_menu_item_toggled), rai, ran)); + } + + /* add the menu for this redirect, because the subplugin + menu is always cleared at the top of redirects_changed(). + this is the result of some poor design in gtkmm and/or + GTK+. + */ + + subplugin_menu.items().push_back (MenuElem (r->name(), *rai->menu)); + rai->valid = true; +} + +void +RouteTimeAxisView::redirect_menu_item_toggled (RouteTimeAxisView::RedirectAutomationInfo* rai, + RouteTimeAxisView::RedirectAutomationNode* ran) +{ + bool showit = ran->menu_item->get_active(); + bool redraw = false; + + if (ran->view == 0 && showit) { + add_redirect_automation_curve (rai->redirect, ran->what); + redraw = true; + } + + if (showit != ran->view->marked_for_display()) { + + if (showit) { + ran->view->set_marked_for_display (true); + ran->view->canvas_display->show(); + } else { + rai->redirect->mark_automation_visible (ran->what, true); + ran->view->set_marked_for_display (false); + ran->view->hide (); + } + + redraw = true; + + } + + if (redraw && !no_redraw) { + + /* now trigger a redisplay */ + + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ + + } +} + +void +RouteTimeAxisView::redirects_changed (void *src) +{ + using namespace Menu_Helpers; + + for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { + (*i)->valid = false; + } + + subplugin_menu.items().clear (); + + _route->foreach_redirect (this, &RouteTimeAxisView::add_redirect_to_subplugin_menu); + _route->foreach_redirect (this, &RouteTimeAxisView::add_existing_redirect_automation_curves); + + for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ) { + + list<RedirectAutomationInfo*>::iterator tmp; + + tmp = i; + ++tmp; + + if (!(*i)->valid) { + + delete *i; + redirect_automation.erase (i); + + } + + i = tmp; + } + + /* change in visibility was possible */ + + _route->gui_changed ("track_height", this); +} + +RedirectAutomationLine * +RouteTimeAxisView::find_redirect_automation_curve (boost::shared_ptr<Redirect> redirect, uint32_t what) +{ + RedirectAutomationNode* ran; + + if ((ran = find_redirect_automation_node (redirect, what)) != 0) { + if (ran->view) { + return dynamic_cast<RedirectAutomationLine*> (ran->view->lines.front()); + } + } + + return 0; +} + +void +RouteTimeAxisView::reset_redirect_automation_curves () +{ + for (vector<RedirectAutomationLine*>::iterator i = redirect_automation_curves.begin(); i != redirect_automation_curves.end(); ++i) { + (*i)->reset(); + } +} + diff --git a/gtk2_ardour/route_time_axis.h b/gtk2_ardour/route_time_axis.h new file mode 100644 index 0000000000..d305fd390c --- /dev/null +++ b/gtk2_ardour/route_time_axis.h @@ -0,0 +1,256 @@ +/* + Copyright (C) 2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: audio_time_axis.h 664 2006-07-05 19:47:25Z drobilla $ +*/ + +#ifndef __ardour_route_time_axis_h__ +#define __ardour_route_time_axis_h__ + +#include <gtkmm/table.h> +#include <gtkmm/button.h> +#include <gtkmm/box.h> +#include <gtkmm/menu.h> +#include <gtkmm/menuitem.h> +#include <gtkmm/radiomenuitem.h> +#include <gtkmm/checkmenuitem.h> + +#include <gtkmm2ext/selector.h> +#include <list> + +#include <ardour/types.h> + +#include "ardour_dialog.h" +#include "route_ui.h" +#include "enums.h" +#include "time_axis_view.h" +#include "canvas.h" +#include "color.h" + +namespace ARDOUR { + class Session; + class Region; + class Diskstream; + class RouteGroup; + class Redirect; + class Insert; + class Location; + class Playlist; +} + +class PublicEditor; +class RegionView; +class StreamView; +class Selection; +class RegionSelection; +class Selectable; +class AutomationTimeAxisView; +class AutomationLine; +class RedirectAutomationLine; +class TimeSelection; + +class RouteTimeAxisView : public RouteUI, public TimeAxisView +{ +public: + RouteTimeAxisView (PublicEditor&, ARDOUR::Session&, boost::shared_ptr<ARDOUR::Route>, ArdourCanvas::Canvas& canvas); + virtual ~RouteTimeAxisView (); + + void show_selection (TimeSelection&); + + void set_samples_per_unit (double); + void set_height (TimeAxisView::TrackHeight); + void show_timestretch (jack_nframes_t start, jack_nframes_t end); + void hide_timestretch (); + void selection_click (GdkEventButton*); + void set_selected_points (PointSelection&); + void set_selected_regionviews (RegionSelection&); + void get_selectables (jack_nframes_t start, jack_nframes_t end, double top, double bot, list<Selectable *>&); + void get_inverted_selectables (Selection&, list<Selectable*>&); + + ARDOUR::Region* find_next_region (jack_nframes_t pos, ARDOUR::RegionPoint, int32_t dir); + + /* Editing operations */ + bool cut_copy_clear (Selection&, Editing::CutCopyOp); + bool paste (jack_nframes_t, float times, Selection&, size_t nth); + + list<TimeAxisView*> get_child_list(); + + /* The editor calls these when mapping an operation across multiple tracks */ + void use_new_playlist (bool prompt); + void use_copy_playlist (bool prompt); + void clear_playlist (); + + void build_playlist_menu (Gtk::Menu *); + + string name() const; + StreamView* view() const { return _view; } + ARDOUR::RouteGroup* edit_group() const; + ARDOUR::Playlist* playlist() const; + +protected: + friend class StreamView; + + struct RedirectAutomationNode { + uint32_t what; + Gtk::CheckMenuItem* menu_item; + AutomationTimeAxisView* view; + RouteTimeAxisView& parent; + + RedirectAutomationNode (uint32_t w, Gtk::CheckMenuItem* mitem, RouteTimeAxisView& p) + : what (w), menu_item (mitem), view (0), parent (p) {} + + ~RedirectAutomationNode (); + }; + + struct RedirectAutomationInfo { + boost::shared_ptr<ARDOUR::Redirect> redirect; + bool valid; + Gtk::Menu* menu; + vector<RedirectAutomationNode*> lines; + + RedirectAutomationInfo (boost::shared_ptr<ARDOUR::Redirect> r) + : redirect (r), valid (true), menu (0) {} + + ~RedirectAutomationInfo (); + }; + + + void diskstream_changed (); + void update_diskstream_display (); + + gint edit_click (GdkEventButton *); + + void build_redirect_window (); + void redirect_click (); + void redirect_add (); + void redirect_remove (); + void redirect_edit (); + void redirect_relist (); + void redirect_row_selected (gint row, gint col, GdkEvent *ev); + void add_to_redirect_display (ARDOUR::Redirect *); + void redirects_changed (void *); + + void add_redirect_to_subplugin_menu (boost::shared_ptr<ARDOUR::Redirect>); + void remove_ran (RedirectAutomationNode* ran); + + void redirect_menu_item_toggled (RouteTimeAxisView::RedirectAutomationInfo*, + RouteTimeAxisView::RedirectAutomationNode*); + + void redirect_automation_track_hidden (RedirectAutomationNode*, + boost::shared_ptr<ARDOUR::Redirect>); + + RedirectAutomationNode* + find_redirect_automation_node (boost::shared_ptr<ARDOUR::Redirect> r, uint32_t); + + RedirectAutomationLine* + find_redirect_automation_curve (boost::shared_ptr<ARDOUR::Redirect> r, uint32_t); + + void add_redirect_automation_curve (boost::shared_ptr<ARDOUR::Redirect> r, uint32_t); + void add_existing_redirect_automation_curves (boost::shared_ptr<ARDOUR::Redirect>); + + void reset_redirect_automation_curves (); + + void update_automation_view (ARDOUR::AutomationType); + + void take_name_changed (void *); + void route_name_changed (void *); + void name_entry_changed (); + + void on_area_realize (); + + virtual void label_view (); + + void add_edit_group_menu_item (ARDOUR::RouteGroup *, Gtk::RadioMenuItem::Group*); + void set_edit_group_from_menu (ARDOUR::RouteGroup *); + + void reset_samples_per_unit (); + + void select_track_color(); + + virtual void build_automation_action_menu (); + virtual void append_extra_display_menu_items () {} + void build_display_menu (); + + void align_style_changed (); + void set_align_style (ARDOUR::AlignStyle); + + virtual void set_playlist (ARDOUR::Playlist *); + void playlist_click (); + void show_playlist_selector (); + void playlist_changed (); + void playlist_state_changed (ARDOUR::Change); + void playlist_modified (); + + void add_playlist_to_playlist_menu (ARDOUR::Playlist*); + void rename_current_playlist (); + + void automation_click (); + virtual void show_all_automation (); + virtual void show_existing_automation (); + virtual void hide_all_automation (); + + void timestretch (jack_nframes_t start, jack_nframes_t end); + + void visual_click (); + void hide_click (); + gint when_displayed (GdkEventAny*); + + void speed_changed (); + + void map_frozen (); + + void color_handler (ColorID, uint32_t); + bool select_me (GdkEventButton*); + + void region_view_added (RegionView*); + void add_ghost_to_redirect (RegionView*, AutomationTimeAxisView*); + + + StreamView* _view; + ArdourCanvas::Canvas& parent_canvas; + bool no_redraw; + + Gtk::HBox other_button_hbox; + Gtk::Table button_table; + Gtk::Button redirect_button; + Gtk::Button edit_group_button; + Gtk::Button playlist_button; + Gtk::Button size_button; + Gtk::Button automation_button; + Gtk::Button hide_button; + Gtk::Button visual_button; + + Gtk::Menu subplugin_menu; + Gtk::Menu* automation_action_menu; + Gtk::Menu edit_group_menu; + Gtk::RadioMenuItem* align_existing_item; + Gtk::RadioMenuItem* align_capture_item; + Gtk::Menu* playlist_menu; + Gtk::Menu* playlist_action_menu; + Gtk::MenuItem* playlist_item; + + ArdourCanvas::SimpleRect* timestretch_rect; + + list<RedirectAutomationInfo*> redirect_automation; + vector<RedirectAutomationLine*> redirect_automation_curves; + + sigc::connection modified_connection; + sigc::connection state_changed_connection; +}; + +#endif /* __ardour_route_time_axis_h__ */ + diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc index 988d6c8b19..8a1fb1c21a 100644 --- a/gtk2_ardour/route_ui.cc +++ b/gtk2_ardour/route_ui.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2002 Paul Davis + Copyright (C) 2002-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,8 +21,8 @@ #include <gtkmm2ext/gtk_ui.h> #include <gtkmm2ext/stop_signal.h> #include <gtkmm2ext/choice.h> -#include <gtkmm2ext/bindable_button.h> #include <gtkmm2ext/doi.h> +#include <gtkmm2ext/bindable_button.h> #include <ardour/route_group.h> #include <pbd/memento_command.h> @@ -45,9 +45,9 @@ using namespace ARDOUR; using namespace PBD; -RouteUI::RouteUI (ARDOUR::Route& rt, ARDOUR::Session& sess, const char* m_name, +RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, const char* m_name, const char* s_name, const char* r_name) - : AxisView(sess), + : AxisView(sess), _route(rt), mute_button(0), solo_button(0), @@ -65,35 +65,31 @@ RouteUI::RouteUI (ARDOUR::Route& rt, ARDOUR::Session& sess, const char* m_name, set_color (unique_random_color()); } - _route.GoingAway.connect (mem_fun (*this, &RouteUI::route_removed)); - _route.active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)); + _route->GoingAway.connect (mem_fun (*this, &RouteUI::route_removed)); + _route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)); - mute_button = manage (new BindableToggleButton (& _route.midi_mute_control(), m_name )); - mute_button->set_bind_button_state (2, GDK_CONTROL_MASK); - solo_button = manage (new BindableToggleButton (& _route.midi_solo_control(), s_name )); - solo_button->set_bind_button_state (2, GDK_CONTROL_MASK); - - if (is_audio_track()) { - AudioTrack* at = dynamic_cast<AudioTrack*>(&_route); + mute_button = manage (new BindableToggleButton (_route->mute_control(), m_name )); + solo_button = manage (new BindableToggleButton (_route->solo_control(), s_name )); + + if (is_track()) { + boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route); - get_diskstream()->record_enable_changed.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)); + t->diskstream().RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)); _session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)); - rec_enable_button = manage (new BindableToggleButton (& at->midi_rec_enable_control(), r_name )); - rec_enable_button->set_bind_button_state (2, GDK_CONTROL_MASK); + rec_enable_button = manage (new BindableToggleButton (t->rec_enable_control(), r_name )); - } else { - rec_enable_button = manage (new BindableToggleButton (0, r_name )); - } + rec_enable_button->unset_flags (Gtk::CAN_FOCUS); + + update_rec_display (); + } mute_button->unset_flags (Gtk::CAN_FOCUS); solo_button->unset_flags (Gtk::CAN_FOCUS); - rec_enable_button->unset_flags (Gtk::CAN_FOCUS); /* map the current state */ - update_rec_display (); map_frozen (); } @@ -146,14 +142,14 @@ RouteUI::mute_press(GdkEventButton* ev) */ if (ev->button == 1) { - set_mix_group_mute (_route, !_route.muted()); + set_mix_group_mute (_route, !_route->muted()); } } else { /* plain click applies change to this route */ - reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route.muted(), this); + reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this); } } } @@ -231,7 +227,7 @@ RouteUI::solo_press(GdkEventButton* ev) // shift-click: set this route to solo safe - _route.set_solo_safe (!_route.solo_safe(), this); + _route->set_solo_safe (!_route->solo_safe(), this); wait_for_release = false; } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) { @@ -241,14 +237,14 @@ RouteUI::solo_press(GdkEventButton* ev) */ if (ev->button == 1) { - set_mix_group_solo (_route, !_route.soloed()); + set_mix_group_solo (_route, !_route->soloed()); } } else { /* click: solo this route */ - reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route.soloed(), this); + reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this); } } } @@ -276,7 +272,7 @@ RouteUI::solo_release(GdkEventButton* ev) gint RouteUI::rec_enable_press(GdkEventButton* ev) { - if (!ignore_toggle && is_audio_track()) { + if (!ignore_toggle && is_track() && rec_enable_button) { if (ev->button == 2 && Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) { // do nothing on midi bind event @@ -298,7 +294,7 @@ RouteUI::rec_enable_press(GdkEventButton* ev) } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) { - set_mix_group_rec_enable (_route, !_route.record_enabled()); + set_mix_group_rec_enable (_route, !_route->record_enabled()); } else { @@ -326,7 +322,7 @@ RouteUI::update_solo_display () { bool x; - if (solo_button->get_active() != (x = _route.soloed())){ + if (solo_button->get_active() != (x = _route->soloed())){ ignore_toggle = true; solo_button->set_active(x); ignore_toggle = false; @@ -334,7 +330,7 @@ RouteUI::update_solo_display () /* show solo safe */ - if (_route.solo_safe()){ + if (_route->solo_safe()){ solo_button->set_name(safe_solo_button_name()); } else { solo_button->set_name(solo_button_name()); @@ -352,7 +348,7 @@ RouteUI::update_mute_display () { bool x; - if (mute_button->get_active() != (x = _route.muted())){ + if (mute_button->get_active() != (x = _route->muted())){ ignore_toggle = true; mute_button->set_active(x); ignore_toggle = false; @@ -360,7 +356,7 @@ RouteUI::update_mute_display () } void -RouteUI::route_rec_enable_changed (void *src) +RouteUI::route_rec_enable_changed () { Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display)); } @@ -374,7 +370,7 @@ RouteUI::session_rec_enable_changed () void RouteUI::update_rec_display () { - bool model = _route.record_enabled(); + bool model = _route->record_enabled(); bool view = rec_enable_button->get_active(); /* first make sure the button's "depressed" visual @@ -440,7 +436,7 @@ RouteUI::refresh_remote_control_menu () limit += 4; /* leave some breathing room */ rc_items.push_back (RadioMenuElem (rc_group, _("None"))); - if (_route.remote_control_id() == 0) { + if (_route->remote_control_id() == 0) { rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back()); rc_active->set_active (); } @@ -449,7 +445,7 @@ RouteUI::refresh_remote_control_menu () snprintf (buf, sizeof (buf), "%u", i); rc_items.push_back (RadioMenuElem (rc_group, buf)); rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back()); - if (_route.remote_control_id() == i) { + if (_route->remote_control_id() == i) { rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back()); rc_active->set_active (); } @@ -467,7 +463,7 @@ RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item) */ if (item->get_active()) { - _route.set_remote_control_id (id); + _route->set_remote_control_id (id); } } @@ -482,14 +478,14 @@ RouteUI::build_solo_menu (void) CheckMenuItem* check; check = new CheckMenuItem(_("Solo-safe")); - check->set_active (_route.solo_safe()); + check->set_active (_route->solo_safe()); check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check)); - _route.solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check)); + _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check)); items.push_back (CheckMenuElem(*check)); check->show_all(); items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn))); + // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn))); } @@ -506,39 +502,39 @@ RouteUI::build_mute_menu(void) check = new CheckMenuItem(_("Pre Fader")); init_mute_menu(PRE_FADER, check); check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check)); - _route.pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check)); + _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check)); items.push_back (CheckMenuElem(*check)); check->show_all(); check = new CheckMenuItem(_("Post Fader")); init_mute_menu(POST_FADER, check); check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check)); - _route.post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check)); + _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check)); items.push_back (CheckMenuElem(*check)); check->show_all(); check = new CheckMenuItem(_("Control Outs")); init_mute_menu(CONTROL_OUTS, check); check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check)); - _route.control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check)); + _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check)); items.push_back (CheckMenuElem(*check)); check->show_all(); check = new CheckMenuItem(_("Main Outs")); init_mute_menu(MAIN_OUTS, check); check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check)); - _route.main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check)); + _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check)); items.push_back (CheckMenuElem(*check)); check->show_all(); items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn))); + // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn))); } void RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check) { - if (_route.get_mute_config (type)) { + if (_route->get_mute_config (type)) { check->set_active (true); } } @@ -546,21 +542,21 @@ RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check) void RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check) { - _route.set_mute_config(type, check->get_active(), this); + _route->set_mute_config(type, check->get_active(), this); } void RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check) { - _route.set_solo_safe (check->get_active(), this); + _route->set_solo_safe (check->get_active(), this); } void -RouteUI::set_mix_group_solo(Route& route, bool yn) +RouteUI::set_mix_group_solo(boost::shared_ptr<Route> route, bool yn) { RouteGroup* mix_group; - if((mix_group = route.mix_group()) != 0){ + if((mix_group = route->mix_group()) != 0){ _session.begin_reversible_command (_("mix group solo change")); Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this); mix_group->apply(&Route::set_solo, yn, this); @@ -568,7 +564,7 @@ RouteUI::set_mix_group_solo(Route& route, bool yn) _session.add_command (cmd); _session.commit_reversible_command (); } else { - reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route.soloed(), this); + reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this); } } @@ -595,11 +591,11 @@ RouteUI::reversibly_apply_audio_track_boolean (string name, void (AudioTrack::*f } void -RouteUI::set_mix_group_mute(Route& route, bool yn) +RouteUI::set_mix_group_mute(boost::shared_ptr<Route> route, bool yn) { RouteGroup* mix_group; - if((mix_group = route.mix_group()) != 0){ + if((mix_group = route->mix_group()) != 0){ _session.begin_reversible_command (_("mix group mute change")); Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this); mix_group->apply(&Route::set_mute, yn, this); @@ -607,16 +603,16 @@ RouteUI::set_mix_group_mute(Route& route, bool yn) _session.add_command(cmd); _session.commit_reversible_command (); } else { - reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route.muted(), this); + reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this); } } void -RouteUI::set_mix_group_rec_enable(Route& route, bool yn) +RouteUI::set_mix_group_rec_enable(boost::shared_ptr<Route> route, bool yn) { RouteGroup* mix_group; - if((mix_group = route.mix_group()) != 0){ + if((mix_group = route->mix_group()) != 0){ _session.begin_reversible_command (_("mix group rec-enable change")); Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this); mix_group->apply (&Route::set_record_enable, yn, this); @@ -624,7 +620,7 @@ RouteUI::set_mix_group_rec_enable(Route& route, bool yn) _session.add_command(cmd); _session.commit_reversible_command (); } else { - reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route.record_enabled(), this); + reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this); } } @@ -655,7 +651,7 @@ RouteUI::set_color (const Gdk::Color & c) snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue()); xml_node->add_property ("color", buf); - _route.gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */ + _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */ } @@ -663,9 +659,9 @@ void RouteUI::ensure_xml_node () { if (xml_node == 0) { - if ((xml_node = _route.extra_xml ("GUI")) == 0) { + if ((xml_node = _route->extra_xml ("GUI")) == 0) { xml_node = new XMLNode ("GUI"); - _route.add_extra_xml (*xml_node); + _route->add_extra_xml (*xml_node); } } } @@ -710,10 +706,10 @@ RouteUI::remove_this_route () vector<string> choices; string prompt; - if (is_audio_track()) { - prompt = string_compose (_("Do you really want to remove track \"%1\" ?\n\nYou may also lose the playlist used by this track.\n(cannot be undone)"), _route.name()); + if (is_track()) { + prompt = string_compose (_("Do you really want to remove track \"%1\" ?\n\nYou may also lose the playlist used by this track.\n(cannot be undone)"), _route->name()); } else { - prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route.name()); + prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name()); } choices.push_back (_("No, do nothing.")); @@ -747,7 +743,7 @@ RouteUI::route_rename () ArdourPrompter name_prompter (true); string result; name_prompter.set_prompt (_("New Name: ")); - name_prompter.set_initial_text (_route.name()); + name_prompter.set_initial_text (_route->name()); name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT); name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false); name_prompter.show_all (); @@ -757,7 +753,7 @@ RouteUI::route_rename () case Gtk::RESPONSE_ACCEPT: name_prompter.get_result (result); if (result.length()) { - _route.set_name (result, this); + _route->set_name (result, this); } break; } @@ -771,7 +767,7 @@ RouteUI::name_changed (void *src) { ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::name_changed), src)); - name_label.set_text (_route.name()); + name_label.set_text (_route->name()); } void @@ -780,8 +776,8 @@ RouteUI::toggle_route_active () bool yn; if (route_active_menu_item) { - if (route_active_menu_item->get_active() != (yn = _route.active())) { - _route.set_active (!yn); + if (route_active_menu_item->get_active() != (yn = _route->active())) { + _route->set_active (!yn); } } } @@ -790,7 +786,7 @@ void RouteUI::route_active_changed () { if (route_active_menu_item) { - Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route.active())); + Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active())); } } @@ -803,12 +799,12 @@ RouteUI::toggle_polarity () ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity)); - if ((x = polarity_menu_item->get_active()) != _route.phase_invert()) { - _route.set_phase_invert (x, this); + if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) { + _route->set_phase_invert (x, this); if (x) { name_label.set_text (X_("Ø ") + name_label.get_text()); } else { - name_label.set_text (_route.name()); + name_label.set_text (_route->name()); } } } @@ -823,7 +819,7 @@ RouteUI::polarity_changed () void RouteUI::solo_safe_toggle(void* src, Gtk::CheckMenuItem* check) { - bool yn = _route.solo_safe (); + bool yn = _route->solo_safe (); if (check->get_active() != yn) { check->set_active (yn); @@ -834,7 +830,7 @@ RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check) { ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check)); - bool yn = _route.get_mute_config(PRE_FADER); + bool yn = _route->get_mute_config(PRE_FADER); if (check->get_active() != yn) { check->set_active (yn); } @@ -845,7 +841,7 @@ RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check) { ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check)); - bool yn = _route.get_mute_config(POST_FADER); + bool yn = _route->get_mute_config(POST_FADER); if (check->get_active() != yn) { check->set_active (yn); } @@ -856,7 +852,7 @@ RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check) { ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check)); - bool yn = _route.get_mute_config(CONTROL_OUTS); + bool yn = _route->get_mute_config(CONTROL_OUTS); if (check->get_active() != yn) { check->set_active (yn); } @@ -867,7 +863,7 @@ RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check) { ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check)); - bool yn = _route.get_mute_config(MAIN_OUTS); + bool yn = _route->get_mute_config(MAIN_OUTS); if (check->get_active() != yn) { check->set_active (yn); } @@ -876,42 +872,55 @@ RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check) void RouteUI::disconnect_input () { - _route.disconnect_inputs (this); + _route->disconnect_inputs (this); } void RouteUI::disconnect_output () { - _route.disconnect_outputs (this); + _route->disconnect_outputs (this); +} + +bool +RouteUI::is_track () const +{ + return dynamic_cast<Track*>(_route.get()) != 0; +} + +Track* +RouteUI::track() const +{ + return dynamic_cast<Track*>(_route.get()); } bool RouteUI::is_audio_track () const { - return dynamic_cast<AudioTrack*>(&_route) != 0; + return dynamic_cast<AudioTrack*>(_route.get()) != 0; +} + +AudioTrack* +RouteUI::audio_track() const +{ + return dynamic_cast<AudioTrack*>(_route.get()); } -AudioDiskstream* +Diskstream* RouteUI::get_diskstream () const { - AudioTrack *at; + boost::shared_ptr<Track> t; - if ((at = dynamic_cast<AudioTrack*>(&_route)) != 0) { - return &at->disk_stream(); + if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) { + return &t->diskstream(); } else { return 0; } } -AudioTrack* -RouteUI::audio_track() const -{ - return dynamic_cast<AudioTrack*>(&_route); -} string RouteUI::name() const { - return _route.name(); + return _route->name(); } void @@ -919,7 +928,7 @@ RouteUI::map_frozen () { ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen)); - AudioTrack* at = dynamic_cast<AudioTrack*>(&_route); + AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get()); if (at) { switch (at->freeze_state()) { @@ -932,3 +941,4 @@ RouteUI::map_frozen () } } } + diff --git a/gtk2_ardour/route_ui.h b/gtk2_ardour/route_ui.h index 69c9b7f5a9..7415eddad6 100644 --- a/gtk2_ardour/route_ui.h +++ b/gtk2_ardour/route_ui.h @@ -26,13 +26,10 @@ #include <pbd/xml++.h> #include <ardour/ardour.h> #include <ardour/route.h> +#include <ardour/track.h> #include "axis_view.h" -namespace Gtkmm2ext { - class BindableToggleButton; -} - namespace ARDOUR { class AudioTrack; } @@ -43,21 +40,30 @@ namespace Gtk { class Widget; } +class BindableToggleButton; + class RouteUI : public virtual AxisView { public: - RouteUI(ARDOUR::Route&, ARDOUR::Session&, const char*, const char*, const char*); + RouteUI(boost::shared_ptr<ARDOUR::Route>, ARDOUR::Session&, const char*, const char*, const char*); virtual ~RouteUI(); + bool is_track() const; bool is_audio_track() const; - ARDOUR::AudioDiskstream* get_diskstream() const; - ARDOUR::Route& route() const { return _route; } + boost::shared_ptr<ARDOUR::Route> route() const { return _route; } + + // FIXME: make these return shared_ptr + ARDOUR::Track* track() const; ARDOUR::AudioTrack* audio_track() const; + + ARDOUR::Diskstream* get_diskstream() const; string name() const; - - ARDOUR::Route& _route; + + // protected: XXX sigh this should be here + + boost::shared_ptr<ARDOUR::Route> _route; void set_color (const Gdk::Color & c); bool choose_color (); @@ -65,9 +71,9 @@ class RouteUI : public virtual AxisView bool ignore_toggle; bool wait_for_release; - Gtkmm2ext::BindableToggleButton * mute_button; - Gtkmm2ext::BindableToggleButton * solo_button; - Gtkmm2ext::BindableToggleButton * rec_enable_button; + BindableToggleButton* mute_button; + BindableToggleButton* solo_button; + BindableToggleButton* rec_enable_button; virtual string solo_button_name () const { return "SoloButton"; } virtual string safe_solo_button_name () const { return "SafeSoloButton"; } @@ -89,7 +95,8 @@ class RouteUI : public virtual AxisView void solo_changed(void*); void mute_changed(void*); - void route_rec_enable_changed(void*); + virtual void redirects_changed (void *) {} + void route_rec_enable_changed(); void session_rec_enable_changed(); void build_solo_menu (void); @@ -108,9 +115,9 @@ class RouteUI : public virtual AxisView void build_mute_menu(void); void init_mute_menu(ARDOUR::mute_type, Gtk::CheckMenuItem*); - void set_mix_group_solo(ARDOUR::Route&, bool); - void set_mix_group_mute(ARDOUR::Route&, bool); - void set_mix_group_rec_enable(ARDOUR::Route&, bool); + void set_mix_group_solo(boost::shared_ptr<ARDOUR::Route>, bool); + void set_mix_group_mute(boost::shared_ptr<ARDOUR::Route>, bool); + void set_mix_group_rec_enable(boost::shared_ptr<ARDOUR::Route>, bool); int set_color_from_route (); diff --git a/gtk2_ardour/selectable.h b/gtk2_ardour/selectable.h index b4be7090e2..b52214c9c9 100644 --- a/gtk2_ardour/selectable.h +++ b/gtk2_ardour/selectable.h @@ -34,7 +34,7 @@ class Selectable : public virtual sigc::trackable virtual void set_selected (bool yn) { if (yn != _selected) { - _selected = true; + _selected = yn; Selected (_selected); /* EMIT_SIGNAL */ } } diff --git a/gtk2_ardour/selection.cc b/gtk2_ardour/selection.cc index 2e4ed8a117..086d878994 100644 --- a/gtk2_ardour/selection.cc +++ b/gtk2_ardour/selection.cc @@ -24,7 +24,7 @@ #include <ardour/playlist.h> -#include "regionview.h" +#include "region_view.h" #include "selection.h" #include "selection_templates.h" #include "time_axis_view.h" @@ -46,7 +46,7 @@ Selection& Selection::operator= (const Selection& other) { if (&other != this) { - audio_regions = other.audio_regions; + regions = other.regions; tracks = other.tracks; time = other.time; lines = other.lines; @@ -57,7 +57,7 @@ Selection::operator= (const Selection& other) bool operator== (const Selection& a, const Selection& b) { - return a.audio_regions == b.audio_regions && + return a.regions == b.regions && a.tracks == b.tracks && a.time.track == b.time.track && a.time.group == b.time.group && @@ -71,7 +71,7 @@ void Selection::clear () { clear_tracks (); - clear_audio_regions (); + clear_regions (); clear_points (); clear_lines(); clear_time (); @@ -83,8 +83,8 @@ void Selection::dump_region_layers() { cerr << "region selection layer dump" << endl; - for (AudioRegionSelection::iterator i = audio_regions.begin(); i != audio_regions.end(); ++i) { - cerr << "layer: " << (int)(*i)->region.layer() << endl; + for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) { + cerr << "layer: " << (int)(*i)->region().layer() << endl; } } @@ -99,10 +99,10 @@ Selection::clear_redirects () } void -Selection::clear_audio_regions () +Selection::clear_regions () { - if (!audio_regions.empty()) { - audio_regions.clear_all (); + if (!regions.empty()) { + regions.clear_all (); RegionsChanged(); } } @@ -151,7 +151,7 @@ Selection::clear_lines () } void -Selection::toggle (Redirect* r) +Selection::toggle (boost::shared_ptr<Redirect> r) { RedirectSelection::iterator i; @@ -196,29 +196,29 @@ Selection::toggle (TimeAxisView* track) } void -Selection::toggle (AudioRegionView* r) +Selection::toggle (RegionView* r) { - AudioRegionSelection::iterator i; + RegionSelection::iterator i; - if ((i = find (audio_regions.begin(), audio_regions.end(), r)) == audio_regions.end()) { - audio_regions.add (r); + if ((i = find (regions.begin(), regions.end(), r)) == regions.end()) { + regions.add (r); } else { - audio_regions.erase (i); + regions.erase (i); } RegionsChanged (); } void -Selection::toggle (vector<AudioRegionView*>& r) +Selection::toggle (vector<RegionView*>& r) { - AudioRegionSelection::iterator i; + RegionSelection::iterator i; - for (vector<AudioRegionView*>::iterator x = r.begin(); x != r.end(); ++x) { - if ((i = find (audio_regions.begin(), audio_regions.end(), (*x))) == audio_regions.end()) { - audio_regions.add ((*x)); + for (vector<RegionView*>::iterator x = r.begin(); x != r.end(); ++x) { + if ((i = find (regions.begin(), regions.end(), (*x))) == regions.end()) { + regions.add ((*x)); } else { - audio_regions.erase (i); + regions.erase (i); } } @@ -243,7 +243,7 @@ Selection::toggle (jack_nframes_t start, jack_nframes_t end) void -Selection::add (Redirect* r) +Selection::add (boost::shared_ptr<Redirect> r) { if (find (redirects.begin(), redirects.end(), r) == redirects.end()) { redirects.push_back (r); @@ -310,22 +310,22 @@ Selection::add (TimeAxisView* track) } void -Selection::add (AudioRegionView* r) +Selection::add (RegionView* r) { - if (find (audio_regions.begin(), audio_regions.end(), r) == audio_regions.end()) { - audio_regions.add (r); + if (find (regions.begin(), regions.end(), r) == regions.end()) { + regions.add (r); RegionsChanged (); } } void -Selection::add (vector<AudioRegionView*>& v) +Selection::add (vector<RegionView*>& v) { bool changed = false; - for (vector<AudioRegionView*>::iterator i = v.begin(); i != v.end(); ++i) { - if (find (audio_regions.begin(), audio_regions.end(), (*i)) == audio_regions.end()) { - audio_regions.add ((*i)); + for (vector<RegionView*>::iterator i = v.begin(); i != v.end(); ++i) { + if (find (regions.begin(), regions.end(), (*i)) == regions.end()) { + regions.add ((*i)); changed = true; } } @@ -381,9 +381,9 @@ Selection::add (AutomationList* ac) } void -Selection::remove (Redirect* r) +Selection::remove (boost::shared_ptr<Redirect> r) { - list<Redirect*>::iterator i; + RedirectSelection::iterator i; if ((i = find (redirects.begin(), redirects.end(), r)) != redirects.end()) { redirects.erase (i); RedirectsChanged (); @@ -451,9 +451,9 @@ Selection::remove (const list<Playlist*>& pllist) } void -Selection::remove (AudioRegionView* r) +Selection::remove (RegionView* r) { - audio_regions.remove (r); + regions.remove (r); RegionsChanged (); } @@ -491,7 +491,7 @@ Selection::remove (AutomationList *ac) } void -Selection::set (Redirect *r) +Selection::set (boost::shared_ptr<Redirect> r) { clear_redirects (); add (r); @@ -526,17 +526,16 @@ Selection::set (const list<Playlist*>& pllist) } void -Selection::set (AudioRegionView* r) +Selection::set (RegionView* r) { - clear_audio_regions (); + clear_regions (); add (r); } void -Selection::set (vector<AudioRegionView*>& v) +Selection::set (vector<RegionView*>& v) { - - clear_audio_regions (); + clear_regions (); // make sure to deselect any automation selections clear_points(); add (v); @@ -590,15 +589,15 @@ Selection::selected (TimeAxisView* tv) } bool -Selection::selected (AudioRegionView* arv) +Selection::selected (RegionView* rv) { - return find (audio_regions.begin(), audio_regions.end(), arv) != audio_regions.end(); + return find (regions.begin(), regions.end(), rv) != regions.end(); } bool Selection::empty () { - return audio_regions.empty () && + return regions.empty () && tracks.empty () && points.empty () && playlists.empty () && @@ -612,7 +611,7 @@ Selection::empty () void Selection::set (list<Selectable*>& selectables) { - clear_audio_regions(); + clear_regions(); clear_points (); add (selectables); } @@ -620,14 +619,14 @@ Selection::set (list<Selectable*>& selectables) void Selection::add (list<Selectable*>& selectables) { - AudioRegionView* arv; + RegionView* rv; AutomationSelectable* as; - vector<AudioRegionView*> arvs; + vector<RegionView*> rvs; vector<AutomationSelectable*> autos; for (std::list<Selectable*>::iterator i = selectables.begin(); i != selectables.end(); ++i) { - if ((arv = dynamic_cast<AudioRegionView*> (*i)) != 0) { - arvs.push_back (arv); + if ((rv = dynamic_cast<RegionView*> (*i)) != 0) { + rvs.push_back (rv); } else if ((as = dynamic_cast<AutomationSelectable*> (*i)) != 0) { autos.push_back (as); } else { @@ -638,8 +637,8 @@ Selection::add (list<Selectable*>& selectables) } } - if (!arvs.empty()) { - add (arvs); + if (!rvs.empty()) { + add (rvs); } if (!autos.empty()) { diff --git a/gtk2_ardour/selection.h b/gtk2_ardour/selection.h index ebeda1aea7..7b503a5e63 100644 --- a/gtk2_ardour/selection.h +++ b/gtk2_ardour/selection.h @@ -22,6 +22,7 @@ #define __ardour_gtk_selection_h__ #include <vector> +#include <boost/shared_ptr.hpp> #include <sigc++/signal.h> @@ -34,7 +35,7 @@ #include "point_selection.h" class TimeAxisView; -class AudioRegionView; +class RegionView; class Selectable; namespace ARDOUR { @@ -60,7 +61,7 @@ class Selection : public sigc::trackable }; TrackSelection tracks; - AudioRegionSelection audio_regions; + RegionSelection regions; TimeSelection time; AutomationSelection lines; PlaylistSelection playlists; @@ -88,55 +89,55 @@ class Selection : public sigc::trackable void dump_region_layers(); bool selected (TimeAxisView*); - bool selected (AudioRegionView*); + bool selected (RegionView*); void set (list<Selectable*>&); void add (list<Selectable*>&); void set (TimeAxisView*); void set (const list<TimeAxisView*>&); - void set (AudioRegionView*); - void set (std::vector<AudioRegionView*>&); + void set (RegionView*); + void set (std::vector<RegionView*>&); long set (TimeAxisView*, jack_nframes_t, jack_nframes_t); void set (ARDOUR::AutomationList*); void set (ARDOUR::Playlist*); void set (const list<ARDOUR::Playlist*>&); - void set (ARDOUR::Redirect*); + void set (boost::shared_ptr<ARDOUR::Redirect>); void set (AutomationSelectable*); void toggle (TimeAxisView*); void toggle (const list<TimeAxisView*>&); - void toggle (AudioRegionView*); - void toggle (std::vector<AudioRegionView*>&); + void toggle (RegionView*); + void toggle (std::vector<RegionView*>&); long toggle (jack_nframes_t, jack_nframes_t); void toggle (ARDOUR::AutomationList*); void toggle (ARDOUR::Playlist*); void toggle (const list<ARDOUR::Playlist*>&); - void toggle (ARDOUR::Redirect*); + void toggle (boost::shared_ptr<ARDOUR::Redirect>); void add (TimeAxisView*); void add (const list<TimeAxisView*>&); - void add (AudioRegionView*); - void add (std::vector<AudioRegionView*>&); + void add (RegionView*); + void add (std::vector<RegionView*>&); long add (jack_nframes_t, jack_nframes_t); void add (ARDOUR::AutomationList*); void add (ARDOUR::Playlist*); void add (const list<ARDOUR::Playlist*>&); - void add (ARDOUR::Redirect*); + void add (boost::shared_ptr<ARDOUR::Redirect>); void remove (TimeAxisView*); void remove (const list<TimeAxisView*>&); - void remove (AudioRegionView*); + void remove (RegionView*); void remove (uint32_t selection_id); void remove (jack_nframes_t, jack_nframes_t); void remove (ARDOUR::AutomationList*); void remove (ARDOUR::Playlist*); void remove (const list<ARDOUR::Playlist*>&); - void remove (ARDOUR::Redirect*); + void remove (boost::shared_ptr<ARDOUR::Redirect>); void replace (uint32_t time_index, jack_nframes_t start, jack_nframes_t end); - void clear_audio_regions(); + void clear_regions(); void clear_tracks (); void clear_time(); void clear_lines (); @@ -144,10 +145,8 @@ class Selection : public sigc::trackable void clear_redirects (); void clear_points (); - void foreach_audio_region (void (ARDOUR::AudioRegion::*method)(void)); - void foreach_audio_region (void (ARDOUR::Region::*method)(void)); - template<class A> void foreach_audio_region (void (ARDOUR::AudioRegion::*method)(A), A arg); - template<class A> void foreach_audio_region (void (ARDOUR::Region::*method)(A), A arg); + void foreach_region (void (ARDOUR::Region::*method)(void)); + template<class A> void foreach_region (void (ARDOUR::Region::*method)(A), A arg); private: uint32_t next_time_id; diff --git a/gtk2_ardour/selection_templates.h b/gtk2_ardour/selection_templates.h index c2ca70b526..9511db7d61 100644 --- a/gtk2_ardour/selection_templates.h +++ b/gtk2_ardour/selection_templates.h @@ -27,35 +27,21 @@ */ #include <ardour/region.h> -#include <ardour/audioregion.h> #include "selection.h" +#include "region_view.h" inline void -Selection::foreach_audio_region (void (ARDOUR::AudioRegion::*method)(void)) { - for (AudioRegionSelection::iterator i = audio_regions.begin(); i != audio_regions.end(); ++i) { - ((*i)->region.*(method))(); - } -} - -inline void -Selection::foreach_audio_region (void (ARDOUR::Region::*method)(void)) { - for (AudioRegionSelection::iterator i = audio_regions.begin(); i != audio_regions.end(); ++i) { - ((*i)->region.*(method))(); - } -} - -template<class A> inline void -Selection::foreach_audio_region (void (ARDOUR::AudioRegion::*method)(A), A arg) { - for (AudioRegionSelection::iterator i = audio_regions.begin(); i != audio_regions.end(); ++i) { - ((*i)->region.*(method))(arg); +Selection::foreach_region (void (ARDOUR::Region::*method)(void)) { + for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) { + ((*i)->region().*(method))(); } } template<class A> inline void -Selection::foreach_audio_region (void (ARDOUR::Region::*method)(A), A arg) { - for (AudioRegionSelection::iterator i = audio_regions.begin(); i != audio_regions.end(); ++i) { - ((*i)->region.*(method))(arg); +Selection::foreach_region (void (ARDOUR::Region::*method)(A), A arg) { + for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) { + ((*i)->region().*(method))(arg); } } @@ -64,14 +50,14 @@ Selection::foreach_audio_region (void (ARDOUR::Region::*method)(A), A arg) { template<class A> inline void Selection::foreach_route (void (ARDOUR::Route::*method)(A), A arg) { for (list<ARDOUR::Route*>::iterator i = routes.begin(); i != routes.end(); ++i) { - ((*i)->region.*(method))(arg); + ((*i)->region().*(method))(arg); } } template<class A1, class A2> inline void Selection::foreach_route (void (ARDOUR::Route::*method)(A1,A2), A1 arg1, A2 arg2) { for (list<ARDOUR::Route*>::iterator i = routes.begin(); i != routes.end(); ++i) { - ((*i)->region.*(method))(arg1, arg2); + ((*i)->region().*(method))(arg1, arg2); } } diff --git a/gtk2_ardour/send_ui.cc b/gtk2_ardour/send_ui.cc index be95f753e7..9925ff51d4 100644 --- a/gtk2_ardour/send_ui.cc +++ b/gtk2_ardour/send_ui.cc @@ -30,7 +30,7 @@ using namespace ARDOUR; using namespace PBD; -SendUI::SendUI (Send& s, Session& se) +SendUI::SendUI (boost::shared_ptr<Send> s, Session& se) : _send (s), _session (se), gpm (s, se), @@ -53,10 +53,10 @@ SendUI::SendUI (Send& s, Session& se) show_all (); - _send.set_metering (true); + _send->set_metering (true); - _send.output_changed.connect (mem_fun (*this, &SendUI::ins_changed)); - _send.output_changed.connect (mem_fun (*this, &SendUI::outs_changed)); + _send->output_changed.connect (mem_fun (*this, &SendUI::ins_changed)); + _send->output_changed.connect (mem_fun (*this, &SendUI::outs_changed)); panners.set_width (Wide); panners.setup_pan (); @@ -70,7 +70,7 @@ SendUI::SendUI (Send& s, Session& se) SendUI::~SendUI () { - _send.set_metering (false); + _send->set_metering (false); /* XXX not clear that we need to do this */ @@ -118,7 +118,7 @@ SendUI::fast_update () } } -SendUIWindow::SendUIWindow (Send& s, Session& ss) +SendUIWindow::SendUIWindow (boost::shared_ptr<Send> s, Session& ss) { ui = new SendUI (s, ss); @@ -131,7 +131,7 @@ SendUIWindow::SendUIWindow (Send& s, Session& ss) add (vpacker); set_name ("SendUIWindow"); - s.GoingAway.connect (mem_fun (*this, &SendUIWindow::send_going_away)); + s->GoingAway.connect (mem_fun (*this, &SendUIWindow::send_going_away)); signal_delete_event().connect (bind (ptr_fun (just_hide_it), reinterpret_cast<Window *> (this))); diff --git a/gtk2_ardour/send_ui.h b/gtk2_ardour/send_ui.h index d1a49930ea..1d5a74e102 100644 --- a/gtk2_ardour/send_ui.h +++ b/gtk2_ardour/send_ui.h @@ -35,7 +35,7 @@ class IOSelector; class SendUI : public Gtk::HBox { public: - SendUI (ARDOUR::Send&, ARDOUR::Session&); + SendUI (boost::shared_ptr<ARDOUR::Send>, ARDOUR::Session&); ~SendUI(); void update (); @@ -44,7 +44,7 @@ class SendUI : public Gtk::HBox IOSelector* io; private: - ARDOUR::Send& _send; + boost::shared_ptr<ARDOUR::Send> _send; ARDOUR::Session& _session; GainMeter gpm; PannerUI panners; @@ -62,7 +62,7 @@ class SendUI : public Gtk::HBox class SendUIWindow : public Gtk::Window { public: - SendUIWindow(ARDOUR::Send&, ARDOUR::Session&); + SendUIWindow(boost::shared_ptr<ARDOUR::Send>, ARDOUR::Session&); ~SendUIWindow(); SendUI* ui; diff --git a/gtk2_ardour/sfdb_ui.cc b/gtk2_ardour/sfdb_ui.cc index 79546880de..d9ded04d2b 100644 --- a/gtk2_ardour/sfdb_ui.cc +++ b/gtk2_ardour/sfdb_ui.cc @@ -97,6 +97,9 @@ SoundFileBox::SoundFileBox () (mem_fun (*this, &SoundFileBox::add_field_clicked)); remove_field_btn.signal_clicked().connect (mem_fun (*this, &SoundFileBox::remove_field_clicked)); + + Gtk::CellRendererText* cell(dynamic_cast<Gtk::CellRendererText*>(field_view.get_column_cell_renderer(1))); + cell->signal_edited().connect (mem_fun (*this, &SoundFileBox::field_edited)); field_view.get_selection()->signal_changed().connect (mem_fun (*this, &SoundFileBox::field_selected)); Library->fields_changed.connect (mem_fun (*this, &SoundFileBox::setup_fields)); @@ -260,6 +263,13 @@ SoundFileBox::remove_field_clicked () } void +SoundFileBox::field_edited (const Glib::ustring& str1, const Glib::ustring& str2) +{ + cout << "field_edited" << endl; + Library->save_changes (); +} + +void SoundFileBox::delete_row (const Gtk::TreeModel::iterator& iter) { Gtk::TreeModel::Row row = *iter; @@ -394,6 +404,9 @@ SoundFileOmega::set_mode (Editing::ImportMode mode) case Editing::ImportToTrack: split_check.set_sensitive (false); break; + case Editing::ImportAsTapeTrack: + split_check.set_sensitive (true); + break; } } @@ -433,5 +446,8 @@ SoundFileOmega::mode_changed () case Editing::ImportToTrack: split_check.set_sensitive (false); break; + case Editing::ImportAsTapeTrack: + split_check.set_sensitive (true); + break; } } diff --git a/gtk2_ardour/sfdb_ui.h b/gtk2_ardour/sfdb_ui.h index 79c73b97ac..8ef57d7b9f 100644 --- a/gtk2_ardour/sfdb_ui.h +++ b/gtk2_ardour/sfdb_ui.h @@ -100,6 +100,7 @@ class SoundFileBox : public Gtk::VBox void stop_btn_clicked (); void add_field_clicked (); void remove_field_clicked (); + void field_edited (const Glib::ustring&, const Glib::ustring&); void delete_row (const Gtk::TreeModel::iterator& iter); void field_selected (); diff --git a/gtk2_ardour/streamview.cc b/gtk2_ardour/streamview.cc index a60e0d59e7..d1d163d7a2 100644 --- a/gtk2_ardour/streamview.cc +++ b/gtk2_ardour/streamview.cc @@ -1,28 +1,42 @@ +/* + Copyright (C) 2001, 2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + #include <cmath> #include <gtkmm.h> #include <gtkmm2ext/gtk_ui.h> -#include <ardour/audioplaylist.h> -#include <ardour/audioregion.h> -#include <ardour/audiosource.h> -#include <ardour/audio_diskstream.h> -#include <ardour/audio_track.h> -#include <ardour/playlist_templates.h> +#include <ardour/playlist.h> +#include <ardour/region.h> #include <ardour/source.h> +#include <ardour/diskstream.h> +#include <ardour/track.h> #include "streamview.h" -#include "regionview.h" -#include "taperegionview.h" -#include "audio_time_axis.h" +#include "region_view.h" +#include "route_time_axis.h" #include "canvas-waveview.h" #include "canvas-simplerect.h" #include "region_selection.h" #include "selection.h" #include "public_editor.h" #include "ardour_ui.h" -#include "crossfade_view.h" #include "rgb_macros.h" #include "gui_thread.h" #include "utils.h" @@ -32,52 +46,36 @@ using namespace ARDOUR; using namespace PBD; using namespace Editing; -StreamView::StreamView (AudioTimeAxisView& tv) +StreamView::StreamView (RouteTimeAxisView& tv) : _trackview (tv) + , canvas_group(new ArdourCanvas::Group(*_trackview.canvas_display)) + , canvas_rect(new ArdourCanvas::SimpleRect (*canvas_group)) + , _samples_per_unit(_trackview.editor.get_current_zoom()) + , rec_updating(false) + , rec_active(false) + , use_rec_regions(tv.editor.show_waveforms_recording()) + , region_color(_trackview.color()) + , stream_base_color(0xFFFFFFFF) { - region_color = _trackview.color(); - crossfades_visible = true; - - if (tv.is_audio_track()) { - /* TRACK */ - //stream_base_color = RGBA_TO_UINT (222,223,218,255); - stream_base_color = color_map[cAudioTrackBase]; - } else { - /* BUS */ - //stream_base_color = RGBA_TO_UINT (230,226,238,255); - stream_base_color = color_map[cAudioBusBase]; - } - /* set_position() will position the group */ - canvas_group = new ArdourCanvas::Group(*_trackview.canvas_display); - canvas_rect = new ArdourCanvas::SimpleRect (*canvas_group); canvas_rect->property_x1() = 0.0; canvas_rect->property_y1() = 0.0; canvas_rect->property_x2() = 1000000.0; canvas_rect->property_y2() = (double) tv.height; - canvas_rect->property_outline_color_rgba() = color_map[cAudioTrackOutline]; canvas_rect->property_outline_what() = (guint32) (0x1|0x2|0x8); // outline ends and bottom - canvas_rect->property_fill_color_rgba() = stream_base_color; + // (Fill/Outline colours set in derived classes) canvas_rect->signal_event().connect (bind (mem_fun (_trackview.editor, &PublicEditor::canvas_stream_view_event), canvas_rect, &_trackview)); - _samples_per_unit = _trackview.editor.get_current_zoom(); - _amplitude_above_axis = 1.0; - - if (_trackview.is_audio_track()) { - _trackview.audio_track()->diskstream_changed.connect (mem_fun (*this, &StreamView::diskstream_changed)); + if (_trackview.is_track()) { + _trackview.track()->DiskstreamChanged.connect (mem_fun (*this, &StreamView::diskstream_changed)); _trackview.session().TransportStateChange.connect (mem_fun (*this, &StreamView::transport_changed)); - _trackview.get_diskstream()->record_enable_changed.connect (mem_fun (*this, &StreamView::rec_enable_changed)); + _trackview.get_diskstream()->RecordEnableChanged.connect (mem_fun (*this, &StreamView::rec_enable_changed)); _trackview.session().RecordStateChanged.connect (mem_fun (*this, &StreamView::sess_rec_enable_changed)); } - rec_updating = false; - rec_active = false; - use_rec_regions = tv.editor.show_waveforms_recording (); - last_rec_peak_frame = 0; - ColorChanged.connect (mem_fun (*this, &StreamView::color_handler)); } @@ -90,7 +88,7 @@ StreamView::~StreamView () void StreamView::attach () { - if (_trackview.is_audio_track()) { + if (_trackview.is_track()) { display_diskstream (_trackview.get_diskstream()); } } @@ -115,13 +113,13 @@ StreamView::set_height (gdouble h) canvas_rect->property_y2() = h; - for (AudioRegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) { + for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) { (*i)->set_height (h); } - for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + /*for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { (*i)->set_height (h); - } + }*/ for (vector<RecBoxInfo>::iterator i = rec_rects.begin(); i != rec_rects.end(); ++i) { RecBoxInfo &recbox = (*i); @@ -134,7 +132,7 @@ StreamView::set_height (gdouble h) int StreamView::set_samples_per_unit (gdouble spp) { - AudioRegionViewList::iterator i; + RegionViewList::iterator i; if (spp < 1.0) { return -1; @@ -146,10 +144,6 @@ StreamView::set_samples_per_unit (gdouble spp) (*i)->set_samples_per_unit (spp); } - for (CrossfadeViewList::iterator xi = crossfade_views.begin(); xi != crossfade_views.end(); ++xi) { - (*xi)->set_samples_per_unit (spp); - } - for (vector<RecBoxInfo>::iterator xi = rec_rects.begin(); xi != rec_rects.end(); ++xi) { RecBoxInfo &recbox = (*xi); @@ -163,25 +157,6 @@ StreamView::set_samples_per_unit (gdouble spp) return 0; } -int -StreamView::set_amplitude_above_axis (gdouble app) - -{ - AudioRegionViewList::iterator i; - - if (app < 1.0) { - return -1; - } - - _amplitude_above_axis = app; - - for (i = region_views.begin(); i != region_views.end(); ++i) { - (*i)->set_amplitude_above_axis (app); - } - - return 0; -} - void StreamView::add_region_view (Region *r) { @@ -189,87 +164,17 @@ StreamView::add_region_view (Region *r) } void -StreamView::add_region_view_internal (Region *r, bool wait_for_waves) -{ - ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::add_region_view), r)); - - AudioRegion* region = dynamic_cast<AudioRegion*> (r); - - if (region == 0) { - return; - } - - AudioRegionView *region_view; - list<AudioRegionView *>::iterator i; - - for (i = region_views.begin(); i != region_views.end(); ++i) { - if (&(*i)->region == region) { - - /* great. we already have a AudioRegionView for this Region. use it again. - */ - - (*i)->set_valid (true); - return; - } - } - - switch (_trackview.audio_track()->mode()) { - case Normal: - region_view = new AudioRegionView (canvas_group, _trackview, *region, - _samples_per_unit, region_color); - break; - case Destructive: - region_view = new TapeAudioRegionView (canvas_group, _trackview, *region, - _samples_per_unit, region_color); - break; - } - - region_view->init (_amplitude_above_axis, region_color, wait_for_waves); - region_views.push_front (region_view); - - /* follow global waveform setting */ - - region_view->set_waveform_visible(_trackview.editor.show_waveforms()); - - /* catch regionview going away */ - - region->GoingAway.connect (mem_fun (*this, &StreamView::remove_region_view)); - - AudioRegionViewAdded (region_view); -} - -void StreamView::remove_region_view (Region *r) { ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::remove_region_view), r)); - AudioRegion* ar = dynamic_cast<AudioRegion*> (r); - - if (ar == 0) { - return; - } - - for (list<AudioRegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) { - if (&((*i)->region) == ar) { + for (list<RegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) { + if (&((*i)->region()) == r) { delete *i; region_views.erase (i); break; } } - - for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end();) { - list<CrossfadeView*>::iterator tmp; - - tmp = i; - ++tmp; - - if ((*i)->crossfade.involves (*ar)) { - delete *i; - crossfade_views.erase (i); - } - - i = tmp; - } } void @@ -282,14 +187,8 @@ StreamView::remove_rec_region (Region *r) /*NOTREACHED*/ } - AudioRegion* ar = dynamic_cast<AudioRegion*> (r); - - if (ar == 0) { - return; - } - - for (list<AudioRegion *>::iterator i = rec_regions.begin(); i != rec_regions.end(); ++i) { - if (*i == ar) { + for (list<Region *>::iterator i = rec_regions.begin(); i != rec_regions.end(); ++i) { + if (*i == r) { rec_regions.erase (i); break; } @@ -299,21 +198,15 @@ StreamView::remove_rec_region (Region *r) void StreamView::undisplay_diskstream () { - - for (AudioRegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) { - delete *i; - } - - for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) { delete *i; } region_views.clear(); - crossfade_views.clear (); } void -StreamView::display_diskstream (AudioDiskstream *ds) +StreamView::display_diskstream (Diskstream *ds) { playlist_change_connection.disconnect(); playlist_changed (ds); @@ -325,21 +218,13 @@ StreamView::playlist_modified () { ENSURE_GUI_THREAD (mem_fun (*this, &StreamView::playlist_modified)); - /* if the playlist is modified, make sure xfades are on top and all the regionviews are stacked - correctly. - */ - - for (AudioRegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) { + for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) { region_layered (*i); } - - for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { - (*i)->get_canvas_group()->raise_to_top(); - } } void -StreamView::playlist_changed (AudioDiskstream *ds) +StreamView::playlist_changed (Diskstream *ds) { ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::playlist_changed), ds)); @@ -362,69 +247,6 @@ StreamView::playlist_changed (AudioDiskstream *ds) playlist_connections.push_back (ds->playlist()->RegionRemoved.connect (mem_fun (*this, &StreamView::remove_region_view))); playlist_connections.push_back (ds->playlist()->StateChanged.connect (mem_fun (*this, &StreamView::playlist_state_changed))); playlist_connections.push_back (ds->playlist()->Modified.connect (mem_fun (*this, &StreamView::playlist_modified))); - playlist_connections.push_back (ds->playlist()->NewCrossfade.connect (mem_fun (*this, &StreamView::add_crossfade))); -} - -void -StreamView::add_crossfade (Crossfade *crossfade) -{ - AudioRegionView* lview = 0; - AudioRegionView* rview = 0; - - ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::add_crossfade), crossfade)); - - /* first see if we already have a CrossfadeView for this Crossfade */ - - for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { - if (&(*i)->crossfade == crossfade) { - if (!crossfades_visible) { - (*i)->hide(); - } else { - (*i)->show (); - } - (*i)->set_valid (true); - return; - } - } - - /* create a new one */ - - for (list<AudioRegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) { - if (!lview && &((*i)->region) == &crossfade->out()) { - lview = *i; - } - if (!rview && &((*i)->region) == &crossfade->in()) { - rview = *i; - } - } - - CrossfadeView *cv = new CrossfadeView (_trackview.canvas_display, - _trackview, - *crossfade, - _samples_per_unit, - region_color, - *lview, *rview); - - crossfade->Invalidated.connect (mem_fun (*this, &StreamView::remove_crossfade)); - crossfade_views.push_back (cv); - - if (!crossfades_visible) { - cv->hide (); - } -} - -void -StreamView::remove_crossfade (Crossfade *xfade) -{ - ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::remove_crossfade), xfade)); - - for (list<CrossfadeView*>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { - if (&(*i)->crossfade == xfade) { - delete *i; - crossfade_views.erase (i); - break; - } - } } void @@ -436,64 +258,12 @@ StreamView::playlist_state_changed (Change ignored) } void -StreamView::redisplay_diskstream () -{ - list<AudioRegionView *>::iterator i, tmp; - list<CrossfadeView*>::iterator xi, tmpx; - - - for (i = region_views.begin(); i != region_views.end(); ++i) { - (*i)->set_valid (false); - } - - for (xi = crossfade_views.begin(); xi != crossfade_views.end(); ++xi) { - (*xi)->set_valid (false); - if ((*xi)->visible()) { - (*xi)->show (); - } - } - - if (_trackview.is_audio_track()) { - _trackview.get_diskstream()->playlist()->foreach_region (this, &StreamView::add_region_view); - _trackview.get_diskstream()->playlist()->foreach_crossfade (this, &StreamView::add_crossfade); - } - - for (i = region_views.begin(); i != region_views.end(); ) { - tmp = i; - tmp++; - - if (!(*i)->is_valid()) { - delete *i; - region_views.erase (i); - } - - i = tmp; - } - - for (xi = crossfade_views.begin(); xi != crossfade_views.end();) { - tmpx = xi; - tmpx++; - - if (!(*xi)->valid()) { - delete *xi; - crossfade_views.erase (xi); - } - - xi = tmpx; - } - - /* now fix layering */ - - playlist_modified (); -} - -void -StreamView::diskstream_changed (void *src_ignored) +StreamView::diskstream_changed () { - AudioTrack *at; + Track *t; - if ((at = _trackview.audio_track()) != 0) { - AudioDiskstream& ds = at->disk_stream(); + if ((t = _trackview.track()) != 0) { + Diskstream& ds = t->diskstream(); /* XXX grrr: when will SigC++ allow me to bind references? */ Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*this, &StreamView::display_diskstream), &ds)); } else { @@ -505,7 +275,7 @@ void StreamView::apply_color (Gdk::Color& color, ColorTarget target) { - list<AudioRegionView *>::iterator i; + list<RegionView *>::iterator i; switch (target) { case RegionColor: @@ -513,76 +283,18 @@ StreamView::apply_color (Gdk::Color& color, ColorTarget target) for (i = region_views.begin(); i != region_views.end(); ++i) { (*i)->set_color (region_color); } - // stream_base_color = RGBA_TO_UINT (color.red/256, color.green/256, color.blue/256, 255); - // gnome_canvas_item_set (canvas_rect, "fill_color_rgba", stream_base_color, NULL); break; case StreamBaseColor: - // stream_base_color = RGBA_TO_UINT (color.red/256, color.green/256, color.blue/256, 255); - // gnome_canvas_item_set (canvas_rect, "fill_color_rgba", stream_base_color, NULL); + stream_base_color = RGBA_TO_UINT ( + color.get_red_p(), color.get_green_p(), color.get_blue_p(), 255); + canvas_rect->property_fill_color_rgba() = stream_base_color; break; } } void -StreamView::set_show_waveforms (bool yn) -{ - for (list<AudioRegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) { - (*i)->set_waveform_visible (yn); - } -} - -void -StreamView::set_selected_regionviews (AudioRegionSelection& regions) -{ - bool selected; - - // cerr << _trackview.name() << " (selected = " << regions.size() << ")" << endl; - for (list<AudioRegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) { - - selected = false; - - for (AudioRegionSelection::iterator ii = regions.begin(); ii != regions.end(); ++ii) { - if (*i == *ii) { - selected = true; - } - } - - // cerr << "\tregion " << (*i)->region.name() << " selected = " << selected << endl; - (*i)->set_selected (selected); - } -} - -void -StreamView::get_selectables (jack_nframes_t start, jack_nframes_t end, list<Selectable*>& results) -{ - for (list<AudioRegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) { - if ((*i)->region.coverage(start, end) != OverlapNone) { - results.push_back (*i); - } - } -} - -void -StreamView::get_inverted_selectables (Selection& sel, list<Selectable*>& results) -{ - for (list<AudioRegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) { - if (!sel.audio_regions.contains (*i)) { - results.push_back (*i); - } - } -} - -void -StreamView::set_waveform_shape (WaveformShape shape) -{ - for (AudioRegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) { - (*i)->set_waveform_shape (shape); - } -} - -void -StreamView::region_layered (AudioRegionView* rv) +StreamView::region_layered (RegionView* rv) { rv->get_canvas_group()->lower_to_bottom(); @@ -590,11 +302,14 @@ StreamView::region_layered (AudioRegionView* rv) get events - the parent group does instead ... */ - rv->get_canvas_group()->raise (rv->region.layer() + 1); + /* this used to be + 1, but regions to the left ended up below + ..something.. and couldn't receive events. why? good question. + */ + rv->get_canvas_group()->raise (rv->region().layer() + 2); } void -StreamView::rec_enable_changed (void *src) +StreamView::rec_enable_changed () { Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box)); } @@ -612,161 +327,6 @@ StreamView::transport_changed() } void -StreamView::setup_rec_box () -{ - // cerr << _trackview.name() << " streamview SRB\n"; - - if (_trackview.session().transport_rolling()) { - - // cerr << "\trolling\n"; - - if (!rec_active && - _trackview.session().record_status() == Session::Recording && - _trackview.get_diskstream()->record_enabled()) { - - if (_trackview.audio_track()->mode() == Normal && use_rec_regions && rec_regions.size() == rec_rects.size()) { - - /* add a new region, but don't bother if they set use_rec_regions mid-record */ - - AudioRegion::SourceList sources; - - for (list<sigc::connection>::iterator prc = peak_ready_connections.begin(); prc != peak_ready_connections.end(); ++prc) { - (*prc).disconnect(); - } - peak_ready_connections.clear(); - - for (uint32_t n=0; n < _trackview.get_diskstream()->n_channels(); ++n) { - AudioSource *src = (AudioSource *) _trackview.get_diskstream()->write_source (n); - if (src) { - sources.push_back (src); - peak_ready_connections.push_back (src->PeakRangeReady.connect (bind (mem_fun (*this, &StreamView::rec_peak_range_ready), src))); - } - } - - // handle multi - - jack_nframes_t start = 0; - if (rec_regions.size() > 0) { - start = rec_regions.back()->start() + _trackview.get_diskstream()->get_captured_frames(rec_regions.size()-1); - } - - AudioRegion * region = new AudioRegion(sources, start, 1 , "", 0, (Region::Flag)(Region::DefaultFlags | Region::DoNotSaveState), false); - region->set_position (_trackview.session().transport_frame(), this); - rec_regions.push_back (region); - /* catch it if it goes away */ - region->GoingAway.connect (mem_fun (*this, &StreamView::remove_rec_region)); - - /* we add the region later */ - } - - /* start a new rec box */ - - AudioTrack* at; - - at = _trackview.audio_track(); /* we know what it is already */ - AudioDiskstream& ds = at->disk_stream(); - jack_nframes_t frame_pos = ds.current_capture_start (); - gdouble xstart = _trackview.editor.frame_to_pixel (frame_pos); - gdouble xend; - uint32_t fill_color; - - switch (_trackview.audio_track()->mode()) { - case Normal: - xend = xstart; - fill_color = color_map[cRecordingRectFill]; - break; - - case Destructive: - xend = xstart + 2; - fill_color = color_map[cRecordingRectFill]; - /* make the recording rect translucent to allow - the user to see the peak data coming in, etc. - */ - fill_color = UINT_RGBA_CHANGE_A (fill_color, 120); - break; - } - - ArdourCanvas::SimpleRect * rec_rect = new Gnome::Canvas::SimpleRect (*canvas_group); - rec_rect->property_x1() = xstart; - rec_rect->property_y1() = 1.0; - rec_rect->property_x2() = xend; - rec_rect->property_y2() = (double) _trackview.height - 1; - rec_rect->property_outline_color_rgba() = color_map[cRecordingRectOutline]; - rec_rect->property_fill_color_rgba() = fill_color; - - RecBoxInfo recbox; - recbox.rectangle = rec_rect; - recbox.start = _trackview.session().transport_frame(); - recbox.length = 0; - - rec_rects.push_back (recbox); - - screen_update_connection.disconnect(); - screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (mem_fun (*this, &StreamView::update_rec_box)); - rec_updating = true; - rec_active = true; - - } else if (rec_active && - (_trackview.session().record_status() != Session::Recording || - !_trackview.get_diskstream()->record_enabled())) { - - screen_update_connection.disconnect(); - rec_active = false; - rec_updating = false; - - } - - } else { - - // cerr << "\tNOT rolling, rec_rects = " << rec_rects.size() << " rec_regions = " << rec_regions.size() << endl; - - if (!rec_rects.empty() || !rec_regions.empty()) { - - /* disconnect rapid update */ - screen_update_connection.disconnect(); - - for (list<sigc::connection>::iterator prc = peak_ready_connections.begin(); prc != peak_ready_connections.end(); ++prc) { - (*prc).disconnect(); - } - peak_ready_connections.clear(); - - rec_updating = false; - rec_active = false; - last_rec_peak_frame = 0; - - /* remove temp regions */ - for (list<AudioRegion*>::iterator iter=rec_regions.begin(); iter != rec_regions.end(); ) - { - list<AudioRegion*>::iterator tmp; - - tmp = iter; - ++tmp; - - /* this will trigger the remove_region_view */ - delete *iter; - - iter = tmp; - } - - rec_regions.clear(); - - // cerr << "\tclear " << rec_rects.size() << " rec rects\n"; - - - /* transport stopped, clear boxes */ - for (vector<RecBoxInfo>::iterator iter=rec_rects.begin(); iter != rec_rects.end(); ++iter) { - RecBoxInfo &rect = (*iter); - delete rect.rectangle; - } - - rec_rects.clear(); - - } - } -} - - -void StreamView::update_rec_box () { if (rec_active && rec_rects.size() > 0) { @@ -776,7 +336,7 @@ StreamView::update_rec_box () double xstart; double xend; - switch (_trackview.audio_track()->mode()) { + switch (_trackview.track()->mode()) { case Normal: rect.length = at - rect.start; xstart = _trackview.editor.frame_to_pixel (rect.start); @@ -795,12 +355,12 @@ StreamView::update_rec_box () } } -AudioRegionView* -StreamView::find_view (const AudioRegion& region) +RegionView* +StreamView::find_view (const Region& region) { - for (list<AudioRegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) { + for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) { - if (&(*i)->region == ®ion) { + if (&(*i)->region() == ®ion) { return *i; } } @@ -808,172 +368,51 @@ StreamView::find_view (const AudioRegion& region) } void -StreamView::foreach_regionview (sigc::slot<void,AudioRegionView*> slot) +StreamView::foreach_regionview (sigc::slot<void,RegionView*> slot) { - for (list<AudioRegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) { + for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) { slot (*i); } } void -StreamView::foreach_crossfadeview (void (CrossfadeView::*pmf)(void)) -{ - for (list<CrossfadeView*>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { - ((*i)->*pmf) (); - } -} - -void -StreamView::rec_peak_range_ready (jack_nframes_t start, jack_nframes_t cnt, Source * src) -{ - // this is called from the peak building thread - - ENSURE_GUI_THREAD(bind (mem_fun (*this, &StreamView::rec_peak_range_ready), start, cnt, src)); - - if (rec_peak_ready_map.size() == 0 || start+cnt > last_rec_peak_frame) { - last_rec_peak_frame = start + cnt; - } - - rec_peak_ready_map[src] = true; - - if (rec_peak_ready_map.size() == _trackview.get_diskstream()->n_channels()) { - this->update_rec_regions (); - rec_peak_ready_map.clear(); - } -} - -void -StreamView::update_rec_regions () +StreamView::set_selected_regionviews (RegionSelection& regions) { - if (use_rec_regions) { - - uint32_t n = 0; - - for (list<AudioRegion*>::iterator iter = rec_regions.begin(); iter != rec_regions.end(); n++) { - - list<AudioRegion*>::iterator tmp; - - tmp = iter; - ++tmp; - - if (!canvas_item_visible (rec_rects[n].rectangle)) { - /* rect already hidden, this region is done */ - iter = tmp; - continue; - } - - AudioRegion * region = (*iter); - jack_nframes_t origlen = region->length(); - - if (region == rec_regions.back() && rec_active) { - - if (last_rec_peak_frame > region->start()) { - - jack_nframes_t nlen = last_rec_peak_frame - region->start(); - - if (nlen != region->length()) { - - region->freeze (); - region->set_position (_trackview.get_diskstream()->get_capture_start_frame(n), this); - region->set_length (nlen, this); - region->thaw ("updated"); - - if (origlen == 1) { - /* our special initial length */ - add_region_view_internal (region, false); - } - - /* also update rect */ - ArdourCanvas::SimpleRect * rect = rec_rects[n].rectangle; - gdouble xend = _trackview.editor.frame_to_pixel (region->position() + region->length()); - rect->property_x2() = xend; - } - } - - } else { - - jack_nframes_t nlen = _trackview.get_diskstream()->get_captured_frames(n); - - if (nlen != region->length()) { - - if (region->source(0).length() >= region->start() + nlen) { - - region->freeze (); - region->set_position (_trackview.get_diskstream()->get_capture_start_frame(n), this); - region->set_length (nlen, this); - region->thaw ("updated"); - - if (origlen == 1) { - /* our special initial length */ - add_region_view_internal (region, false); - } - - /* also hide rect */ - ArdourCanvas::Item * rect = rec_rects[n].rectangle; - rect->hide(); + bool selected; - } - } + // cerr << _trackview.name() << " (selected = " << regions.size() << ")" << endl; + for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) { + + selected = false; + + for (RegionSelection::iterator ii = regions.begin(); ii != regions.end(); ++ii) { + if (*i == *ii) { + selected = true; } - - iter = tmp; } + + // cerr << "\tregion " << (*i)->region().name() << " selected = " << selected << endl; + (*i)->set_selected (selected); } } void -StreamView::show_all_xfades () -{ - foreach_crossfadeview (&CrossfadeView::show); - crossfades_visible = true; -} - -void -StreamView::hide_all_xfades () -{ - foreach_crossfadeview (&CrossfadeView::hide); - crossfades_visible = false; -} - -void -StreamView::hide_xfades_involving (AudioRegionView& rv) +StreamView::get_selectables (jack_nframes_t start, jack_nframes_t end, list<Selectable*>& results) { - for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { - if ((*i)->crossfade.involves (rv.region)) { - (*i)->fake_hide (); + for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) { + if ((*i)->region().coverage(start, end) != OverlapNone) { + results.push_back (*i); } } } void -StreamView::reveal_xfades_involving (AudioRegionView& rv) +StreamView::get_inverted_selectables (Selection& sel, list<Selectable*>& results) { - for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { - if ((*i)->crossfade.involves (rv.region) && (*i)->visible()) { - (*i)->show (); + for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) { + if (!sel.regions.contains (*i)) { + results.push_back (*i); } } } -void -StreamView::color_handler (ColorID id, uint32_t val) -{ - switch (id) { - case cAudioTrackBase: - if (_trackview.is_audio_track()) { - canvas_rect->property_fill_color_rgba() = val; - } - break; - case cAudioBusBase: - if (!_trackview.is_audio_track()) { - canvas_rect->property_fill_color_rgba() = val; - } - break; - case cAudioTrackOutline: - canvas_rect->property_outline_color_rgba() = val; - break; - - default: - break; - } -} diff --git a/gtk2_ardour/streamview.h b/gtk2_ardour/streamview.h index 00ec2d93f2..5a0e10974f 100644 --- a/gtk2_ardour/streamview.h +++ b/gtk2_ardour/streamview.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2001 Paul Davis + Copyright (C) 2001, 2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,8 +14,6 @@ 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_streamview_h__ @@ -37,141 +35,116 @@ namespace Gdk { namespace ARDOUR { class Route; - class AudioDiskstream; + class Diskstream; class Crossfade; class PeakData; - class AudioRegion; + class Region; class Source; } struct RecBoxInfo { - ArdourCanvas::SimpleRect* rectangle; - jack_nframes_t start; - jack_nframes_t length; + ArdourCanvas::SimpleRect* rectangle; + jack_nframes_t start; + jack_nframes_t length; }; class PublicEditor; class Selectable; -class AudioTimeAxisView; -class AudioRegionView; -class AudioRegionSelection; +class RouteTimeAxisView; +class RegionView; +class RegionSelection; class CrossfadeView; class Selection; class StreamView : public sigc::trackable { - public: - StreamView (AudioTimeAxisView&); - ~StreamView (); +public: + virtual ~StreamView (); - void set_waveform_shape (WaveformShape); + RouteTimeAxisView& trackview() { return _trackview; } - AudioTimeAxisView& trackview() { return _trackview; } + void attach (); void set_zoom_all(); - int set_height (gdouble); int set_position (gdouble x, gdouble y); + virtual int set_height (gdouble); - int set_samples_per_unit (gdouble spp); - gdouble get_samples_per_unit () { return _samples_per_unit; } - - int set_amplitude_above_axis (gdouble app); - gdouble get_amplitude_above_axis () { return _amplitude_above_axis; } - - void set_show_waveforms (bool yn); - void set_show_waveforms_recording (bool yn) { use_rec_regions = yn; } + virtual int set_samples_per_unit (gdouble spp); + gdouble get_samples_per_unit () { return _samples_per_unit; } ArdourCanvas::Item* canvas_item() { return canvas_group; } - sigc::signal<void,AudioRegionView*> AudioRegionViewAdded; - enum ColorTarget { RegionColor, StreamBaseColor }; - void apply_color (Gdk::Color&, ColorTarget t); - void set_selected_regionviews (AudioRegionSelection&); + Gdk::Color get_region_color () const { return region_color; } + void apply_color (Gdk::Color&, ColorTarget t); + + RegionView* find_view (const ARDOUR::Region&); + void foreach_regionview (sigc::slot<void,RegionView*> slot); + + void set_selected_regionviews (RegionSelection&); void get_selectables (jack_nframes_t start, jack_nframes_t end, list<Selectable* >&); void get_inverted_selectables (Selection&, list<Selectable* >& results); - Gdk::Color get_region_color () const { return region_color; } - void foreach_regionview (sigc::slot<void,AudioRegionView*> slot); - void foreach_crossfadeview (void (CrossfadeView::*pmf)(void)); + void add_region_view (ARDOUR::Region*); + void region_layered (RegionView*); + + sigc::signal<void,RegionView*> RegionViewAdded; - void attach (); +protected: + StreamView (RouteTimeAxisView&); - void region_layered (AudioRegionView*); +//private: (FIXME?) + + void transport_changed(); + void rec_enable_changed(); + void sess_rec_enable_changed(); + virtual void setup_rec_box () = 0; + void update_rec_box (); + virtual void update_rec_regions () = 0; - AudioRegionView* find_view (const ARDOUR::AudioRegion&); - - void show_all_xfades (); - void hide_all_xfades (); - void hide_xfades_involving (AudioRegionView&); - void reveal_xfades_involving (AudioRegionView&); + virtual void add_region_view_internal (ARDOUR::Region*, bool wait_for_waves) = 0; + virtual void remove_region_view (ARDOUR::Region* ); + void remove_rec_region (ARDOUR::Region*); + + void display_diskstream (ARDOUR::Diskstream* ); + virtual void undisplay_diskstream (); + virtual void redisplay_diskstream () = 0; + void diskstream_changed (); + + void playlist_state_changed (ARDOUR::Change); + virtual void playlist_changed (ARDOUR::Diskstream* ); + virtual void playlist_modified (); + + virtual void color_handler (ColorID, uint32_t) = 0; - private: - AudioTimeAxisView& _trackview; - ArdourCanvas::Group* canvas_group; + RouteTimeAxisView& _trackview; + ArdourCanvas::Group* canvas_group; ArdourCanvas::SimpleRect* canvas_rect; /* frame around the whole thing */ - typedef list<AudioRegionView* > AudioRegionViewList; - AudioRegionViewList region_views; - - typedef list<CrossfadeView*> CrossfadeViewList; - CrossfadeViewList crossfade_views; + typedef list<RegionView* > RegionViewList; + RegionViewList region_views; double _samples_per_unit; - double _amplitude_above_axis; - - sigc::connection screen_update_connection; - vector<RecBoxInfo> rec_rects; - list<ARDOUR::AudioRegion* > rec_regions; - bool rec_updating; - bool rec_active; - bool use_rec_regions; - list<sigc::connection> peak_ready_connections; - jack_nframes_t last_rec_peak_frame; - map<ARDOUR::Source*, bool> rec_peak_ready_map; - - void update_rec_box (); - void transport_changed(); - void rec_enable_changed(void* src = 0); - void sess_rec_enable_changed(); - void setup_rec_box (); - void rec_peak_range_ready (jack_nframes_t start, jack_nframes_t cnt, ARDOUR::Source* src); - void update_rec_regions (); - - void add_region_view (ARDOUR::Region*); - void add_region_view_internal (ARDOUR::Region*, bool wait_for_waves); - void remove_region_view (ARDOUR::Region* ); - void remove_rec_region (ARDOUR::Region*); - void remove_audio_region_view (ARDOUR::AudioRegion* ); - void remove_audio_rec_region (ARDOUR::AudioRegion*); - - void display_diskstream (ARDOUR::AudioDiskstream* ); - void undisplay_diskstream (); - void redisplay_diskstream (); - void diskstream_changed (void* ); - void playlist_state_changed (ARDOUR::Change); - void playlist_changed (ARDOUR::AudioDiskstream* ); - void playlist_modified (); - - bool crossfades_visible; - void add_crossfade (ARDOUR::Crossfade*); - void remove_crossfade (ARDOUR::Crossfade*); - - /* XXX why are these different? */ - - Gdk::Color region_color; - uint32_t stream_base_color; - void color_handler (ColorID, uint32_t); + sigc::connection screen_update_connection; + vector<RecBoxInfo> rec_rects; + list<ARDOUR::Region* > rec_regions; + bool rec_updating; + bool rec_active; + bool use_rec_regions; + + Gdk::Color region_color; ///< Contained region color + uint32_t stream_base_color; ///< Background color vector<sigc::connection> playlist_connections; - sigc::connection playlist_change_connection; + sigc::connection playlist_change_connection; }; #endif /* __ardour_streamview_h__ */ + diff --git a/gtk2_ardour/taperegionview.cc b/gtk2_ardour/tape_region_view.cc index 641d067350..bd5ce8af02 100644 --- a/gtk2_ardour/taperegionview.cc +++ b/gtk2_ardour/tape_region_view.cc @@ -30,7 +30,7 @@ #include <ardour/audiosource.h> #include <ardour/audio_diskstream.h> -#include "taperegionview.h" +#include "tape_region_view.h" #include "audio_time_axis.h" #include "gui_thread.h" @@ -42,72 +42,33 @@ using namespace PBD; using namespace Editing; using namespace ArdourCanvas; -TapeAudioRegionView::TapeAudioRegionView (ArdourCanvas::Group *parent, AudioTimeAxisView &tv, +const TimeAxisViewItem::Visibility TapeAudioRegionView::default_tape_visibility + = TimeAxisViewItem::Visibility ( + TimeAxisViewItem::ShowNameHighlight | + TimeAxisViewItem::ShowFrame | + TimeAxisViewItem::HideFrameRight | + TimeAxisViewItem::FullWidthNameHighlight); + +TapeAudioRegionView::TapeAudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, AudioRegion& r, double spu, Gdk::Color& basic_color) : AudioRegionView (parent, tv, r, spu, basic_color, - TimeAxisViewItem::Visibility (TimeAxisViewItem::ShowNameHighlight| - TimeAxisViewItem::ShowFrame| - TimeAxisViewItem::HideFrameLR| - TimeAxisViewItem::FullWidthNameHighlight)) + TimeAxisViewItem::Visibility ((r.position() != 0) ? default_tape_visibility : + TimeAxisViewItem::Visibility (default_tape_visibility|TimeAxisViewItem::HideFrameLeft))) { } void -TapeAudioRegionView::init (double amplitude_above_axis, Gdk::Color& basic_color, bool wfw) +TapeAudioRegionView::init (Gdk::Color& basic_color, bool wfw) { - XMLNode *node; - - editor = 0; - valid = true; - in_destructor = false; - _amplitude_above_axis = amplitude_above_axis; - zero_line = 0; - wait_for_waves = wfw; - _height = 0; - - _flags = 0; - - if ((node = region.extra_xml ("GUI")) != 0) { - set_flags (node); - } else { - _flags = WaveformVisible; - store_flags (); - } - - fade_in_handle = 0; - fade_out_handle = 0; - gain_line = 0; - sync_mark = 0; - - compute_colors (basic_color); - - create_waves (); - - name_highlight->set_data ("regionview", this); - - reset_width_dependent_items ((double) region.length() / samples_per_unit); - - set_height (trackview.height); - - region_muted (); - region_resized (BoundsChanged); - set_waveview_data_src(); - region_locked (); - - /* no events, no state changes */ - - set_colors (); - - // ColorChanged.connect (mem_fun (*this, &AudioRegionView::color_handler)); + AudioRegionView::init(basic_color, wfw); /* every time the wave data changes and peaks are ready, redraw */ - - for (uint32_t n = 0; n < region.n_channels(); ++n) { - region.source(n).PeaksReady.connect (bind (mem_fun(*this, &TapeAudioRegionView::update), n)); + for (uint32_t n = 0; n < audio_region().n_channels(); ++n) { + audio_region().source(n).PeaksReady.connect (bind (mem_fun(*this, &TapeAudioRegionView::update), n)); } } @@ -129,7 +90,7 @@ TapeAudioRegionView::update (uint32_t n) /* this triggers a cache invalidation and redraw in the waveview */ - waves[n]->property_data_src() = ®ion; + waves[n]->property_data_src() = &_region; } void diff --git a/gtk2_ardour/taperegionview.h b/gtk2_ardour/tape_region_view.h index 3e23e0fc19..ed3852e3a9 100644 --- a/gtk2_ardour/taperegionview.h +++ b/gtk2_ardour/tape_region_view.h @@ -23,23 +23,25 @@ #include <vector> -#include "regionview.h" +#include "audio_region_view.h" class TapeAudioRegionView : public AudioRegionView { public: TapeAudioRegionView (ArdourCanvas::Group *, - AudioTimeAxisView&, + RouteTimeAxisView&, ARDOUR::AudioRegion&, double initial_samples_per_unit, Gdk::Color& base_color); ~TapeAudioRegionView (); protected: - void init (double amplitude_above_axis, Gdk::Color& base_color, bool wait_for_waves); + void init (Gdk::Color& base_color, bool wait_for_waves); void set_frame_color (); void update (uint32_t n); + + static const TimeAxisViewItem::Visibility default_tape_visibility; }; #endif /* __gtk_ardour_tape_audio_region_view_h__ */ diff --git a/gtk2_ardour/time_axis_view.cc b/gtk2_ardour/time_axis_view.cc index b5ab5baa10..6261241139 100644 --- a/gtk2_ardour/time_axis_view.cc +++ b/gtk2_ardour/time_axis_view.cc @@ -128,6 +128,7 @@ TimeAxisView::TimeAxisView (ARDOUR::Session& sess, PublicEditor& ed, TimeAxisVie controls_table.attach (name_hbox, 0, 4, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); controls_table.show_all (); + controls_table.set_no_show_all (); controls_vbox.pack_start (controls_table, false, false); controls_vbox.show (); @@ -661,8 +662,6 @@ TimeAxisView::show_selection (TimeSelection& ts) void TimeAxisView::reshow_selection (TimeSelection& ts) { - cerr << name() << ": reshow selection" << endl; - show_selection (ts); for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) { @@ -882,7 +881,7 @@ TimeAxisView::reset_height() set_height_pixels (height); for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) { - (*i)->set_height ((TrackHeight)(*i)->height); + (*i)->set_height_pixels ((TrackHeight)(*i)->height); } } diff --git a/gtk2_ardour/time_axis_view.h b/gtk2_ardour/time_axis_view.h index c607c78166..31ff3d84ee 100644 --- a/gtk2_ardour/time_axis_view.h +++ b/gtk2_ardour/time_axis_view.h @@ -54,7 +54,7 @@ namespace Gtk { } class PublicEditor; -class AudioRegionSelection; +class RegionSelection; class TimeSelection; class PointSelection; class TimeAxisViewItem; @@ -183,7 +183,7 @@ class TimeAxisView : public virtual AxisView virtual bool cut_copy_clear (Selection&, Editing::CutCopyOp) { return false; } virtual bool paste (jack_nframes_t, float times, Selection&, size_t nth) { return false; } - virtual void set_selected_regionviews (AudioRegionSelection&) {} + virtual void set_selected_regionviews (RegionSelection&) {} virtual void set_selected_points (PointSelection&) {} virtual ARDOUR::Region* find_next_region (jack_nframes_t pos, ARDOUR::RegionPoint, int32_t dir) { diff --git a/gtk2_ardour/time_axis_view_item.cc b/gtk2_ardour/time_axis_view_item.cc index abab306a84..28fafcaa09 100644 --- a/gtk2_ardour/time_axis_view_item.cc +++ b/gtk2_ardour/time_axis_view_item.cc @@ -137,8 +137,12 @@ TimeAxisViewItem::TimeAxisViewItem(const string & it_name, ArdourCanvas::Group& uint32_t outline_what = 0x1|0x2|0x4|0x8; - if (visibility & HideFrameLR) { - outline_what &= ~(0x1 | 0x2); + if (visibility & HideFrameLeft) { + outline_what &= ~(0x1); + } + + if (visibility & HideFrameRight) { + outline_what &= ~(0x2); } if (visibility & HideFrameTB) { diff --git a/gtk2_ardour/time_axis_view_item.h b/gtk2_ardour/time_axis_view_item.h index b23350eef7..9ddb06876a 100644 --- a/gtk2_ardour/time_axis_view_item.h +++ b/gtk2_ardour/time_axis_view_item.h @@ -316,9 +316,10 @@ class TimeAxisViewItem : public Selectable ShowNameHighlight = 0x2, ShowNameText = 0x4, ShowHandles = 0x8, - HideFrameLR = 0x10, - HideFrameTB = 0x20, - FullWidthNameHighlight = 0x40 + HideFrameLeft = 0x10, + HideFrameRight = 0x20, + HideFrameTB = 0x40, + FullWidthNameHighlight = 0x80 }; /** diff --git a/gtk2_ardour/utils.cc b/gtk2_ardour/utils.cc index 91cb7ad58b..ef90c34755 100644 --- a/gtk2_ardour/utils.cc +++ b/gtk2_ardour/utils.cc @@ -215,7 +215,7 @@ get_font_for_style (string widgetname) { Gtk::Window window (WINDOW_TOPLEVEL); Gtk::Label foobar; - Glib::RefPtr<Style> style; + Glib::RefPtr<Gtk::Style> style; window.add (foobar); foobar.set_name (widgetname); @@ -435,12 +435,10 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev) if (!special_handling_of_unmodified_accelerators || ev->state & (Gdk::MOD1_MASK| - Gdk::MOD2_MASK| Gdk::MOD3_MASK| Gdk::MOD4_MASK| Gdk::MOD5_MASK| - Gdk::CONTROL_MASK| - Gdk::LOCK_MASK)) { + Gdk::CONTROL_MASK)) { /* no special handling or modifiers in effect: accelerate first */ diff --git a/gtk2_ardour/visual_time_axis.cc b/gtk2_ardour/visual_time_axis.cc index c27ed33089..e44ea4011e 100644 --- a/gtk2_ardour/visual_time_axis.cc +++ b/gtk2_ardour/visual_time_axis.cc @@ -255,7 +255,7 @@ VisualTimeAxis::set_time_axis_color(Gdk::Color c) } void -VisualTimeAxis::set_selected_regionviews (AudioRegionSelection& regions) +VisualTimeAxis::set_selected_regionviews (RegionSelection& regions) { // Not handled by purely visual TimeAxis } diff --git a/gtk2_ardour/visual_time_axis.h b/gtk2_ardour/visual_time_axis.h index 4be2da3b9a..c68ce8da1c 100644 --- a/gtk2_ardour/visual_time_axis.h +++ b/gtk2_ardour/visual_time_axis.h @@ -42,7 +42,7 @@ class ImageFrameView; class ImageFrameTimeAxisView; class MarkersTimeAxisView; class TimeSelection; -class AudioRegionSelection; +class RegionSelection; class MarkerTimeAxis; class TimeAxisViewStrip; @@ -105,7 +105,7 @@ class VisualTimeAxis : public TimeAxisView /** * Not implemented */ - virtual void set_selected_regionviews(AudioRegionSelection&) ; + virtual void set_selected_regionviews(RegionSelection&) ; //---------------------------------------------------------------------------------// diff --git a/libs/appleutility/AUOutputBL.cpp b/libs/appleutility/AUOutputBL.cpp new file mode 100644 index 0000000000..8509f46288 --- /dev/null +++ b/libs/appleutility/AUOutputBL.cpp @@ -0,0 +1,160 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + AUOutputBL.h + +=============================================================================*/ +#include "AUOutputBL.h" + +/* +struct AudioBufferList +{ + UInt32 mNumberBuffers; + AudioBuffer mBuffers[1]; +}; +struct AudioBuffer +{ + UInt32 mNumberChannels; // number of interleaved channels in the buffer + UInt32 mDataByteSize; // the size of the buffer pointed to by mData + void* mData; // the pointer to the buffer +}; +*/ + +AUOutputBL::AUOutputBL (const CAStreamBasicDescription &inDesc, UInt32 inDefaultNumFrames) + : mFormat (inDesc), + mBufferMemory(NULL), + mBufferList (NULL), + mNumberBuffers (0), // keep this here, so can ensure integrity of ABL + mBufferSize (0), + mFrames(inDefaultNumFrames) +{ + mNumberBuffers = mFormat.IsInterleaved() ? 1 : mFormat.NumberChannels(); + mBufferList = reinterpret_cast<AudioBufferList*>(new Byte[sizeof(UInt32) + (mNumberBuffers * sizeof(AudioBuffer))]); +} + +AUOutputBL::~AUOutputBL() +{ + if (mBufferMemory) + delete[] mBufferMemory; + + if (mBufferList) + delete [] mBufferList; +} + +void AUOutputBL::Prepare (UInt32 inNumFrames, bool inWantNullBufferIfAllocated) +{ + UInt32 channelsPerBuffer = mFormat.IsInterleaved() ? mFormat.NumberChannels() : 1; + + if (mBufferMemory == NULL || inWantNullBufferIfAllocated) + { + mBufferList->mNumberBuffers = mNumberBuffers; + AudioBuffer *buf = &mBufferList->mBuffers[0]; + for (UInt32 i = 0; i < mNumberBuffers; ++i, ++buf) { + buf->mNumberChannels = channelsPerBuffer; + buf->mDataByteSize = mFormat.FramesToBytes (inNumFrames); + buf->mData = NULL; + } + } + else + { + UInt32 nBytes = mFormat.FramesToBytes (inNumFrames); + if ((nBytes * mNumberBuffers) > AllocatedBytes()) + throw OSStatus(-10874);//(kAudioUnitErr_TooManyFramesToProcess); + + mBufferList->mNumberBuffers = mNumberBuffers; + AudioBuffer *buf = &mBufferList->mBuffers[0]; + Byte* p = mBufferMemory; + for (UInt32 i = 0; i < mNumberBuffers; ++i, ++buf) { + buf->mNumberChannels = channelsPerBuffer; + buf->mDataByteSize = nBytes; + buf->mData = p; + p += mBufferSize; + } + } +} + + +void AUOutputBL::Allocate (UInt32 inNumFrames) +{ + if (inNumFrames) + { + UInt32 nBytes = mFormat.FramesToBytes (inNumFrames); + + if (nBytes <= AllocatedBytes()) + return; + + // align successive buffers for Altivec and to take alternating + // cache line hits by spacing them by odd multiples of 16 + if (mNumberBuffers > 1) + nBytes = (nBytes + (0x10 - (nBytes & 0xF))) | 0x10; + + mBufferSize = nBytes; + + UInt32 memorySize = mBufferSize * mNumberBuffers; + Byte *newMemory = new Byte[memorySize]; + memset(newMemory, 0, memorySize); // make buffer "hot" + + Byte *oldMemory = mBufferMemory; + mBufferMemory = newMemory; + delete[] oldMemory; + + mFrames = inNumFrames; + } + else + { + if (mBufferMemory) { + delete [] mBufferMemory; + mBufferMemory = NULL; + } + mBufferSize = 0; + mFrames = 0; + } +} + +#if DEBUG +void AUOutputBL::Print() +{ + printf ("AUOutputBL::Print\n"); + mFormat.Print(); + printf ("Num Buffers:%ld, mFrames:%ld, allocatedMemory:%c\n", mBufferList->mNumberBuffers, mFrames, (mBufferMemory != NULL ? 'T' : 'F')); + AudioBuffer *buf = &mBufferList->mBuffers[0]; + for (UInt32 i = 0; i < mBufferList->mNumberBuffers; ++i, ++buf) + printf ("\tBuffer:%ld, Size:%ld, Chans:%ld, Buffer:%X\n", i, buf->mDataByteSize, buf->mNumberChannels, int(buf->mData)); +} +#endif + diff --git a/libs/appleutility/AUOutputBL.h b/libs/appleutility/AUOutputBL.h new file mode 100644 index 0000000000..b80588abac --- /dev/null +++ b/libs/appleutility/AUOutputBL.h @@ -0,0 +1,115 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + AUOutputBL.h + +=============================================================================*/ + +#ifndef __AUOutputBL_h__ +#define __AUOutputBL_h__ + +#include "CAStreamBasicDescription.h" +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include <CoreServices/CoreServices.h> +#else + #include <AssertMacros.h> +#endif + +// ____________________________________________________________________________ +// +// AUOutputBL - Simple Buffer List wrapper targetted to use with retrieving AU output +// Works in one of two ways (both adjustable)... Can use it with NULL pointers, or allocate +// memory to receive the data in. + +// Before using this with any call to AudioUnitRender, it needs to be Prepared +// as some calls to AudioUnitRender can reset the ABL + +class AUOutputBL { +public: + + // you CANNOT use one of these - it will crash! +// AUOutputBL (); + + // this is the constructor that you use + // it can't be reset once you've constructed it + AUOutputBL (const CAStreamBasicDescription &inDesc, UInt32 inDefaultNumFrames = 512); + ~AUOutputBL(); + + void Prepare () + { + Prepare (mFrames); + } + + // this version can throw if this is an allocted ABL and inNumFrames is > AllocatedFrames() + // you can set the bool to true if you want a NULL buffer list even if allocated + // inNumFrames must be a valid number (will throw if inNumFrames is 0) + void Prepare (UInt32 inNumFrames, bool inWantNullBufferIfAllocated = false); + + AudioBufferList* ABL() { return mBufferList; } + + // You only need to call this if you want to allocate a buffer list + // if you want an empty buffer list, just call Prepare() + // if you want to dispose previously allocted memory, pass in 0 + // then you either have an empty buffer list, or you can re-allocate + // Memory is kept around if an Allocation request is less than what is currently allocated + void Allocate (UInt32 inNumberFrames); + + UInt32 AllocatedFrames() const { return mFrames; } + + const CAStreamBasicDescription& GetFormat() const { return mFormat; } + +#if DEBUG + void Print(); +#endif + +private: + UInt32 AllocatedBytes () const { return (mBufferSize * mNumberBuffers); } + + CAStreamBasicDescription mFormat; + Byte* mBufferMemory; + AudioBufferList* mBufferList; + UInt32 mNumberBuffers; + UInt32 mBufferSize; + UInt32 mFrames; + +// don't want to copy these.. can if you want, but more code to write! + AUOutputBL (const AUOutputBL &c) {} + AUOutputBL& operator= (const AUOutputBL& c) { return *this; } +}; + +#endif // __AUOutputBL_h__ diff --git a/libs/appleutility/CAAudioChannelLayout.cpp b/libs/appleutility/CAAudioChannelLayout.cpp new file mode 100644 index 0000000000..585ff44fb7 --- /dev/null +++ b/libs/appleutility/CAAudioChannelLayout.cpp @@ -0,0 +1,138 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CAAudioChannelLayout.cpp + +=============================================================================*/ + +//============================================================================= +// Includes +//============================================================================= + +// Self Include +#include "CAAudioChannelLayout.h" +#include <stdlib.h> +#include <string.h> + +//============================================================================= +// CAAudioChannelLayout +//============================================================================= + +AudioChannelLayout* CAAudioChannelLayout::Create(UInt32 inNumberChannelDescriptions) +{ + UInt32 theSize = CalculateByteSize(inNumberChannelDescriptions); + AudioChannelLayout* theAnswer = static_cast<AudioChannelLayout*>(calloc(1, theSize)); + if(theAnswer != NULL) + { + SetAllToUnknown(*theAnswer, inNumberChannelDescriptions); + } + return theAnswer; +} + +void CAAudioChannelLayout::Destroy(AudioChannelLayout* inChannelLayout) +{ + free(inChannelLayout); +} + +void CAAudioChannelLayout::SetAllToUnknown(AudioChannelLayout& outChannelLayout, UInt32 inNumberChannelDescriptions) +{ + outChannelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions; + outChannelLayout.mChannelBitmap = 0; + outChannelLayout.mNumberChannelDescriptions = inNumberChannelDescriptions; + for(UInt32 theChannelIndex = 0; theChannelIndex < inNumberChannelDescriptions; ++theChannelIndex) + { + outChannelLayout.mChannelDescriptions[theChannelIndex].mChannelLabel = kAudioChannelLabel_Unknown; + outChannelLayout.mChannelDescriptions[theChannelIndex].mChannelFlags = 0; + outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[0] = 0; + outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[1] = 0; + outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[2] = 0; + } +} + +bool operator== (const AudioChannelLayout &x, const AudioChannelLayout &y) +{ + // compare based on the number of channel descriptions present + // (this may be too strict a comparison if all you care about are matching layout tags) + UInt32 theSize1 = CAAudioChannelLayout::CalculateByteSize(x.mNumberChannelDescriptions); + UInt32 theSize2 = CAAudioChannelLayout::CalculateByteSize(y.mNumberChannelDescriptions); + + if (theSize1 != theSize2) + return false; + + return !memcmp (&x, &y, theSize1); +} + +// counting the one bits in a word +inline UInt32 CountOnes(UInt32 x) +{ + // secret magic algorithm for counting bits in a word. + UInt32 t; + x = x - ((x >> 1) & 0x55555555); + t = ((x >> 2) & 0x33333333); + x = (x & 0x33333333) + t; + x = (x + (x >> 4)) & 0x0F0F0F0F; + x = x + (x << 8); + x = x + (x << 16); + return x >> 24; +} + +UInt32 CAAudioChannelLayout::NumberChannels (const AudioChannelLayout& inLayout) +{ + if (inLayout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) + return inLayout.mNumberChannelDescriptions; + + if (inLayout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) + return CountOnes (inLayout.mChannelBitmap); + + return AudioChannelLayoutTag_GetNumberOfChannels(inLayout.mChannelLayoutTag); +} + +void CAShowAudioChannelLayout (FILE* file, const AudioChannelLayout *layout) +{ + fprintf (file, "\tTag=0x%lX, ", layout->mChannelLayoutTag); + if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) + fprintf (file, "Using Bitmap:0x%lX\n", layout->mChannelBitmap); + else { + fprintf (file, "Num Chan Descs=%ld\n", layout->mNumberChannelDescriptions); + const AudioChannelDescription *desc = layout->mChannelDescriptions; + for (unsigned int i = 0; i < layout->mNumberChannelDescriptions; ++i, ++desc) { + fprintf (file, "\t\tLabel=%ld, Flags=0x%lX, ", desc->mChannelLabel, desc->mChannelFlags); + fprintf (file, "[az=%f,el=%f,dist=%f]\n", desc->mCoordinates[0], desc->mCoordinates[1], desc->mCoordinates[2]); + } + } +} diff --git a/libs/appleutility/CAAudioChannelLayout.h b/libs/appleutility/CAAudioChannelLayout.h new file mode 100644 index 0000000000..8f995b8614 --- /dev/null +++ b/libs/appleutility/CAAudioChannelLayout.h @@ -0,0 +1,162 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CAAudioChannelLayout.h + +=============================================================================*/ +#if !defined(__CAAudioChannelLayout_h__) +#define __CAAudioChannelLayout_h__ + +//============================================================================= +// Includes +//============================================================================= + +// System Includes +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include <CoreAudio/CoreAudioTypes.h> + #include <CoreFoundation/CoreFoundation.h> +#else + #include <CoreAudioTypes.h> + #include <CoreFoundation.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if !HAL_Build + #include "CAReferenceCounted.h" +#endif + +//============================================================================= +// CAAudioChannelLayout +//============================================================================= + +bool operator== (const AudioChannelLayout &x, const AudioChannelLayout &y); + +extern "C" void CAShowAudioChannelLayout (FILE* file, const AudioChannelLayout *layout); + +class CAAudioChannelLayout +{ +// static Construction/Destruction +public: + static AudioChannelLayout* Create(UInt32 inNumberChannelDescriptions); + static void Destroy(AudioChannelLayout* inChannelLayout); + static UInt32 CalculateByteSize(UInt32 inNumberChannelDescriptions) { + return offsetof(AudioChannelLayout, mChannelDescriptions) + inNumberChannelDescriptions * sizeof(AudioChannelDescription); + } + static void SetAllToUnknown(AudioChannelLayout& outChannelLayout, UInt32 inNumberChannelDescriptions); + static UInt32 NumberChannels(const AudioChannelLayout& inLayout); + +#if !HAL_Build +// object methods +public: + CAAudioChannelLayout (); + + CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround); + // if inChooseSurround is false, then symmetrical speaker arrangements + // are chosen in place of surround layouts if there is a choice + // This call chooses layouts based on the expected defaults in + // AudioUnit usage + CAAudioChannelLayout (AudioChannelLayoutTag inTag); + CAAudioChannelLayout (const CAAudioChannelLayout &c); + CAAudioChannelLayout (const AudioChannelLayout* inChannelLayout); + ~CAAudioChannelLayout(); + + CAAudioChannelLayout& operator= (const AudioChannelLayout* inChannelLayout); + CAAudioChannelLayout& operator= (const CAAudioChannelLayout& c); + bool operator== (const CAAudioChannelLayout &c) const; + + void SetWithTag(AudioChannelLayoutTag inTag); + + bool IsValid() const { return NumberChannels() > 0; } + UInt32 Size() const { return mLayoutHolder ? mLayoutHolder->Size() : 0; } + + UInt32 NumberChannels() const { return NumberChannels(Layout()); } + + AudioChannelLayoutTag Tag() const { return Layout().mChannelLayoutTag; } + const AudioChannelLayout& Layout() const { return mLayoutHolder->Layout(); } + operator const AudioChannelLayout *() const { return &Layout(); } + + void Print () const { Print (stdout); } + void Print (FILE* file) const; + + OSStatus Save (CFPropertyListRef *outData) const; + OSStatus Restore (CFPropertyListRef &inData); + +private: + class ACLRefCounter : public CAReferenceCounted { + public: + ACLRefCounter (UInt32 inDataSize) + { + if (inDataSize < offsetof(AudioChannelLayout, mChannelDescriptions)) + inDataSize = offsetof(AudioChannelLayout, mChannelDescriptions); + + mLayout = static_cast<AudioChannelLayout*>(malloc (inDataSize)); + memset (mLayout, 0, inDataSize); + mByteSize = inDataSize; + } + + const AudioChannelLayout & Layout() const { return *mLayout; } + + UInt32 Size () const { return mByteSize; } + + private: + AudioChannelLayout *mLayout; + UInt32 mByteSize; + + // only the constructors can change the actual state of the layout + friend CAAudioChannelLayout::CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround); + friend OSStatus CAAudioChannelLayout::Restore (CFPropertyListRef &inData); + friend CAAudioChannelLayout& CAAudioChannelLayout::operator= (const AudioChannelLayout* inChannelLayout); + friend void CAAudioChannelLayout::SetWithTag(AudioChannelLayoutTag inTag); + + AudioChannelLayout * GetLayout() { return mLayout; } + ~ACLRefCounter() { if (mLayout) { free(mLayout); mLayout = NULL; } } + + private: + ACLRefCounter () : mLayout(NULL) { } + ACLRefCounter(const ACLRefCounter& c) : mLayout(NULL) { } + ACLRefCounter& operator=(const ACLRefCounter& c) { return *this; } + }; + + ACLRefCounter *mLayoutHolder; +#endif // HAL_Build + +}; + +#endif diff --git a/libs/appleutility/CAAudioChannelLayoutObject.cpp b/libs/appleutility/CAAudioChannelLayoutObject.cpp new file mode 100644 index 0000000000..8c4030048d --- /dev/null +++ b/libs/appleutility/CAAudioChannelLayoutObject.cpp @@ -0,0 +1,199 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CAAudioChannelLayoutObject.cpp + +=============================================================================*/ + +#include "CAAudioChannelLayout.h" +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include <CoreServices/CoreServices.h> + #include <AudioToolbox/AudioFormat.h> +#else + #include <CoreServices.h> + #include <AudioFormat.h> +#endif + + +CAAudioChannelLayout::CAAudioChannelLayout () +{ + mLayoutHolder = new ACLRefCounter (offsetof(AudioChannelLayout, mChannelDescriptions)); +} + +//============================================================================= +// CAAudioChannelLayout::CAAudioChannelLayout +//============================================================================= +CAAudioChannelLayout::CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround) +{ + // this chooses default layouts based on the number of channels... + UInt32 theSize = CalculateByteSize (inNumberChannels); + + mLayoutHolder = new ACLRefCounter (theSize); + + AudioChannelLayout* layout = mLayoutHolder->GetLayout(); + + layout->mNumberChannelDescriptions = inNumberChannels; + + switch (inNumberChannels) + { + case 1: + layout->mChannelLayoutTag = kAudioChannelLayoutTag_Mono; + break; + case 2: + layout->mChannelLayoutTag = inChooseSurround ? kAudioChannelLayoutTag_Binaural : kAudioChannelLayoutTag_Stereo; + break; + case 4: + layout->mChannelLayoutTag = inChooseSurround ? kAudioChannelLayoutTag_Ambisonic_B_Format : kAudioChannelLayoutTag_AudioUnit_4; + break; + case 5: + layout->mChannelLayoutTag = inChooseSurround ? kAudioChannelLayoutTag_AudioUnit_5_0 : kAudioChannelLayoutTag_AudioUnit_5; + break; + case 6: + layout->mChannelLayoutTag = inChooseSurround ? kAudioChannelLayoutTag_AudioUnit_6_0 : kAudioChannelLayoutTag_AudioUnit_6; + break; + case 7: + layout->mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_7_0; + break; + case 8: + layout->mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_8; + break; + default: + // here we have a "broken" layout, in the sense that we haven't any idea how to lay this out + // the layout itself is all set to zeros + // ### no longer true ### + SetAllToUnknown(*layout, inNumberChannels); + break; + } +} + +//============================================================================= +// CAAudioChannelLayout::CAAudioChannelLayout +//============================================================================= +CAAudioChannelLayout::CAAudioChannelLayout (AudioChannelLayoutTag inLayoutTag) + : mLayoutHolder(NULL) +{ + SetWithTag(inLayoutTag); +} + +//============================================================================= +// CAAudioChannelLayout::CAAudioChannelLayout +//============================================================================= +CAAudioChannelLayout::CAAudioChannelLayout (const CAAudioChannelLayout &c) + : mLayoutHolder(NULL) +{ + *this = c; +} + + +//============================================================================= +// CAAudioChannelLayout::AudioChannelLayout +//============================================================================= +CAAudioChannelLayout::CAAudioChannelLayout (const AudioChannelLayout* inChannelLayout) + : mLayoutHolder(NULL) +{ + *this = inChannelLayout; +} + +//============================================================================= +// CAAudioChannelLayout::~CAAudioChannelLayout +//============================================================================= +CAAudioChannelLayout::~CAAudioChannelLayout () +{ + if (mLayoutHolder) { + mLayoutHolder->release(); + mLayoutHolder = NULL; + } +} + +//============================================================================= +// CAAudioChannelLayout::CAAudioChannelLayout +//============================================================================= +CAAudioChannelLayout& CAAudioChannelLayout::operator= (const CAAudioChannelLayout &c) +{ + if (mLayoutHolder != c.mLayoutHolder) { + if (mLayoutHolder) + mLayoutHolder->release(); + + if ((mLayoutHolder = c.mLayoutHolder) != NULL) + mLayoutHolder->retain(); + } + + return *this; +} + +CAAudioChannelLayout& CAAudioChannelLayout::operator= (const AudioChannelLayout* inChannelLayout) +{ + if (mLayoutHolder) + mLayoutHolder->release(); + + UInt32 theSize = CalculateByteSize (inChannelLayout->mNumberChannelDescriptions); + + mLayoutHolder = new ACLRefCounter (theSize); + + memcpy(mLayoutHolder->mLayout, inChannelLayout, theSize); + return *this; +} + +void CAAudioChannelLayout::SetWithTag(AudioChannelLayoutTag inTag) +{ + if (mLayoutHolder) + mLayoutHolder->release(); + + mLayoutHolder = new ACLRefCounter(offsetof(AudioChannelLayout, mChannelDescriptions[0])); + AudioChannelLayout* layout = mLayoutHolder->GetLayout(); + layout->mChannelLayoutTag = inTag; +} + +//============================================================================= +// CAAudioChannelLayout::operator== +//============================================================================= +bool CAAudioChannelLayout::operator== (const CAAudioChannelLayout &c) const +{ + if (mLayoutHolder == c.mLayoutHolder) + return true; + return Layout() == c.Layout(); +} + +//============================================================================= +// CAAudioChannelLayout::Print +//============================================================================= +void CAAudioChannelLayout::Print (FILE* file) const +{ + CAShowAudioChannelLayout (file, &Layout()); +} + diff --git a/libs/appleutility/CAAudioUnit.cpp b/libs/appleutility/CAAudioUnit.cpp new file mode 100644 index 0000000000..9244877d29 --- /dev/null +++ b/libs/appleutility/CAAudioUnit.cpp @@ -0,0 +1,1202 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CAAudioUnit.cpp + +=============================================================================*/ + +#include "CAAudioUnit.h" + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include <AudioUnit/MusicDevice.h> +#else + #include <MusicDevice.h> +#endif + +#include "CAReferenceCounted.h" +#include "AUOutputBL.h" //this is for the Preroll only + + +struct StackAUChannelInfo { + StackAUChannelInfo (UInt32 inSize) : mChanInfo ((AUChannelInfo*)malloc (inSize)) {} + ~StackAUChannelInfo() { free (mChanInfo); } + + AUChannelInfo* mChanInfo; +}; + + + +class CAAudioUnit::AUState : public CAReferenceCounted { +public: + AUState (Component inComp) + : mUnit(0), mNode (0) + { + OSStatus result = ::OpenAComponent (inComp, &mUnit); + if (result) + throw result; + Init(); + } + + AUState (const AUNode &inNode, const AudioUnit& inUnit) + : mUnit (inUnit), mNode (inNode) + { + Init(); + } + + ~AUState(); + + AudioUnit mUnit; + AUNode mNode; + + OSStatus GetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element, + Float32 &outValue) const + { + if (mGetParamProc != NULL) { + return reinterpret_cast<AudioUnitGetParameterProc>(mGetParamProc) (mConnInstanceStorage, + inID, scope, element, &outValue); + } + return AudioUnitGetParameter(mUnit, inID, scope, element, &outValue); + } + + OSStatus SetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element, + Float32 value, UInt32 bufferOffsetFrames) + { + if (mSetParamProc != NULL) { + return reinterpret_cast<AudioUnitSetParameterProc>(mSetParamProc) (mConnInstanceStorage, + inID, scope, element, value, bufferOffsetFrames); + } + return AudioUnitSetParameter(mUnit, inID, scope, element, value, bufferOffsetFrames); + } + + OSStatus Render (AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inOutputBusNumber, + UInt32 inNumberFrames, + AudioBufferList * ioData) + { + if (mRenderProc != NULL) { + return reinterpret_cast<AudioUnitRenderProc>(mRenderProc) (mConnInstanceStorage, + ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData); + } + return AudioUnitRender(mUnit, ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData); + } + + OSStatus MIDIEvent (UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame) + { +#if !TARGET_OS_WIN32 + if (mMIDIEventProc != NULL) { + return reinterpret_cast<MusicDeviceMIDIEventProc>(mMIDIEventProc) (mConnInstanceStorage, + inStatus, inData1, inData2, inOffsetSampleFrame); + } + return MusicDeviceMIDIEvent (mUnit, inStatus, inData1, inData2, inOffsetSampleFrame); +#else + return paramErr; +#endif + } + + OSStatus StartNote (MusicDeviceInstrumentID inInstrument, + MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams * inParams) + { +#if !TARGET_OS_WIN32 + return MusicDeviceStartNote (mUnit, inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, inParams); +#else + return paramErr; +#endif + } + OSStatus StopNote (MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame) + { +#if !TARGET_OS_WIN32 + return MusicDeviceStopNote (mUnit, inGroupID, inNoteInstanceID, inOffsetSampleFrame); +#else + return paramErr; +#endif + } + +private: + // get the fast dispatch pointers + void Init() + { + UInt32 size = sizeof(AudioUnitRenderProc); + if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch, + kAudioUnitScope_Global, kAudioUnitRenderSelect, + &mRenderProc, &size) != noErr) + mRenderProc = NULL; + if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch, + kAudioUnitScope_Global, kAudioUnitGetParameterSelect, + &mGetParamProc, &size) != noErr) + mGetParamProc = NULL; + if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch, + kAudioUnitScope_Global, kAudioUnitSetParameterSelect, + &mSetParamProc, &size) != noErr) + mSetParamProc = NULL; + + if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch, + kAudioUnitScope_Global, kMusicDeviceMIDIEventSelect, + &mMIDIEventProc, &size) != noErr) + mMIDIEventProc = NULL; + + if (mRenderProc || mGetParamProc || mSetParamProc || mMIDIEventProc) + mConnInstanceStorage = GetComponentInstanceStorage(mUnit); + else + mConnInstanceStorage = NULL; + } + + ProcPtr mRenderProc, mGetParamProc, mSetParamProc, mMIDIEventProc; + + void * mConnInstanceStorage; + +private: + // get the compiler to tell us when we do a bad thing!!! + AUState () {} + AUState (const AUState&) {} + AUState& operator= (const AUState&) { return *this; } +}; + + +CAAudioUnit::AUState::~AUState () +{ + if (mUnit && (mNode == 0)) { + ::CloseComponent (mUnit); + } + mNode = 0; + mUnit = 0; +} + +OSStatus CAAudioUnit::Open (const CAComponent& inComp, CAAudioUnit &outUnit) +{ + try { + outUnit = inComp; + return noErr; + } catch (OSStatus res) { + return res; + } catch (...) { + return -1; + } +} + +CAAudioUnit::CAAudioUnit (const AudioUnit& inUnit) + : mComp (inUnit), mDataPtr (new AUState (-1, inUnit)) +{ +} + +CAAudioUnit::CAAudioUnit (const CAComponent& inComp) + : mComp (inComp), mDataPtr (0) +{ + mDataPtr = new AUState (mComp.Comp()); +} + +CAAudioUnit::CAAudioUnit (const AUNode &inNode, const AudioUnit& inUnit) + : mComp (inUnit), mDataPtr(new AUState (inNode, inUnit)) +{ +} + +CAAudioUnit::~CAAudioUnit () +{ + if (mDataPtr) { + mDataPtr->release(); + mDataPtr = NULL; + } +} + +CAAudioUnit& CAAudioUnit::operator= (const CAAudioUnit &a) +{ + if (mDataPtr != a.mDataPtr) { + if (mDataPtr) + mDataPtr->release(); + + if ((mDataPtr = a.mDataPtr) != NULL) + mDataPtr->retain(); + + mComp = a.mComp; + } + + return *this; +} + +bool CAAudioUnit::operator== (const CAAudioUnit& y) const +{ + if (mDataPtr == y.mDataPtr) return true; + AudioUnit au1 = mDataPtr ? mDataPtr->mUnit : 0; + AudioUnit au2 = y.mDataPtr ? y.mDataPtr->mUnit : 0; + return au1 == au2; +} + +bool CAAudioUnit::operator== (const AudioUnit& y) const +{ + if (!mDataPtr) return false; + return mDataPtr->mUnit == y; +} + +#pragma mark __State Management + +bool CAAudioUnit::IsValid () const +{ + return mDataPtr ? mDataPtr->mUnit != 0 : false; +} + +AudioUnit CAAudioUnit::AU() const +{ + return mDataPtr ? mDataPtr->mUnit : 0; +} + +AUNode CAAudioUnit::GetAUNode () const +{ + return mDataPtr ? mDataPtr->mNode : 0; +} + +#pragma mark __Format Handling + +bool CAAudioUnit::CanDo ( int inChannelsIn, + int inChannelsOut) const +{ + // this is the default assumption of an audio effect unit + Boolean* isWritable = 0; + UInt32 dataSize = 0; + // lets see if the unit has any channel restrictions + OSStatus result = AudioUnitGetPropertyInfo (AU(), + kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, + &dataSize, isWritable); //don't care if this is writable + + // if this property is NOT implemented an FX unit + // is expected to deal with same channel valance in and out + if (result) + { + if (Comp().Desc().IsEffect() && (inChannelsIn == inChannelsOut) + || Comp().Desc().IsOffline() && (inChannelsIn == inChannelsOut)) + { + return true; + } + else + { + // the au should either really tell us about this + // or we will assume the worst + return false; + } + } + + StackAUChannelInfo info (dataSize); + + result = GetProperty (kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, + info.mChanInfo, &dataSize); + if (result) { return false; } + + return ValidateChannelPair (inChannelsIn, inChannelsOut, info.mChanInfo, (dataSize / sizeof (AUChannelInfo))); +} + +bool CAAudioUnit::ValidateChannelPair (int inChannelsIn, + int inChannelsOut, + const AUChannelInfo * info, + UInt32 numChanInfo) const +{ +// we've the following cases (some combinations) to test here: +/* +>0 An explicit number of channels on either side +0 that side (generally input!) has no elements +-1 wild card: +-1,-1 any num channels as long as same channels on in and out +-1,-2 any num channels channels on in and out - special meaning +-2+ indicates total num channs AU can handle + - elements configurable to any num channels, + - element count in scope must be writable +*/ + + //now chan layout can contain -1 for either scope (ie. doesn't care) + for (unsigned int i = 0; i < numChanInfo; ++i) + { + //less than zero on both sides - check for special attributes + if ((info[i].inChannels < 0) && (info[i].outChannels < 0)) + { + // these are our wild card matches + if (info[i].inChannels == -1 && info[i].outChannels == -1) { + if (inChannelsOut == inChannelsIn) { + return true; + } + } + else if ((info[i].inChannels == -1 && info[i].outChannels == -2) + || (info[i].inChannels == -2 && info[i].outChannels == -1)) + { + return true; + } + // these are our total num channels matches + // element count MUST be writable + else { + bool outWrite = false; bool inWrite = false; + IsElementCountWritable (kAudioUnitScope_Output, outWrite); + IsElementCountWritable (kAudioUnitScope_Input, inWrite); + if (inWrite && outWrite) { + if ((inChannelsOut <= abs(info[i].outChannels)) + && (inChannelsIn <= abs(info[i].inChannels))) + { + return true; + } + } + } + } + + // special meaning on input, specific num on output + else if (info[i].inChannels < 0) { + if (info[i].outChannels == inChannelsOut) + { + // can do any in channels + if (info[i].inChannels == -1) { + return true; + } + // total chans on input + else { + bool inWrite = false; + IsElementCountWritable (kAudioUnitScope_Input, inWrite); + if (inWrite && (inChannelsIn <= abs(info[i].inChannels))) { + return true; + } + } + } + } + + // special meaning on output, specific num on input + else if (info[i].outChannels < 0) { + if (info[i].inChannels == inChannelsIn) + { + // can do any out channels + if (info[i].outChannels == -1) { + return true; + } + // total chans on output + else { + bool outWrite = false; + IsElementCountWritable (kAudioUnitScope_Output, outWrite); + if (outWrite && (inChannelsOut <= abs(info[i].outChannels))) { + return true; + } + } + } + } + + // both chans in struct >= 0 - thus has to explicitly match + else if ((info[i].inChannels == inChannelsIn) && (info[i].outChannels == inChannelsOut)) { + return true; + } + + // now check to see if a wild card on the args (inChannelsIn or inChannelsOut chans is zero) is found + // tells us to match just one side of the scopes + else if (inChannelsIn == 0) { + if (info[i].outChannels == inChannelsOut) { + return true; + } + } + else if (inChannelsOut == 0) { + if (info[i].inChannels == inChannelsIn) { + return true; + } + } + } + + return false; +} + +bool CheckDynCount (SInt32 inTotalChans, const CAAUChanHelper &inHelper) +{ + int totalChans = 0; + for (unsigned int i = 0; i < inHelper.mNumEls; ++i) + totalChans += inHelper.mChans[i]; + return (totalChans <= inTotalChans); +} + +bool CAAudioUnit::CheckOneSide (const CAAUChanHelper &inHelper, + bool checkOutput, + const AUChannelInfo *info, + UInt32 numInfo) const +{ + // now we can use the wildcard option (see above impl) to see if this matches + for (unsigned int el = 0; el < inHelper.mNumEls; ++el) { + bool testAlready = false; + for (unsigned int i = 0; i < el; ++i) { + if (inHelper.mChans[i] == inHelper.mChans[el]) { + testAlready = true; + break; + } + } + if (!testAlready) { + if (checkOutput) { + if (!ValidateChannelPair (0, inHelper.mChans[el], info, numInfo)) return false; + } else { + if (!ValidateChannelPair (inHelper.mChans[el], 0, info, numInfo)) return false; + } + } + } + return true; +} + +bool CAAudioUnit::CanDo (const CAAUChanHelper &inputs, + const CAAUChanHelper &outputs) const + +{ +// first check our state + // huh! + if (inputs.mNumEls == 0 && outputs.mNumEls == 0) return false; + + UInt32 elCount; + if (GetElementCount (kAudioUnitScope_Input, elCount)) { return false; } + if (elCount != inputs.mNumEls) return false; + + if (GetElementCount (kAudioUnitScope_Output, elCount)) { return false; } + if (elCount != outputs.mNumEls) return false; + +// (1) special cases (effects and sources (generators and instruments) only) + UInt32 dataSize = 0; + if (GetPropertyInfo (kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, &dataSize, NULL) != noErr) + { + if (Comp().Desc().IsEffect() || Comp().Desc().IsOffline()) { + UInt32 numChan = outputs.mNumEls > 0 ? outputs.mChans[0] : inputs.mChans[0]; + for (unsigned int in = 0; in < inputs.mNumEls; ++in) + if (numChan != inputs.mChans[in]) return false; + for (unsigned int out = 0; out < outputs.mNumEls; ++out) + if (numChan != outputs.mChans[out]) return false; + return true; + } + + // in this case, all the channels have to match the current config + if (Comp().Desc().IsGenerator() || Comp().Desc().IsMusicDevice()) { + for (unsigned int in = 0; in < inputs.mNumEls; ++in) { + UInt32 chan; + if (NumberChannels (kAudioUnitScope_Input, in, chan)) return false; + if (chan != UInt32(inputs.mChans[in])) return false; + } + for (unsigned int out = 0; out < outputs.mNumEls; ++out) { + UInt32 chan; + if (NumberChannels (kAudioUnitScope_Output, out, chan)) return false; + if (chan != UInt32(outputs.mChans[out])) return false; + } + return true; + } + + // if we get here we can't determine anything about channel capabilities + return false; + } + + StackAUChannelInfo info (dataSize); + + if (GetProperty (kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, + info.mChanInfo, &dataSize) != noErr) + { + return false; + } + + int numInfo = dataSize / sizeof(AUChannelInfo); + +// (2) Test for dynamic capability (or no elements on that scope) + SInt32 dynInChans = 0; + if (ValidateDynamicScope (kAudioUnitScope_Input, dynInChans, info.mChanInfo, numInfo)) { + if (CheckDynCount (dynInChans, inputs) == false) return false; + } + + SInt32 dynOutChans = 0; + if (ValidateDynamicScope (kAudioUnitScope_Output, dynOutChans, info.mChanInfo, numInfo)) { + if (CheckDynCount (dynOutChans, outputs) == false) return false; + } + + if (dynOutChans && dynInChans) { return true; } + +// (3) Just need to test one side + if (dynInChans || (inputs.mNumEls == 0)) { + return CheckOneSide (outputs, true, info.mChanInfo, numInfo); + } + + if (dynOutChans || (outputs.mNumEls == 0)) { + return CheckOneSide (inputs, false, info.mChanInfo, numInfo); + } + +// (4) - not a dynamic AU, has ins and outs, and has channel constraints so we test every possible pairing + for (unsigned int in = 0; in < inputs.mNumEls; ++in) + { + bool testInAlready = false; + for (unsigned int i = 0; i < in; ++i) { + if (inputs.mChans[i] == inputs.mChans[in]) { + testInAlready = true; + break; + } + } + if (!testInAlready) { + for (unsigned int out = 0; out < outputs.mNumEls; ++out) { + // try to save a little bit and not test the same pairing multiple times... + bool testOutAlready = false; + for (unsigned int i = 0; i < out; ++i) { + if (outputs.mChans[i] == outputs.mChans[out]) { + testOutAlready = true; + break; + } + } + if (!testOutAlready) { + if (!ValidateChannelPair (inputs.mChans[in], outputs.mChans[out],info.mChanInfo, numInfo)) { + return false; + } + } + } + } + } + + return true; +} + +bool CAAudioUnit::SupportsNumChannels () const +{ + // this is the default assumption of an audio effect unit + Boolean* isWritable = 0; + UInt32 dataSize = 0; + // lets see if the unit has any channel restrictions + OSStatus result = AudioUnitGetPropertyInfo (AU(), + kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, + &dataSize, isWritable); //don't care if this is writable + + // if this property is NOT implemented an FX unit + // is expected to deal with same channel valance in and out + if (result) { + if (Comp().Desc().IsEffect() || Comp().Desc().IsOffline()) + return true; + } + return result == noErr; +} + +bool CAAudioUnit::GetChannelLayouts (AudioUnitScope inScope, + AudioUnitElement inEl, + ChannelTagVector &outChannelVector) const +{ + if (HasChannelLayouts (inScope, inEl) == false) return false; + + UInt32 dataSize; + OSStatus result = AudioUnitGetPropertyInfo (AU(), + kAudioUnitProperty_SupportedChannelLayoutTags, + inScope, inEl, + &dataSize, NULL); + + if (result == kAudioUnitErr_InvalidProperty) { + // if we get here we can do layouts but we've got the speaker config property + outChannelVector.erase (outChannelVector.begin(), outChannelVector.end()); + outChannelVector.push_back (kAudioChannelLayoutTag_Stereo); + outChannelVector.push_back (kAudioChannelLayoutTag_StereoHeadphones); + outChannelVector.push_back (kAudioChannelLayoutTag_Quadraphonic); + outChannelVector.push_back (kAudioChannelLayoutTag_AudioUnit_5_0); + return true; + } + + if (result) return false; + + bool canDo = false; + // OK lets get our channel layouts and see if the one we want is present + AudioChannelLayoutTag* info = (AudioChannelLayoutTag*)malloc (dataSize); + result = AudioUnitGetProperty (AU(), + kAudioUnitProperty_SupportedChannelLayoutTags, + inScope, inEl, + info, &dataSize); + if (result) goto home; + + outChannelVector.erase (outChannelVector.begin(), outChannelVector.end()); + for (unsigned int i = 0; i < (dataSize / sizeof (AudioChannelLayoutTag)); ++i) + outChannelVector.push_back (info[i]); + +home: + free (info); + return canDo; +} + +bool CAAudioUnit::HasChannelLayouts (AudioUnitScope inScope, + AudioUnitElement inEl) const +{ + OSStatus result = AudioUnitGetPropertyInfo (AU(), + kAudioUnitProperty_SupportedChannelLayoutTags, + inScope, inEl, + NULL, NULL); + return !result; +} + +OSStatus CAAudioUnit::GetChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl, + CAAudioChannelLayout &outLayout) const +{ + UInt32 size; + OSStatus result = AudioUnitGetPropertyInfo (AU(), kAudioUnitProperty_AudioChannelLayout, + inScope, inEl, &size, NULL); + if (result) return result; + + AudioChannelLayout *layout = (AudioChannelLayout*)malloc (size); + + require_noerr (result = AudioUnitGetProperty (AU(), kAudioUnitProperty_AudioChannelLayout, + inScope, inEl, layout, &size), home); + + outLayout = CAAudioChannelLayout (layout); + +home: + free (layout); + return result; +} + +OSStatus CAAudioUnit::SetChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl, + CAAudioChannelLayout &inLayout) +{ + OSStatus result = AudioUnitSetProperty (AU(), + kAudioUnitProperty_AudioChannelLayout, + inScope, inEl, + inLayout, inLayout.Size()); + return result; +} + +OSStatus CAAudioUnit::SetChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl, + AudioChannelLayout &inLayout, + UInt32 inSize) +{ + OSStatus result = AudioUnitSetProperty (AU(), + kAudioUnitProperty_AudioChannelLayout, + inScope, inEl, + &inLayout, inSize); + return result; +} + +OSStatus CAAudioUnit::ClearChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl) +{ + return AudioUnitSetProperty (AU(), + kAudioUnitProperty_AudioChannelLayout, + inScope, inEl, NULL, 0); +} + +OSStatus CAAudioUnit::GetFormat (AudioUnitScope inScope, + AudioUnitElement inEl, + AudioStreamBasicDescription &outFormat) const +{ + UInt32 dataSize = sizeof (AudioStreamBasicDescription); + return AudioUnitGetProperty (AU(), kAudioUnitProperty_StreamFormat, + inScope, inEl, + &outFormat, &dataSize); +} + +OSStatus CAAudioUnit::SetFormat (AudioUnitScope inScope, + AudioUnitElement inEl, + const AudioStreamBasicDescription &inFormat) +{ + return AudioUnitSetProperty (AU(), kAudioUnitProperty_StreamFormat, + inScope, inEl, + const_cast<AudioStreamBasicDescription*>(&inFormat), + sizeof (AudioStreamBasicDescription)); +} + +OSStatus CAAudioUnit::GetSampleRate (AudioUnitScope inScope, + AudioUnitElement inEl, + Float64 &outRate) const +{ + UInt32 dataSize = sizeof (Float64); + return AudioUnitGetProperty (AU(), kAudioUnitProperty_SampleRate, + inScope, inEl, + &outRate, &dataSize); +} + +OSStatus CAAudioUnit::SetSampleRate (AudioUnitScope inScope, + AudioUnitElement inEl, + Float64 inRate) +{ + AudioStreamBasicDescription desc; + OSStatus result = GetFormat (inScope, inEl, desc); + if (result) return result; + desc.mSampleRate = inRate; + return SetFormat (inScope, inEl, desc); +} + +OSStatus CAAudioUnit::SetSampleRate (Float64 inSampleRate) +{ + OSStatus result; + + UInt32 elCount; + require_noerr (result = GetElementCount(kAudioUnitScope_Input, elCount), home); + if (elCount) { + for (unsigned int i = 0; i < elCount; ++i) { + require_noerr (result = SetSampleRate (kAudioUnitScope_Input, i, inSampleRate), home); + } + } + + require_noerr (result = GetElementCount(kAudioUnitScope_Output, elCount), home); + if (elCount) { + for (unsigned int i = 0; i < elCount; ++i) { + require_noerr (result = SetSampleRate (kAudioUnitScope_Output, i, inSampleRate), home); + } + } + +home: + return result; +} + +OSStatus CAAudioUnit::NumberChannels (AudioUnitScope inScope, + AudioUnitElement inEl, + UInt32 &outChans) const +{ + AudioStreamBasicDescription desc; + OSStatus result = GetFormat (inScope, inEl, desc); + if (!result) + outChans = desc.mChannelsPerFrame; + return result; +} + +OSStatus CAAudioUnit::SetNumberChannels (AudioUnitScope inScope, + AudioUnitElement inEl, + UInt32 inChans) +{ + // set this as the output of the AU + CAStreamBasicDescription desc; + OSStatus result = GetFormat (inScope, inEl, desc); + if (result) return result; + desc.SetCanonical (inChans, desc.IsInterleaved()); + result = SetFormat (inScope, inEl, desc); + return result; +} + +OSStatus CAAudioUnit::IsElementCountWritable (AudioUnitScope inScope, bool &outWritable) const +{ + Boolean isWritable; + UInt32 outDataSize; + OSStatus result = GetPropertyInfo (kAudioUnitProperty_ElementCount, inScope, 0, &outDataSize, &isWritable); + if (result) + return result; + outWritable = isWritable ? true : false; + return noErr; +} + +OSStatus CAAudioUnit::GetElementCount (AudioUnitScope inScope, UInt32 &outCount) const +{ + UInt32 propSize = sizeof(outCount); + return GetProperty (kAudioUnitProperty_ElementCount, inScope, 0, &outCount, &propSize); +} + +OSStatus CAAudioUnit::SetElementCount (AudioUnitScope inScope, UInt32 inCount) +{ + return SetProperty (kAudioUnitProperty_ElementCount, inScope, 0, &inCount, sizeof(inCount)); +} + +bool CAAudioUnit::HasDynamicScope (AudioUnitScope inScope, SInt32 &outTotalNumChannels) const +{ + // ok - now we need to check the AU's capability here. + // this is the default assumption of an audio effect unit + Boolean* isWritable = 0; + UInt32 dataSize = 0; + OSStatus result = GetPropertyInfo (kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, + &dataSize, isWritable); //don't care if this is writable + + // AU has to explicitly tell us about this. + if (result) return false; + + StackAUChannelInfo info (dataSize); + + result = GetProperty (kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, + info.mChanInfo, &dataSize); + if (result) return false; + + return ValidateDynamicScope (inScope, outTotalNumChannels, info.mChanInfo, (dataSize / sizeof(AUChannelInfo))); +} + +// as we've already checked that the element count is writable +// the following conditions will match this.. +/* +-1, -2 -> signifies no restrictions +-2, -1 -> signifies no restrictions -> in this case outTotalNumChannels == -1 (any num channels) + +-N (where N is less than -2), signifies the total channel count on the scope side (in or out) +*/ +bool CAAudioUnit::ValidateDynamicScope (AudioUnitScope inScope, + SInt32 &outTotalNumChannels, + const AUChannelInfo *info, + UInt32 numInfo) const +{ + bool writable = false; + OSStatus result = IsElementCountWritable (inScope, writable); + if (result || (writable == false)) + return false; + + //now chan layout can contain -1 for either scope (ie. doesn't care) + for (unsigned int i = 0; i < numInfo; ++i) + { + // lets test the special wild card case first... + // this says the AU can do any num channels on input or output - for eg. Matrix Mixer + if (((info[i].inChannels == -1) && (info[i].outChannels == -2)) + || ((info[i].inChannels == -2) && (info[i].outChannels == -1))) + { + outTotalNumChannels = -1; + return true; + } + + // ok lets now test our special case.... + if (inScope == kAudioUnitScope_Input) { + // isn't dynamic on this side at least + if (info[i].inChannels >= 0) + continue; + + if (info[i].inChannels < -2) { + outTotalNumChannels = abs (info[i].inChannels); + return true; + } + } + + else if (inScope == kAudioUnitScope_Output) { + // isn't dynamic on this side at least + if (info[i].outChannels >= 0) + continue; + + if (info[i].outChannels < -2) { + outTotalNumChannels = abs (info[i].outChannels); + return true; + } + } + + else { + break; // wrong scope was specified + } + } + + return false; +} + +OSStatus CAAudioUnit::ConfigureDynamicScope (AudioUnitScope inScope, + UInt32 inNumElements, + UInt32 *inChannelsPerElement, + Float64 inSampleRate) +{ + SInt32 numChannels = 0; + bool isDyamic = HasDynamicScope (inScope, numChannels); + if (isDyamic == false) + return kAudioUnitErr_InvalidProperty; + + //lets to a sanity check... + // if numChannels == -1, then it can do "any"... + if (numChannels > 0) { + SInt32 count = 0; + for (unsigned int i = 0; i < inNumElements; ++i) + count += inChannelsPerElement[i]; + if (count > numChannels) + return kAudioUnitErr_InvalidPropertyValue; + } + + OSStatus result = SetElementCount (inScope, inNumElements); + if (result) + return result; + + CAStreamBasicDescription desc; + desc.mSampleRate = inSampleRate; + for (unsigned int i = 0; i < inNumElements; ++i) { + desc.SetCanonical (inChannelsPerElement[i], false); + result = SetFormat (inScope, i, desc); + if (result) + return result; + } + return noErr; +} + +#pragma mark __Properties + +bool CAAudioUnit::CanBypass () const +{ + Boolean outWritable; + OSStatus result = AudioUnitGetPropertyInfo (AU(), kAudioUnitProperty_BypassEffect, + kAudioUnitScope_Global, 0, + NULL, &outWritable); + return (!result && outWritable); +} + +bool CAAudioUnit::GetBypass () const +{ + UInt32 dataSize = sizeof (UInt32); + UInt32 outBypass; + OSStatus result = AudioUnitGetProperty (AU(), kAudioUnitProperty_BypassEffect, + kAudioUnitScope_Global, 0, + &outBypass, &dataSize); + return (result ? false : outBypass); +} + +OSStatus CAAudioUnit::SetBypass (bool inBypass) const +{ + UInt32 bypass = inBypass ? 1 : 0; + return AudioUnitSetProperty (AU(), kAudioUnitProperty_BypassEffect, + kAudioUnitScope_Global, 0, + &bypass, sizeof (UInt32)); +} + +Float64 CAAudioUnit::Latency () const +{ + Float64 secs; + UInt32 size = sizeof(secs); + if (GetProperty (kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0, &secs, &size)) + return 0; + return secs; +} + +OSStatus CAAudioUnit::GetAUPreset (CFPropertyListRef &outData) const +{ + UInt32 dataSize = sizeof(outData); + return AudioUnitGetProperty (AU(), kAudioUnitProperty_ClassInfo, + kAudioUnitScope_Global, 0, + &outData, &dataSize); +} + +OSStatus CAAudioUnit::SetAUPreset (CFPropertyListRef &inData) +{ + return AudioUnitSetProperty (AU(), kAudioUnitProperty_ClassInfo, + kAudioUnitScope_Global, 0, + &inData, sizeof (CFPropertyListRef)); +} + +OSStatus CAAudioUnit::GetPresentPreset (AUPreset &outData) const +{ + UInt32 dataSize = sizeof(outData); + OSStatus result = AudioUnitGetProperty (AU(), kAudioUnitProperty_PresentPreset, + kAudioUnitScope_Global, 0, + &outData, &dataSize); + if (result == kAudioUnitErr_InvalidProperty) { + dataSize = sizeof(outData); + result = AudioUnitGetProperty (AU(), kAudioUnitProperty_CurrentPreset, + kAudioUnitScope_Global, 0, + &outData, &dataSize); + if (result == noErr) { + // we now retain the CFString in the preset so for the client of this API + // it is consistent (ie. the string should be released when done) + if (outData.presetName) + CFRetain (outData.presetName); + } + } + return result; +} + +OSStatus CAAudioUnit::SetPresentPreset (AUPreset &inData) +{ + OSStatus result = AudioUnitSetProperty (AU(), kAudioUnitProperty_PresentPreset, + kAudioUnitScope_Global, 0, + &inData, sizeof (AUPreset)); + if (result == kAudioUnitErr_InvalidProperty) { + result = AudioUnitSetProperty (AU(), kAudioUnitProperty_CurrentPreset, + kAudioUnitScope_Global, 0, + &inData, sizeof (AUPreset)); + } + return result; +} + +bool CAAudioUnit::HasCustomView () const +{ + UInt32 dataSize = 0; + OSStatus result = GetPropertyInfo(kAudioUnitProperty_GetUIComponentList, + kAudioUnitScope_Global, 0, + &dataSize, NULL); + if (result || !dataSize) { + dataSize = 0; + result = GetPropertyInfo(kAudioUnitProperty_CocoaUI, + kAudioUnitScope_Global, 0, + &dataSize, NULL); + if (result || !dataSize) + return false; + } + return true; +} + +OSStatus CAAudioUnit::GetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element, + Float32 &outValue) const +{ + return mDataPtr ? mDataPtr->GetParameter (inID, scope, element, outValue) : paramErr; +} + +OSStatus CAAudioUnit::SetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element, + Float32 value, UInt32 bufferOffsetFrames) +{ + return mDataPtr ? mDataPtr->SetParameter (inID, scope, element, value, bufferOffsetFrames) : paramErr; +} + +OSStatus CAAudioUnit::MIDIEvent (UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame) +{ + return mDataPtr ? mDataPtr->MIDIEvent (inStatus, inData1, inData2, inOffsetSampleFrame) : paramErr; +} + +OSStatus CAAudioUnit::StartNote (MusicDeviceInstrumentID inInstrument, + MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams * inParams) +{ + return mDataPtr ? mDataPtr->StartNote (inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, inParams) + : paramErr; +} + +OSStatus CAAudioUnit::StopNote (MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame) +{ + return mDataPtr ? mDataPtr->StopNote (inGroupID, inNoteInstanceID, inOffsetSampleFrame) : paramErr; +} + +#pragma mark __Render + +OSStatus CAAudioUnit::Render (AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inOutputBusNumber, + UInt32 inNumberFrames, + AudioBufferList * ioData) +{ + return mDataPtr ? mDataPtr->Render (ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData) : paramErr; +} + +static AURenderCallbackStruct sRenderCallback; +static OSStatus PrerollRenderProc ( void * /*inRefCon*/, + AudioUnitRenderActionFlags * /*inActionFlags*/, + const AudioTimeStamp * /*inTimeStamp*/, + UInt32 /*inBusNumber*/, + UInt32 /*inNumFrames*/, + AudioBufferList *ioData) +{ + AudioBuffer *buf = ioData->mBuffers; + for (UInt32 i = ioData->mNumberBuffers; i--; ++buf) + memset((Byte *)buf->mData, 0, buf->mDataByteSize); + + return noErr; +} + +OSStatus CAAudioUnit::Preroll (UInt32 inFrameSize) +{ + CAStreamBasicDescription desc; + OSStatus result = GetFormat (kAudioUnitScope_Input, 0, desc); + bool hasInput = false; + //we have input + if (result == noErr) + { + sRenderCallback.inputProc = PrerollRenderProc; + sRenderCallback.inputProcRefCon = 0; + + result = SetProperty (kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, + 0, &sRenderCallback, sizeof(sRenderCallback)); + if (result) return result; + hasInput = true; + } + + AudioUnitRenderActionFlags flags = 0; + AudioTimeStamp time; + memset (&time, 0, sizeof(time)); + time.mFlags = kAudioTimeStampSampleTimeValid; + + CAStreamBasicDescription outputFormat; + require_noerr (result = GetFormat (kAudioUnitScope_Output, 0, outputFormat), home); + { + AUOutputBL list (outputFormat, inFrameSize); + list.Prepare (); + + require_noerr (result = Render (&flags, &time, 0, inFrameSize, list.ABL()), home); + require_noerr (result = GlobalReset(), home); + } + +home: + if (hasInput) { + // remove our installed callback + sRenderCallback.inputProc = 0; + sRenderCallback.inputProcRefCon = 0; + + SetProperty (kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, + 0, &sRenderCallback, sizeof(sRenderCallback)); + } + return result; +} + +#pragma mark __CAAUChanHelper + +CAAUChanHelper::CAAUChanHelper(const CAAudioUnit &inAU, AudioUnitScope inScope) + :mChans(NULL), mNumEls(0), mDidAllocate(false) +{ + UInt32 elCount; + if (inAU.GetElementCount (inScope, elCount)) return; + if (elCount > 8) { + mChans = new UInt32[elCount]; + mDidAllocate = true; + memset (mChans, 0, sizeof(int) * elCount); + } else { + mChans = mStaticChans; + memset (mChans, 0, sizeof(int) * 8); + } + for (unsigned int i = 0; i < elCount; ++i) { + UInt32 numChans; + if (inAU.NumberChannels (inScope, i, numChans)) return; + mChans[i] = numChans; + } + mNumEls = elCount; +} + +CAAUChanHelper::~CAAUChanHelper() +{ + if (mDidAllocate) delete [] mChans; +} + +CAAUChanHelper& CAAUChanHelper::operator= (const CAAUChanHelper &c) +{ + if (mDidAllocate) delete [] mChans; + if (c.mDidAllocate) { + mChans = new UInt32[c.mNumEls]; + mDidAllocate = true; + } else { + mDidAllocate = false; + mChans = mStaticChans; + } + memcpy (mChans, c.mChans, c.mNumEls * sizeof(int)); + + return *this; +} + +#pragma mark __Print Utilities + +void CAAudioUnit::Print (FILE* file) const +{ + fprintf (file, "AudioUnit:%p\n", AU()); + if (IsValid()) { + fprintf (file, "\tnode=%ld\t", (long)GetAUNode()); Comp().Print (file); + } +} diff --git a/libs/appleutility/CAAudioUnit.h b/libs/appleutility/CAAudioUnit.h new file mode 100644 index 0000000000..6bc31bf30b --- /dev/null +++ b/libs/appleutility/CAAudioUnit.h @@ -0,0 +1,383 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CAAudioUnit.h + +=============================================================================*/ + +#ifndef __CAAudioUnit_h__ +#define __CAAudioUnit_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include <CoreServices/CoreServices.h> + #include <CoreAudio/CoreAudio.h> + #include <AudioUnit/AudioUnit.h> + #include <AudioToolbox/AUGraph.h> +#else + #include <ConditionalMacros.h> + #include <CoreServices.h> + #include <CoreAudioTypes.h> + #include <AudioUnit.h> + #include <AUGraph.h> +#endif + +#include <vector> +#include "CAStreamBasicDescription.h" +#include "CAComponent.h" +#include "CAAudioChannelLayout.h" + +// defined below +class CAAUChanHelper; + +// These constructors will NOT throw exceptions - so "check" after creation if AU IsValid() +// The destructor will NOT automatically close the AU down +// This state should be managed by the Caller +// once closed, the unit represented by this object is no longer valid +// it is up to the user of this object to ensure its validity is in sync +// if it is removed from a graph + +// methods that can significantly change the state of the AU (like its format) are +// NOT const whereas those that don't change the externally related state of the AU are not const + +class CAAudioUnit { +public: + typedef std::vector<AudioChannelLayoutTag> ChannelTagVector; + typedef ChannelTagVector::iterator ChannelTagVectorIter; + +public: + CAAudioUnit () + : mDataPtr(0) {} + + CAAudioUnit (const AudioUnit& inUnit); + + CAAudioUnit (const AUNode &inNode, const AudioUnit& inUnit); + + CAAudioUnit (const CAAudioUnit& y) + : mDataPtr(0) { *this = y; } + + static OSStatus Open (const CAComponent& inComp, CAAudioUnit &outUnit); + + ~CAAudioUnit (); + + + CAAudioUnit& operator= (const CAAudioUnit& y); + + bool operator== (const CAAudioUnit& y) const; + + bool operator== (const AudioUnit& y) const; + +#pragma mark __State Management + bool IsValid () const; + + AudioUnit AU() const; + operator AudioUnit () const { return AU(); } + + const CAComponent& Comp() const { return mComp; } + + bool FromAUGraph () const { return GetAUNode() != 0 || GetAUNode() != -1; } + + AUNode GetAUNode () const; + operator AUNode () const { return GetAUNode(); } + +#pragma mark __API Wrapper + OSStatus Initialize() const { return AudioUnitInitialize(AU()); } + OSStatus Uninitialize() const { return AudioUnitUninitialize(AU()); } + OSStatus GetPropertyInfo(AudioUnitPropertyID propID, AudioUnitScope scope, AudioUnitElement element, + UInt32 *outDataSize, Boolean *outWritable) const + { + return AudioUnitGetPropertyInfo(AU(), propID, scope, element, outDataSize, outWritable); + } + OSStatus GetProperty(AudioUnitPropertyID propID, AudioUnitScope scope, AudioUnitElement element, + void *outData, UInt32 *ioDataSize) const + { + return AudioUnitGetProperty(AU(), propID, scope, element, outData, ioDataSize); + } + OSStatus SetProperty(AudioUnitPropertyID propID, AudioUnitScope scope, AudioUnitElement element, + const void *inData, UInt32 inDataSize) + { + return AudioUnitSetProperty(AU(), propID, scope, element, inData, inDataSize); + } + OSStatus SetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element, + Float32 value, UInt32 bufferOffsetFrames=0); + + OSStatus GetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element, + Float32 &outValue) const; + + OSStatus Render (AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inOutputBusNumber, + UInt32 inNumberFrames, + AudioBufferList * ioData); + + OSStatus Reset (AudioUnitScope scope, AudioUnitElement element) + { + return AudioUnitReset (AU(), scope, element); + } + OSStatus GlobalReset () + { + return AudioUnitReset (AU(), kAudioUnitScope_Global, 0); + } + + OSStatus Preroll (UInt32 inFrameSize); + + OSStatus AddRenderNotify (AURenderCallback inProc, void *inProcRefCon) + { + return AudioUnitAddRenderNotify (AU(), inProc, inProcRefCon); + } + + OSStatus RemoveRenderNotify (AURenderCallback inProc, void *inProcRefCon) + { + return AudioUnitRemoveRenderNotify (AU(), inProc, inProcRefCon); + } + + +// Fast dispatch support for MIDI Effects or Music Devices + OSStatus MIDIEvent (UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame); + + // uses the default VoiceForGroup value - this is the normal case + OSStatus StartNote (MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams * inParams) + { + return StartNote (kMusicNoteEvent_UseGroupInstrument, + inGroupID, outNoteInstanceID, + inOffsetSampleFrame, inParams); + } + + OSStatus StartNote (MusicDeviceInstrumentID inInstrument, + MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams * inParams); + + OSStatus StopNote (MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame); + +#pragma mark __Format Utilities + // typically you ask this about an AU + // These Questions are asking about Input and Output... + + // These ones just say whether an AU can do a single combination of channels + // and is fine if the AU has a single output (and if an input, a single input) + bool CanDo (int inChannelsInOut) const + { + return CanDo (inChannelsInOut, inChannelsInOut); + } + + bool CanDo ( int inChannelsIn, + int inChannelsOut) const; + + // This version does a more thorough test for ANY AU with ANY ins/outs + // you pass in the channel helper (for the current element count on that scope) + + bool CanDo ( const CAAUChanHelper &input, + const CAAUChanHelper &output) const; + + bool SupportsNumChannels () const; + + bool HasChannelLayouts (AudioUnitScope inScope, + AudioUnitElement inEl) const; + + bool GetChannelLayouts (AudioUnitScope inScope, + AudioUnitElement inEl, + ChannelTagVector &outChannelVector) const; + + OSStatus GetChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl, + CAAudioChannelLayout &outLayout) const; + + OSStatus SetChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl, + CAAudioChannelLayout &inLayout); + + OSStatus SetChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl, + AudioChannelLayout &inLayout, + UInt32 inSize); + + OSStatus ClearChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl); + + OSStatus GetFormat (AudioUnitScope inScope, + AudioUnitElement inEl, + AudioStreamBasicDescription &outFormat) const; + // if an AudioChannelLayout is either required or set, this call can fail + // and the SetChannelLayout call should be used to set the format + OSStatus SetFormat (AudioUnitScope inScope, + AudioUnitElement inEl, + const AudioStreamBasicDescription &inFormat); + + OSStatus GetSampleRate (AudioUnitScope inScope, + AudioUnitElement inEl, + Float64 &outRate) const; + OSStatus SetSampleRate (AudioUnitScope inScope, + AudioUnitElement inEl, + Float64 inRate); + + // this sets the sample rate on all in/out buses of the AU + OSStatus SetSampleRate (Float64 inSampleRate); + + OSStatus NumberChannels (AudioUnitScope inScope, + AudioUnitElement inEl, + UInt32 &outChans) const; + + OSStatus GetNumberChannels (AudioUnitScope inScope, + AudioUnitElement inEl, + UInt32 &outChans) const + { + return NumberChannels (inScope, inEl, outChans); + } + + OSStatus SetNumberChannels (AudioUnitScope inScope, + AudioUnitElement inEl, + UInt32 inChans); + + OSStatus IsElementCountWritable (AudioUnitScope inScope, bool &outWritable) const; + + OSStatus GetElementCount (AudioUnitScope inScope, UInt32 &outCount) const; + + OSStatus SetElementCount (AudioUnitScope inScope, UInt32 inCount); + + // value of -1 for outTotalNumChannels indicates no restriction on num channels + // for ex. the Matrix Mixer satisfies this (its in/out element count is writable, and can be set to + // any number of channels. + // outTotalNumChannels is only valid if method returns true... + bool HasDynamicInputs (SInt32 &outTotalNumChannels) const + { + return HasDynamicScope (kAudioUnitScope_Input, outTotalNumChannels); + } + + bool HasDynamicOutputs (SInt32 &outTotalNumChannels) const + { + return HasDynamicScope (kAudioUnitScope_Output, outTotalNumChannels); + } + + // here, if the in (or out) elements are dynamic, then you supply the number of elements + // you want on in (or out) scope, and the number of channels on each consecutive element + OSStatus ConfigureDynamicInput (UInt32 inNumElements, UInt32 *inChannelsPerElement, Float64 inSampleRate) + { + return ConfigureDynamicScope (kAudioUnitScope_Input, inNumElements, inChannelsPerElement, inSampleRate); + } + + OSStatus ConfigureDynamicOutput (UInt32 inNumElements, UInt32 *inChannelsPerElement, Float64 inSampleRate) + { + return ConfigureDynamicScope (kAudioUnitScope_Output, inNumElements, inChannelsPerElement, inSampleRate); + } + + bool CanBypass () const; + + bool GetBypass () const; + + OSStatus SetBypass (bool inBypass) const; + + Float64 Latency () const; + + // these calls just deal with the global preset state + // you could rescope them to deal with presets on the part scope + OSStatus GetAUPreset (CFPropertyListRef &outData) const; + + OSStatus SetAUPreset (CFPropertyListRef &inData); + + OSStatus GetPresentPreset (AUPreset &outData) const; + + OSStatus SetPresentPreset (AUPreset &inData); + + bool HasCustomView () const; + +#pragma mark __Print + void Print () const { Print (stdout); } + void Print (FILE* file) const; + +private: + CAComponent mComp; + + class AUState; + AUState* mDataPtr; + + // this can throw - so wrap this up in a static that returns a result code... + CAAudioUnit (const CAComponent& inComp); + + bool HasDynamicScope (AudioUnitScope inScope, SInt32 &outTotalNumChannels) const; + OSStatus ConfigureDynamicScope (AudioUnitScope inScope, + UInt32 inNumElements, + UInt32 *inChannelsPerElement, + Float64 inSampleRate); + bool ValidateChannelPair (int inChannelsIn, + int inChannelsOut, + const AUChannelInfo * info, + UInt32 numChanInfo) const; + + bool ValidateDynamicScope (AudioUnitScope inScope, + SInt32 &outTotalNumChannels, + const AUChannelInfo * info, + UInt32 numInfo) const; + bool CheckOneSide (const CAAUChanHelper &inHelper, + bool checkOutput, + const AUChannelInfo *info, + UInt32 numInfo) const; + +}; + +class CAAUChanHelper { +public: + CAAUChanHelper() + : mChans(mStaticChans), mNumEls(0), mDidAllocate(false) + { + memset (mChans, 0, sizeof(UInt32) * 8); + } + CAAUChanHelper(const CAAudioUnit &inAU, AudioUnitScope inScope); + CAAUChanHelper (const CAAUChanHelper &c) :mChans(mStaticChans), mNumEls(0), mDidAllocate(false) { *this = c; } + + ~CAAUChanHelper(); + + CAAUChanHelper& operator= (const CAAUChanHelper &c); + + UInt32 * mChans; + UInt32 mNumEls; + +private: + UInt32 mStaticChans[8]; + bool mDidAllocate; +}; + +#endif diff --git a/libs/appleutility/CACFDictionary.cpp b/libs/appleutility/CACFDictionary.cpp new file mode 100644 index 0000000000..c209b5fc36 --- /dev/null +++ b/libs/appleutility/CACFDictionary.cpp @@ -0,0 +1,478 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CACFDictionary.cpp + CAAudioEngine + +=============================================================================*/ + +//============================================================================= +// Includes +//============================================================================= + +// Self Include +#include "CACFDictionary.h" + +// PublicUtility Includes +#include "CACFString.h" +#include "CACFNumber.h" + +//============================================================================= +// CACFDictionary +//============================================================================= + +bool CACFDictionary::HasKey(const CFStringRef inKey) const +{ + return CFDictionaryContainsKey(mCFDictionary, inKey) != 0; +} + +UInt32 CACFDictionary::Size () const +{ + return CFDictionaryGetCount(mCFDictionary); +} + +void CACFDictionary::GetKeys (const void **keys) const +{ + CFDictionaryGetKeysAndValues(mCFDictionary, keys, NULL); +} + +bool CACFDictionary::GetBool(const CFStringRef inKey, bool& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFBooleanGetTypeID())) + { + outValue = CFBooleanGetValue(static_cast<CFBooleanRef>(theValue)); + theAnswer = true; + } + else if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + SInt32 theNumericValue = 0; + CFNumberGetValue(static_cast<CFNumberRef>(theValue), kCFNumberSInt32Type, &theNumericValue); + outValue = theNumericValue != 0; + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetSInt32(const CFStringRef inKey, SInt32& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast<CFNumberRef>(theValue), kCFNumberSInt32Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetUInt32(const CFStringRef inKey, UInt32& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast<CFNumberRef>(theValue), kCFNumberSInt32Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetSInt64(const CFStringRef inKey, SInt64& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast<CFNumberRef>(theValue), kCFNumberSInt64Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetUInt64(const CFStringRef inKey, UInt64& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast<CFNumberRef>(theValue), kCFNumberSInt64Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetFloat32(const CFStringRef inKey, Float32& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast<CFNumberRef>(theValue), kCFNumberFloat32Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetFloat64(const CFStringRef inKey, Float64& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast<CFNumberRef>(theValue), kCFNumberFloat64Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetString(const CFStringRef inKey, CFStringRef& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFStringGetTypeID())) + { + outValue = static_cast<CFStringRef>(theValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetArray(const CFStringRef inKey, CFArrayRef& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFArrayGetTypeID())) + { + outValue = static_cast<CFArrayRef>(theValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetDictionary(const CFStringRef inKey, CFDictionaryRef& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFDictionaryGetTypeID())) + { + outValue = static_cast<CFDictionaryRef>(theValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetData(const CFStringRef inKey, CFDataRef& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFDataGetTypeID())) + { + outValue = static_cast<CFDataRef>(theValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetCFType(const CFStringRef inKey, CFTypeRef& outValue) const +{ + bool theAnswer = false; + + if(mCFDictionary != NULL) + { + outValue = CFDictionaryGetValue(mCFDictionary, inKey); + theAnswer = (outValue != NULL); + } + + return theAnswer; +} + +bool CACFDictionary::GetCFTypeWithCStringKey(const char* inKey, CFTypeRef& outValue) const +{ + bool theAnswer = false; + + if(mCFDictionary != NULL) + { + CACFString theKey(inKey); + if(theKey.IsValid()) + { + theAnswer = GetCFType(theKey.GetCFString(), outValue); + } + } + + return theAnswer; +} + +bool CACFDictionary::AddSInt32(const CFStringRef inKey, SInt32 inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFNumber theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFNumber()); + } + + return theAnswer; +} + +bool CACFDictionary::AddUInt32(const CFStringRef inKey, UInt32 inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFNumber theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFNumber()); + } + + return theAnswer; +} + +bool CACFDictionary::AddSInt64(const CFStringRef inKey, SInt64 inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFNumber theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFNumber()); + } + + return theAnswer; +} + +bool CACFDictionary::AddUInt64(const CFStringRef inKey, UInt64 inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFNumber theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFNumber()); + } + + return theAnswer; +} + +bool CACFDictionary::AddFloat32(const CFStringRef inKey, Float32 inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFNumber theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFNumber()); + } + + return theAnswer; +} + +bool CACFDictionary::AddFloat64(const CFStringRef inKey, Float64 inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFNumber theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFNumber()); + } + + return theAnswer; +} + +bool CACFDictionary::AddNumber(const CFStringRef inKey, const CFNumberRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + theAnswer = AddCFType(inKey, inValue); + } + + return theAnswer; +} + +bool CACFDictionary::AddString(const CFStringRef inKey, const CFStringRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + theAnswer = AddCFType(inKey, inValue); + } + + return theAnswer; +} + +bool CACFDictionary::AddArray(const CFStringRef inKey, const CFArrayRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + theAnswer = AddCFType(inKey, inValue); + } + + return theAnswer; +} + +bool CACFDictionary::AddDictionary(const CFStringRef inKey, const CFDictionaryRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + theAnswer = AddCFType(inKey, inValue); + } + + return theAnswer; +} + +bool CACFDictionary::AddData(const CFStringRef inKey, const CFDataRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + theAnswer = AddCFType(inKey, inValue); + } + + return theAnswer; +} + +bool CACFDictionary::AddCFType(const CFStringRef inKey, const CFTypeRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CFDictionarySetValue(mCFDictionary, inKey, inValue); + theAnswer = true; + } + + return theAnswer; +} + +bool CACFDictionary::AddCFTypeWithCStringKey(const char* inKey, const CFTypeRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFString theKey(inKey); + if(theKey.IsValid()) + { + theAnswer = AddCFType(theKey.GetCFString(), inValue); + } + } + + return theAnswer; +} + +bool CACFDictionary::AddCString(const CFStringRef inKey, const char* inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFString theValue(inValue); + if(theValue.IsValid()) + { + theAnswer = AddCFType(inKey, theValue.GetCFString()); + } + } + + return theAnswer; +} diff --git a/libs/appleutility/CACFDictionary.h b/libs/appleutility/CACFDictionary.h new file mode 100644 index 0000000000..362b1c8821 --- /dev/null +++ b/libs/appleutility/CACFDictionary.h @@ -0,0 +1,141 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CACFDictionary.h + +=============================================================================*/ +#if !defined(__CACFDictionary_h__) +#define __CACFDictionary_h__ + +//============================================================================= +// Includes +//============================================================================= + +// System Includes +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include <CoreFoundation/CoreFoundation.h> +#else + #include <CoreFoundation.h> +#endif + +//============================================================================= +// CACFDictionary +//============================================================================= + +class CACFDictionary +{ + +// Construction/Destruction +public: + CACFDictionary(bool inRelease) : mCFDictionary(CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)), mRelease(inRelease), mMutable(true) {} + CACFDictionary(const CFDictionaryRef inCFDictionary, bool inRelease) : mCFDictionary(const_cast<CFMutableDictionaryRef>(inCFDictionary)), mRelease(inRelease), mMutable(true) {} + CACFDictionary(const CFMutableDictionaryRef inCFDictionary, bool inRelease) : mCFDictionary(inCFDictionary), mRelease(inRelease), mMutable(true) {} + CACFDictionary(const CACFDictionary& inDictionary) : mCFDictionary(inDictionary.mCFDictionary), mRelease(inDictionary.mRelease), mMutable(inDictionary.mMutable) { if(mRelease && (mCFDictionary != NULL)) { CFRetain(mCFDictionary); } } + CACFDictionary& operator=(const CACFDictionary& inDictionary) { mCFDictionary = inDictionary.mCFDictionary; mRelease = inDictionary.mRelease; mMutable = inDictionary.mMutable; if(mRelease && (mCFDictionary != NULL)) { CFRetain(mCFDictionary); } return *this; } + ~CACFDictionary() { if(mRelease && (mCFDictionary != NULL)) { CFRelease(mCFDictionary); } } + +// Attributes +public: + bool IsValid() const { return mCFDictionary != NULL; } + bool IsMutable() const { return mMutable;} + bool CanModify() const { return mMutable && (mCFDictionary != NULL); } + + bool WillRelease() const { return mRelease; } + void ShouldRelease(bool inRelease) { mRelease = inRelease; } + + CFDictionaryRef GetDict() const { return mCFDictionary; } + CFDictionaryRef GetCFDictionary() const { return mCFDictionary; } + CFDictionaryRef CopyCFDictionary() const { if(mCFDictionary != NULL) { CFRetain(mCFDictionary); } return mCFDictionary; } + + CFMutableDictionaryRef GetMutableDict() { return mCFDictionary; } + CFMutableDictionaryRef GetCFMutableDictionary() const { return mCFDictionary; } + CFMutableDictionaryRef CopyCFMutableDictionary() const { if(mCFDictionary != NULL) { CFRetain(mCFDictionary); } return mCFDictionary; } + void SetCFMutableDictionaryFromCopy(CFDictionaryRef inDictionary, bool inRelease = true) { if(mRelease && (mCFDictionary != NULL)) { CFRelease(mCFDictionary); } mCFDictionary = CFDictionaryCreateMutableCopy(NULL, 0, inDictionary); mMutable = true; mRelease = inRelease; } + + CFPropertyListRef AsPropertyList() const { return mCFDictionary; } + OSStatus GetDictIfMutable(CFMutableDictionaryRef& outDict) const { OSStatus theAnswer = -1; if(mMutable) { outDict = mCFDictionary; theAnswer = 0; } return theAnswer; } + +// Item Operations +public: + bool HasKey(const CFStringRef inKey) const; + UInt32 Size() const; + void GetKeys(const void** keys) const; + + bool GetBool(const CFStringRef inKey, bool& outValue) const; + bool GetSInt32(const CFStringRef inKey, SInt32& outValue) const; + bool GetUInt32(const CFStringRef inKey, UInt32& outValue) const; + bool GetSInt64(const CFStringRef inKey, SInt64& outValue) const; + bool GetUInt64(const CFStringRef inKey, UInt64& outValue) const; + bool GetFloat32(const CFStringRef inKey, Float32& outValue) const; + bool GetFloat64(const CFStringRef inKey, Float64& outValue) const; + bool GetString(const CFStringRef inKey, CFStringRef& outValue) const; + bool GetArray(const CFStringRef inKey, CFArrayRef& outValue) const; + bool GetDictionary(const CFStringRef inKey, CFDictionaryRef& outValue) const; + bool GetData(const CFStringRef inKey, CFDataRef& outValue) const; + bool GetCFType(const CFStringRef inKey, CFTypeRef& outValue) const; + + bool GetCFTypeWithCStringKey(const char* inKey, CFTypeRef& outValue) const; + + bool AddSInt32(const CFStringRef inKey, SInt32 inValue); + bool AddUInt32(const CFStringRef inKey, UInt32 inValue); + bool AddSInt64(const CFStringRef inKey, SInt64 inValue); + bool AddUInt64(const CFStringRef inKey, UInt64 inValue); + bool AddFloat32(const CFStringRef inKey, Float32 inValue); + bool AddFloat64(const CFStringRef inKey, Float64 inValue); + bool AddNumber(const CFStringRef inKey, const CFNumberRef inValue); + bool AddString(const CFStringRef inKey, const CFStringRef inValue); + bool AddArray(const CFStringRef inKey, const CFArrayRef inValue); + bool AddDictionary(const CFStringRef inKey, const CFDictionaryRef inValue); + bool AddData(const CFStringRef inKey, const CFDataRef inValue); + bool AddCFType(const CFStringRef inKey, const CFTypeRef inValue); + + bool AddCFTypeWithCStringKey(const char* inKey, const CFTypeRef inValue); + bool AddCString(const CFStringRef inKey, const char* inValue); + + void Clear() { if(CanModify()) { CFDictionaryRemoveAllValues(mCFDictionary); } } + + void Show() { CFShow(mCFDictionary); } + +// Implementation +private: + CFMutableDictionaryRef mCFDictionary; + bool mRelease; + bool mMutable; +}; + +#endif //__CACFDictionary_h__ diff --git a/libs/appleutility/CACFNumber.cpp b/libs/appleutility/CACFNumber.cpp new file mode 100644 index 0000000000..3b6160c8bb --- /dev/null +++ b/libs/appleutility/CACFNumber.cpp @@ -0,0 +1,65 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CACFNumber.cp + +=============================================================================*/ + +//============================================================================= +// Includes +//============================================================================= + +#include "CACFNumber.h" + +//============================================================================= +// CACFNumber +//============================================================================= + +Float32 CACFNumber::GetFixed32() const +{ + SInt32 theFixedValue = GetSInt32(); + + // this is a 16.16 value so convert it to a float + Float32 theSign = theFixedValue < 0 ? -1.0 : 1.0; + theFixedValue *= (SInt32)theSign; + Float32 theWholePart = (theFixedValue & 0x7FFF0000) >> 16; + Float32 theFractPart = theFixedValue & 0x0000FFFF; + theFractPart /= 65536.0; + + return theSign * (theWholePart + theFractPart); +} diff --git a/libs/appleutility/CACFNumber.h b/libs/appleutility/CACFNumber.h new file mode 100644 index 0000000000..3991637bac --- /dev/null +++ b/libs/appleutility/CACFNumber.h @@ -0,0 +1,102 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CACFNumber.h + +=============================================================================*/ +#if !defined(__CACFNumber_h__) +#define __CACFNumber_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include <CoreAudio/CoreAudioTypes.h> + #include <CoreFoundation/CFNumber.h> +#else + #include <CoreAudioTypes.h> + #include <CFNumber.h> +#endif + +//============================================================================= +// CACFNumber +//============================================================================= + +class CACFNumber +{ +// Construction/Destruction +public: + CACFNumber(CFNumberRef inCFNumber, bool inWillRelease = true) : mCFNumber(inCFNumber), mWillRelease(inWillRelease) {} + CACFNumber(SInt32 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberSInt32Type, &inValue)), mWillRelease(true) {} + CACFNumber(UInt32 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberSInt32Type, &inValue)), mWillRelease(true) {} + CACFNumber(SInt64 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberSInt64Type, &inValue)), mWillRelease(true) {} + CACFNumber(UInt64 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberSInt64Type, &inValue)), mWillRelease(true) {} + CACFNumber(Float32 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberFloat32Type, &inValue)), mWillRelease(true) {} + CACFNumber(Float64 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberFloat64Type, &inValue)), mWillRelease(true) {} + ~CACFNumber() { Release(); } + CACFNumber(const CACFNumber& inNumber) : mCFNumber(inNumber.mCFNumber), mWillRelease(inNumber.mWillRelease) { Retain(); } + CACFNumber& operator=(const CACFNumber& inNumber) { Release(); mCFNumber = inNumber.mCFNumber; mWillRelease = inNumber.mWillRelease; Retain(); return *this; } + CACFNumber& operator=(CFNumberRef inCFNumber) { Release(); mCFNumber = inCFNumber; mWillRelease = true; return *this; } + +private: + void Retain() { if(mWillRelease && (mCFNumber != NULL)) { CFRetain(mCFNumber); } } + void Release() { if(mWillRelease && (mCFNumber != NULL)) { CFRelease(mCFNumber); } } + + CFNumberRef mCFNumber; + bool mWillRelease; + +// Operations +public: + void AllowRelease() { mWillRelease = true; } + void DontAllowRelease() { mWillRelease = false; } + bool IsValid() { return mCFNumber != NULL; } + +// Value Access +public: + CFNumberRef GetCFNumber() const { return mCFNumber; } + CFNumberRef CopyCFNumber() const { if(mCFNumber != NULL) { CFRetain(mCFNumber); } return mCFNumber; } + + SInt8 GetSInt8() const { SInt8 theAnswer = 0; if(mCFNumber != NULL) { CFNumberGetValue(mCFNumber, kCFNumberSInt8Type, &theAnswer); } return theAnswer; } + SInt32 GetSInt32() const { SInt32 theAnswer = 0; if(mCFNumber != NULL) { CFNumberGetValue(mCFNumber, kCFNumberSInt32Type, &theAnswer); } return theAnswer; } + Float32 GetFloat32() const { Float32 theAnswer = 0.0; if(mCFNumber != NULL) { CFNumberGetValue(mCFNumber, kCFNumberFloat32Type, &theAnswer); } return theAnswer; } + Float32 GetFixed32() const; + SInt64 GetSInt64() const { SInt64 theAnswer = 0; if(mCFNumber != NULL) { CFNumberGetValue(mCFNumber, kCFNumberSInt64Type, &theAnswer); } return theAnswer; } +}; + +#endif diff --git a/libs/appleutility/CACFString.cpp b/libs/appleutility/CACFString.cpp new file mode 100644 index 0000000000..ec3b18a8b6 --- /dev/null +++ b/libs/appleutility/CACFString.cpp @@ -0,0 +1,106 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CACFString.cp + +=============================================================================*/ + +//============================================================================= +// Includes +//============================================================================= + +#include "CACFString.h" + +//============================================================================= +// CACFString +//============================================================================= + +UInt32 CACFString::GetStringByteLength(CFStringRef inCFString, CFStringEncoding inEncoding) +{ + UInt32 theAnswer = 0; + + if(inCFString != NULL) + { + CFRange theRange = { 0, CFStringGetLength(inCFString) }; + CFStringGetBytes(inCFString, theRange, inEncoding, 0, false, NULL, 0x7FFFFFFF, (CFIndex*)&theAnswer); + } + + return theAnswer; +} + +void CACFString::GetCString(CFStringRef inCFString, char* outString, UInt32& ioStringSize, CFStringEncoding inEncoding) +{ + if(ioStringSize > 0) + { + if(inCFString != NULL) + { + CFIndex theLength = 0; + CFRange theRange = { 0, CFStringGetLength(inCFString) }; + CFStringGetBytes(inCFString, theRange, inEncoding, 0, false, (UInt8*)outString, ioStringSize - 1, &theLength); + outString[theLength] = 0; + ioStringSize = theLength + 1; + } + else + { + outString[0] = 0; + ioStringSize = 1; + } + } +} + +void CACFString::GetUnicodeString(CFStringRef inCFString, UInt16* outString, UInt32& ioStringSize) +{ + if(ioStringSize > 0) + { + if(inCFString != NULL) + { + CFRange theStringRange = { 0, CFStringGetLength(inCFString) }; + if(static_cast<UInt32>(theStringRange.length) > ioStringSize) + { + theStringRange.length = ioStringSize; + } + CFStringGetCharacters(inCFString, theStringRange, outString); + ioStringSize = theStringRange.length; + } + else + { + outString[0] = 0; + ioStringSize = 0; + } + } +} diff --git a/libs/appleutility/CACFString.h b/libs/appleutility/CACFString.h new file mode 100644 index 0000000000..51fa64ebff --- /dev/null +++ b/libs/appleutility/CACFString.h @@ -0,0 +1,156 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CACFString.h + +=============================================================================*/ +#if !defined(__CACFString_h__) +#define __CACFString_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include <CoreAudio/CoreAudioTypes.h> + #include <CoreFoundation/CFString.h> +#else + #include <CoreAudioTypes.h> + #include <CFString.h> +#endif + +//============================================================================= +// CACFString +//============================================================================= + +class CACFString +{ +// Construction/Destruction +public: + CACFString() : mCFString(NULL), mWillRelease(true) {} + CACFString(CFStringRef inCFString, bool inWillRelease = true) : mCFString(inCFString), mWillRelease(inWillRelease) {} + CACFString(const char* inCString, bool inWillRelease = true) : mCFString(CFStringCreateWithCString(NULL, inCString, kCFStringEncodingASCII)), mWillRelease(inWillRelease) {} + CACFString(const char* inCString, CFStringEncoding inCStringEncoding, bool inWillRelease = true) : mCFString(CFStringCreateWithCString(NULL, inCString, inCStringEncoding)), mWillRelease(inWillRelease) {} + ~CACFString() { Release(); } + CACFString(const CACFString& inString) : mCFString(inString.mCFString), mWillRelease(inString.mWillRelease) { Retain(); } + CACFString& operator=(const CACFString& inString) { Release(); mCFString = inString.mCFString; mWillRelease = inString.mWillRelease; Retain(); return *this; } + CACFString& operator=(CFStringRef inCFString) { Release(); mCFString = inCFString; mWillRelease = true; return *this; } + +private: + void Retain() { if(mWillRelease && (mCFString != NULL)) { CFRetain(mCFString); } } + void Release() { if(mWillRelease && (mCFString != NULL)) { CFRelease(mCFString); } } + + CFStringRef mCFString; + bool mWillRelease; + +// Operations +public: + void AllowRelease() { mWillRelease = true; } + void DontAllowRelease() { mWillRelease = false; } + bool IsValid() const { return mCFString != NULL; } + bool StartsWith(CFStringRef inString) const { bool theAnswer = false; if(mCFString != NULL) { theAnswer = CFStringHasPrefix(mCFString, inString); } return theAnswer; } + bool EndsWith(CFStringRef inString) const { bool theAnswer = false; if(mCFString != NULL) { theAnswer = CFStringHasSuffix(mCFString, inString); } return theAnswer; } + +// Value Access +public: + CFStringRef GetCFString() const { return mCFString; } + CFStringRef CopyCFString() const { if(mCFString != NULL) { CFRetain(mCFString); } return mCFString; } + UInt32 GetLength() const { UInt32 theAnswer = 0; if(mCFString != NULL) { theAnswer = CFStringGetLength(mCFString); } return theAnswer; } + UInt32 GetByteLength(CFStringEncoding inEncoding = kCFStringEncodingUTF8) const { UInt32 theAnswer = 0; if(mCFString != NULL) { theAnswer = GetStringByteLength(mCFString, inEncoding); } return theAnswer; } + void GetCString(char* outString, UInt32& ioStringSize, CFStringEncoding inEncoding = kCFStringEncodingUTF8) const { GetCString(mCFString, outString, ioStringSize, inEncoding); } + void GetUnicodeString(UInt16* outString, UInt32& ioStringSize) const { GetUnicodeString(mCFString, outString, ioStringSize); } + + static UInt32 GetStringByteLength(CFStringRef inCFString, CFStringEncoding inEncoding = kCFStringEncodingUTF8); + static void GetCString(CFStringRef inCFString, char* outString, UInt32& ioStringSize, CFStringEncoding inEncoding = kCFStringEncodingUTF8); + static void GetUnicodeString(CFStringRef inCFString, UInt16* outString, UInt32& ioStringSize); + +}; + +inline bool operator<(const CACFString& x, const CACFString& y) { return CFStringCompare(x.GetCFString(), y.GetCFString(), 0) == kCFCompareLessThan; } +inline bool operator==(const CACFString& x, const CACFString& y) { return CFStringCompare(x.GetCFString(), y.GetCFString(), 0) == kCFCompareEqualTo; } +inline bool operator!=(const CACFString& x, const CACFString& y) { return !(x == y); } +inline bool operator<=(const CACFString& x, const CACFString& y) { return (x < y) || (x == y); } +inline bool operator>=(const CACFString& x, const CACFString& y) { return !(x < y); } +inline bool operator>(const CACFString& x, const CACFString& y) { return !((x < y) || (x == y)); } + +//============================================================================= +// CACFMutableString +//============================================================================= + +class CACFMutableString +{ +// Construction/Destruction +public: + CACFMutableString() : mCFMutableString(NULL), mWillRelease(true) {} + CACFMutableString(CFMutableStringRef inCFMutableString, bool inWillRelease = true) : mCFMutableString(inCFMutableString), mWillRelease(inWillRelease) {} + CACFMutableString(CFStringRef inStringToCopy, bool /*inMakeCopy*/, bool inWillRelease = true) : mCFMutableString(CFStringCreateMutableCopy(NULL, 0, inStringToCopy)), mWillRelease(inWillRelease) {} + CACFMutableString(const char* inCString, bool inWillRelease = true) : mCFMutableString(NULL), mWillRelease(inWillRelease) { CACFString theString(inCString); mCFMutableString = CFStringCreateMutableCopy(NULL, 0, theString.GetCFString()); } + CACFMutableString(const char* inCString, CFStringEncoding inCStringEncoding, bool inWillRelease = true) : mCFMutableString(NULL), mWillRelease(inWillRelease) { CACFString theString(inCString, inCStringEncoding); mCFMutableString = CFStringCreateMutableCopy(NULL, 0, theString.GetCFString()); } + ~CACFMutableString() { Release(); } + CACFMutableString(const CACFMutableString& inString) : mCFMutableString(inString.mCFMutableString), mWillRelease(inString.mWillRelease) { Retain(); } + CACFMutableString operator=(const CACFMutableString& inString) { Release(); mCFMutableString = inString.mCFMutableString; mWillRelease = inString.mWillRelease; Retain(); return *this; } + CACFMutableString operator=(CFMutableStringRef inCFMutableString) { Release(); mCFMutableString = inCFMutableString; mWillRelease = true; return *this; } + +private: + void Retain() { if(mWillRelease && (mCFMutableString != NULL)) { CFRetain(mCFMutableString); } } + void Release() { if(mWillRelease && (mCFMutableString != NULL)) { CFRelease(mCFMutableString); } } + + CFMutableStringRef mCFMutableString; + bool mWillRelease; + +// Operations +public: + void AllowRelease() { mWillRelease = true; } + void DontAllowRelease() { mWillRelease = false; } + bool IsValid() { return mCFMutableString != NULL; } + bool StartsWith(CFStringRef inString) const { bool theAnswer = false; if(mCFMutableString != NULL) { theAnswer = CFStringHasPrefix(mCFMutableString, inString); } return theAnswer; } + bool EndsWith(CFStringRef inString) const { bool theAnswer = false; if(mCFMutableString != NULL) { theAnswer = CFStringHasSuffix(mCFMutableString, inString); } return theAnswer; } + void Append(CFStringRef inString) { if(mCFMutableString != NULL) { CFStringAppend(mCFMutableString, inString); } } + +// Value Access +public: + CFMutableStringRef GetCFMutableString() const { return mCFMutableString; } + CFMutableStringRef CopyCFMutableString() const { if(mCFMutableString != NULL) { CFRetain(mCFMutableString); } return mCFMutableString; } + UInt32 GetLength() const { UInt32 theAnswer = 0; if(mCFMutableString != NULL) { theAnswer = CFStringGetLength(mCFMutableString); } return theAnswer; } + UInt32 GetByteLength(CFStringEncoding inEncoding = kCFStringEncodingUTF8) const { UInt32 theAnswer = 0; if(mCFMutableString != NULL) { theAnswer = CACFString::GetStringByteLength(mCFMutableString, inEncoding); } return theAnswer; } + void GetCString(char* outString, UInt32& ioStringSize, CFStringEncoding inEncoding = kCFStringEncodingUTF8) const { CACFString::GetCString(mCFMutableString, outString, ioStringSize, inEncoding); } + void GetUnicodeString(UInt16* outString, UInt32& ioStringSize) const { CACFString::GetUnicodeString(mCFMutableString, outString, ioStringSize); } + +}; + +#endif diff --git a/libs/appleutility/CAComponent.cpp b/libs/appleutility/CAComponent.cpp new file mode 100644 index 0000000000..700d9e2b3e --- /dev/null +++ b/libs/appleutility/CAComponent.cpp @@ -0,0 +1,257 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CAComponent.cpp + +=============================================================================*/ + +#include "CAComponent.h" +#include "CAComponentDescription.h" +#include "CACFDictionary.h" +#include <stdlib.h> + +CAComponent::CAComponent (const ComponentDescription& inDesc, CAComponent* next) + : mManuName(0), mAUName(0), mCompName(0), mCompInfo (0) +{ + mComp = FindNextComponent ((next ? next->Comp() : NULL), const_cast<ComponentDescription*>(&inDesc)); + if (mComp) + GetComponentInfo (Comp(), &mDesc, NULL, NULL, NULL); + else + memcpy (&mDesc, &inDesc, sizeof(ComponentDescription)); +} + +CAComponent::CAComponent (const Component& comp) + : mComp (comp), + mManuName(0), + mAUName(0), + mCompName(0), + mCompInfo (0) +{ + GetComponentInfo (Comp(), &mDesc, NULL, NULL, NULL); +} + +CAComponent::CAComponent (const ComponentInstance& compInst) + : mComp (Component(compInst)), + mManuName(0), + mAUName(0), + mCompName(0), + mCompInfo (0) +{ + GetComponentInfo (Comp(), &mDesc, NULL, NULL, NULL); +} + +CAComponent::CAComponent (OSType inType, OSType inSubtype, OSType inManu) + : mDesc (inType, inSubtype, inManu), + mManuName(0), mAUName(0), mCompName(0), mCompInfo (0) +{ + mComp = FindNextComponent (NULL, &mDesc); + GetComponentInfo (Comp(), &mDesc, NULL, NULL, NULL); +} + +CAComponent::~CAComponent () +{ + Clear(); +} + +OSStatus CAComponent::GetResourceVersion (UInt32 &outVersion) const +{ + bool versionFound = false; + short componentResFileID = kResFileNotOpened; + OSStatus result; + short thngResourceCount; + + short curRes = CurResFile(); + require_noerr (result = OpenAComponentResFile( mComp, &componentResFileID), home); + require_noerr (result = componentResFileID <= 0, home); + + UseResFile(componentResFileID); + + thngResourceCount = Count1Resources(kComponentResourceType); + + require_noerr (result = ResError(), home); + // only go on if we successfully found at least 1 thng resource + require_noerr (thngResourceCount <= 0 ? -1 : 0, home); + + // loop through all of the Component thng resources trying to + // find one that matches this Component description + for (short i = 0; i < thngResourceCount && (!versionFound); i++) + { + // try to get a handle to this code resource + Handle thngResourceHandle = Get1IndResource(kComponentResourceType, i+1); + if (thngResourceHandle != NULL && ((*thngResourceHandle) != NULL)) + { + if (UInt32(GetHandleSize(thngResourceHandle)) >= sizeof(ExtComponentResource)) + { + ExtComponentResource * componentThng = (ExtComponentResource*) (*thngResourceHandle); + + // check to see if this is the thng resource for the particular Component that we are looking at + // (there often is more than one Component described in the resource) + if ((componentThng->cd.componentType == mDesc.Type()) + && (componentThng->cd.componentSubType == mDesc.SubType()) + && (componentThng->cd.componentManufacturer == mDesc.Manu())) + { + outVersion = componentThng->componentVersion; + versionFound = true; + } + } + ReleaseResource(thngResourceHandle); + } + } + + if (!versionFound) + result = resNotFound; + + UseResFile(curRes); // revert + + if ( componentResFileID != kResFileNotOpened ) + CloseComponentResFile(componentResFileID); + +home: + return result; +} + +void CAComponent::Clear () +{ + if (mManuName) { CFRelease (mManuName); mManuName = 0; } + if (mAUName) { CFRelease (mAUName); mAUName = 0; } + if (mCompName) { CFRelease (mCompName); mCompName = 0; } + if (mCompInfo) { CFRelease (mCompInfo); mCompInfo = 0; } +} + +CAComponent& CAComponent::operator= (const CAComponent& y) +{ + Clear(); + + mComp = y.mComp; + mDesc = y.mDesc; + + if (y.mManuName) { mManuName = y.mManuName; CFRetain (mManuName); } + if (y.mAUName) { mAUName = y.mAUName; CFRetain (mAUName); } + if (y.mCompName) { mCompName = y.mCompName; CFRetain (mCompName); } + if (y.mCompInfo) { mCompInfo = y.mCompInfo; CFRetain (mCompInfo); } + + return *this; +} + +void CAComponent::SetCompNames () const +{ + if (!mCompName) { + Handle h1 = NewHandle(4); + CAComponentDescription desc; + OSStatus err = GetComponentInfo (Comp(), &desc, h1, 0, 0); + + if (err) { DisposeHandle(h1); return; } + + HLock(h1); + char* ptr1 = *h1; + // Get the manufacturer's name... look for the ':' character convention + int len = *ptr1++; + char* displayStr = 0; + + const_cast<CAComponent*>(this)->mCompName = CFStringCreateWithPascalString(NULL, (const unsigned char*)*h1, kCFStringEncodingMacRoman); + + for (int i = 0; i < len; ++i) { + if (ptr1[i] == ':') { // found the name + ptr1[i] = 0; + displayStr = ptr1; + break; + } + } + + if (displayStr) + { + const_cast<CAComponent*>(this)->mManuName = CFStringCreateWithCString(NULL, displayStr, kCFStringEncodingMacRoman); + + //move displayStr ptr past the manu, to the name + // we move the characters down a index, because the handle doesn't have any room + // at the end for the \0 + int i = strlen(displayStr), j = 0; + while (displayStr[++i] == ' ' && i < len) + ; + while (i < len) + displayStr[j++] = displayStr[i++]; + displayStr[j] = 0; + + const_cast<CAComponent*>(this)->mAUName = CFStringCreateWithCString(NULL, displayStr, kCFStringEncodingMacRoman); + } + + DisposeHandle (h1); + } +} + +void CAComponent::SetCompInfo () const +{ + if (!mCompInfo) { + Handle h1 = NewHandle(4); + CAComponentDescription desc; + OSStatus err = GetComponentInfo (Comp(), &desc, 0, h1, 0); + if (err) return; + HLock (h1); + const_cast<CAComponent*>(this)->mCompInfo = CFStringCreateWithPascalString(NULL, (const unsigned char*)*h1, kCFStringEncodingMacRoman); + + DisposeHandle (h1); + } +} + +void _ShowCF (FILE* file, CFStringRef str) +{ + if (CFGetTypeID(str) != CFStringGetTypeID()) { + CFShow(str); + return; + } + + UInt32 len = CFStringGetLength(str); + char* chars = (char*)malloc (len * 2); // give us plenty of room for unichar chars + if (CFStringGetCString (str, chars, len * 2, kCFStringEncodingUTF8)) + fprintf (file, "%s", chars); + else + CFShow (str); + + free (chars); +} + +void CAComponent::Print(FILE* file) const +{ + fprintf (file, "CAComponent: 0x%X", int(Comp())); + if (mManuName) { + fprintf (file, ", Manu:"); _ShowCF (file, mManuName); + if (mAUName) fprintf (file, ", Name:"); _ShowCF (file, mAUName); + } + fprintf (file, ", "); + Desc ().Print(file); +} diff --git a/libs/appleutility/CAComponent.h b/libs/appleutility/CAComponent.h new file mode 100644 index 0000000000..2ace42532d --- /dev/null +++ b/libs/appleutility/CAComponent.h @@ -0,0 +1,120 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CAComponent.h + +=============================================================================*/ + +#ifndef __CAComponent_h__ +#define __CAComponent_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include <CoreServices/CoreServices.h> +#else + #include <ConditionalMacros.h> + #include <CoreServices.h> +#endif + +#include "CAComponentDescription.h" + +class CAComponent +{ +public: + CAComponent () + : mComp (0), mDesc(), mManuName(0), mAUName(0), mCompName(0), mCompInfo (0) {} + + // if next is specifed that is used to find the next component after that one + CAComponent (const ComponentDescription& inDesc, CAComponent* next = 0); + + CAComponent (const CAComponent& y) + : mComp (0), mDesc(), mManuName(0), mAUName(0), mCompName(0), mCompInfo (0) { *this = y; } + + CAComponent (const Component& comp); + + CAComponent (const ComponentInstance& compInst); + + CAComponent (OSType inType, OSType inSubtype = 0, OSType inManu = 0); + + ~CAComponent (); + + CAComponent& operator= (const CAComponent& y); + + // returns true if this object references a valid component + bool IsValid () const { return Comp() != 0; } + + bool HasAUStrings() const { SetCompNames (); return mManuName != 0; } + + // CFStringRef should be retained by caller if needed beyond lifetime of this object + + // Can return NULL if component doesn't follow AU naming conventions + CFStringRef GetAUManu () const { SetCompNames (); return mManuName; } + CFStringRef GetAUName () const { SetCompNames (); return mAUName ? mAUName : mCompName; } + + // Return value of NULL indicates a problem getting that information from the component + CFStringRef GetCompName () const { SetCompNames(); return mCompName; } + CFStringRef GetCompInfo () const { SetCompInfo(); return mCompInfo; } + + const CAComponentDescription& Desc () const { return mDesc; } + + OSStatus Open (ComponentInstance& outInst) const + { + return OpenAComponent (Comp(), &outInst); + } + + OSStatus GetResourceVersion (UInt32 &outVersion) const; + + const Component& Comp() const { return mComp; } + + void Print(FILE* file = stdout) const; + + OSStatus Save (CFPropertyListRef *outData) const; + + OSStatus Restore (CFPropertyListRef &inData); + +private: + Component mComp; + CAComponentDescription mDesc; + + CFStringRef mManuName, mAUName, mCompName, mCompInfo; + + void SetCompNames () const; + void SetCompInfo () const; + void Clear (); +}; + +#endif diff --git a/libs/appleutility/CAComponentDescription.cpp b/libs/appleutility/CAComponentDescription.cpp new file mode 100644 index 0000000000..261a2b881c --- /dev/null +++ b/libs/appleutility/CAComponentDescription.cpp @@ -0,0 +1,123 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CAComponentDescription.cpp + +=============================================================================*/ + +#include "CAComponentDescription.h" +#include <ctype.h> + +extern "C" void CAShowComponentDescription(const ComponentDescription *desc) +{ + CAComponentDescription::_CAShowComponentDescription (desc, stdout); +} + +char *StringForOSType (OSType t, char *writeLocation) +{ + char *p = writeLocation; + unsigned char str[4], *q = str; + *(UInt32 *)str = EndianU32_NtoB(t); + for (int i = 0; i < 4; ++i) { + if (isprint(*q) && *q != '\\') + *p++ = *q++; + else { + sprintf(p, "\\x%02X", *q++); + p += 4; + } + } + *p = '\0'; + return writeLocation; +} + + +void CAComponentDescription::_CAShowComponentDescription(const ComponentDescription *desc, FILE* file) +{ + if (desc) + { + char str[24]; + fprintf (file, "ComponentDescription: %s - ", StringForOSType(desc->componentType, str)); + fprintf (file, "%s - ", StringForOSType(desc->componentSubType, str)); + fprintf (file, "%s", StringForOSType(desc->componentManufacturer, str)); + fprintf (file, ", 0x%lX, 0x%lX\n", desc->componentFlags, desc->componentFlagsMask); + } +} + +CAComponentDescription::CAComponentDescription (OSType inType, OSType inSubtype, OSType inManu) +{ + componentType = inType; + componentSubType = inSubtype; + componentManufacturer = inManu; + componentFlags = 0; + componentFlagsMask = 0; +} + +bool CAComponentDescription::IsAU () const +{ + bool flag = IsEffect() || IsMusicDevice() || IsOffline(); + if (flag) return true; + + switch (componentType) { + case kAudioUnitType_Output: + case kAudioUnitType_FormatConverter: + case kAudioUnitType_Mixer: + return true; + } + return false; +} + +inline bool _MatchTest (const OSType &inTypeA, const OSType &inTypeB) +{ + return ((inTypeA == inTypeB) || (!inTypeA && !inTypeB) || (inTypeA && !inTypeB) || (!inTypeA && inTypeB)); +} + +bool CAComponentDescription::Matches (const ComponentDescription &desc) const +{ + bool matches = false; + + // see if the type matches + matches = _MatchTest (componentType, desc.componentType); + + if (matches) + matches = _MatchTest (componentSubType, desc.componentSubType); + + if (matches) + matches = _MatchTest (componentManufacturer, desc.componentManufacturer); + + return matches; +} diff --git a/libs/appleutility/CAComponentDescription.h b/libs/appleutility/CAComponentDescription.h new file mode 100644 index 0000000000..a681902b91 --- /dev/null +++ b/libs/appleutility/CAComponentDescription.h @@ -0,0 +1,148 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CAComponentDescription.h + +=============================================================================*/ + +#ifndef __CAComponentDescription_h__ +#define __CAComponentDescription_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include <CoreServices/CoreServices.h> + #include <AudioUnit/AudioUnit.h> +#else + #include <ConditionalMacros.h> + #include <CoreServices.h> + #include <AudioUnit.h> +#endif + +#include "CACFDictionary.h" +#include <stdio.h> +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif + +void CAShowComponentDescription(const ComponentDescription *desc); + +#ifdef __cplusplus +} +#endif + + +// ____________________________________________________________________________ +// +// CAComponentDescription +class CAComponentDescription : public ComponentDescription { +public: + CAComponentDescription() { memset (this, 0, sizeof (ComponentDescription)); } + + CAComponentDescription (OSType inType, OSType inSubtype = 0, OSType inManu = 0); + + CAComponentDescription(const ComponentDescription& desc) { memcpy (this, &desc, sizeof (ComponentDescription)); } + + // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + // + // interrogation + + bool IsAU () const; + + bool IsAUFX() const { return componentType == kAudioUnitType_Effect; } + bool IsAUFM() const { return componentType == kAudioUnitType_MusicEffect; } + + bool IsEffect () const { return IsAUFX() || IsAUFM() || IsPanner(); } + + bool IsOffline () const { return componentType == 'auol'; } + + bool IsFConv () const { return componentType == kAudioUnitType_FormatConverter; } + + bool IsPanner () const { return componentType == kAudioUnitType_Panner; } + + bool IsMusicDevice () const { return componentType == kAudioUnitType_MusicDevice; } + +#ifndef MAC_OS_X_VERSION_10_4 + bool IsGenerator () const { return componentType =='augn'; } +#else + bool IsGenerator () const { return componentType ==kAudioUnitType_Generator; } +#endif + + bool IsOutput () const { return componentType == kAudioUnitType_Output; } + + bool IsSource () const { return IsMusicDevice() || IsGenerator(); } + + OSType Type () const { return componentType; } + OSType SubType () const { return componentSubType; } + OSType Manu () const { return componentManufacturer; } + + int Count() const { return CountComponents(const_cast<CAComponentDescription*>(this)); } + + // does a semantic match where "wild card" values for type, subtype, manu will match + bool Matches (const ComponentDescription &desc) const; + + // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + // + // other + + void Print(FILE* file = stdout) const { _CAShowComponentDescription (this, file); } + + OSStatus Save (CFPropertyListRef *outData) const; + OSStatus Restore (CFPropertyListRef &inData); + +private: + static void _CAShowComponentDescription (const ComponentDescription *desc, FILE* file); + friend void CAShowComponentDescription (const ComponentDescription *desc); +}; + +inline bool operator< (const ComponentDescription& x, const ComponentDescription& y) +{ + return memcmp (&x, &y, offsetof (ComponentDescription, componentFlags)) < 0; +} + +inline bool operator== (const ComponentDescription& x, const ComponentDescription& y) +{ + return !memcmp (&x, &y, offsetof (ComponentDescription, componentFlags)); +} + +inline bool operator!= (const ComponentDescription& x, const ComponentDescription& y) +{ + return !(x == y); +} + +#endif diff --git a/libs/appleutility/CAConditionalMacros.h b/libs/appleutility/CAConditionalMacros.h new file mode 100644 index 0000000000..62f642709a --- /dev/null +++ b/libs/appleutility/CAConditionalMacros.h @@ -0,0 +1,74 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CAConditionalMacros.h + +=============================================================================*/ +#if !defined(__CAConditionalMacros_h__) +#define __CAConditionalMacros_h__ + +//============================================================================= +// This file exists to make figuring out how to include system headers +// easier in a cross platform world. We throw in an include of the standard +// ConditionalMacros too. +//============================================================================= + +// ########## THIS FILE SHOULD GO AWAY SOON, replaced by __COREAUDIO_USE_FLAT_INCLUDES__ +// but for now, use this as a way to define __COREAUDIO_USE_FLAT_INCLUDES__ programmatically + +// TargetConditionals.h defines the bare minimum we need +#include "TargetConditionals.h" + +// Determine whether or not to use framework style includes for system headers +#if !defined(CoreAudio_Use_Framework_Includes) && !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #if TARGET_RT_MAC_MACHO + #define CoreAudio_Use_Framework_Includes 1 + #else + #define CoreAudio_Use_Framework_Includes 0 + #endif +#endif + +// Include the regular ConditionalMacros.h too, since it has useful stuff that +// TargetConditionals.h lacks for some reason. +#if CoreAudio_Use_Framework_Includes + #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/ConditionalMacros.h> +#else + #include "ConditionalMacros.h" +#endif + +#endif diff --git a/libs/appleutility/CADebugMacros.cpp b/libs/appleutility/CADebugMacros.cpp new file mode 100644 index 0000000000..edee1f3d51 --- /dev/null +++ b/libs/appleutility/CADebugMacros.cpp @@ -0,0 +1,84 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CADebugMacros.cp + +=============================================================================*/ + +#include "CADebugMacros.h" +#include <stdio.h> +#include <stdarg.h> +#if TARGET_API_MAC_OSX + #include <syslog.h> +#endif + +#if DEBUG +#include <stdio.h> + +void DebugPrint(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); +} +#endif // DEBUG + +#if TARGET_API_MAC_OSX +void LogError(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); +#if DEBUG + vprintf(fmt, args); +#endif + vsyslog(LOG_ERR, fmt, args); + va_end(args); +} + +void LogWarning(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); +#if DEBUG + vprintf(fmt, args); +#endif + vsyslog(LOG_WARNING, fmt, args); + va_end(args); +} +#endif diff --git a/libs/appleutility/CADebugMacros.h b/libs/appleutility/CADebugMacros.h new file mode 100644 index 0000000000..1abae40187 --- /dev/null +++ b/libs/appleutility/CADebugMacros.h @@ -0,0 +1,414 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CADebugMacros.h + +=============================================================================*/ +#if !defined(__CADebugMacros_h__) +#define __CADebugMacros_h__ + +//============================================================================= +// CADebugMacros +//============================================================================= + +//#define CoreAudio_StopOnFailure 1 +//#define CoreAudio_TimeStampMessages 1 +//#define CoreAudio_ThreadStampMessages 1 +//#define CoreAudio_FlushDebugMessages 1 + +#define CA4CCToCString(the4CC) { ((char*)&the4CC)[0], ((char*)&the4CC)[1], ((char*)&the4CC)[2], ((char*)&the4CC)[3], 0 } + +#pragma mark Basic Definitions + +#if DEBUG || CoreAudio_Debug + + // can be used to break into debugger immediately, also see CADebugger + #define BusError() (*(long *)0 = 0) + + // basic debugging print routines + #if TARGET_OS_MAC && !TARGET_API_MAC_CARBON + extern pascal void DebugStr(const unsigned char* debuggerMsg); + #define DebugMessage(msg) DebugStr("\p"msg) + #define DebugMessageN1(msg, N1) + #define DebugMessageN2(msg, N1, N2) + #define DebugMessageN3(msg, N1, N2, N3) + #else + #include "CADebugPrintf.h" + + #if (CoreAudio_FlushDebugMessages && !CoreAudio_UseSysLog) || defined(CoreAudio_UseSideFile) + #define FlushRtn ;fflush(DebugPrintfFile) + #else + #define FlushRtn + #endif + + #if CoreAudio_ThreadStampMessages + #include <pthread.h> + #include "CAHostTimeBase.h" + #define DebugMessage(msg) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: %s"DebugPrintfLineEnding, pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), msg) FlushRtn + #define DebugMessageN1(msg, N1) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1) FlushRtn + #define DebugMessageN2(msg, N1, N2) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2) FlushRtn + #define DebugMessageN3(msg, N1, N2, N3) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3) FlushRtn + #define DebugMessageN4(msg, N1, N2, N3, N4) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4) FlushRtn + #define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5) FlushRtn + #define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6) FlushRtn + #define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7) FlushRtn + #define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7, N8) FlushRtn + #define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7, N8, N9) FlushRtn + #elif CoreAudio_TimeStampMessages + #include "CAHostTimeBase.h" + #define DebugMessage(msg) DebugPrintfRtn(DebugPrintfFile, "%.4f: %s"DebugPrintfLineEnding, pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), msg) FlushRtn + #define DebugMessageN1(msg, N1) DebugPrintfRtn(DebugPrintfFile, "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1) FlushRtn + #define DebugMessageN2(msg, N1, N2) DebugPrintfRtn(DebugPrintfFile, "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2) FlushRtn + #define DebugMessageN3(msg, N1, N2, N3) DebugPrintfRtn(DebugPrintfFile, "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3) FlushRtn + #define DebugMessageN4(msg, N1, N2, N3, N4) DebugPrintfRtn(DebugPrintfFile, "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4) FlushRtn + #define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugPrintfRtn(DebugPrintfFile, "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5) FlushRtn + #define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugPrintfRtn(DebugPrintfFile, "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6) FlushRtn + #define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugPrintfRtn(DebugPrintfFile, "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7) FlushRtn + #define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugPrintfRtn(DebugPrintfFile, "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7, N8) FlushRtn + #define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugPrintfRtn(DebugPrintfFile, "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7, N8, N9) FlushRtn + #else + #define DebugMessage(msg) DebugPrintfRtn(DebugPrintfFile, "%s"DebugPrintfLineEnding, msg) FlushRtn + #define DebugMessageN1(msg, N1) DebugPrintfRtn(DebugPrintfFile, msg DebugPrintfLineEnding, N1) FlushRtn + #define DebugMessageN2(msg, N1, N2) DebugPrintfRtn(DebugPrintfFile, msg DebugPrintfLineEnding, N1, N2) FlushRtn + #define DebugMessageN3(msg, N1, N2, N3) DebugPrintfRtn(DebugPrintfFile, msg DebugPrintfLineEnding, N1, N2, N3) FlushRtn + #define DebugMessageN4(msg, N1, N2, N3, N4) DebugPrintfRtn(DebugPrintfFile, msg DebugPrintfLineEnding, N1, N2, N3, N4) FlushRtn + #define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugPrintfRtn(DebugPrintfFile, msg DebugPrintfLineEnding, N1, N2, N3, N4, N5) FlushRtn + #define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugPrintfRtn(DebugPrintfFile, msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6) FlushRtn + #define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugPrintfRtn(DebugPrintfFile, msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6, N7) FlushRtn + #define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugPrintfRtn(DebugPrintfFile, msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6, N7, N8) FlushRtn + #define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugPrintfRtn(DebugPrintfFile, msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6, N7, N8, N9) FlushRtn + #endif + #endif + void DebugPrint(const char *fmt, ...); // can be used like printf + #define DEBUGPRINT(msg) DebugPrint msg // have to double-parenthesize arglist (see Debugging.h) + #if VERBOSE + #define vprint(msg) DEBUGPRINT(msg) + #else + #define vprint(msg) + #endif + + #if CoreAudio_StopOnFailure + #include "CADebugger.h" + #define STOP CADebuggerStop() + #else + #define STOP + #endif + +#else + #define DebugMessage(msg) + #define DebugMessageN1(msg, N1) + #define DebugMessageN2(msg, N1, N2) + #define DebugMessageN3(msg, N1, N2, N3) + #define DebugMessageN4(msg, N1, N2, N3, N4) + #define DebugMessageN5(msg, N1, N2, N3, N4, N5) + #define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) + #define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) + #define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) + #define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) + #define DEBUGPRINT(msg) + #define vprint(msg) + #define STOP +#endif + +void LogError(const char *fmt, ...); // writes to syslog (and stderr if debugging) +void LogWarning(const char *fmt, ...); // writes to syslog (and stderr if debugging) + +#if DEBUG || CoreAudio_Debug + +#pragma mark Debug Macros + +#define Assert(inCondition, inMessage) \ + if(!(inCondition)) \ + { \ + DebugMessage(inMessage); \ + STOP; \ + } + +#define AssertNoError(inError, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + char __4CC[5] = CA4CCToCString(__Err); \ + DebugMessageN2(inMessage ", Error: %ld (%s)", __Err, __4CC); \ + STOP; \ + } \ + } + +#define AssertNoKernelError(inError, inMessage) \ + { \ + unsigned int __Err = (unsigned int)(inError); \ + if(__Err != 0) \ + { \ + DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ + STOP; \ + } \ + } + +#define FailIf(inCondition, inHandler, inMessage) \ + if(inCondition) \ + { \ + DebugMessage(inMessage); \ + STOP; \ + goto inHandler; \ + } + +#define FailWithAction(inCondition, inAction, inHandler, inMessage) \ + if(inCondition) \ + { \ + DebugMessage(inMessage); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNULL(inPointer, inAction, inHandler, inMessage) \ + if((inPointer) == NULL) \ + { \ + DebugMessage(inMessage); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfKernelError(inKernelError, inException, inMessage) \ + { \ + kern_return_t __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#define FailIfError(inError, inException, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + char __4CC[5] = CA4CCToCString(__Err); \ + DebugMessageN2(inMessage ", Error: %ld (%s)", __Err, __4CC); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#if defined(__cplusplus) + +#define Throw(inException) STOP; throw (inException) + +#define ThrowIf(inCondition, inException, inMessage) \ + if(inCondition) \ + { \ + DebugMessage(inMessage); \ + Throw(inException); \ + } + +#define ThrowIfNULL(inPointer, inException, inMessage) \ + if((inPointer) == NULL) \ + { \ + DebugMessage(inMessage); \ + Throw(inException); \ + } + +#define ThrowIfKernelError(inKernelError, inException, inMessage) \ + { \ + kern_return_t __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ + Throw(inException); \ + } \ + } + +#define ThrowIfError(inError, inException, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + char __4CC[5] = CA4CCToCString(__Err); \ + DebugMessageN2(inMessage ", Error: %ld (%s)", __Err, __4CC); \ + Throw(inException); \ + } \ + } + +#if TARGET_OS_WIN32 +#define ThrowIfWinError(inError, inException, inMessage) \ + { \ + HRESULT __Err = (inError); \ + if(FAILED(__Err)) \ + { \ + DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ + Throw(inException); \ + } \ + } +#endif + +#define SubclassResponsibility(inMethodName, inException) \ + { \ + DebugMessage(inMethodName": Subclasses must implement this method"); \ + Throw(inException); \ + } + +#endif // defined(__cplusplus) + +#else + +#pragma mark Release Macros + +#define Assert(inCondition, inMessage) \ + if(!(inCondition)) \ + { \ + STOP; \ + } + +#define AssertNoError(inError, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + STOP; \ + } \ + } + +#define AssertNoKernelError(inError, inMessage) \ + { \ + unsigned int __Err = (unsigned int)(inError); \ + if(__Err != 0) \ + { \ + STOP; \ + } \ + } + +#define FailIf(inCondition, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + goto inHandler; \ + } + +#define FailWithAction(inCondition, inAction, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNULL(inPointer, inAction, inHandler, inMessage) \ + if((inPointer) == NULL) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfKernelError(inKernelError, inException, inMessage) \ + if((inKernelError) != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfError(inError, inException, inMessage) \ + if((inError) != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#if defined(__cplusplus) + +#define Throw(inException) STOP; throw (inException) + +#define ThrowIf(inCondition, inException, inMessage) \ + if(inCondition) \ + { \ + Throw(inException); \ + } + +#define ThrowIfNULL(inPointer, inException, inMessage) \ + if((inPointer) == NULL) \ + { \ + Throw(inException); \ + } + +#define ThrowIfKernelError(inKernelError, inException, inMessage) \ + { \ + kern_return_t __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + Throw(inException); \ + } \ + } + +#define ThrowIfError(inError, inException, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + Throw(inException); \ + } \ + } + +#if TARGET_OS_WIN32 +#define ThrowIfWinError(inError, inException, inMessage) \ + { \ + HRESULT __Err = (inError); \ + if(FAILED(__Err)) \ + { \ + Throw(inException); \ + } \ + } +#endif + +#define SubclassResponsibility(inMethodName, inException) \ + { \ + Throw(inException); \ + } + +#endif // defined(__cplusplus) + +#endif // DEBUG || CoreAudio_Debug + +#endif diff --git a/libs/appleutility/CAMath.h b/libs/appleutility/CAMath.h new file mode 100644 index 0000000000..32b4e7f0b3 --- /dev/null +++ b/libs/appleutility/CAMath.h @@ -0,0 +1,64 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CAMath.h + +=============================================================================*/ + +#ifndef __CAMath_h__ +#define __CAMath_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include <CoreAudio/CoreAudioTypes.h> +#else + #include <CoreAudioTypes.h> +#endif + +inline bool fiszero(Float64 f) { return (f == 0.); } +inline bool fiszero(Float32 f) { return (f == 0.f); } + +inline bool fnonzero(Float64 f) { return !fiszero(f); } +inline bool fnonzero(Float32 f) { return !fiszero(f); } + +inline bool fequal(const Float64 &a, const Float64 &b) { return a == b; } +inline bool fequal(const Float32 &a, const Float32 &b) { return a == b; } + +inline bool fnotequal(const Float64 &a, const Float64 &b) { return !fequal(a, b); } +inline bool fnotequal(const Float32 &a, const Float32 &b) { return !fequal(a, b); } + +#endif // __CAMath_h__ diff --git a/libs/appleutility/CAReferenceCounted.h b/libs/appleutility/CAReferenceCounted.h new file mode 100644 index 0000000000..d57f97c31f --- /dev/null +++ b/libs/appleutility/CAReferenceCounted.h @@ -0,0 +1,83 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CAReferenceCounted.h + +=============================================================================*/ + +#ifndef __CAReferenceCounted_h__ +#define __CAReferenceCounted_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include <CoreServices/CoreServices.h> +#else + #include <CoreServices.h> +#endif + +#if TARGET_OS_WIN32 + #include "CAWindows.h" +#endif + +// base class for reference-counted objects +class CAReferenceCounted { +public: + CAReferenceCounted() : mRefCount(1) {} + + void retain() { IncrementAtomic(&mRefCount); } + + void release() + { + // this returns the ORIGINAL value, not the new one. + SInt32 rc = DecrementAtomic(&mRefCount); + if (rc == 1) { + delete this; + } + } + +protected: + virtual ~CAReferenceCounted() { } + +private: + SInt32 mRefCount; + + CAReferenceCounted(const CAReferenceCounted &a) : mRefCount(0) { } + CAReferenceCounted operator=(const CAReferenceCounted &a) { return *this; } +}; + + +#endif // __CAReferenceCounted_h__ diff --git a/libs/appleutility/CAStreamBasicDescription.cpp b/libs/appleutility/CAStreamBasicDescription.cpp new file mode 100644 index 0000000000..f65bdd99ac --- /dev/null +++ b/libs/appleutility/CAStreamBasicDescription.cpp @@ -0,0 +1,520 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CAStreamBasicDescription.cpp + +=============================================================================*/ + +#include "CAConditionalMacros.h" + +#include "CAStreamBasicDescription.h" +#include "CAMath.h" + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include <CoreFoundation/CFByteOrder.h> +#else + #include <CFByteOrder.h> +#endif + +#pragma mark This file needs to compile on more earlier versions of the OS, so please keep that in mind when editing it + +const AudioStreamBasicDescription CAStreamBasicDescription::sEmpty = { 0.0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +CAStreamBasicDescription::CAStreamBasicDescription(double inSampleRate, UInt32 inFormatID, + UInt32 inBytesPerPacket, UInt32 inFramesPerPacket, + UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame, + UInt32 inBitsPerChannel, UInt32 inFormatFlags) +{ + mSampleRate = inSampleRate; + mFormatID = inFormatID; + mBytesPerPacket = inBytesPerPacket; + mFramesPerPacket = inFramesPerPacket; + mBytesPerFrame = inBytesPerFrame; + mChannelsPerFrame = inChannelsPerFrame; + mBitsPerChannel = inBitsPerChannel; + mFormatFlags = inFormatFlags; +} + +void CAStreamBasicDescription::PrintFormat(FILE *f, const char *indent, const char *name) const +{ + fprintf(f, "%s%s ", indent, name); + char formatID[5]; + *(UInt32 *)formatID = CFSwapInt32HostToBig(mFormatID); + formatID[4] = '\0'; + fprintf(f, "%2ld ch, %6.0f Hz, '%-4.4s' (0x%08lX) ", + NumberChannels(), mSampleRate, formatID, + mFormatFlags); + if (mFormatID == kAudioFormatLinearPCM) { + bool isInt = !(mFormatFlags & kLinearPCMFormatFlagIsFloat); + int wordSize = SampleWordSize(); + const char *endian = (wordSize > 1) ? + ((mFormatFlags & kLinearPCMFormatFlagIsBigEndian) ? " big-endian" : " little-endian" ) : ""; + const char *sign = isInt ? + ((mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) ? " signed" : " unsigned") : ""; + const char *floatInt = isInt ? "integer" : "float"; + char packed[32]; + if (wordSize > 0 && PackednessIsSignificant()) { + if (mFormatFlags & kLinearPCMFormatFlagIsPacked) + sprintf(packed, "packed in %d bytes", wordSize); + else + sprintf(packed, "unpacked in %d bytes", wordSize); + } else + packed[0] = '\0'; + const char *align = (wordSize > 0 && AlignmentIsSignificant()) ? + ((mFormatFlags & kLinearPCMFormatFlagIsAlignedHigh) ? " high-aligned" : " low-aligned") : ""; + const char *deinter = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) ? ", deinterleaved" : ""; + const char *commaSpace = (packed[0]!='\0') || (align[0]!='\0') ? ", " : ""; + + fprintf(f, "%ld-bit%s%s %s%s%s%s%s\n", + mBitsPerChannel, endian, sign, floatInt, + commaSpace, packed, align, deinter); + } else if (mFormatID == 'alac') { // kAudioFormatAppleLossless + int sourceBits = 0; + switch (mFormatFlags) + { + case 1: // kAppleLosslessFormatFlag_16BitSourceData + sourceBits = 16; + break; + case 2: // kAppleLosslessFormatFlag_20BitSourceData + sourceBits = 20; + break; + case 3: // kAppleLosslessFormatFlag_24BitSourceData + sourceBits = 24; + break; + case 4: // kAppleLosslessFormatFlag_32BitSourceData + sourceBits = 32; + break; + } + if (sourceBits) + fprintf(f, "from %d-bit source, ", sourceBits); + else + fprintf(f, "from UNKNOWN source bit depth, "); + + fprintf(f, "%ld frames/packet\n", mFramesPerPacket); + } + else + fprintf(f, "%ld bits/channel, %ld bytes/packet, %ld frames/packet, %ld bytes/frame\n", + mBitsPerChannel, mBytesPerPacket, mFramesPerPacket, mBytesPerFrame); +} + +void CAStreamBasicDescription::NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription) +{ + // the only thing that changes is to make mixable linear PCM into the canonical linear PCM format + if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0)) + { + // the canonical linear PCM format is 32 bit native endian floats + ioDescription.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; + ioDescription.mBytesPerPacket = sizeof(Float32) * ioDescription.mChannelsPerFrame; + ioDescription.mFramesPerPacket = 1; + ioDescription.mBytesPerFrame = sizeof(Float32) * ioDescription.mChannelsPerFrame; + ioDescription.mBitsPerChannel = 8 * sizeof(Float32); + } +} + +void CAStreamBasicDescription::ResetFormat(AudioStreamBasicDescription& ioDescription) +{ + ioDescription.mSampleRate = 0; + ioDescription.mFormatID = 0; + ioDescription.mBytesPerPacket = 0; + ioDescription.mFramesPerPacket = 0; + ioDescription.mBytesPerFrame = 0; + ioDescription.mChannelsPerFrame = 0; + ioDescription.mBitsPerChannel = 0; + ioDescription.mFormatFlags = 0; +} + +void CAStreamBasicDescription::FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription) +{ + if(fiszero(ioDescription.mSampleRate)) + { + ioDescription.mSampleRate = inTemplateDescription.mSampleRate; + } + if(ioDescription.mFormatID == 0) + { + ioDescription.mFormatID = inTemplateDescription.mFormatID; + } + if(ioDescription.mFormatFlags == 0) + { + ioDescription.mFormatFlags = inTemplateDescription.mFormatFlags; + } + if(ioDescription.mBytesPerPacket == 0) + { + ioDescription.mBytesPerPacket = inTemplateDescription.mBytesPerPacket; + } + if(ioDescription.mFramesPerPacket == 0) + { + ioDescription.mFramesPerPacket = inTemplateDescription.mFramesPerPacket; + } + if(ioDescription.mBytesPerFrame == 0) + { + ioDescription.mBytesPerFrame = inTemplateDescription.mBytesPerFrame; + } + if(ioDescription.mChannelsPerFrame == 0) + { + ioDescription.mChannelsPerFrame = inTemplateDescription.mChannelsPerFrame; + } + if(ioDescription.mBitsPerChannel == 0) + { + ioDescription.mBitsPerChannel = inTemplateDescription.mBitsPerChannel; + } +} + +void CAStreamBasicDescription::GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, bool inAbbreviate) +{ + switch(inDescription.mFormatID) + { + case kAudioFormatLinearPCM: + { + const char* theEndianString = NULL; + if((inDescription.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0) + { + #if TARGET_RT_LITTLE_ENDIAN + theEndianString = "Big Endian"; + #endif + } + else + { + #if TARGET_RT_BIG_ENDIAN + theEndianString = "Little Endian"; + #endif + } + + const char* theKindString = NULL; + if((inDescription.mFormatFlags & kAudioFormatFlagIsFloat) != 0) + { + theKindString = (inAbbreviate ? "Float" : "Floating Point"); + } + else if((inDescription.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0) + { + theKindString = (inAbbreviate ? "SInt" : "Signed Integer"); + } + else + { + theKindString = (inAbbreviate ? "UInt" : "Unsigned Integer"); + } + + const char* thePackingString = NULL; + if((inDescription.mFormatFlags & kAudioFormatFlagIsPacked) == 0) + { + if((inDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0) + { + thePackingString = "High"; + } + else + { + thePackingString = "Low"; + } + } + + const char* theMixabilityString = NULL; + if((inDescription.mFormatFlags & kIsNonMixableFlag) == 0) + { + theMixabilityString = "Mixable"; + } + else + { + theMixabilityString = "Unmixable"; + } + + if(inAbbreviate) + { + if(theEndianString != NULL) + { + if(thePackingString != NULL) + { + sprintf(outName, "%s %d Ch %s %s %s%d/%s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8); + } + else + { + sprintf(outName, "%s %d Ch %s %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, theKindString, (int)inDescription.mBitsPerChannel); + } + } + else + { + if(thePackingString != NULL) + { + sprintf(outName, "%s %d Ch %s %s%d/%s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)((inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8)); + } + else + { + sprintf(outName, "%s %d Ch %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theKindString, (int)inDescription.mBitsPerChannel); + } + } + } + else + { + if(theEndianString != NULL) + { + if(thePackingString != NULL) + { + sprintf(outName, "%s %d Channel %d Bit %s %s Aligned %s in %d Bits", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8); + } + else + { + sprintf(outName, "%s %d Channel %d Bit %s %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString); + } + } + else + { + if(thePackingString != NULL) + { + sprintf(outName, "%s %d Channel %d Bit %s Aligned %s in %d Bits", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8); + } + else + { + sprintf(outName, "%s %d Channel %d Bit %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString); + } + } + } + } + break; + + case kAudioFormatAC3: + strcpy(outName, "AC-3"); + break; + + case kAudioFormat60958AC3: + strcpy(outName, "AC-3 for SPDIF"); + break; + + default: + { + char* the4CCString = (char*)&inDescription.mFormatID; + outName[0] = the4CCString[0]; + outName[1] = the4CCString[1]; + outName[2] = the4CCString[2]; + outName[3] = the4CCString[3]; + outName[4] = 0; + } + break; + }; +} + +#if CoreAudio_Debug +#include "CALogMacros.h" + +void CAStreamBasicDescription::PrintToLog(const AudioStreamBasicDescription& inDesc) +{ + PrintFloat (" Sample Rate: ", inDesc.mSampleRate); + Print4CharCode (" Format ID: ", inDesc.mFormatID); + PrintHex (" Format Flags: ", inDesc.mFormatFlags); + PrintInt (" Bytes per Packet: ", inDesc.mBytesPerPacket); + PrintInt (" Frames per Packet: ", inDesc.mFramesPerPacket); + PrintInt (" Bytes per Frame: ", inDesc.mBytesPerFrame); + PrintInt (" Channels per Frame: ", inDesc.mChannelsPerFrame); + PrintInt (" Bits per Channel: ", inDesc.mBitsPerChannel); +} +#endif + +bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) +{ + bool theAnswer = false; + bool isDone = false; + + // note that if either side is 0, that field is skipped + + // format ID is the first order sort + if((!isDone) && ((x.mFormatID != 0) && (y.mFormatID != 0))) + { + if(x.mFormatID != y.mFormatID) + { + // formats are sorted numerically except that linear + // PCM is always first + if(x.mFormatID == kAudioFormatLinearPCM) + { + theAnswer = true; + } + else if(y.mFormatID == kAudioFormatLinearPCM) + { + theAnswer = false; + } + else + { + theAnswer = x.mFormatID < y.mFormatID; + } + isDone = true; + } + } + + + // mixable is always better than non-mixable for linear PCM and should be the second order sort item + if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM))) + { + if(((x.mFormatFlags & kIsNonMixableFlag) == 0) && ((y.mFormatFlags & kIsNonMixableFlag) != 0)) + { + theAnswer = true; + isDone = true; + } + else if(((x.mFormatFlags & kIsNonMixableFlag) != 0) && ((y.mFormatFlags & kIsNonMixableFlag) == 0)) + { + theAnswer = false; + isDone = true; + } + } + + // floating point vs integer for linear PCM only + if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM))) + { + if((x.mFormatFlags & kAudioFormatFlagIsFloat) != (y.mFormatFlags & kAudioFormatFlagIsFloat)) + { + // floating point is better than integer + theAnswer = y.mFormatFlags & kAudioFormatFlagIsFloat; + isDone = true; + } + } + + // bit depth + if((!isDone) && ((x.mBitsPerChannel != 0) && (y.mBitsPerChannel != 0))) + { + if(x.mBitsPerChannel != y.mBitsPerChannel) + { + // deeper bit depths are higher quality + theAnswer = x.mBitsPerChannel < y.mBitsPerChannel; + isDone = true; + } + } + + // sample rate + if((!isDone) && fnonzero(x.mSampleRate) && fnonzero(y.mSampleRate)) + { + if(fnotequal(x.mSampleRate, y.mSampleRate)) + { + // higher sample rates are higher quality + theAnswer = x.mSampleRate < y.mSampleRate; + isDone = true; + } + } + + // number of channels + if((!isDone) && ((x.mChannelsPerFrame != 0) && (y.mChannelsPerFrame != 0))) + { + if(x.mChannelsPerFrame != y.mChannelsPerFrame) + { + // more channels is higher quality + theAnswer = x.mChannelsPerFrame < y.mChannelsPerFrame; + isDone = true; + } + } + + return theAnswer; +} + +static bool MatchFormatFlags(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) +{ + UInt32 xFlags = x.mFormatFlags; + UInt32 yFlags = y.mFormatFlags; + + // match wildcards + if (x.mFormatID == 0 || y.mFormatID == 0 || xFlags == 0 || yFlags == 0) + return true; + + if (x.mFormatID == kAudioFormatLinearPCM) + { + // knock off the all clear flag + xFlags = xFlags & ~kAudioFormatFlagsAreAllClear; + yFlags = yFlags & ~kAudioFormatFlagsAreAllClear; + + // if both kAudioFormatFlagIsPacked bits are set, then we don't care about the kAudioFormatFlagIsAlignedHigh bit. + if (xFlags & yFlags & kAudioFormatFlagIsPacked) { + xFlags = xFlags & ~kAudioFormatFlagIsAlignedHigh; + yFlags = yFlags & ~kAudioFormatFlagIsAlignedHigh; + } + + // if both kAudioFormatFlagIsFloat bits are set, then we don't care about the kAudioFormatFlagIsSignedInteger bit. + if (xFlags & yFlags & kAudioFormatFlagIsFloat) { + xFlags = xFlags & ~kAudioFormatFlagIsSignedInteger; + yFlags = yFlags & ~kAudioFormatFlagIsSignedInteger; + } + + // if the bit depth is 8 bits or less and the format is packed, we don't care about endianness + if((x.mBitsPerChannel <= 8) && ((xFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked)) + { + xFlags = xFlags & ~kAudioFormatFlagIsBigEndian; + } + if((y.mBitsPerChannel <= 8) && ((yFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked)) + { + yFlags = yFlags & ~kAudioFormatFlagIsBigEndian; + } + + // if the number of channels is 0 or 1, we don't care about non-interleavedness + if (x.mChannelsPerFrame <= 1 && y.mChannelsPerFrame <= 1) { + xFlags &= ~kLinearPCMFormatFlagIsNonInterleaved; + yFlags &= ~kLinearPCMFormatFlagIsNonInterleaved; + } + } + return xFlags == yFlags; +} + +bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) +{ + // the semantics for equality are: + // 1) Values must match exactly + // 2) wildcard's are ignored in the comparison + +#define MATCH(name) ((x.name) == 0 || (y.name) == 0 || (x.name) == (y.name)) + + return + // check the sample rate + (fiszero(x.mSampleRate) || fiszero(y.mSampleRate) || fequal(x.mSampleRate, y.mSampleRate)) + + // check the format ids + && MATCH(mFormatID) + + // check the format flags + && MatchFormatFlags(x, y) + + // check the bytes per packet + && MATCH(mBytesPerPacket) + + // check the frames per packet + && MATCH(mFramesPerPacket) + + // check the bytes per frame + && MATCH(mBytesPerFrame) + + // check the channels per frame + && MATCH(mChannelsPerFrame) + + // check the channels per frame + && MATCH(mBitsPerChannel) ; +} + +bool SanityCheck(const AudioStreamBasicDescription& x) +{ + return (x.mSampleRate >= 0.); +} diff --git a/libs/appleutility/CAStreamBasicDescription.h b/libs/appleutility/CAStreamBasicDescription.h new file mode 100644 index 0000000000..aa41c40fe4 --- /dev/null +++ b/libs/appleutility/CAStreamBasicDescription.h @@ -0,0 +1,224 @@ +/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + CAStreamBasicDescription.h + +=============================================================================*/ + +#ifndef __CAStreamBasicDescription_h__ +#define __CAStreamBasicDescription_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include <CoreAudio/CoreAudioTypes.h> + #include <CoreFoundation/CoreFoundation.h> +#else + #include "CoreAudioTypes.h" + #include "CoreFoundation.h" +#endif + +#include "CADebugMacros.h" +#include <string.h> // for memset, memcpy +#include <stdio.h> // for FILE * + +#pragma mark This file needs to compile on more earlier versions of the OS, so please keep that in mind when editing it + +// define the IsMixable format flag for all versions of the system +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3) + enum { kIsNonMixableFlag = kAudioFormatFlagIsNonMixable }; +#else + enum { kIsNonMixableFlag = (1L << 6) }; +#endif + +//============================================================================= +// CAStreamBasicDescription +// +// This is a wrapper class for the AudioStreamBasicDescription struct. +// It adds a number of convenience routines, but otherwise adds nothing +// to the footprint of the original struct. +//============================================================================= +class CAStreamBasicDescription : + public AudioStreamBasicDescription +{ + +// Constants +public: + static const AudioStreamBasicDescription sEmpty; + +// Construction/Destruction +public: + CAStreamBasicDescription() { memset (this, 0, sizeof(AudioStreamBasicDescription)); } + + CAStreamBasicDescription(const AudioStreamBasicDescription &desc) + { + SetFrom(desc); + } + + CAStreamBasicDescription( double inSampleRate, UInt32 inFormatID, + UInt32 inBytesPerPacket, UInt32 inFramesPerPacket, + UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame, + UInt32 inBitsPerChannel, UInt32 inFormatFlags); + +// Assignment + CAStreamBasicDescription& operator=(const AudioStreamBasicDescription& v) { SetFrom(v); return *this; } + + void SetFrom(const AudioStreamBasicDescription &desc) + { + memcpy(this, &desc, sizeof(AudioStreamBasicDescription)); + } + + // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + // + // interrogation + + bool IsPCM() const { return mFormatID == kAudioFormatLinearPCM; } + + bool PackednessIsSignificant() const + { + Assert(IsPCM(), "PackednessIsSignificant only applies for PCM"); + return (SampleWordSize() << 3) != mBitsPerChannel; + } + + bool AlignmentIsSignificant() const + { + return PackednessIsSignificant() || (mBitsPerChannel & 7) != 0; + } + + bool IsInterleaved() const + { + return !IsPCM() || !(mFormatFlags & kAudioFormatFlagIsNonInterleaved); + } + + // for sanity with interleaved/deinterleaved possibilities, never access mChannelsPerFrame, use these: + UInt32 NumberInterleavedChannels() const { return IsInterleaved() ? mChannelsPerFrame : 1; } + UInt32 NumberChannelStreams() const { return IsInterleaved() ? 1 : mChannelsPerFrame; } + UInt32 NumberChannels() const { return mChannelsPerFrame; } + UInt32 SampleWordSize() const { return (mBytesPerFrame > 0) ? mBytesPerFrame / NumberInterleavedChannels() : 0;} + + UInt32 FramesToBytes(UInt32 nframes) const { return nframes * mBytesPerFrame; } + UInt32 BytesToFrames(UInt32 nbytes) const { + Assert(mBytesPerFrame > 0, "bytesPerFrame must be > 0 in BytesToFrames"); + return nbytes / mBytesPerFrame; + } + + bool SameChannelsAndInterleaving(const CAStreamBasicDescription &a) const + { + return this->NumberChannels() == a.NumberChannels() && this->IsInterleaved() == a.IsInterleaved(); + } + + // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + // + // manipulation + + void SetCanonical(UInt32 nChannels, bool interleaved) + // note: leaves sample rate untouched + { + mFormatID = kAudioFormatLinearPCM; + mFormatFlags = kAudioFormatFlagsNativeFloatPacked; + mBitsPerChannel = 32; + mChannelsPerFrame = nChannels; + mFramesPerPacket = 1; + if (interleaved) + mBytesPerPacket = mBytesPerFrame = nChannels * sizeof(Float32); + else { + mBytesPerPacket = mBytesPerFrame = sizeof(Float32); + mFormatFlags |= kAudioFormatFlagIsNonInterleaved; + } + } + + void ChangeNumberChannels(UInt32 nChannels, bool interleaved) + // alter an existing format + { + Assert(IsPCM(), "ChangeNumberChannels only works for PCM formats"); + UInt32 wordSize = SampleWordSize(); // get this before changing ANYTHING + if (wordSize == 0) + wordSize = (mBitsPerChannel + 7) / 8; + mChannelsPerFrame = nChannels; + mFramesPerPacket = 1; + if (interleaved) { + mBytesPerPacket = mBytesPerFrame = nChannels * wordSize; + mFormatFlags &= ~kAudioFormatFlagIsNonInterleaved; + } else { + mBytesPerPacket = mBytesPerFrame = wordSize; + mFormatFlags |= kAudioFormatFlagIsNonInterleaved; + } + } + + // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + // + // other + + void Print() const + { + Print (stdout); + } + + void Print(FILE* file) const + { + PrintFormat (file, "", "AudioStreamBasicDescription:"); + } + + void PrintFormat(FILE *f, const char *indent, const char *name) const; + + OSStatus Save(CFPropertyListRef *outData) const; + + OSStatus Restore(CFPropertyListRef &inData); + +// Operations + static bool IsMixable(const AudioStreamBasicDescription& inDescription) { return (inDescription.mFormatID == kAudioFormatLinearPCM) && ((inDescription.mFormatFlags & kIsNonMixableFlag) == 0); } + static void NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription); + static void ResetFormat(AudioStreamBasicDescription& ioDescription); + static void FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription); + static void GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, bool inAbbreviate); +#if CoreAudio_Debug + static void PrintToLog(const AudioStreamBasicDescription& inDesc); +#endif +}; + +bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y); +bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y); +#if TARGET_OS_MAC || (TARGET_OS_WIN32 && (_MSC_VER > 600)) +inline bool operator!=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x == y); } +inline bool operator<=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return (x < y) || (x == y); } +inline bool operator>=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x < y); } +inline bool operator>(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !((x < y) || (x == y)); } +#endif + +bool SanityCheck(const AudioStreamBasicDescription& x); + + +#endif // __CAStreamBasicDescription_h__ diff --git a/libs/appleutility/SConscript b/libs/appleutility/SConscript new file mode 100644 index 0000000000..2f3280f8b6 --- /dev/null +++ b/libs/appleutility/SConscript @@ -0,0 +1,23 @@ +# -*- python -*- + +import os +import os.path +import glob + +appleutility_files = glob.glob('*.cpp') + +Import('env install_prefix') +appleutility = env.Copy() + +appleutility.Append(LINKFLAGS='-framework AudioToolbox') +appleutility.Append(LINKFLAGS='-framework AudioUnit') +appleutility.Append(LINKFLAGS='-framework CoreFoundation') +appleutility.Append(LINKFLAGS='-framework CoreServices') + +libappleutility = appleutility.SharedLibrary('appleutility', appleutility_files) + +Default(libappleutility) + +env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libappleutility)) + +env.Alias('tarball', env.Distribute (env['DISTTREE'], ['SConscript'] + appleutility_files + glob.glob('*.h') )) diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index a1bed7aeef..44cec8638c 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -27,9 +27,11 @@ ardour.Append(POTFILE = domain + '.pot') ardour.Append(CPPPATH = '#libs/surfaces/control_protocol') ardour_files=Split(""" +diskstream.cc audio_diskstream.cc audio_library.cc audio_playlist.cc +track.cc audio_track.cc audioengine.cc audiofilesource.cc @@ -88,7 +90,6 @@ sndfile_helpers.cc sndfilesource.cc source.cc state_manager.cc -stateful.cc tempo.cc utils.cc version.cc @@ -99,7 +100,7 @@ arch_specific_objects = [ ] osc_files = [ 'osc.cc' ] vst_files = [ 'vst_plugin.cc', 'session_vst.cc' ] -coreaudio_files = [ 'coreaudiosource.cc' ] +coreaudio_files = [ 'audio_unit.cc', 'coreaudiosource.cc' ] extra_sources = [ ] if ardour['VST']: @@ -199,7 +200,7 @@ ardour.Merge ([ libraries['lrdf'], libraries['samplerate'], libraries['sigc2'], - libraries['pbd3'], + libraries['pbd'], libraries['soundtouch'], libraries['midi++2'], libraries['glib2'], @@ -209,6 +210,9 @@ ardour.Merge ([ if ardour['LIBLO']: ardour.Merge ([ libraries['lo'] ]) +if ardour['COREAUDIO']: + ardour.Merge ([ libraries['appleutility'] ]) + ardour.VersionBuild(['version.cc', 'ardour/version.h'], 'SConscript') def SharedAsmObjectEmitter(target, source, env): diff --git a/libs/ardour/ardour/ardour.h b/libs/ardour/ardour/ardour.h index c0dfea9a95..e3b7cf2313 100644 --- a/libs/ardour/ardour/ardour.h +++ b/libs/ardour/ardour/ardour.h @@ -45,7 +45,7 @@ namespace ARDOUR { static const jack_nframes_t max_frames = JACK_MAX_FRAMES; - int init (AudioEngine&, bool with_vst, bool try_optimization); + int init (bool with_vst, bool try_optimization); int cleanup (); @@ -58,7 +58,7 @@ namespace ARDOUR { const layer_t max_layer = UCHAR_MAX; - id_t new_id(); + microseconds_t get_microseconds (); Change new_change (); @@ -74,7 +74,7 @@ namespace ARDOUR { const char* old; }; -}; +} /* how do we make these be within the Ardour namespace? */ diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h index 9355a3fccb..e2dfc5fd0c 100644 --- a/libs/ardour/ardour/audio_diskstream.h +++ b/libs/ardour/ardour/audio_diskstream.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,12 +14,10 @@ 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: diskstream.h 579 2006-06-12 19:56:37Z essej $ */ -#ifndef __ardour_diskstream_h__ -#define __ardour_diskstream_h__ +#ifndef __ardour_audio_diskstream_h__ +#define __ardour_audio_diskstream_h__ #include <sigc++/signal.h> @@ -33,7 +31,7 @@ #include <pbd/fastlog.h> #include <pbd/ringbufferNPT.h> - +#include <pbd/stateful.h> #include <ardour/ardour.h> #include <ardour/configuration.h> @@ -42,7 +40,8 @@ #include <ardour/route.h> #include <ardour/port.h> #include <ardour/utils.h> -#include <ardour/stateful.h> +#include <ardour/diskstream.h> +#include <ardour/audioplaylist.h> struct tm; @@ -55,53 +54,20 @@ class AudioPlaylist; class AudioFileSource; class IO; -class AudioDiskstream : public Stateful, public sigc::trackable +class AudioDiskstream : public Diskstream { public: - enum Flag { - Recordable = 0x1, - Hidden = 0x2, - Destructive = 0x4 - }; - - AudioDiskstream (Session &, const string& name, Flag f = Recordable); + AudioDiskstream (Session &, const string& name, Diskstream::Flag f = Recordable); AudioDiskstream (Session &, const XMLNode&); - string name() const { return _name; } - - ARDOUR::IO* io() const { return _io; } - void set_io (ARDOUR::IO& io); + const PBD::ID& id() const { return _id; } + // FIXME AudioDiskstream& 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; } - bool destructive() const { return _flags & Destructive; } - - void set_destructive (bool yn); - - jack_nframes_t roll_delay() const { return _roll_delay; } - void set_roll_delay (jack_nframes_t); - - int 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() : ""; @@ -114,14 +80,7 @@ class AudioDiskstream : public Stateful, public sigc::trackable if (n < channels.size()) return channels[n].source; return 0; } - void set_record_enabled (bool yn, void *src); - bool record_enabled() const { return g_atomic_int_get (&_record_enabled); } - void punch_in (); - void punch_out (); - - bool reversed() const { return _actual_speed < 0.0f; } - double speed() const { return _visible_speed; } - void set_speed (double); + void set_record_enabled (bool yn); float peak_power(uint32_t n=0) { float x = channels[n].peak_power; @@ -132,14 +91,13 @@ class AudioDiskstream : public Stateful, public sigc::trackable return minus_infinity(); } } + + AudioPlaylist* audio_playlist () { return dynamic_cast<AudioPlaylist*>(_playlist); } - int use_playlist (AudioPlaylist *); + int use_playlist (Playlist *); 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; @@ -152,51 +110,23 @@ class AudioDiskstream : public Stateful, public sigc::trackable return 0; } - AudioPlaylist *playlist () { return _playlist; } - AudioFileSource *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,AudioDiskstream*> AudioDiskstreamCreated; // XXX use a ref with sigc2 - static sigc::signal<void,list<AudioFileSource*>*> DeleteSources; - /* stateful */ XMLNode& get_state(void); - int set_state(const XMLNode& node); + 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; @@ -213,19 +143,7 @@ class AudioDiskstream : public Stateful, public sigc::trackable } } - 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; } + std::list<Region*>& last_capture_regions () { return _last_capture_regions; } XMLNode* deprecated_io_node; @@ -237,9 +155,8 @@ class AudioDiskstream : public Stateful, public sigc::trackable while they are called. */ - void set_pending_overwrite (bool); + 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); @@ -247,9 +164,6 @@ class AudioDiskstream : public Stateful, public sigc::trackable void reset_write_sources (bool, bool force = false); 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); @@ -257,38 +171,23 @@ class AudioDiskstream : public Stateful, public sigc::trackable 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 */ - ~AudioDiskstream(); - enum TransitionType { - CaptureStart = 0, - CaptureEnd - }; - - struct CaptureTransition { - - TransitionType type; - // the start or end file frame pos - jack_nframes_t capture_val; - }; - struct ChannelInfo { Sample *playback_wrap_buffer; Sample *capture_wrap_buffer; Sample *speed_buffer; - float peak_power; + float peak_power; - AudioFileSource *fades_source; + AudioFileSource *fades_source; AudioFileSource *write_source; Port *source; @@ -310,129 +209,30 @@ class AudioDiskstream : public Stateful, public sigc::trackable jack_nframes_t curr_capture_cnt; }; - typedef vector<ChannelInfo> ChannelList; - - - string _name; - ARDOUR::Session& _session; - ARDOUR::IO* _io; - ChannelList channels; - uint32_t _n_channels; - id_t _id; - - mutable gint _record_enabled; - AudioPlaylist* _playlist; - double _visible_speed; - double _actual_speed; - /* items needed for speed change logic */ - bool _buffer_reallocation_required; - bool _seek_required; + /* The two central butler operations */ + int do_flush (Session::RunContext context, bool force = false); + int do_refill () { return _do_refill(_mixdown_buffer, _gain_buffer, _conversion_buffer); } - 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; - - Glib::Mutex state_lock; + int do_refill_with_alloc(); - 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 (char * workbuf, bool force = false); - int do_refill (Sample *mixdown_buffer, float *gain_buffer, char *workbuf); - - int read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, char * workbuf, 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); + int read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, char * workbuf, + jack_nframes_t& start, jack_nframes_t cnt, + ChannelInfo& channel_info, int channel, bool reversed); 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; - Glib::Mutex capture_info_lock; - - void init (Flag); + void init (Diskstream::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 (double, bool global_change); - void non_realtime_set_speed (); - - std::list<Region*> _last_capture_regions; - std::vector<AudioFileSource*> capturing_sources; int use_pending_capture_data (XMLNode& node); void get_input_sources (); @@ -440,8 +240,29 @@ class AudioDiskstream : public Stateful, public sigc::trackable void set_align_style_from_io(); void setup_destructive_playlist (); void use_destructive_playlist (); + + void engage_record_enable (); + void disengage_record_enable (); + + // Working buffers for do_refill (butler thread) + static void allocate_working_buffers(); + static void free_working_buffers(); + + static size_t _working_buffers_size; + static Sample* _mixdown_buffer; + static gain_t* _gain_buffer; + static char* _conversion_buffer; + + // Uh, /really/ private? (death to friend classes) + int _do_refill (Sample *mixdown_buffer, float *gain_buffer, char *workbuf); + + + std::vector<AudioFileSource*> capturing_sources; + + typedef vector<ChannelInfo> ChannelList; + ChannelList channels; }; -}; /* namespace ARDOUR */ +} // namespace ARDOUR -#endif /* __ardour_diskstream_h__ */ +#endif /* __ardour_audio_diskstream_h__ */ diff --git a/libs/ardour/ardour/audio_library.h b/libs/ardour/ardour/audio_library.h index 2f9e84551b..f5ac6da654 100644 --- a/libs/ardour/ardour/audio_library.h +++ b/libs/ardour/ardour/audio_library.h @@ -28,18 +28,25 @@ #include <sigc++/signal.h> +#include <pbd/stateful.h> + using std::vector; using std::string; using std::map; namespace ARDOUR { -class AudioLibrary +class AudioLibrary : public Stateful { public: AudioLibrary (); ~AudioLibrary (); + static string state_node_name; + + XMLNode& get_state (void); + int set_state (const XMLNode&); + void set_paths (vector<string> paths); vector<string> get_paths (); void scan_paths (); diff --git a/libs/ardour/ardour/audio_track.h b/libs/ardour/ardour/audio_track.h index 1c17cbc859..15b99297c8 100644 --- a/libs/ardour/ardour/audio_track.h +++ b/libs/ardour/ardour/audio_track.h @@ -21,7 +21,7 @@ #ifndef __ardour_audio_track_h__ #define __ardour_audio_track_h__ -#include <ardour/route.h> +#include <ardour/track.h> namespace ARDOUR { @@ -30,79 +30,38 @@ class AudioDiskstream; class AudioPlaylist; class RouteGroup; -class AudioTrack : public Route +class AudioTrack : public Track { public: AudioTrack (Session&, string name, Route::Flag f = Route::Flag (0), TrackMode m = Normal); 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 (); + 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); - bool can_record() const { return true; } - void set_record_enable (bool yn, void *src); + AudioDiskstream& audio_diskstream() const; - AudioDiskstream& disk_stream() const { return *diskstream; } - int set_diskstream (AudioDiskstream&, void *); int use_diskstream (string name); - int use_diskstream (id_t id); - - TrackMode mode() const { return _mode; } - void set_mode (TrackMode m); - sigc::signal<void> ModeChanged; - - jack_nframes_t update_total_latency(); - void set_latency_delay (jack_nframes_t); + int use_diskstream (const PBD::ID& id); int export_stuff (vector<Sample*>& buffers, char * workbuf, 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(); - XMLNode& get_template(); 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: - AudioDiskstream *diskstream; - MeterPoint _saved_meter_point; - TrackMode _mode; - XMLNode& state (bool full); void passthru_silence (jack_nframes_t start_frame, jack_nframes_t end_frame, @@ -110,62 +69,14 @@ class AudioTrack : public Route 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; - - int deprecated_use_diskstream_connections (); + int set_diskstream (AudioDiskstream&, void *); + 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; - - bool _destructive; }; -}; /* namespace ARDOUR*/ +} // namespace ARDOUR #endif /* __ardour_audio_track_h__ */ diff --git a/libs/ardour/ardour/audio_unit.h b/libs/ardour/ardour/audio_unit.h new file mode 100644 index 0000000000..f437ae053a --- /dev/null +++ b/libs/ardour/ardour/audio_unit.h @@ -0,0 +1,111 @@ +/* + Copyright (C) 2006 Paul Davis + Written by 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. + +*/ + +#ifndef __ardour_audio_unit_h__ +#define __ardour_audio_unit_h__ + +#include <stdint.h> + +#include <list> +#include <set> +#include <string> +#include <vector> + +#include <ardour/plugin.h> + +#include <boost/shared_ptr.hpp> + +class CAComponent; +class CAAudioUnit; +class CAComponentDescription; + +namespace ARDOUR { + +class AudioEngine; +class Session; + +class AUPlugin : public ARDOUR::Plugin +{ + public: + AUPlugin (AudioEngine& engine, Session& session, CAComponent* comp); + virtual ~AUPlugin (); + + uint32_t unique_id () const; + const char * label () const; + const char * name () const { return _info->name.c_str(); } + 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 which, float val); + float get_parameter (uint32_t which) const; + + int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const; + uint32_t nth_parameter (uint32_t which, 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); + std::set<uint32_t> automatable() const; + void store_state (ARDOUR::PluginState&); + void restore_state (ARDOUR::PluginState&); + string describe_parameter (uint32_t); + string state_node_name () const { return "audiounit"; } + 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; + + XMLNode& get_state(); + int set_state(const XMLNode& node); + + bool save_preset (string name); + bool load_preset (const string preset_label); + std::vector<std::string> get_presets (); + + bool has_editor () const; + + private: + CAComponent* comp; + CAAudioUnit* unit; +}; + +class AUPluginInfo : public PluginInfo { + public: + AUPluginInfo () { }; + ~AUPluginInfo (); + + CAComponentDescription* desc; + + static PluginInfoList discover (); + PluginPtr load (Session& session); + + private: + static std::string get_name (CAComponentDescription&); +}; + +typedef boost::shared_ptr<AUPluginInfo> AUPluginInfoPtr; + +} // namespace ARDOUR + +#endif // __ardour_audio_unit_h__ diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index 50bf7dddcc..e7500fc7a2 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -34,6 +34,8 @@ #include <ardour/ardour.h> #include <jack/jack.h> #include <jack/transport.h> +#include <ardour/types.h> +#include <ardour/data_type.h> namespace ARDOUR { @@ -104,8 +106,8 @@ class AudioEngine : public sigc::trackable virtual const char *what() const throw() { return "could not connect to engine backend"; } }; - Port *register_audio_input_port (const std::string& portname); - Port *register_audio_output_port (const std::string& portname); + Port *register_input_port (DataType type, const std::string& portname); + Port *register_output_port (DataType type, const std::string& portname); int unregister_port (Port *); int connect (const std::string& source, const std::string& destination); @@ -243,6 +245,6 @@ class AudioEngine : public sigc::trackable mutable gint m_meter_exit; }; -}; /* namespace ARDOUR */ +} // namespace ARDOUR #endif /* __ardour_audioengine_h__ */ diff --git a/libs/ardour/ardour/audiofilesource.h b/libs/ardour/ardour/audiofilesource.h index 36251c07ff..eb3fd750d4 100644 --- a/libs/ardour/ardour/audiofilesource.h +++ b/libs/ardour/ardour/audiofilesource.h @@ -42,7 +42,8 @@ class AudioFileSource : public AudioSource { Removable = 0x8, RemovableIfEmpty = 0x10, RemoveAtDestroy = 0x20, - NoPeakFile = 0x40 + NoPeakFile = 0x40, + Destructive = 0x80 }; virtual ~AudioFileSource (); @@ -95,7 +96,7 @@ class AudioFileSource : public AudioSource { static void set_bwf_serial_number (int); static void set_search_path (string); - static void set_header_position_offset (jack_nframes_t offset, bool negative); + static void set_header_position_offset (jack_nframes_t offset ); static sigc::signal<void> HeaderPositionOffsetChanged; @@ -107,7 +108,7 @@ class AudioFileSource : public AudioSource { to cause issues. */ - void handle_header_position_change (); + virtual void handle_header_position_change () {} protected: @@ -141,7 +142,6 @@ class AudioFileSource : public AudioSource { static char bwf_serial_number[13]; static uint64_t header_position_offset; - static bool header_position_negative; virtual void set_timeline_position (jack_nframes_t pos); virtual void set_header_timeline_position () = 0; @@ -151,7 +151,7 @@ class AudioFileSource : public AudioSource { bool writable() const { return _flags & Writable; } }; -}; /* namespace ARDOUR */ +} // namespace ARDOUR #endif /* __ardour_audiofilesource_h__ */ diff --git a/libs/ardour/ardour/audioplaylist.h b/libs/ardour/ardour/audioplaylist.h index 1b60cf185d..5a77067f8f 100644 --- a/libs/ardour/ardour/audioplaylist.h +++ b/libs/ardour/ardour/audioplaylist.h @@ -77,9 +77,6 @@ class AudioPlaylist : public ARDOUR::Playlist 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: diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h index 009aa4b5b0..683e946713 100644 --- a/libs/ardour/ardour/audioregion.h +++ b/libs/ardour/ardour/audioregion.h @@ -27,8 +27,9 @@ #include <pbd/undo.h> #include <ardour/ardour.h> -#include <ardour/gain.h> #include <ardour/region.h> +#include <ardour/gain.h> +#include <ardour/logcurve.h> #include <ardour/export.h> class XMLNode; @@ -43,14 +44,14 @@ class AudioSource; 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; + 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 @@ -75,11 +76,7 @@ class AudioRegion : public Region AudioRegion (SourceList &, const XMLNode&); ~AudioRegion(); - bool region_list_equivalent (const AudioRegion&) const ; - bool source_equivalent (const AudioRegion&) const; - bool equivalent (const AudioRegion&) const; - bool size_equivalent (const AudioRegion&) const; - bool overlap_equivalent (const AudioRegion&) const; + bool source_equivalent (const Region&) const; bool speed_mismatch (float) const; @@ -96,7 +93,7 @@ class AudioRegion : public Region vector<string> master_source_names(); bool envelope_active () const { return _flags & Region::EnvelopeActive; } - bool fade_in_active () const { return _flags & Region::FadeIn; } + 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))); } @@ -104,20 +101,21 @@ class AudioRegion : public Region 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, char * workbuf, 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 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; - jack_nframes_t master_read_at (Sample *buf, Sample *mixdown_buffer, - float *gain_buffer, char * workbuf, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n=0) const; + virtual jack_nframes_t read_at (Sample *buf, Sample *mixdown_buf, + float *gain_buf, char * workbuf, 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_buf, + float *gain_buf, char * workbuf, + 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); @@ -127,8 +125,7 @@ class AudioRegion : public Region Fast, Slow, LogA, - LogB, - + LogB }; void set_fade_in_active (bool yn); @@ -145,10 +142,6 @@ class AudioRegion : public Region 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 */ @@ -172,20 +165,6 @@ class AudioRegion : public Region 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 (); @@ -197,10 +176,6 @@ class AudioRegion : public Region 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, char * workbuf, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n = 0, @@ -217,6 +192,21 @@ class AudioRegion : public Region void envelope_changed (Change); void source_deleted (Source*); + + + SourceList sources; + + /** Used when timefx are applied, so we can always use the original source. */ + SourceList master_sources; + + 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; }; } /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h index 1dcf5b42f3..35158a24e7 100644 --- a/libs/ardour/ardour/audiosource.h +++ b/libs/ardour/ardour/audiosource.h @@ -33,7 +33,7 @@ #include <ardour/source.h> #include <ardour/ardour.h> -#include <ardour/stateful.h> +#include <pbd/stateful.h> #include <pbd/xml++.h> using std::list; @@ -51,6 +51,13 @@ class AudioSource : public Source AudioSource (const XMLNode&); virtual ~AudioSource (); + /* one could argue that this should belong to Source, but other data types + generally do not come with a model of "offset along an audio timeline" + so its here in AudioSource for now. + */ + + virtual jack_nframes_t natural_position() const { return 0; } + /* returns the number of items in this `audio_source' */ virtual jack_nframes_t length() const { diff --git a/libs/ardour/ardour/buffer.h b/libs/ardour/ardour/buffer.h new file mode 100644 index 0000000000..8a88802ecb --- /dev/null +++ b/libs/ardour/ardour/buffer.h @@ -0,0 +1,106 @@ +/* + Copyright (C) 2006 Paul Davis + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __ardour_buffer_h__ +#define __ardour_buffer_h__ + +#define _XOPEN_SOURCE 600 +#include <cstdlib> // for posix_memalign +#include <cassert> +#include <ardour/types.h> +#include <ardour/data_type.h> + +namespace ARDOUR { + + +/* Yes, this is a bit of a mess right now. I'll clean it up when everything + * using it works out.. */ + + +/** A buffer of recordable/playable data. + * + * This is a datatype-agnostic base class for all buffers (there are no + * methods to actually access the data). This provides a way for code that + * doesn't care about the data type to still deal with buffers (which is + * why the base class can't be a template). + * + * To actually read/write buffer contents, use the appropriate derived class. + */ +class Buffer +{ +public: + Buffer(DataType type, size_t capacity) + : _type(type), _capacity(capacity), _size(0) + {} + + virtual ~Buffer() {} + + /** Maximum capacity of buffer. + * Note in some cases the entire buffer may not contain valid data, use size. */ + size_t capacity() const { return _capacity; } + + /** Amount of valid data in buffer. Use this over capacity almost always. */ + size_t size() const { return _size; } + + /** Type of this buffer. + * Based on this you can static cast a Buffer* to the desired type. */ + DataType type() const { return _type; } + +protected: + DataType _type; + size_t _capacity; + size_t _size; +}; + + +/* Inside every class with a type in it's name is a template waiting to get out... */ + + +/** Buffer containing 32-bit floating point (audio) data. */ +class AudioBuffer : public Buffer +{ +public: + AudioBuffer(size_t capacity) + : Buffer(DataType::AUDIO, capacity) + , _data(NULL) + { + _size = capacity; // For audio buffers, size = capacity (always) +#ifdef NO_POSIX_MEMALIGN + _data = (Sample *) malloc(sizeof(Sample) * capacity); +#else + posix_memalign((void**)_data, 16, sizeof(Sample) * capacity); +#endif + assert(_data); + memset(_data, 0, sizeof(Sample) * capacity); + } + + const Sample* data() const { return _data; } + Sample* data() { return _data; } + +private: + // These are undefined (prevent copies) + AudioBuffer(const AudioBuffer& copy); + AudioBuffer& operator=(const AudioBuffer& copy); + + Sample* _data; ///< Actual buffer contents +}; + + +} // namespace ARDOUR + +#endif // __ardour_buffer_h__ diff --git a/libs/ardour/ardour/configuration.h b/libs/ardour/ardour/configuration.h index 60b5e8a2c3..dd689e9a2d 100644 --- a/libs/ardour/ardour/configuration.h +++ b/libs/ardour/ardour/configuration.h @@ -27,8 +27,9 @@ #include <sys/types.h> #include <string> +#include <pbd/stateful.h> + #include <ardour/types.h> -#include <ardour/stateful.h> #include <ardour/utils.h> #include <ardour/configuration_variable.h> @@ -98,6 +99,6 @@ class Configuration : public Stateful extern Configuration *Config; extern gain_t speed_quietning; /* see comment in configuration.cc */ -}; /* namespace ARDOUR */ +} // namespace ARDOUR #endif /* __ardour_configuration_h__ */ diff --git a/libs/ardour/ardour/connection.h b/libs/ardour/ardour/connection.h index 899bffc06a..da4d4e2684 100644 --- a/libs/ardour/ardour/connection.h +++ b/libs/ardour/ardour/connection.h @@ -25,7 +25,7 @@ #include <string> #include <sigc++/signal.h> #include <glibmm/thread.h> -#include <ardour/stateful.h> +#include <pbd/stateful.h> using std::vector; using std::string; diff --git a/libs/ardour/ardour/control_protocol_manager.h b/libs/ardour/ardour/control_protocol_manager.h index 03b21a299c..8eda7a4555 100644 --- a/libs/ardour/ardour/control_protocol_manager.h +++ b/libs/ardour/ardour/control_protocol_manager.h @@ -8,7 +8,7 @@ #include <glibmm/thread.h> -#include <ardour/stateful.h> +#include <pbd/stateful.h> namespace ARDOUR { @@ -23,6 +23,7 @@ struct ControlProtocolInfo { std::string path; bool requested; bool mandatory; + XMLNode* state; }; class ControlProtocolManager : public sigc::trackable, public Stateful diff --git a/libs/ardour/ardour/curve.h b/libs/ardour/ardour/curve.h index ede060e1cb..7f8a43cfe1 100644 --- a/libs/ardour/ardour/curve.h +++ b/libs/ardour/ardour/curve.h @@ -76,7 +76,7 @@ class Curve : public AutomationList }; -}; /* namespace ARDOUR */ +} // namespace ARDOUR extern "C" { void curve_get_vector_from_c (void *arg, double, double, float*, int32_t); diff --git a/libs/ardour/ardour/data_type.h b/libs/ardour/ardour/data_type.h new file mode 100644 index 0000000000..d49ed108cd --- /dev/null +++ b/libs/ardour/ardour/data_type.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2006 Paul Davis + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __ardour_data_type_h__ +#define __ardour_data_type_h__ + +#include <jack/jack.h> + +namespace ARDOUR { + +class DataType +{ +public: + enum Symbol { + NIL = 0, + AUDIO, + MIDI + }; + + DataType(const Symbol& symbol) + : _symbol(symbol) + {} + + /** Construct from a string (Used for loading from XML) */ + DataType(const string& str) { + if (str == "audio") + _symbol = AUDIO; + //else if (str == "midi") + // _symbol = MIDI; + else + _symbol = NIL; + } + + bool operator==(const Symbol symbol) { return _symbol == symbol; } + bool operator!=(const Symbol symbol) { return _symbol != symbol; } + + /** Get the Jack type this DataType corresponds to */ + const char* to_jack_type() { + switch (_symbol) { + case AUDIO: return JACK_DEFAULT_AUDIO_TYPE; + //case MIDI: return JACK_DEFAULT_MIDI_TYPE; + default: return ""; + } + } + + /** Inverse of the from-string constructor */ + const char* to_string() { + switch (_symbol) { + case AUDIO: return "audio"; + //case MIDI: return "midi"; + default: return "unknown"; // reeeally shouldn't ever happen + } + } + +private: + Symbol _symbol; +}; + + + +} // namespace ARDOUR + +#endif // __ardour_data_type_h__ + diff --git a/libs/ardour/ardour/destructive_filesource.h b/libs/ardour/ardour/destructive_filesource.h index 2d10528ac8..5b773898c3 100644 --- a/libs/ardour/ardour/destructive_filesource.h +++ b/libs/ardour/ardour/destructive_filesource.h @@ -34,6 +34,8 @@ class DestructiveFileSource : public SndFileSource { DestructiveFileSource (std::string path, SampleFormat samp_format, HeaderFormat hdr_format, jack_nframes_t rate, Flag flags = AudioFileSource::Flag (AudioFileSource::Writable)); + DestructiveFileSource (std::string path, Flag flags); + DestructiveFileSource (const XMLNode&); ~DestructiveFileSource (); @@ -49,6 +51,8 @@ class DestructiveFileSource : public SndFileSource { protected: jack_nframes_t write_unlocked (Sample *src, jack_nframes_t cnt, char * workbuf); + virtual void handle_header_position_change (); + private: static jack_nframes_t xfade_frames; static gain_t* out_coefficient; @@ -60,6 +64,7 @@ class DestructiveFileSource : public SndFileSource { jack_nframes_t file_pos; // unit is frames Sample* xfade_buf; + void init (); jack_nframes_t crossfade (Sample* data, jack_nframes_t cnt, int dir, char * workbuf); void set_timeline_position (jack_nframes_t); }; diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h new file mode 100644 index 0000000000..ebce516d8b --- /dev/null +++ b/libs/ardour/ardour/diskstream.h @@ -0,0 +1,319 @@ +/* + Copyright (C) 2000-2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: diskstream.h 579 2006-06-12 19:56:37Z essej $ +*/ + +#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/stateful.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> + + +struct tm; + +namespace ARDOUR { + +class AudioEngine; +class Send; +class Session; +class Playlist; +class IO; + +class Diskstream : public Stateful, public sigc::trackable +{ + public: + enum Flag { + Recordable = 0x1, + Hidden = 0x2, + Destructive = 0x4 + }; + + string name () const { return _name; } + virtual int set_name (string str); + + ARDOUR::IO* io() const { return _io; } + void set_io (ARDOUR::IO& io); + + virtual Diskstream& ref() { _refcnt++; return *this; } + void unref() { if (_refcnt) _refcnt--; if (_refcnt == 0) delete this; } + uint32_t refcnt() const { return _refcnt; } + + virtual float playback_buffer_load() const = 0; + virtual float capture_buffer_load() const = 0; + + 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 a) { _persistent_alignment_style = a; } + + jack_nframes_t roll_delay() const { return _roll_delay; } + void set_roll_delay (jack_nframes_t); + + bool record_enabled() const { return g_atomic_int_get (&_record_enabled); } + virtual void set_record_enabled (bool yn) = 0; + + bool destructive() const { return _flags & Destructive; } + virtual void set_destructive (bool yn); + + const PBD::ID& id() const { return _id; } + bool hidden() const { return _flags & Hidden; } + bool recordable() const { return _flags & Recordable; } + bool reversed() const { return _actual_speed < 0.0f; } + double speed() const { return _visible_speed; } + + virtual void punch_in() {} + virtual void punch_out() {} + + void set_speed (double); + void non_realtime_set_speed (); + + Playlist* playlist () { return _playlist; } + + virtual int use_playlist (Playlist *); + virtual int use_new_playlist () = 0; + virtual int use_copy_playlist () = 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; } + + static jack_nframes_t disk_io_frames() { return disk_io_chunk_frames; } + static void set_disk_io_chunk_frames (uint32_t n) { disk_io_chunk_frames = n; } + + /* Stateful */ + virtual XMLNode& get_state(void) = 0; + virtual int set_state(const XMLNode& node) = 0; + + // FIXME: makes sense for all diskstream types? + virtual void monitor_input (bool) {} + + jack_nframes_t capture_offset() const { return _capture_offset; } + virtual void set_capture_offset (); + + bool slaved() const { return _slaved; } + void set_slaved(bool yn) { _slaved = yn; } + + int set_loop (Location *loc); + + std::list<Region*>& last_capture_regions () { return _last_capture_regions; } + + void handle_input_change (IOChange, void *src); + + sigc::signal<void> RecordEnableChanged; + sigc::signal<void> SpeedChanged; + sigc::signal<void> ReverseChanged; + sigc::signal<void> PlaylistChanged; + sigc::signal<void> AlignmentStyleChanged; + sigc::signal<void,Location *> LoopSet; + + 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,list<Source*>*> DeleteSources; + + protected: + friend class Session; + + Diskstream (Session &, const string& name, Flag f = Recordable); + Diskstream (Session &, const XMLNode&); + + /* the Session is the only point of access for these because they require + * that the Session is "inactive" while they are called. + */ + + virtual void set_pending_overwrite (bool) = 0; + virtual int overwrite_existing_buffers () = 0; + virtual void set_block_size (jack_nframes_t) = 0; + virtual int internal_playback_seek (jack_nframes_t distance) = 0; + virtual int can_internal_playback_seek (jack_nframes_t distance) = 0; + virtual int rename_write_sources () = 0; + virtual void reset_write_sources (bool, bool force = false) = 0; + virtual void non_realtime_input_change () = 0; + + uint32_t read_data_count() const { return _read_data_count; } + uint32_t write_data_count() const { return _write_data_count; } + + protected: + friend class Auditioner; + virtual int seek (jack_nframes_t which_sample, bool complete_refill = false) = 0; + + protected: + friend class Track; + + virtual void prepare (); + virtual int process (jack_nframes_t transport_frame, jack_nframes_t nframes, jack_nframes_t offset, bool can_record, bool rec_monitors_input) = 0; + virtual bool commit (jack_nframes_t nframes) = 0; + virtual void recover (); /* called if commit will not be called, but process was */ + + //private: + + /** Use unref() to destroy a diskstream */ + virtual ~Diskstream(); + + enum TransitionType { + CaptureStart = 0, + CaptureEnd + }; + + struct CaptureTransition { + TransitionType type; + jack_nframes_t capture_val; ///< The start or end file frame position + }; + + /* The two central butler operations */ + virtual int do_flush (Session::RunContext context, bool force = false) = 0; + virtual int do_refill () = 0; + + /** For non-butler contexts (allocates temporary working buffers) */ + virtual int do_refill_with_alloc() = 0; + + + /* XXX fix this redundancy ... */ + + virtual void playlist_changed (Change); + virtual void playlist_modified (); + virtual void playlist_deleted (Playlist*); + + virtual void finish_capture (bool rec_monitors_input) = 0; + virtual void transport_stopped (struct tm&, time_t, bool abort) = 0; + + struct CaptureInfo { + uint32_t start; + uint32_t frames; + }; + + virtual void init (Flag); + + virtual int use_new_write_source (uint32_t n=0) = 0; + + virtual int find_and_use_playlist (const string&) = 0; + + virtual void allocate_temporary_buffers () = 0; + + virtual bool realtime_set_speed (double, bool global_change); + + std::list<Region*> _last_capture_regions; + virtual int use_pending_capture_data (XMLNode& node) = 0; + + virtual void get_input_sources () = 0; + virtual void check_record_status (jack_nframes_t transport_frame, jack_nframes_t nframes, bool can_record) = 0; + virtual void set_align_style_from_io() {} + virtual void setup_destructive_playlist () = 0; + virtual void use_destructive_playlist () = 0; + + static jack_nframes_t disk_io_chunk_frames; + vector<CaptureInfo*> capture_info; + Glib::Mutex capture_info_lock; + + uint32_t i_am_the_modifier; + + string _name; + ARDOUR::Session& _session; + ARDOUR::IO* _io; + uint32_t _n_channels; + PBD::ID _id; + Playlist* _playlist; + + mutable gint _record_enabled; + double _visible_speed; + double _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; + + Glib::Mutex 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; + + unsigned char _flags; +}; + +}; /* namespace ARDOUR */ + +#endif /* __ardour_diskstream_h__ */ diff --git a/libs/ardour/ardour/export.h b/libs/ardour/ardour/export.h index 9a6da1592b..075464767e 100644 --- a/libs/ardour/ardour/export.h +++ b/libs/ardour/ardour/export.h @@ -83,6 +83,6 @@ namespace ARDOUR int status; }; -}; +} // namespace ARDOUR #endif /* __ardour_export_h__ */ diff --git a/libs/ardour/ardour/insert.h b/libs/ardour/ardour/insert.h index 803e16497d..a4c4439942 100644 --- a/libs/ardour/ardour/insert.h +++ b/libs/ardour/ardour/insert.h @@ -98,7 +98,7 @@ struct PluginInsertState : public RedirectState class PluginInsert : public Insert { public: - PluginInsert (Session&, Plugin&, Placement); + PluginInsert (Session&, boost::shared_ptr<Plugin>, Placement); PluginInsert (Session&, const XMLNode&); PluginInsert (const PluginInsert&); ~PluginInsert (); @@ -133,9 +133,6 @@ class PluginInsert : public Insert 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); @@ -144,11 +141,11 @@ class PluginInsert : public Insert float default_parameter_value (uint32_t which); - Plugin& plugin(uint32_t num=0) const { + boost::shared_ptr<Plugin> plugin(uint32_t num=0) const { if (num < _plugins.size()) { - return *_plugins[num]; + return _plugins[num]; } else { - return *_plugins[0]; // we always have one + return _plugins[0]; // we always have one } } @@ -166,7 +163,7 @@ class PluginInsert : public Insert void parameter_changed (uint32_t, float); - vector<Plugin*> _plugins; + vector<boost::shared_ptr<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); @@ -175,9 +172,9 @@ class PluginInsert : public Insert void auto_state_changed (uint32_t which); void automation_list_creation_callback (uint32_t, AutomationList&); - Plugin* plugin_factory (Plugin&); + boost::shared_ptr<Plugin> plugin_factory (boost::shared_ptr<Plugin>); }; -}; /* namespace ARDOUR */ +} // namespace ARDOUR #endif /* __ardour_insert_h__ */ diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h index 8ae45fe65c..b116a58b97 100644 --- a/libs/ardour/ardour/io.h +++ b/libs/ardour/ardour/io.h @@ -31,14 +31,15 @@ #include <pbd/fastlog.h> #include <pbd/undo.h> - -#include <midi++/controllable.h> +#include <pbd/stateful.h> +#include <pbd/controllable.h> #include <ardour/ardour.h> -#include <ardour/stateful.h> #include <ardour/utils.h> #include <ardour/state_manager.h> #include <ardour/curve.h> +#include <ardour/types.h> +#include <ardour/data_type.h> using std::string; using std::vector; @@ -53,6 +54,11 @@ class Port; class Connection; class Panner; +/** A collection of input and output ports with connections. + * + * An IO can contain ports of varying types, making routes/inserts/etc with + * varied combinations of types (eg MIDI and audio) possible. + */ class IO : public Stateful, public ARDOUR::StateManager { @@ -61,7 +67,8 @@ class IO : public Stateful, public ARDOUR::StateManager IO (Session&, string name, int input_min = -1, int input_max = -1, - int output_min = -1, int output_max = -1); + int output_min = -1, int output_max = -1, + DataType default_type = DataType::AUDIO); virtual ~IO(); @@ -75,25 +82,29 @@ class IO : public Stateful, public ARDOUR::StateManager void set_output_minimum (int n); void set_output_maximum (int n); + DataType default_type() const { return _default_type; } + const string& name() const { return _name; } virtual int set_name (string str, void *src); virtual void silence (jack_nframes_t, jack_nframes_t offset); + // These should be moved in to a separate object that manipulates an IO + 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 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; } + 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; } @@ -106,8 +117,8 @@ class IO : public Stateful, public ARDOUR::StateManager 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 add_input_port (string source, void *src, DataType type = DataType::NIL); + int add_output_port (string destination, void *src, DataType type = DataType::NIL); int remove_input_port (Port *, void *src); int remove_output_port (Port *, void *src); @@ -177,25 +188,10 @@ class IO : public Stateful, public ARDOUR::StateManager 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; + PBD::Controllable& gain_control() { + return _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) { @@ -257,7 +253,7 @@ public: void start_pan_touch (uint32_t which); void end_pan_touch (uint32_t which); - id_t id() const { return _id; } + const PBD::ID& id() const { return _id; } void defer_pan_reset (); void allow_pan_reset (); @@ -286,9 +282,10 @@ public: string _name; Connection* _input_connection; Connection* _output_connection; - id_t _id; + PBD::ID _id; bool no_panner_reset; XMLNode* deferred_state; + DataType _default_type; virtual void set_deferred_state() {} @@ -300,31 +297,22 @@ public: 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); - + struct GainControllable : public PBD::Controllable { + GainControllable (IO& i) : io (i) {} + + void set_value (float val); + float get_value (void) const; + 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; + GainControllable _gain_control; /* state management */ Change restore_state (State&); StateManager::State* state_factory (std::string why) const; - 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; @@ -406,6 +394,6 @@ public: int32_t find_output_port_hole (); }; -}; /* namespace ARDOUR */ +} // namespace ARDOUR #endif /*__ardour_io_h__ */ diff --git a/libs/ardour/ardour/ladspa_plugin.h b/libs/ardour/ardour/ladspa_plugin.h index 2451953ce5..99fc884898 100644 --- a/libs/ardour/ardour/ladspa_plugin.h +++ b/libs/ardour/ardour/ladspa_plugin.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,12 +27,12 @@ #include <string> #include <dlfcn.h> -#include <midi++/controllable.h> #include <sigc++/signal.h> +#include <pbd/stateful.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> @@ -137,6 +137,17 @@ class LadspaPlugin : public ARDOUR::Plugin void run (jack_nframes_t nsamples); void latency_compute_run (); }; -} + +class LadspaPluginInfo : public PluginInfo { + public: + LadspaPluginInfo () { }; + ~LadspaPluginInfo () { }; + + PluginPtr load (Session& session); +}; + +typedef boost::shared_ptr<LadspaPluginInfo> LadspaPluginInfoPtr; + +} // namespace ARDOUR #endif /* __ardour_ladspa_plugin_h__ */ diff --git a/libs/ardour/ardour/location.h b/libs/ardour/ardour/location.h index 75f4c5d12a..30c02a80a1 100644 --- a/libs/ardour/ardour/location.h +++ b/libs/ardour/ardour/location.h @@ -32,10 +32,10 @@ #include <glibmm/thread.h> #include <pbd/undo.h> +#include <pbd/stateful.h> -#include "ardour.h" -#include "stateful.h" -#include "state_manager.h" +#include <ardour/ardour.h> +#include <ardour/state_manager.h> using std::string; @@ -199,6 +199,6 @@ class Locations : public Stateful, public StateManager StateManager::State* state_factory (std::string why) const; }; -}; /* namespace ARDOUR */ +} // namespace ARDOUR #endif /* __ardour_location_h__ */ diff --git a/libs/ardour/ardour/logcurve.h b/libs/ardour/ardour/logcurve.h index e65be55772..ac60a10fd7 100644 --- a/libs/ardour/ardour/logcurve.h +++ b/libs/ardour/ardour/logcurve.h @@ -126,7 +126,7 @@ class LogCurveOut : public LogCurve }; -}; /* namespace ARDOUR */ +} // namespace ARDOUR #endif /* __ardour_logcurve_h__ */ diff --git a/libs/ardour/ardour/named_selection.h b/libs/ardour/ardour/named_selection.h index 91bb816181..87b71e73ff 100644 --- a/libs/ardour/ardour/named_selection.h +++ b/libs/ardour/ardour/named_selection.h @@ -24,7 +24,7 @@ #include <string> #include <list> -#include <ardour/stateful.h> +#include <pbd/stateful.h> class XMLNode; diff --git a/libs/ardour/ardour/panner.h b/libs/ardour/ardour/panner.h index 806f350e03..75c59eb924 100644 --- a/libs/ardour/ardour/panner.h +++ b/libs/ardour/ardour/panner.h @@ -27,10 +27,10 @@ #include <iostream> #include <sigc++/signal.h> -#include <midi++/controllable.h> +#include <pbd/stateful.h> +#include <pbd/controllable.h> #include <ardour/types.h> -#include <ardour/stateful.h> #include <ardour/curve.h> using std::istream; @@ -75,24 +75,7 @@ class StreamPanner : public sigc::trackable, public Stateful 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); + PBD::Controllable& control() { return _control; } /* XXX this is wrong. for multi-dimensional panners, there must surely be more than 1 automation curve. @@ -100,7 +83,6 @@ class StreamPanner : public sigc::trackable, public Stateful virtual Curve& automation() = 0; - virtual int load (istream&, string path, uint32_t&) = 0; virtual int save (ostream&) const = 0; @@ -130,12 +112,20 @@ class StreamPanner : public sigc::trackable, public Stateful 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); + struct PanControllable : public PBD::Controllable { + PanControllable (StreamPanner& p) : panner (p) {} + + StreamPanner& panner; + + void set_value (float); + float get_value (void) const; + bool can_send_feedback() const; + }; + PanControllable _control; + + void add_state (XMLNode&); virtual void update () = 0; }; @@ -290,10 +280,6 @@ class Panner : public std::vector<StreamPanner*>, public Stateful, public sigc:: 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 @@ -326,6 +312,6 @@ class Panner : public std::vector<StreamPanner*>, public Stateful, public sigc:: static float current_automation_version_number; }; -}; /* namespace ARDOUR */ +} // namespace ARDOUR #endif /*__ardour_panner_h__ */ diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h index c653c8502e..9fb5b0eb2b 100644 --- a/libs/ardour/ardour/playlist.h +++ b/libs/ardour/ardour/playlist.h @@ -31,12 +31,13 @@ #include <glib.h> #include <sigc++/signal.h> + #include <pbd/undo.h> +#include <pbd/stateful.h> #include <ardour/ardour.h> #include <ardour/crossfade_compare.h> #include <ardour/location.h> -#include <ardour/stateful.h> #include <ardour/state_manager.h> namespace ARDOUR { @@ -53,7 +54,6 @@ class Playlist : public Stateful, public StateManager { 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, char * workbuf, 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; @@ -80,13 +80,15 @@ class Playlist : public Stateful, public StateManager { void add_region (const Region&, jack_nframes_t position, float times = 1, bool with_save = true); void remove_region (Region *); + void get_equivalent_regions (const Region&, std::vector<Region*>&); + void get_region_list_equivalent_regions (const Region&, std::vector<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; + Region* find_region (const PBD::ID&) const; Playlist* cut (list<AudioRange>&, bool result_is_hidden = true); Playlist* copy (list<AudioRange>&, bool result_is_hidden = true); @@ -107,16 +109,15 @@ class Playlist : public Stateful, public StateManager { int set_state (const XMLNode&); XMLNode& get_template (); - sigc::signal<void,Region *> RegionAdded; - sigc::signal<void,Region *> RegionRemoved; - + 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; + 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; @@ -135,8 +136,8 @@ class Playlist : public Stateful, public StateManager { 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; } + const PBD::ID& get_orig_diskstream_id () const { return _orig_diskstream_id; } + void set_orig_diskstream_id (const PBD::ID& did) { _orig_diskstream_id = did; } /* destructive editing */ @@ -190,7 +191,7 @@ class Playlist : public Stateful, public StateManager { bool _frozen; uint32_t subcnt; uint32_t _read_data_count; - id_t _orig_diskstream_id; + PBD::ID _orig_diskstream_id; uint64_t layer_op_counter; jack_nframes_t freeze_length; diff --git a/libs/ardour/ardour/plugin.h b/libs/ardour/ardour/plugin.h index 211b00d0bb..6b11a975ca 100644 --- a/libs/ardour/ardour/plugin.h +++ b/libs/ardour/ardour/plugin.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,15 +18,17 @@ $Id$ */ -#ifndef __ardour_ladspa_h__ -#define __ardour_ladspa_h__ +#ifndef __ardour_plugin_h__ +#define __ardour_plugin_h__ -#include <midi++/controllable.h> +#include <boost/shared_ptr.hpp> #include <sigc++/signal.h> +#include <pbd/stateful.h> +#include <pbd/controllable.h> + #include <jack/types.h> #include <ardour/types.h> -#include <ardour/stateful.h> #include <ardour/plugin_state.h> #include <ardour/cycles.h> @@ -44,6 +46,9 @@ namespace ARDOUR { class AudioEngine; class Session; +class Plugin; +typedef boost::shared_ptr<Plugin> PluginPtr; + class PluginInfo { public: enum Type { @@ -52,11 +57,12 @@ class PluginInfo { VST }; - PluginInfo () { }; + PluginInfo () { } PluginInfo (const PluginInfo &o) : name(o.name), n_inputs(o.n_inputs), n_outputs(o.n_outputs), unique_id(o.unique_id), path (o.path), index(o.index) {} - ~PluginInfo () { }; + virtual ~PluginInfo () { } + string name; string category; uint32_t n_inputs; @@ -65,19 +71,24 @@ class PluginInfo { long unique_id; - private: + virtual PluginPtr load (Session& session) = 0; + + protected: friend class PluginManager; string path; uint32_t index; }; +typedef boost::shared_ptr<PluginInfo> PluginInfoPtr; +typedef std::list<PluginInfoPtr> PluginInfoList; + class Plugin : public Stateful, public sigc::trackable { public: Plugin (ARDOUR::AudioEngine&, ARDOUR::Session&); Plugin (const Plugin&); - ~Plugin (); + virtual ~Plugin (); struct ParameterDescriptor { @@ -136,13 +147,10 @@ class Plugin : public Stateful, public sigc::trackable 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); + PBD::Controllable *get_nth_control (uint32_t); - PluginInfo & get_info() { return _info; } - void set_info (const PluginInfo &inf) { _info = inf; } + PluginInfoPtr get_info() { return _info; } + void set_info (const PluginInfoPtr inf) { _info = inf; } ARDOUR::AudioEngine& engine() const { return _engine; } ARDOUR::Session& session() const { return _session; } @@ -153,21 +161,19 @@ class Plugin : public Stateful, public sigc::trackable protected: ARDOUR::AudioEngine& _engine; ARDOUR::Session& _session; - PluginInfo _info; + PluginInfoPtr _info; uint32_t _cycles; map<string,string> presets; bool save_preset(string name, string domain /* vst, ladspa etc. */); - void setup_midi_controls (); + void setup_controls (); - - struct MIDIPortControl : public MIDI::Controllable { - MIDIPortControl (Plugin&, uint32_t abs_port_id, MIDI::Port *, - float lower, float upper, bool toggled, bool logarithmic); + struct PortControllable : public PBD::Controllable { + PortControllable (Plugin&, uint32_t abs_port_id, + 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); + float get_value () const; Plugin& plugin; uint32_t absolute_port; @@ -176,19 +182,12 @@ class Plugin : public Stateful, public sigc::trackable float range; bool toggled; bool logarithmic; - - bool setting; - float last_written; }; - vector<MIDIPortControl*> midi_controls; - - + vector<PortControllable*> controls; }; -/* this is actually defined in plugin_manager.cc */ - -Plugin * find_plugin(ARDOUR::Session&, string name, long unique_id, PluginInfo::Type); +PluginPtr find_plugin(ARDOUR::Session&, string name, long unique_id, PluginInfo::Type); } // namespace ARDOUR diff --git a/libs/ardour/ardour/plugin_manager.h b/libs/ardour/ardour/plugin_manager.h index 1a07c67c8d..8e6c0bd1c7 100644 --- a/libs/ardour/ardour/plugin_manager.h +++ b/libs/ardour/ardour/plugin_manager.h @@ -6,34 +6,33 @@ #include <string> #include <ardour/types.h> +#include <ardour/plugin.h> +#include <ardour/audio_unit.h> namespace ARDOUR { -class PluginInfo; class Plugin; class Session; class AudioEngine; class PluginManager { public: - PluginManager (ARDOUR::AudioEngine&); + PluginManager (); ~PluginManager (); - std::list<PluginInfo*> &vst_plugin_info () { return _vst_plugin_info; } - std::list<PluginInfo*> &ladspa_plugin_info () { return _ladspa_plugin_info; } + ARDOUR::PluginInfoList &vst_plugin_info () { return _vst_plugin_info; } + ARDOUR::PluginInfoList &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; + ARDOUR::PluginInfoList _vst_plugin_info; + ARDOUR::PluginInfoList _ladspa_plugin_info; std::map<uint32_t, std::string> rdf_type; std::string ladspa_path; @@ -61,3 +60,4 @@ class PluginManager { } /* namespace ARDOUR */ #endif /* __ardour_plugin_manager_h__ */ + diff --git a/libs/ardour/ardour/port.h b/libs/ardour/ardour/port.h index ff9c25e1c4..86c99cb7e3 100644 --- a/libs/ardour/ardour/port.h +++ b/libs/ardour/ardour/port.h @@ -33,24 +33,24 @@ class AudioEngine; class Port : public sigc::trackable { public: virtual ~Port() { - free (port); + free (_port); } Sample *get_buffer (jack_nframes_t nframes) { if (_flags & JackPortIsOutput) { return _buffer; } else { - return (Sample *) jack_port_get_buffer (port, nframes); + return (Sample *) jack_port_get_buffer (_port, nframes); } } void reset_buffer () { if (_flags & JackPortIsOutput) { - _buffer = (Sample *) jack_port_get_buffer (port, 0); + _buffer = (Sample *) jack_port_get_buffer (_port, 0); } else { _buffer = 0; /* catch illegal attempts to use it */ } - silent = false; + _silent = false; } std::string name() { @@ -58,7 +58,7 @@ class Port : public sigc::trackable { } std::string short_name() { - return jack_port_short_name (port); + return jack_port_short_name (_port); } int set_name (std::string str); @@ -68,7 +68,7 @@ class Port : public sigc::trackable { } bool is_mine (jack_client_t *client) { - return jack_port_is_mine (client, port); + return jack_port_is_mine (client, _port); } const char* type() const { @@ -76,21 +76,21 @@ class Port : public sigc::trackable { } int connected () const { - return jack_port_connected (port); + return jack_port_connected (_port); } bool connected_to (const std::string& portname) const { - return jack_port_connected_to (port, portname.c_str()); + return jack_port_connected_to (_port, portname.c_str()); } const char ** get_connections () const { - return jack_port_get_connections (port); + return jack_port_get_connections (_port); } void reset_overs () { _short_overs = 0; _long_overs = 0; - overlen = 0; + _overlen = 0; } void reset_peak_meter () { @@ -103,18 +103,18 @@ class Port : public sigc::trackable { } void enable_metering() { - metering++; + _metering++; } void disable_metering () { - if (metering) { metering--; } + if (_metering) { _metering--; } } - float peak_db() const { return _peak_db; } + 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; } + 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); @@ -128,7 +128,7 @@ class Port : public sigc::trackable { } bool monitoring_input () const { - return jack_port_monitoring_input (port); + return jack_port_monitoring_input (_port); } bool can_monitor () const { @@ -136,30 +136,29 @@ class Port : public sigc::trackable { } void ensure_monitor_input (bool yn) { - jack_port_request_monitor (port, yn); + jack_port_request_monitor (_port, yn); } void request_monitor_input (bool yn) { - jack_port_request_monitor (port, yn); + jack_port_request_monitor (_port, yn); } jack_nframes_t latency () const { - return jack_port_get_latency (port); + return jack_port_get_latency (_port); } void set_latency (jack_nframes_t nframes) { - jack_port_set_latency (port, nframes); + jack_port_set_latency (_port, nframes); } sigc::signal<void,bool> MonitorInputChanged; sigc::signal<void,bool> ClockSyncChanged; - bool is_silent() const { return silent; } + bool is_silent() const { return _silent; } + /** Assumes that the port is an audio output port */ void silence (jack_nframes_t nframes, jack_nframes_t offset) { - /* assumes that the port is an output port */ - - if (!silent) { + if (!_silent) { memset (_buffer + offset, 0, sizeof (Sample) * nframes); if (offset == 0) { /* XXX this isn't really true, but i am not sure @@ -167,13 +166,13 @@ class Port : public sigc::trackable { want to set it true when the entire port buffer has been overrwritten. */ - silent = true; + _silent = true; } } } void mark_silence (bool yn) { - silent = yn; + _silent = yn; } private: @@ -184,7 +183,7 @@ class Port : public sigc::trackable { /* engine isn't supposed to below here */ - Sample *_buffer; + Sample *_buffer; /* cache these 3 from JACK so that we can access them for reconnecting. @@ -194,20 +193,20 @@ class Port : public sigc::trackable { std::string _type; std::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; + 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; + static jack_nframes_t _long_over_length; + static jack_nframes_t _short_over_length; }; -}; /* namespace ARDOUR */ +} // namespace ARDOUR #endif /* __ardour_port_h__ */ diff --git a/libs/ardour/ardour/redirect.h b/libs/ardour/ardour/redirect.h index ede55a1d80..658cab5d3b 100644 --- a/libs/ardour/ardour/redirect.h +++ b/libs/ardour/ardour/redirect.h @@ -25,6 +25,7 @@ #include <vector> #include <set> #include <map> +#include <boost/shared_ptr.hpp> #include <sigc++/signal.h> #include <glibmm/thread.h> @@ -64,7 +65,7 @@ class Redirect : public IO Redirect (const Redirect&); virtual ~Redirect (); - static Redirect *clone (const Redirect&); + static boost::shared_ptr<Redirect> clone (boost::shared_ptr<const Redirect>); bool active () const { return _active; } void set_active (bool yn, void *src); @@ -148,6 +149,6 @@ class Redirect : public IO void* _gui; /* generic, we don't know or care what this is */ }; -}; /* namespace ARDOUR */ +} // namespace ARDOUR #endif /* __ardour_redirect_h__ */ diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h index aae776625e..3773a3b893 100644 --- a/libs/ardour/ardour/region.h +++ b/libs/ardour/ardour/region.h @@ -24,7 +24,6 @@ #include <pbd/undo.h> #include <ardour/ardour.h> -#include <ardour/logcurve.h> #include <ardour/state_manager.h> class XMLNode; @@ -36,22 +35,22 @@ class Source; enum RegionEditState { EditChangesNothing = 0, - EditChangesName = 1, - EditChangesID = 2 + 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; +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 @@ -95,9 +94,9 @@ class Region : public Stateful, public StateManager 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(); + virtual ~Region(); - ARDOUR::id_t id() const { return _id; } + const PBD::ID& id() const { return _id; } /* Note: changing the name of a Region does not constitute an edit */ @@ -105,9 +104,10 @@ class Region : public Stateful, public StateManager 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 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; @@ -118,14 +118,13 @@ class Region : public Stateful, public StateManager 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 hidden() const { return _flags & Hidden; } + bool muted() const { return _flags & Muted; } + bool opaque () const { return _flags & Opaque; } + bool locked() const { return _flags & Locked; } + bool automatic() const { return _flags & Automatic; } bool whole_file() const { return _flags & WholeFile ; } - Flag flags() const { return _flags; } + Flag flags() const { return _flags; } virtual bool should_save_state () const { return !(_flags & DoNotSaveState); }; @@ -139,12 +138,14 @@ class Region : public Stateful, public StateManager 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, char * workbuf, 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; + + bool equivalent (const Region&) const; + bool size_equivalent (const Region&) const; + bool overlap_equivalent (const Region&) const; + bool region_list_equivalent (const Region&) const; + virtual bool source_equivalent (const Region&) const = 0; + + virtual bool speed_mismatch (float) const = 0; /* EDITING OPERATIONS */ @@ -173,7 +174,6 @@ class Region : public Stateful, public StateManager 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; } @@ -189,9 +189,9 @@ class Region : public Stateful, public StateManager /* serialization */ + XMLNode& get_state (); virtual XMLNode& state (bool); - XMLNode& get_state (); - int set_state (const XMLNode&); + virtual int set_state (const XMLNode&); sigc::signal<void,Region*> GoingAway; @@ -211,23 +211,6 @@ class Region : public Stateful, public StateManager 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; - Glib::Mutex 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 */ @@ -251,6 +234,23 @@ class Region : public Stateful, public StateManager virtual bool verify_length (jack_nframes_t) = 0; virtual void recompute_at_start () = 0; virtual void recompute_at_end () = 0; + + + 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; + Glib::Mutex lock; + PBD::ID _id; + ARDOUR::Playlist* _playlist; + mutable uint32_t _read_data_count; // modified in read() + Change pending_changed; + uint64_t _last_layer_op; // timestamp }; } /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 5686dfc908..8271c1cf6a 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -27,17 +27,20 @@ #include <map> #include <string> +#include <boost/shared_ptr.hpp> + #include <pbd/fastlog.h> #include <glibmm/thread.h> #include <pbd/xml++.h> #include <pbd/undo.h> -#include <midi++/controllable.h> +#include <pbd/stateful.h> +#include <pbd/controllable.h> #include <ardour/ardour.h> -#include <ardour/stateful.h> #include <ardour/io.h> #include <ardour/session.h> #include <ardour/redirect.h> +#include <ardour/types.h> namespace ARDOUR { @@ -56,17 +59,19 @@ class Route : public IO { protected: - typedef list<Redirect *> RedirectList; + typedef list<boost::shared_ptr<Redirect> > RedirectList; public: enum Flag { Hidden = 0x1, MasterOut = 0x2, - ControlOut = 0x4, + 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&, std::string name, int input_min, int input_max, int output_min, int output_max, + Flag flags = Flag(0), DataType default_type = DataType::AUDIO); + Route (Session&, const XMLNode&); virtual ~Route(); @@ -138,19 +143,19 @@ class Route : public IO void flush_redirects (); - template<class T> void foreach_redirect (T *obj, void (T::*func)(Redirect *)) { + template<class T> void foreach_redirect (T *obj, void (T::*func)(boost::shared_ptr<Redirect>)) { Glib::RWLock::ReaderLock lm (redirect_lock); for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) { (obj->*func) (*i); } } - Redirect *nth_redirect (uint32_t n) { + boost::shared_ptr<Redirect> nth_redirect (uint32_t n) { Glib::RWLock::ReaderLock lm (redirect_lock); RedirectList::iterator i; for (i = _redirects.begin(); i != _redirects.end() && n; ++i, --n); if (i == _redirects.end()) { - return 0; + return boost::shared_ptr<Redirect> (); } else { return *i; } @@ -158,9 +163,9 @@ class Route : public IO uint32_t max_redirect_outs () const { return redirect_max_outs; } - int add_redirect (Redirect *, void *src, uint32_t* err_streams = 0); + int add_redirect (boost::shared_ptr<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 remove_redirect (boost::shared_ptr<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); @@ -209,37 +214,31 @@ class Route : public IO 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; + bool feeds (boost::shared_ptr<Route>); + set<boost::shared_ptr<Route> > fed_by; + + struct ToggleControllable : public PBD::Controllable { + enum ToggleType { + MuteControl = 0, + SoloControl + }; + + ToggleControllable (Route&, ToggleType); + void set_value (float); + float get_value (void) const; + + Route& route; + ToggleType type; }; - MIDI::Controllable& midi_solo_control() { - return _midi_solo_control; + PBD::Controllable& solo_control() { + return _solo_control; } - MIDI::Controllable& midi_mute_control() { - return _midi_mute_control; + + PBD::Controllable& mute_control() { + return _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 (); @@ -299,8 +298,8 @@ class Route : public IO std::string _comment; bool _have_internal_generator; - MIDIToggleControl _midi_solo_control; - MIDIToggleControl _midi_mute_control; + ToggleControllable _solo_control; + ToggleControllable _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); @@ -342,12 +341,12 @@ class Route : public IO /* plugin count handling */ struct InsertCount { - ARDOUR::Insert& insert; + boost::shared_ptr<ARDOUR::Insert> insert; int32_t cnt; int32_t in; int32_t out; - InsertCount (ARDOUR::Insert& ins) : insert (ins), cnt (-1) {} + InsertCount (boost::shared_ptr<ARDOUR::Insert> ins) : insert (ins), cnt (-1) {} }; int32_t apply_some_plugin_counts (std::list<InsertCount>& iclist); @@ -358,6 +357,6 @@ class Route : public IO void redirect_active_proxy (Redirect*, void*); }; -}; /* namespace ARDOUR*/ +} // namespace ARDOUR #endif /* __ardour_route_h__ */ diff --git a/libs/ardour/ardour/route_group.h b/libs/ardour/ardour/route_group.h index c9f966666f..e9fad1aa2b 100644 --- a/libs/ardour/ardour/route_group.h +++ b/libs/ardour/ardour/route_group.h @@ -26,7 +26,7 @@ #include <string> #include <stdint.h> #include <sigc++/signal.h> -#include <ardour/stateful.h> +#include <pbd/stateful.h> #include <ardour/types.h> using std::string; @@ -35,6 +35,7 @@ using std::list; namespace ARDOUR { class Route; +class Track; class AudioTrack; class Session; @@ -43,7 +44,7 @@ class RouteGroup : public Stateful, public sigc::trackable { enum Flag { Relative = 0x1, Active = 0x2, - Hidden = 0x4, + Hidden = 0x4 }; RouteGroup (Session& s, const string &n, Flag f = Flag(0)); @@ -90,7 +91,7 @@ class RouteGroup : public Stateful, public sigc::trackable { /* to use these, #include <ardour/route_group_specialized.h> */ - template<class T> void apply (void (AudioTrack::*func)(T, void *), T val, void *src); + template<class T> void apply (void (Track::*func)(T, void *), T val, void *src); /* fills at_set with all members of the group that are AudioTracks */ diff --git a/libs/ardour/ardour/route_group_specialized.h b/libs/ardour/ardour/route_group_specialized.h index 0424002dcd..250d3744df 100644 --- a/libs/ardour/ardour/route_group_specialized.h +++ b/libs/ardour/ardour/route_group_specialized.h @@ -7,11 +7,11 @@ namespace ARDOUR { template<class T> void -RouteGroup::apply (void (AudioTrack::*func)(T, void *), T val, void *src) +RouteGroup::apply (void (Track::*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) { + Track *at; + if ((at = dynamic_cast<Track*>(*i)) != 0) { (at->*func)(val, this); } } diff --git a/libs/ardour/ardour/send.h b/libs/ardour/ardour/send.h index a94318f2a5..0a068e8af0 100644 --- a/libs/ardour/ardour/send.h +++ b/libs/ardour/ardour/send.h @@ -24,12 +24,12 @@ #include <sigc++/signal.h> #include <string> + +#include <pbd/stateful.h> #include <ardour/ardour.h> #include <ardour/audioengine.h> - -#include "io.h" -#include "stateful.h" -#include "redirect.h" +#include <ardour/io.h> +#include <ardour/redirect.h> namespace ARDOUR { @@ -58,6 +58,6 @@ class Send : public Redirect { uint32_t expected_inputs; }; -}; /* namespace ARDOUR */ +} // namespace ARDOUR #endif /* __ardour_send_h__ */ diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 7a9e50ae9b..0c53cc32e7 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -36,14 +36,16 @@ #include <pbd/error.h> #include <pbd/undo.h> #include <pbd/pool.h> +#include <pbd/rcu.h> #include <midi++/types.h> #include <midi++/mmc.h> +#include <pbd/stateful.h> + #include <ardour/ardour.h> #include <ardour/configuration.h> #include <ardour/location.h> -#include <ardour/stateful.h> #include <ardour/gain.h> #include <ardour/io.h> @@ -55,11 +57,16 @@ namespace MIDI { class Port; } +namespace PBD { + class Controllable; +} + namespace ARDOUR { class Port; class AudioEngine; class Slave; +class Diskstream; class AudioDiskstream; class Route; class AuxInput; @@ -95,9 +102,9 @@ class Session : public sigc::trackable, public Stateful { private: - typedef std::pair<Route*,bool> RouteBooleanState; + typedef std::pair<boost::shared_ptr<Route>,bool> RouteBooleanState; typedef vector<RouteBooleanState> GlobalRouteBooleanState; - typedef std::pair<Route*,MeterPoint> RouteMeterState; + typedef std::pair<boost::shared_ptr<Route>,MeterPoint> RouteMeterState; typedef vector<RouteMeterState> GlobalRouteMeterState; public: @@ -110,7 +117,7 @@ class Session : public sigc::trackable, public Stateful enum SlaveSource { None = 0, MTC, - JACK, + JACK }; enum AutoConnectOption { @@ -141,7 +148,7 @@ class Session : public sigc::trackable, public Stateful */ StopOnce, - AutoLoop, + AutoLoop }; enum Action { @@ -151,16 +158,17 @@ class Session : public sigc::trackable, public Stateful Clear }; - Type type; - Action action; - jack_nframes_t action_frame; - jack_nframes_t target_frame; - float speed; + Type type; + Action action; + jack_nframes_t action_frame; + jack_nframes_t target_frame; + float speed; union { - void* ptr; - bool yes_or_no; - Session::SlaveSource slave; + void* ptr; + bool yes_or_no; + Session::SlaveSource slave; + Route* route; }; list<AudioRange> audio_range; @@ -262,52 +270,39 @@ class Session : public sigc::trackable, public Stateful vector<Sample*>& get_silent_buffers (uint32_t howmany); vector<Sample*>& get_send_buffers () { return _send_buffers; } - AudioDiskstream *diskstream_by_id (id_t id); - AudioDiskstream *diskstream_by_name (string name); + Diskstream* diskstream_by_id (const PBD::ID& id); + Diskstream* diskstream_by_name (string name); bool have_captured() const { return _have_captured; } void refill_all_diskstream_buffers (); uint32_t diskstream_buffer_size() const { return dstream_buffer_size; } - /* XXX fix required here when we get new diskstream types *, but - not sure of the direction to take this in until then. - */ - - uint32_t get_next_diskstream_id() const { return n_audio_diskstreams(); } - uint32_t n_audio_diskstreams() const; + uint32_t get_next_diskstream_id() const { return n_diskstreams(); } + uint32_t n_diskstreams() const; - typedef list<AudioDiskstream *> AudioDiskstreamList; + typedef list<Diskstream *> DiskstreamList; - Session::AudioDiskstreamList audio_disk_streams() const { - Glib::RWLock::ReaderLock lm (diskstream_lock); - return audio_diskstreams; /* XXX yes, force a copy */ - } - - void foreach_audio_diskstream (void (AudioDiskstream::*func)(void)); - template<class T> void foreach_audio_diskstream (T *obj, void (T::*func)(AudioDiskstream&)); - - typedef list<Route *> RouteList; + typedef std::list<boost::shared_ptr<Route> > RouteList; - RouteList get_routes() const { - Glib::RWLock::ReaderLock rlock (route_lock); - return routes; /* XXX yes, force a copy */ + boost::shared_ptr<RouteList> get_routes() const { + return routes.reader (); } - uint32_t nroutes() const { return routes.size(); } + uint32_t nroutes() const { return routes.reader()->size(); } uint32_t ntracks () const; uint32_t nbusses () const; struct RoutePublicOrderSorter { - bool operator() (Route *, Route *b); + bool operator() (boost::shared_ptr<Route>, boost::shared_ptr<Route> b); }; template<class T> void foreach_route (T *obj, void (T::*func)(Route&)); - template<class T> void foreach_route (T *obj, void (T::*func)(Route*)); + template<class T> void foreach_route (T *obj, void (T::*func)(boost::shared_ptr<Route>)); template<class T, class A> void foreach_route (T *obj, void (T::*func)(Route&, A), A arg); - Route *route_by_name (string); - Route *route_by_remote_id (uint32_t id); + boost::shared_ptr<Route> route_by_name (string); + boost::shared_ptr<Route> route_by_remote_id (uint32_t id); bool route_name_unique (string) const; @@ -349,8 +344,8 @@ class Session : public sigc::trackable, public Stateful sigc::signal<void> DurationChanged; sigc::signal<void> HaltOnXrun; - sigc::signal<void,Route*> RouteAdded; - sigc::signal<void,AudioDiskstream*> AudioDiskstreamAdded; + sigc::signal<void,boost::shared_ptr<Route> > RouteAdded; + sigc::signal<void,Diskstream*> DiskstreamAdded; // FIXME: make a shared_ptr void request_roll (); void request_bounded_roll (jack_nframes_t start, jack_nframes_t end); @@ -362,15 +357,14 @@ class Session : public sigc::trackable, public Stateful void goto_start () { request_locate (start_location->start(), false); } void use_rf_shuttle_speed (); void request_transport_speed (float speed); - void request_overwrite_buffer (AudioDiskstream*); - void request_diskstream_speed (AudioDiskstream&, float speed); + void request_overwrite_buffer (Diskstream*); + void request_diskstream_speed (Diskstream&, float speed); void request_input_change_handling (); bool locate_pending() const { return static_cast<bool>(post_transport_work&PostTransportLocate); } bool transport_locked () const; int wipe (); - int wipe_diskstream (AudioDiskstream *); int remove_region_from_region_list (Region&); @@ -500,9 +494,6 @@ class Session : public sigc::trackable, public Stateful void add_instant_xml (XMLNode&, const std::string& dir); - void swap_configuration(Configuration** new_config); - void copy_configuration(Configuration* new_config); - enum StateOfTheState { Clean = 0x0, Dirty = 0x1, @@ -543,13 +534,13 @@ class Session : public sigc::trackable, public Stateful /* fundamental operations. duh. */ + boost::shared_ptr<AudioTrack> new_audio_track (int input_channels, int output_channels, TrackMode mode = Normal); + boost::shared_ptr<Route> new_audio_route (int input_channels, int output_channels); - AudioTrack *new_audio_track (int input_channels, int output_channels, TrackMode mode = Normal); - - Route *new_audio_route (int input_channels, int output_channels); + void remove_route (boost::shared_ptr<Route>); - void remove_route (Route&); - void resort_routes (void *src); + void resort_routes (); + void resort_routes_using (boost::shared_ptr<RouteList>); AudioEngine &engine() { return _engine; }; @@ -630,7 +621,7 @@ class Session : public sigc::trackable, public Stateful string path_from_region_name (string name, string identifier); AudioRegion* find_whole_file_parent (AudioRegion&); - void find_equivalent_playlist_regions (AudioRegion&, std::vector<AudioRegion*>& result); + void find_equivalent_playlist_regions (Region&, std::vector<Region*>& result); AudioRegion *XMLRegionFactory (const XMLNode&, bool full); @@ -698,7 +689,7 @@ class Session : public sigc::trackable, public Stateful AudioFileSource *create_audio_source_for_session (ARDOUR::AudioDiskstream&, uint32_t which_channel, bool destructive); - Source *get_source (ARDOUR::id_t); + Source *source_by_id (const PBD::ID&); /* playlist management */ @@ -707,8 +698,6 @@ class Session : public sigc::trackable, public Stateful sigc::signal<void,Playlist*> PlaylistAdded; sigc::signal<void,Playlist*> PlaylistRemoved; - Playlist *get_playlist (string name); - uint32_t n_playlists() const; template<class T> void foreach_playlist (T *obj, void (T::*func)(Playlist *)); @@ -731,9 +720,9 @@ class Session : public sigc::trackable, public Stateful /* auditioning */ - Auditioner& the_auditioner() { return *auditioner; } + boost::shared_ptr<Auditioner> the_auditioner() { return auditioner; } void audition_playlist (); - void audition_region (AudioRegion&); + void audition_region (Region&); void cancel_audition (); bool is_auditioning () const; @@ -770,8 +759,8 @@ class Session : public sigc::trackable, public Stateful /* control/master out */ - IO* control_out() const { return _control_out; } - IO* master_out() const { return _master_out; } + boost::shared_ptr<IO> control_out() const { return _control_out; } + boost::shared_ptr<IO> master_out() const { return _master_out; } /* insert/send management */ @@ -908,7 +897,7 @@ class Session : public sigc::trackable, public Stateful /* clicking */ - IO& click_io() { return *_click_io; } + boost::shared_ptr<IO> click_io() { return _click_io; } void set_clicking (bool yn); bool get_clicking() const; @@ -1003,14 +992,20 @@ class Session : public sigc::trackable, public Stateful static apply_gain_to_buffer_t apply_gain_to_buffer; static mix_buffers_with_gain_t mix_buffers_with_gain; static mix_buffers_no_gain_t mix_buffers_no_gain; - + + static sigc::signal<void> SendFeedback; + + /* Controllables */ + + PBD::Controllable* controllable_by_id (const PBD::ID&); + protected: friend class AudioEngine; void set_block_size (jack_nframes_t nframes); void set_frame_rate (jack_nframes_t nframes); protected: - friend class AudioDiskstream; + friend class Diskstream; void stop_butler (); void wait_till_butler_finished(); @@ -1072,9 +1067,9 @@ class Session : public sigc::trackable, public Stateful float _meter_falloff; bool _end_location_is_free; - void set_worst_io_latencies (bool take_lock); + void set_worst_io_latencies (); void set_worst_io_latencies_x (IOChange asifwecare, void *ignored) { - set_worst_io_latencies (true); + set_worst_io_latencies (); } void update_latency_compensation_proxy (void* ignored); @@ -1472,12 +1467,12 @@ class Session : public sigc::trackable, public Stateful bool waiting_to_start; void set_auto_loop (bool yn); - void overwrite_some_buffers (AudioDiskstream*); + void overwrite_some_buffers (Diskstream*); void flush_all_redirects (); void locate (jack_nframes_t, bool with_roll, bool with_flush, bool with_loop=false); void start_locate (jack_nframes_t, bool with_roll, bool with_flush, bool with_loop=false); void force_locate (jack_nframes_t frame, bool with_roll = false); - void set_diskstream_speed (AudioDiskstream*, float speed); + void set_diskstream_speed (Diskstream*, float speed); void set_transport_speed (float speed, bool abort = false); void stop_transport (bool abort = false); void start_transport (); @@ -1508,21 +1503,21 @@ class Session : public sigc::trackable, public Stateful /* disk-streams */ - AudioDiskstreamList audio_diskstreams; + DiskstreamList diskstreams; mutable Glib::RWLock diskstream_lock; uint32_t dstream_buffer_size; - void add_diskstream (AudioDiskstream*); + void add_diskstream (Diskstream*); int load_diskstreams (const XMLNode&); /* routes stuff */ - RouteList routes; - mutable Glib::RWLock route_lock; - void add_route (Route*); + SerializedRCUManager<RouteList> routes; + + void add_route (boost::shared_ptr<Route>); uint32_t destructive_index; int load_routes (const XMLNode&); - Route* XMLRouteFactory (const XMLNode&); + boost::shared_ptr<Route> XMLRouteFactory (const XMLNode&); /* mixer stuff */ @@ -1532,7 +1527,7 @@ class Session : public sigc::trackable, public Stateful bool currently_soloing; void route_mute_changed (void *src); - void route_solo_changed (void *src, Route *); + void route_solo_changed (void *src, boost::shared_ptr<Route>); void catch_up_on_solo (); void update_route_solo_state (); void modify_solo_mute (bool, bool); @@ -1541,7 +1536,7 @@ class Session : public sigc::trackable, public Stateful /* REGION MANAGEMENT */ mutable Glib::Mutex region_lock; - typedef map<ARDOUR::id_t,AudioRegion *> AudioRegionList; + typedef map<PBD::ID,AudioRegion *> AudioRegionList; AudioRegionList audio_regions; void region_renamed (Region *); @@ -1554,7 +1549,7 @@ class Session : public sigc::trackable, public Stateful /* SOURCES */ mutable Glib::Mutex audio_source_lock; - typedef std::map<id_t, AudioSource *> AudioSourceList; + typedef std::map<PBD::ID,AudioSource *> AudioSourceList; AudioSourceList audio_sources; @@ -1579,7 +1574,7 @@ class Session : public sigc::trackable, public Stateful Playlist *XMLPlaylistFactory (const XMLNode&); void playlist_length_changed (Playlist *); - void diskstream_playlist_changed (AudioDiskstream *); + void diskstream_playlist_changed (Diskstream *); /* NAMED SELECTIONS */ @@ -1599,7 +1594,7 @@ class Session : public sigc::trackable, public Stateful /* AUDITIONING */ - Auditioner *auditioner; + boost::shared_ptr<Auditioner> auditioner; void set_audition (AudioRegion*); void non_realtime_set_audition (); AudioRegion *pending_audition_region; @@ -1716,7 +1711,7 @@ class Session : public sigc::trackable, public Stateful Clicks clicks; bool _clicking; - IO* _click_io; + boost::shared_ptr<IO> _click_io; Sample* click_data; Sample* click_emphasis_data; jack_nframes_t click_length; @@ -1748,8 +1743,8 @@ class Session : public sigc::trackable, public Stateful /* main outs */ uint32_t main_outs; - IO* _master_out; - IO* _control_out; + boost::shared_ptr<IO> _master_out; + boost::shared_ptr<IO> _control_out; AutoConnectOption input_auto_connect; AutoConnectOption output_auto_connect; @@ -1782,8 +1777,15 @@ class Session : public sigc::trackable, public Stateful LayerModel layer_model; CrossfadeModel xfade_model; + + typedef std::list<PBD::Controllable*> Controllables; + Glib::Mutex controllables_lock; + Controllables controllables; + + void add_controllable (PBD::Controllable*); + void remove_controllable (PBD::Controllable*); }; -}; /* namespace ARDOUR */ +} // namespace ARDOUR #endif /* __ardour_session_h__ */ diff --git a/libs/ardour/ardour/session_region.h b/libs/ardour/ardour/session_region.h index 13d88a9aa4..4f0fb92e3b 100644 --- a/libs/ardour/ardour/session_region.h +++ b/libs/ardour/ardour/session_region.h @@ -10,7 +10,7 @@ template<class T> void Session::foreach_audio_region (T *obj, void (T::*func)(Au { Glib::Mutex::Lock lm (region_lock); for (AudioRegionList::iterator i = audio_regions.begin(); i != audio_regions.end(); i++) { - (obj->*func) ((*i).second); + (obj->*func) (i->second); } } diff --git a/libs/ardour/ardour/session_route.h b/libs/ardour/ardour/session_route.h index afe78b394e..feacc14775 100644 --- a/libs/ardour/ardour/session_route.h +++ b/libs/ardour/ardour/session_route.h @@ -33,14 +33,10 @@ namespace ARDOUR { template<class T> void Session::foreach_route (T *obj, void (T::*func)(Route&)) { - RouteList public_order; - - { - Glib::RWLock::ReaderLock lm (route_lock); - public_order = routes; - } - + boost::shared_ptr<RouteList> r = routes.reader(); + RouteList public_order (*r); RoutePublicOrderSorter cmp; + public_order.sort (cmp); for (RouteList::iterator i = public_order.begin(); i != public_order.end(); i++) { @@ -49,16 +45,12 @@ Session::foreach_route (T *obj, void (T::*func)(Route&)) } template<class T> void -Session::foreach_route (T *obj, void (T::*func)(Route*)) +Session::foreach_route (T *obj, void (T::*func)(boost::shared_ptr<Route>)) { - RouteList public_order; - - { - Glib::RWLock::ReaderLock lm (route_lock); - public_order = routes; - } - + boost::shared_ptr<RouteList> r = routes.reader(); + RouteList public_order (*r); RoutePublicOrderSorter cmp; + public_order.sort (cmp); for (RouteList::iterator i = public_order.begin(); i != public_order.end(); i++) { @@ -66,18 +58,13 @@ Session::foreach_route (T *obj, void (T::*func)(Route*)) } } - template<class T, class A> void Session::foreach_route (T *obj, void (T::*func)(Route&, A), A arg1) { - RouteList public_order; - - { - Glib::RWLock::ReaderLock lm (route_lock); - public_order = routes; - } - + boost::shared_ptr<RouteList> r = routes.reader(); + RouteList public_order (*r); RoutePublicOrderSorter cmp; + public_order.sort (cmp); for (RouteList::iterator i = public_order.begin(); i != public_order.end(); i++) { diff --git a/libs/ardour/ardour/sndfilesource.h b/libs/ardour/ardour/sndfilesource.h index 5e3c1f621d..4764339451 100644 --- a/libs/ardour/ardour/sndfilesource.h +++ b/libs/ardour/ardour/sndfilesource.h @@ -51,7 +51,7 @@ class SndFileSource : public AudioFileSource { int update_header (jack_nframes_t when, struct tm&, time_t); int flush_header (); - void handle_smpte_offset_change (jack_nframes_t offset, bool negative); + jack_nframes_t natural_position () const; protected: void set_header_timeline_position (); @@ -75,7 +75,7 @@ class SndFileSource : public AudioFileSource { int setup_broadcast_info (jack_nframes_t when, struct tm&, time_t); }; -}; /* namespace ARDOUR */ +} // namespace ARDOUR #endif /* __sndfile_source_h__ */ diff --git a/libs/ardour/ardour/source.h b/libs/ardour/ardour/source.h index f3133c71cd..f57ea79854 100644 --- a/libs/ardour/ardour/source.h +++ b/libs/ardour/ardour/source.h @@ -25,8 +25,9 @@ #include <sigc++/signal.h> +#include <pbd/stateful.h> + #include <ardour/ardour.h> -#include <ardour/stateful.h> namespace ARDOUR { @@ -40,7 +41,7 @@ class Source : public Stateful, public sigc::trackable std::string name() const { return _name; } int set_name (std::string str, bool destructive); - ARDOUR::id_t id() const { return _id; } + const PBD::ID& id() const { return _id; } uint32_t use_cnt() const { return _use_cnt; } void use (); @@ -60,7 +61,7 @@ class Source : public Stateful, public sigc::trackable time_t _timestamp; private: - ARDOUR::id_t _id; + PBD::ID _id; }; } diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h index 13e8eb6348..db06894607 100644 --- a/libs/ardour/ardour/tempo.h +++ b/libs/ardour/ardour/tempo.h @@ -27,10 +27,10 @@ #include <cmath> #include <glibmm/thread.h> #include <pbd/undo.h> +#include <pbd/stateful.h> #include <sigc++/signal.h> #include <ardour/ardour.h> -#include <ardour/stateful.h> #include <ardour/state_manager.h> class XMLNode; diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h new file mode 100644 index 0000000000..f16e9d29d9 --- /dev/null +++ b/libs/ardour/ardour/track.h @@ -0,0 +1,158 @@ +/* + Copyright (C) 2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __ardour_track_h__ +#define __ardour_track_h__ + +#include <ardour/route.h> + +namespace ARDOUR { + +class Session; +class Diskstream; +class Playlist; +class RouteGroup; + +class Track : public Route +{ + public: + Track (Session&, string name, Route::Flag f = Route::Flag (0), TrackMode m = Normal, DataType default_type = DataType::AUDIO); + + virtual ~Track (); + + int set_name (string str, void *src); + + 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) = 0; + + 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) = 0; + + 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) = 0; + + void toggle_monitor_input (); + + bool can_record() const { return true; } + + Diskstream& diskstream() const { return *_diskstream; } + + virtual int use_diskstream (string name) = 0; + virtual int use_diskstream (const PBD::ID& id) = 0; + + TrackMode mode() const { return _mode; } + void set_mode (TrackMode m); + + jack_nframes_t update_total_latency(); + void set_latency_delay (jack_nframes_t); + + enum FreezeState { + NoFreeze, + Frozen, + UnFrozen + }; + + FreezeState freeze_state() const; + + virtual void freeze (InterThreadInfo&) = 0; + virtual void unfreeze () = 0; + + virtual void bounce (InterThreadInfo&) = 0; + virtual void bounce_range (jack_nframes_t start, jack_nframes_t end, InterThreadInfo&) = 0; + + XMLNode& get_state(); + XMLNode& get_template(); + virtual int set_state(const XMLNode& node) = 0; + + PBD::Controllable& rec_enable_control() { return _rec_enable_control; } + + bool record_enabled() const; + void set_record_enable (bool yn, void *src); + + void set_meter_point (MeterPoint, void* src); + + sigc::signal<void> ModeChanged; + sigc::signal<void> DiskstreamChanged; + sigc::signal<void> FreezeChange; + + protected: + Track (Session& sess, const XMLNode& node, DataType default_type = DataType::AUDIO); + + virtual XMLNode& state (bool full) = 0; + + virtual 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) = 0; + + virtual uint32_t n_process_buffers () = 0; + + Diskstream *_diskstream; + MeterPoint _saved_meter_point; + TrackMode _mode; + + //private: (FIXME) + struct FreezeRecordInsertInfo { + FreezeRecordInsertInfo(XMLNode& st, boost::shared_ptr<Insert> ins) + : state (st), insert (ins) {} + + XMLNode state; + boost::shared_ptr<Insert> insert; + PBD::ID id; + UndoAction memento; + }; + + struct FreezeRecord { + FreezeRecord() + : playlist(0) + , have_mementos(false) + {} + + ~FreezeRecord(); + + Playlist* playlist; + vector<FreezeRecordInsertInfo*> insert_info; + bool have_mementos; + FreezeState state; + }; + + struct RecEnableControllable : public PBD::Controllable { + RecEnableControllable (Track&); + + void set_value (float); + float get_value (void) const; + + Track& track; + }; + + //virtual void diskstream_record_enable_changed (void *src) = 0; + //virtual void diskstream_input_channel_changed (void *src) = 0; + + //virtual void input_change_handler (void *src) = 0; + + virtual void set_state_part_two () = 0; + + FreezeRecord _freeze_record; + XMLNode* pending_state; + sigc::connection recenable_connection; + sigc::connection ic_connection; + RecEnableControllable _rec_enable_control; + bool _destructive; +}; + +}; /* namespace ARDOUR*/ + +#endif /* __ardour_track_h__ */ diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index a0a209b569..b2230f12d7 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -30,6 +30,8 @@ #include <inttypes.h> #include <jack/types.h> #include <control_protocol/smpte.h> +#include <pbd/id.h> + #include <map> #if __GNUC__ < 3 @@ -45,7 +47,7 @@ namespace ARDOUR { typedef float pan_t; typedef float gain_t; typedef uint32_t layer_t; - typedef uint64_t id_t; + typedef uint64_t microseconds_t; enum IOChange { NoChange = 0, @@ -69,7 +71,7 @@ namespace ARDOUR { PanAutomation = 0x2, PluginAutomation = 0x4, SoloAutomation = 0x8, - MuteAutomation = 0x10, + MuteAutomation = 0x10 }; enum AutoState { @@ -188,10 +190,10 @@ namespace ARDOUR { enum EditMode { Slide, - Splice, + Splice }; - enum RegionPoint { + enum RegionPoint { Start, End, SyncPoint @@ -241,7 +243,7 @@ namespace ARDOUR { PeakDatum min; PeakDatum max; }; -}; +} std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf); std::istream& operator>>(std::istream& o, ARDOUR::HeaderFormat& sf); diff --git a/libs/ardour/ardour/utils.h b/libs/ardour/ardour/utils.h index 3a9905b3ac..ee4482d260 100644 --- a/libs/ardour/ardour/utils.h +++ b/libs/ardour/ardour/utils.h @@ -25,6 +25,10 @@ #include <string> #include <cmath> +#ifdef HAVE_COREAUDIO +#include <CoreFoundation/CoreFoundation.h> +#endif + #include "ardour.h" class XMLNode; @@ -50,9 +54,11 @@ int tokenize_fullpath (std::string fullpath, std::string& path, std::string& nam int touch_file(std::string path); -uint32_t long get_uid(); - std::string region_name_from_path (std::string path); std::string path_expand (std::string); +#ifdef HAVE_COREAUDIO +std::string CFStringRefToStdString(CFStringRef stringRef); +#endif // HAVE_COREAUDIO + #endif /* __ardour_utils_h__ */ diff --git a/libs/ardour/ardour/vst_plugin.h b/libs/ardour/ardour/vst_plugin.h index ee8e6e986b..3636fe275a 100644 --- a/libs/ardour/ardour/vst_plugin.h +++ b/libs/ardour/ardour/vst_plugin.h @@ -28,11 +28,9 @@ #include <string> #include <dlfcn.h> -#include <midi++/controllable.h> #include <sigc++/signal.h> - +#include <pbd/stateful.h> #include <jack/types.h> -#include <ardour/stateful.h> #include <ardour/plugin_state.h> #include <ardour/plugin.h> @@ -106,6 +104,14 @@ class VSTPlugin : public ARDOUR::Plugin bool been_resumed; }; -} +class VSTPluginInfo : public PluginInfo +{ + VSTPluginInfo () {} + ~VSTPluginInfo () {} + + PluginPtr load (Session& session); +}; + +} // namespace ARDOUR #endif /* __ardour_vst_plugin_h__ */ diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index 977616dd8b..7d2a2103bb 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2003 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,8 +14,6 @@ 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: diskstream.cc 567 2006-06-07 14:54:12Z trutkin $ */ #include <fstream> @@ -23,6 +21,7 @@ #include <unistd.h> #include <cmath> #include <cerrno> +#include <cassert> #include <string> #include <climits> #include <fcntl.h> @@ -56,32 +55,30 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -jack_nframes_t AudioDiskstream::disk_io_chunk_frames; - -sigc::signal<void,AudioDiskstream*> AudioDiskstream::AudioDiskstreamCreated; -sigc::signal<void,list<AudioFileSource*>*> AudioDiskstream::DeleteSources; -sigc::signal<void> AudioDiskstream::DiskOverrun; -sigc::signal<void> AudioDiskstream::DiskUnderrun; +size_t AudioDiskstream::_working_buffers_size = 0; +Sample* AudioDiskstream::_mixdown_buffer = 0; +gain_t* AudioDiskstream::_gain_buffer = 0; +char* AudioDiskstream::_conversion_buffer = 0; -AudioDiskstream::AudioDiskstream (Session &sess, const string &name, Flag flag) - : _name (name), - _session (sess) +AudioDiskstream::AudioDiskstream (Session &sess, const string &name, Diskstream::Flag flag) + : Diskstream(sess, name, flag) + , deprecated_io_node(NULL) { /* prevent any write sources from being created */ in_set_state = true; - init (flag); + init(flag); use_new_playlist (); in_set_state = false; - AudioDiskstreamCreated (this); /* EMIT SIGNAL */ + DiskstreamCreated (this); /* EMIT SIGNAL */ } AudioDiskstream::AudioDiskstream (Session& sess, const XMLNode& node) - : _session (sess) - + : Diskstream(sess, node) + , deprecated_io_node(NULL) { in_set_state = true; init (Recordable); @@ -97,7 +94,7 @@ AudioDiskstream::AudioDiskstream (Session& sess, const XMLNode& node) use_destructive_playlist (); } - AudioDiskstreamCreated (this); /* EMIT SIGNAL */ + DiskstreamCreated (this); /* EMIT SIGNAL */ } void @@ -130,44 +127,9 @@ AudioDiskstream::init_channel (ChannelInfo &chan) void -AudioDiskstream::init (Flag f) +AudioDiskstream::init (Diskstream::Flag f) { - _id = new_id(); - _refcnt = 0; - _flags = f; - _io = 0; - _alignment_style = ExistingMaterial; - _persistent_alignment_style = ExistingMaterial; - first_input_change = true; - _playlist = 0; - i_am_the_modifier = 0; - g_atomic_int_set (&_record_enabled, 0); - was_recording = false; - capture_start_frame = 0; - capture_captured = 0; - _visible_speed = 1.0f; - _actual_speed = 1.0f; - _buffer_reallocation_required = false; - _seek_required = false; - first_recordable_frame = max_frames; - last_recordable_frame = max_frames; - _roll_delay = 0; - _capture_offset = 0; - _processed = false; - _slaved = false; - adjust_capture_position = 0; - last_possibly_recording = 0; - loop_location = 0; - wrap_buffer_size = 0; - speed_buffer_size = 0; - last_phase = 0; - phi = (uint64_t) (0x1000000); - file_frame = 0; - playback_sample = 0; - playback_distance = 0; - _read_data_count = 0; - _write_data_count = 0; - deprecated_io_node = 0; + Diskstream::init(f); /* there are no channels at this point, so these two calls just get speed_buffer_size and wrap_buffer @@ -177,13 +139,8 @@ AudioDiskstream::init (Flag f) set_block_size (_session.get_block_size()); allocate_temporary_buffers (); - pending_overwrite = false; - overwrite_frame = 0; - overwrite_queued = false; - input_change_pending = NoChange; - add_channel (); - _n_channels = 1; + assert(_n_channels == 1); } void @@ -217,26 +174,33 @@ AudioDiskstream::~AudioDiskstream () { Glib::Mutex::Lock lm (state_lock); - if (_playlist) { - _playlist->unref (); - } - - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { + for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) destroy_channel((*chan)); - } channels.clear(); } void -AudioDiskstream::handle_input_change (IOChange change, void *src) +AudioDiskstream::allocate_working_buffers() { - Glib::Mutex::Lock lm (state_lock); + assert(disk_io_frames() > 0); - if (!(input_change_pending & change)) { - input_change_pending = IOChange (input_change_pending|change); - _session.request_input_change_handling (); - } + _working_buffers_size = disk_io_frames(); + _mixdown_buffer = new Sample[_working_buffers_size]; + _gain_buffer = new gain_t[_working_buffers_size]; + _conversion_buffer = new char[_working_buffers_size * 4]; +} + +void +AudioDiskstream::free_working_buffers() +{ + delete _mixdown_buffer; + delete _gain_buffer; + delete _conversion_buffer; + _working_buffers_size = 0; + _mixdown_buffer = 0; + _gain_buffer = 0; + _conversion_buffer = 0; } void @@ -334,9 +298,9 @@ AudioDiskstream::find_and_use_playlist (const string& name) Playlist* pl; AudioPlaylist* playlist; - if ((pl = _session.get_playlist (name)) == 0) { - error << string_compose(_("AudioDiskstream: Session doesn't know about a Playlist called \"%1\""), name) << endmsg; - return -1; + if ((pl = _session.playlist_by_name (name)) == 0) { + playlist = new AudioPlaylist(_session, name); + pl = playlist; } if ((playlist = dynamic_cast<AudioPlaylist*> (pl)) == 0) { @@ -348,57 +312,15 @@ AudioDiskstream::find_and_use_playlist (const string& name) } int -AudioDiskstream::use_playlist (AudioPlaylist* playlist) +AudioDiskstream::use_playlist (Playlist* playlist) { - { - Glib::Mutex::Lock lm (state_lock); - - if (playlist == _playlist) { - return 0; - } + assert(dynamic_cast<AudioPlaylist*>(playlist)); - plstate_connection.disconnect(); - plmod_connection.disconnect (); - plgone_connection.disconnect (); - - if (_playlist) { - _playlist->unref(); - } - - _playlist = playlist; - _playlist->ref(); - - if (!in_set_state && recordable()) { - reset_write_sources (false); - } - - plstate_connection = _playlist->StateChanged.connect (mem_fun (*this, &AudioDiskstream::playlist_changed)); - plmod_connection = _playlist->Modified.connect (mem_fun (*this, &AudioDiskstream::playlist_modified)); - plgone_connection = _playlist->GoingAway.connect (mem_fun (*this, &AudioDiskstream::playlist_deleted)); - } - - if (!overwrite_queued) { - _session.request_overwrite_buffer (this); - overwrite_queued = true; - } - - PlaylistChanged (); /* EMIT SIGNAL */ - _session.set_dirty (); + Diskstream::use_playlist(playlist); return 0; } -void -AudioDiskstream::playlist_deleted (Playlist* pl) -{ - /* this catches an ordering issue with session destruction. playlists - are destroyed before diskstreams. we have to invalidate any handles - we have to the playlist. - */ - - _playlist = 0; -} - int AudioDiskstream::use_new_playlist () { @@ -426,6 +348,8 @@ AudioDiskstream::use_new_playlist () int AudioDiskstream::use_copy_playlist () { + assert(audio_playlist()); + if (destructive()) { return 0; } @@ -440,7 +364,7 @@ AudioDiskstream::use_copy_playlist () newname = Playlist::bump_name (_playlist->name(), _session); - if ((playlist = new AudioPlaylist (*_playlist, newname)) != 0) { + if ((playlist = new AudioPlaylist (*audio_playlist(), newname)) != 0) { playlist->set_orig_diskstream_id (id()); return use_playlist (playlist); } else { @@ -459,8 +383,10 @@ AudioDiskstream::setup_destructive_playlist () /* a single full-sized region */ + cerr << "setup DS using " << srcs.front()->natural_position () << endl; + AudioRegion* region = new AudioRegion (srcs, 0, max_frames, _name); - _playlist->add_region (*region, 0); + _playlist->add_region (*region, srcs.front()->natural_position()); } void @@ -488,6 +414,7 @@ AudioDiskstream::use_destructive_playlist () for (n = 0, chan = channels.begin(); chan != channels.end(); ++chan, ++n) { (*chan).write_source = dynamic_cast<AudioFileSource*>(®ion->source (n)); + assert((*chan).write_source); (*chan).write_source->set_allow_remove_if_empty (false); } @@ -495,104 +422,6 @@ AudioDiskstream::use_destructive_playlist () } void -AudioDiskstream::set_io (IO& io) -{ - _io = &io; - set_align_style_from_io (); -} - -int -AudioDiskstream::set_name (string str, void *src) -{ - if (str != _name) { - _playlist->set_name (str); - _name = str; - - if (!in_set_state && recordable()) { - /* rename existing capture files so that they have the correct name */ - return rename_write_sources (); - } else { - return -1; - } - } - - return 0; -} - -void -AudioDiskstream::set_speed (double sp) -{ - _session.request_diskstream_speed (*this, sp); - - /* to force a rebuffering at the right place */ - playlist_modified(); -} - -bool -AudioDiskstream::realtime_set_speed (double sp, bool global) -{ - bool changed = false; - double new_speed = sp * _session.transport_speed(); - - if (_visible_speed != sp) { - _visible_speed = sp; - changed = true; - } - - if (new_speed != _actual_speed) { - - jack_nframes_t required_wrap_size = (jack_nframes_t) floor (_session.get_block_size() * - fabs (new_speed)) + 1; - - if (required_wrap_size > wrap_buffer_size) { - _buffer_reallocation_required = true; - } - - _actual_speed = new_speed; - phi = (uint64_t) (0x1000000 * fabs(_actual_speed)); - } - - if (changed) { - if (!global) { - _seek_required = true; - } - speed_changed (); /* EMIT SIGNAL */ - } - - return _buffer_reallocation_required || _seek_required; -} - -void -AudioDiskstream::non_realtime_set_speed () -{ - if (_buffer_reallocation_required) - { - Glib::Mutex::Lock lm (state_lock); - allocate_temporary_buffers (); - - _buffer_reallocation_required = false; - } - - if (_seek_required) { - if (speed() != 1.0f || speed() != -1.0f) { - seek ((jack_nframes_t) (_session.transport_frame() * (double) speed()), true); - } - else { - seek (_session.transport_frame(), true); - } - - _seek_required = false; - } -} - -void -AudioDiskstream::prepare () -{ - _processed = false; - playback_distance = 0; -} - -void AudioDiskstream::check_record_status (jack_nframes_t transport_frame, jack_nframes_t nframes, bool can_record) { int possibly_recording; @@ -755,7 +584,7 @@ AudioDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes returns a non-zero value, in which case, ::commit should not be called. */ - // If we can't take the state lock return. + // If we can't take the state lock return. if (!state_lock.trylock()) { return 1; } @@ -1011,13 +840,6 @@ AudioDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes return ret; } -void -AudioDiskstream::recover () -{ - state_lock.unlock(); - _processed = false; -} - bool AudioDiskstream::commit (jack_nframes_t nframes) { @@ -1153,13 +975,19 @@ AudioDiskstream::seek (jack_nframes_t frame, bool complete_refill) (*chan).capture_buf->reset (); } + /* can't rec-enable in destructive mode if transport is before start */ + + if (destructive() && record_enabled() && frame < _session.current_start_frame()) { + disengage_record_enable (); + } + playback_sample = frame; file_frame = frame; if (complete_refill) { - while ((ret = do_refill (0, 0, 0)) > 0); + while ((ret = do_refill_with_alloc ()) > 0) ; } else { - ret = do_refill (0, 0, 0); + ret = do_refill_with_alloc (); } return ret; @@ -1251,7 +1079,7 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, this_read = min(cnt,this_read); - if (_playlist->read (buf+offset, mixdown_buffer, gain_buffer, workbuf, start, this_read, channel) != this_read) { + if (audio_playlist()->read (buf+offset, mixdown_buffer, gain_buffer, workbuf, start, this_read, channel) != this_read) { error << string_compose(_("AudioDiskstream %1: cannot read %2 from playlist at frame %3"), _id, this_read, start) << endmsg; return -1; @@ -1285,14 +1113,27 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, } int -AudioDiskstream::do_refill (Sample* mixdown_buffer, float* gain_buffer, char * workbuf) +AudioDiskstream::do_refill_with_alloc() +{ + Sample* mix_buf = new Sample[disk_io_chunk_frames]; + float* gain_buf = new float[disk_io_chunk_frames]; + char* work_buf = new char[disk_io_chunk_frames * 4]; + + int ret = _do_refill(mix_buf, gain_buf, work_buf); + + delete [] mix_buf; + delete [] gain_buf; + delete [] work_buf; + + return ret; +} + +int +AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer, char * workbuf) { int32_t ret = 0; jack_nframes_t to_read; RingBufferNPT<Sample>::rw_vector vector; - bool free_mixdown; - bool free_gain; - bool free_workbuf; bool reversed = (_visible_speed * _session.transport_speed()) < 0.0f; jack_nframes_t total_space; jack_nframes_t zero_fill; @@ -1300,6 +1141,10 @@ AudioDiskstream::do_refill (Sample* mixdown_buffer, float* gain_buffer, char * w ChannelList::iterator i; jack_nframes_t ts; + assert(mixdown_buffer); + assert(gain_buffer); + assert(workbuf); + channels.front().playback_buf->get_write_vector (&vector); if ((total_space = vector.len[0] + vector.len[1]) == 0) { @@ -1406,33 +1251,6 @@ AudioDiskstream::do_refill (Sample* mixdown_buffer, float* gain_buffer, char * w zero_fill = 0; } } - - /* Please note: the code to allocate buffers isn't run - during normal butler thread operation. Its there - for other times when we need to call do_refill() - from somewhere other than the butler thread. - */ - - if (mixdown_buffer == 0) { - mixdown_buffer = new Sample[disk_io_chunk_frames]; - free_mixdown = true; - } else { - free_mixdown = false; - } - - if (gain_buffer == 0) { - gain_buffer = new float[disk_io_chunk_frames]; - free_gain = true; - } else { - free_gain = false; - } - - if (workbuf == 0) { - workbuf = new char[disk_io_chunk_frames * 4]; - free_workbuf = true; - } else { - free_workbuf = false; - } jack_nframes_t file_frame_tmp = 0; @@ -1501,37 +1319,30 @@ AudioDiskstream::do_refill (Sample* mixdown_buffer, float* gain_buffer, char * w file_frame = file_frame_tmp; out: - if (free_mixdown) { - delete [] mixdown_buffer; - } - if (free_gain) { - delete [] gain_buffer; - } - if (free_workbuf) { - delete [] workbuf; - } return ret; } +/** Flush pending data to disk. + * + * Important note: this function will write *AT MOST* disk_io_chunk_frames + * of data to disk. it will never write more than that. If it writes that + * much and there is more than that waiting to be written, it will return 1, + * otherwise 0 on success or -1 on failure. + * + * If there is less than disk_io_chunk_frames to be written, no data will be + * written at all unless @a force_flush is true. + */ int -AudioDiskstream::do_flush (char * workbuf, bool force_flush) +AudioDiskstream::do_flush (Session::RunContext context, bool force_flush) { + char* workbuf = _session.conversion_buffer(context); + uint32_t to_write; int32_t ret = 0; RingBufferNPT<Sample>::rw_vector vector; RingBufferNPT<CaptureTransition>::rw_vector transvec; jack_nframes_t total; - - /* important note: this function will write *AT MOST* - disk_io_chunk_frames of data to disk. it will never - write more than that. if its writes that much and there - is more than that waiting to be written, it will return 1, - otherwise 0 on success or -1 on failure. - - if there is less than disk_io_chunk_frames to be written, - no data will be written at all unless `force_flush' is true. - */ _write_data_count = 0; @@ -1546,7 +1357,6 @@ AudioDiskstream::do_flush (char * workbuf, bool force_flush) goto out; } - /* if there are 2+ chunks of disk i/o possible for this track, let the caller know so that it can arrange for us to be called again, ASAP. @@ -1564,7 +1374,6 @@ AudioDiskstream::do_flush (char * workbuf, bool force_flush) to_write = min (disk_io_chunk_frames, (jack_nframes_t) vector.len[0]); - // check the transition buffer when recording destructive // important that we get this after the capture buf @@ -1652,21 +1461,6 @@ AudioDiskstream::do_flush (char * workbuf, bool force_flush) } void -AudioDiskstream::playlist_changed (Change ignored) -{ - playlist_modified (); -} - -void -AudioDiskstream::playlist_modified () -{ - if (!i_am_the_modifier && !overwrite_queued) { - _session.request_overwrite_buffer (this); - overwrite_queued = true; - } -} - -void AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_capture) { uint32_t buffer_position; @@ -1679,7 +1473,6 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca ChannelList::iterator chan; vector<CaptureInfo*>::iterator ci; uint32_t n = 0; - list<AudioFileSource*>* deletion_list; bool mark_write_completed = false; finish_capture (true); @@ -1689,7 +1482,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca */ while (more_work && !err) { - switch (do_flush ( _session.conversion_buffer(Session::TransportContext), true)) { + switch (do_flush (Session::TransportContext, true)) { case 0: more_work = false; break; @@ -1712,7 +1505,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca ChannelList::iterator chan; - deletion_list = new list<AudioFileSource*>; + list<Source*>* deletion_list = new list<Source*>; for ( chan = channels.begin(); chan != channels.end(); ++chan) { @@ -1900,17 +1693,17 @@ AudioDiskstream::finish_capture (bool rec_monitors_input) } void -AudioDiskstream::set_record_enabled (bool yn, void* src) +AudioDiskstream::set_record_enabled (bool yn) { - bool rolling = _session.transport_speed() != 0.0f; - if (!recordable() || !_session.record_enabling_legal()) { return; } - - /* if we're turning on rec-enable, there needs to be an - input connection. - */ + + /* can't rec-enable in destructive mode if transport is before start */ + + if (destructive() && yn && _session.transport_frame() < _session.current_start_frame()) { + return; + } if (yn && channels[0].source == 0) { @@ -1927,42 +1720,57 @@ AudioDiskstream::set_record_enabled (bool yn, void* src) if (record_enabled() != yn) { if (yn) { - g_atomic_int_set (&_record_enabled, 1); - capturing_sources.clear (); - if (Config->get_use_hardware_monitoring()) { - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { - if ((*chan).source) { - (*chan).source->request_monitor_input (!(_session.get_auto_input() && rolling)); - } - capturing_sources.push_back ((*chan).write_source); - } - } else { - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { - capturing_sources.push_back ((*chan).write_source); - } - } - + engage_record_enable (); } else { - g_atomic_int_set (&_record_enabled, 0); - if (Config->get_use_hardware_monitoring()) { - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { - if ((*chan).source) { - (*chan).source->request_monitor_input (false); - } - } + disengage_record_enable (); + } + } +} + +void +AudioDiskstream::engage_record_enable () +{ + bool rolling = _session.transport_speed() != 0.0f; + + g_atomic_int_set (&_record_enabled, 1); + capturing_sources.clear (); + if (Config->get_use_hardware_monitoring()) { + for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { + if ((*chan).source) { + (*chan).source->request_monitor_input (!(_session.get_auto_input() && rolling)); } - capturing_sources.clear (); + capturing_sources.push_back ((*chan).write_source); + } + } else { + for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { + capturing_sources.push_back ((*chan).write_source); } + } + + RecordEnableChanged (); /* EMIT SIGNAL */ +} - record_enable_changed (src); /* EMIT SIGNAL */ +void +AudioDiskstream::disengage_record_enable () +{ + g_atomic_int_set (&_record_enabled, 0); + if (Config->get_use_hardware_monitoring()) { + for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { + if ((*chan).source) { + (*chan).source->request_monitor_input (false); + } + } } + capturing_sources.clear (); + RecordEnableChanged (); /* EMIT SIGNAL */ } + XMLNode& AudioDiskstream::get_state () { XMLNode* node = new XMLNode ("AudioDiskstream"); - char buf[64]; + char buf[64] = ""; LocaleGuard lg (X_("POSIX")); snprintf (buf, sizeof(buf), "0x%x", _flags); @@ -1977,7 +1785,7 @@ AudioDiskstream::get_state () node->add_property ("speed", buf); node->add_property("name", _name); - snprintf (buf, sizeof(buf), "%" PRIu64, id()); + id().print (buf); node->add_property("id", buf); if (!capturing_sources.empty() && _session.get_record_enabled()) { @@ -2044,11 +1852,11 @@ AudioDiskstream::set_state (const XMLNode& node) if (deprecated_io_node) { if ((prop = deprecated_io_node->property ("id")) != 0) { - sscanf (prop->value().c_str(), "%" PRIu64, &_id); + _id = prop->value (); } } else { if ((prop = node.property ("id")) != 0) { - sscanf (prop->value().c_str(), "%" PRIu64, &_id); + _id = prop->value (); } } @@ -2061,8 +1869,7 @@ AudioDiskstream::set_state (const XMLNode& node) } // create necessary extra channels - // we are always constructed with one - // and we always need one + // we are always constructed with one and we always need one if (nchans > _n_channels) { @@ -2293,23 +2100,6 @@ AudioDiskstream::monitor_input (bool yn) } void -AudioDiskstream::set_capture_offset () -{ - if (_io == 0) { - /* can't capture, so forget it */ - return; - } - - _capture_offset = _io->input_latency(); -} - -void -AudioDiskstream::set_persistent_align_style (AlignStyle a) -{ - _persistent_alignment_style = a; -} - -void AudioDiskstream::set_align_style_from_io () { bool have_physical = false; @@ -2334,20 +2124,6 @@ AudioDiskstream::set_align_style_from_io () } } -void -AudioDiskstream::set_align_style (AlignStyle a) -{ - if (record_enabled() && _session.actively_recording()) { - return; - } - - - if (a != _alignment_style) { - _alignment_style = a; - AlignmentStyleChanged (); - } -} - int AudioDiskstream::add_channel () { @@ -2399,58 +2175,6 @@ AudioDiskstream::capture_buffer_load () const } int -AudioDiskstream::set_loop (Location *location) -{ - if (location) { - if (location->start() >= location->end()) { - error << string_compose(_("Location \"%1\" not valid for track loop (start >= end)"), location->name()) << endl; - return -1; - } - } - - loop_location = location; - - LoopSet (location); /* EMIT SIGNAL */ - return 0; -} - -jack_nframes_t -AudioDiskstream::get_capture_start_frame (uint32_t n) -{ - Glib::Mutex::Lock lm (capture_info_lock); - - if (capture_info.size() > n) { - return capture_info[n]->start; - } - else { - return capture_start_frame; - } -} - -jack_nframes_t -AudioDiskstream::get_captured_frames (uint32_t n) -{ - Glib::Mutex::Lock lm (capture_info_lock); - - if (capture_info.size() > n) { - return capture_info[n]->frames; - } - else { - return capture_captured; - } -} - -void -AudioDiskstream::punch_in () -{ -} - -void -AudioDiskstream::punch_out () -{ -} - -int AudioDiskstream::use_pending_capture_data (XMLNode& node) { const XMLProperty* prop; @@ -2545,22 +2269,3 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node) return 0; } - -void -AudioDiskstream::set_roll_delay (jack_nframes_t nframes) -{ - _roll_delay = nframes; -} - -void -AudioDiskstream::set_destructive (bool yn) -{ - if (yn != destructive()) { - reset_write_sources (true, true); - if (yn) { - _flags |= Destructive; - } else { - _flags &= ~Destructive; - } - } -} diff --git a/libs/ardour/audio_library.cc b/libs/ardour/audio_library.cc index 7f421e86c8..ad008f6312 100644 --- a/libs/ardour/audio_library.cc +++ b/libs/ardour/audio_library.cc @@ -46,6 +46,8 @@ using namespace PBD; static char* SOUNDFILE = "http://ardour.org/ontology/Soundfile"; +string AudioLibrary::state_node_name = "AudioLibrary"; + AudioLibrary::AudioLibrary () { // sfdb_paths.push_back("/Users/taybin/sounds"); @@ -74,8 +76,6 @@ AudioLibrary::AudioLibrary () } lrdf_free_statements(matches); - - scan_paths(); } AudioLibrary::~AudioLibrary () @@ -356,6 +356,8 @@ void AudioLibrary::set_paths (vector<string> paths) { sfdb_paths = paths; + + scan_paths (); } vector<string> @@ -429,5 +431,50 @@ AudioLibrary::safe_file_extension(string file) file.rfind(".maud")== string::npos && file.rfind(".vwe") == string::npos && file.rfind(".paf") == string::npos && +#ifdef HAVE_COREAUDIO + file.rfind(".mp3") == string::npos && + file.rfind(".aac") == string::npos && + file.rfind(".mp4") == string::npos && +#endif // HAVE_COREAUDIO file.rfind(".voc") == string::npos); } + +XMLNode& +AudioLibrary::get_state () +{ + XMLNode* root = new XMLNode(X_("AudioLibrary")); + + for (vector<string>::iterator i = sfdb_paths.begin(); i != sfdb_paths.end(); ++i) { + XMLNode* node = new XMLNode(X_("Path")); + node->add_property("value", *i); + root->add_child_nocopy(*node); + } + + return *root; +} + +int +AudioLibrary::set_state (const XMLNode& node) +{ + if (node.name() != X_("AudioLibrary")) { + fatal << "programming error: AudioLibrary: incorrect XML node sent to set_state()" << endmsg; + return -1; + } + + XMLNodeList nodes = node.children(X_("Path")); + + vector<string> paths; + XMLProperty* prop; + XMLNode* child; + for (XMLNodeConstIterator iter = nodes.begin(); iter != nodes.end(); ++iter) { + child = *iter; + + if ((prop = child->property(X_("value"))) != 0) { + paths.push_back(prop->value()); + } + } + + set_paths (paths); + + return 0; +} diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc index 85c11647f4..93d380679d 100644 --- a/libs/ardour/audio_playlist.cc +++ b/libs/ardour/audio_playlist.cc @@ -243,16 +243,18 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, ch for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) { + // FIXME: Should be vector<AudioRegion*> 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, workbuf, start, cnt, chan_n, read_frames, skip_frames); - _read_data_count += (*i)->read_data_count(); + AudioRegion* const ar = dynamic_cast<AudioRegion*>(*i); + assert(ar); + ar->read_at (buf, mixdown_buffer, gain_buffer, workbuf, start, cnt, chan_n, read_frames, skip_frames); + _read_data_count += ar->read_data_count(); } for (vector<Crossfade*>::iterator i = x.begin(); i != x.end(); ++i) { - (*i)->read_at (buf, mixdown_buffer, gain_buffer, workbuf, start, cnt, chan_n); /* don't JACK up _read_data_count, since its the same data as we just @@ -880,38 +882,6 @@ AudioPlaylist::crossfade_changed (Change ignored) 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) { - if (Config->get_use_overlap_equivalency()) { - if (ar->overlap_equivalent (other)) { - results.push_back (ar); - } else if (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) { diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc index 74b7dd071c..78af23e3df 100644 --- a/libs/ardour/audio_track.cc +++ b/libs/ardour/audio_track.cc @@ -41,9 +41,7 @@ using namespace ARDOUR; using namespace PBD; AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode mode) - : Route (sess, name, 1, -1, -1, -1, flag), - diskstream (0), - _midi_rec_enable_control (*this, _session.midi_port()) + : Track (sess, name, flag, mode) { AudioDiskstream::Flag dflags = AudioDiskstream::Flag (0); @@ -59,54 +57,34 @@ AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode AudioDiskstream* ds = new AudioDiskstream (_session, name, dflags); - _declickable = true; - _freeze_record.state = NoFreeze; - _saved_meter_point = _meter_point; - _mode = mode; - set_diskstream (*ds, this); - - // session.SMPTEOffsetChanged.connect (mem_fun (*this, &AudioTrack::handle_smpte_offset_change)); - - // we do this even though Route already did it in it's init - reset_midi_control (_session.midi_port(), _session.get_midi_control()); - } AudioTrack::AudioTrack (Session& sess, const XMLNode& node) - : Route (sess, "to be renamed", 0, 0, -1, -1), - diskstream (0), - _midi_rec_enable_control (*this, _session.midi_port()) + : Track (sess, node) { - _freeze_record.state = NoFreeze; set_state (node); - _declickable = true; - _saved_meter_point = _meter_point; - - // we do this even though Route already did it in it's init - reset_midi_control (_session.midi_port(), _session.get_midi_control()); } AudioTrack::~AudioTrack () { - if (diskstream) { - diskstream->unref(); - } } int AudioTrack::deprecated_use_diskstream_connections () { - if (diskstream->deprecated_io_node == 0) { + AudioDiskstream& diskstream = audio_diskstream(); + + if (diskstream.deprecated_io_node == 0) { return 0; } const XMLProperty* prop; - XMLNode& node (*diskstream->deprecated_io_node); + XMLNode& node (*diskstream.deprecated_io_node); /* don't do this more than once. */ - diskstream->deprecated_io_node = 0; + diskstream.deprecated_io_node = 0; set_input_minimum (-1); set_input_maximum (-1); @@ -149,15 +127,15 @@ AudioTrack::deprecated_use_diskstream_connections () int AudioTrack::set_diskstream (AudioDiskstream& ds, void *src) { - if (diskstream) { - diskstream->unref(); + if (_diskstream) { + _diskstream->unref(); } - diskstream = &ds.ref(); - diskstream->set_io (*this); - diskstream->set_destructive (_mode == Destructive); + _diskstream = &ds.ref(); + _diskstream->set_io (*this); + _diskstream->set_destructive (_mode == Destructive); - if (diskstream->deprecated_io_node) { + if (audio_diskstream().deprecated_io_node) { if (!connecting_legal) { ConnectingLegal.connect (mem_fun (*this, &AudioTrack::deprecated_use_diskstream_connections)); @@ -166,13 +144,13 @@ AudioTrack::set_diskstream (AudioDiskstream& ds, void *src) } } - diskstream->set_record_enabled (false, this); - diskstream->monitor_input (false); + _diskstream->set_record_enabled (false); + _diskstream->monitor_input (false); ic_connection.disconnect(); - ic_connection = input_changed.connect (mem_fun (*diskstream, &AudioDiskstream::handle_input_change)); + ic_connection = input_changed.connect (mem_fun (*_diskstream, &Diskstream::handle_input_change)); - diskstream_changed (src); /* EMIT SIGNAL */ + DiskstreamChanged (); /* EMIT SIGNAL */ return 0; } @@ -182,8 +160,8 @@ AudioTrack::use_diskstream (string name) { AudioDiskstream *dstream; - if ((dstream = _session.diskstream_by_name (name)) == 0) { - error << string_compose(_("AudioTrack: diskstream \"%1\" not known by session"), name) << endmsg; + if ((dstream = dynamic_cast<AudioDiskstream*>(_session.diskstream_by_name (name))) == 0) { + error << string_compose(_("AudioTrack: audio diskstream \"%1\" not known by session"), name) << endmsg; return -1; } @@ -191,60 +169,22 @@ AudioTrack::use_diskstream (string name) } int -AudioTrack::use_diskstream (id_t id) +AudioTrack::use_diskstream (const PBD::ID& id) { AudioDiskstream *dstream; - if ((dstream = _session.diskstream_by_id (id)) == 0) { - error << string_compose(_("AudioTrack: diskstream \"%1\" not known by session"), id) << endmsg; + if ((dstream = dynamic_cast<AudioDiskstream*>(_session.diskstream_by_id (id))) == 0) { + error << string_compose(_("AudioTrack: audio diskstream \"%1\" not known by session"), id) << endmsg; return -1; } return set_diskstream (*dstream, this); } -bool -AudioTrack::record_enabled () const +AudioDiskstream& +AudioTrack::audio_diskstream() const { - return diskstream->record_enabled (); -} - -void -AudioTrack::set_record_enable (bool yn, void *src) -{ - if (_freeze_record.state == Frozen) { - return; - } - - if (_mix_group && src != _mix_group && _mix_group->is_active()) { - _mix_group->apply (&AudioTrack::set_record_enable, yn, _mix_group); - return; - } - - /* keep track of the meter point as it was before we rec-enabled */ - - if (!diskstream->record_enabled()) { - _saved_meter_point = _meter_point; - } - - diskstream->set_record_enabled (yn, src); - - if (diskstream->record_enabled()) { - set_meter_point (MeterInput, this); - } else { - set_meter_point (_saved_meter_point, this); - } - - if (_session.get_midi_feedback()) { - _midi_rec_enable_control.send_feedback (record_enabled()); - } - -} - -void -AudioTrack::set_meter_point (MeterPoint p, void *src) -{ - Route::set_meter_point (p, src); + return *dynamic_cast<AudioDiskstream*>(_diskstream); } int @@ -252,7 +192,6 @@ AudioTrack::set_state (const XMLNode& node) { const XMLProperty *prop; XMLNodeConstIterator iter; - XMLNodeList midi_kids; if (Route::set_state (node)) { return -1; @@ -271,36 +210,6 @@ AudioTrack::set_state (const XMLNode& node) _mode = Normal; } - midi_kids = node.children ("MIDI"); - - for (iter = midi_kids.begin(); iter != midi_kids.end(); ++iter) { - - XMLNodeList kids; - XMLNodeConstIterator miter; - XMLNode* child; - - kids = (*iter)->children (); - - for (miter = kids.begin(); miter != kids.end(); ++miter) { - - child =* miter; - - if (child->name() == "rec_enable") { - - MIDI::eventType ev = MIDI::on; /* initialize to keep gcc happy */ - MIDI::byte additional = 0; /* ditto */ - MIDI::channel_t chn = 0; /* ditto */ - - if (get_midi_node_info (child, ev, chn, additional)) { - _midi_rec_enable_control.set_control_type (chn, ev, additional); - } else { - error << string_compose(_("MIDI rec_enable control specification for %1 is incomplete, so it has been ignored"), _name) << endmsg; - } - } - } - } - - if ((prop = node.property ("diskstream-id")) == 0) { /* some old sessions use the diskstream name rather than the ID */ @@ -317,7 +226,7 @@ AudioTrack::set_state (const XMLNode& node) } else { - id_t id = strtoull (prop->value().c_str(), 0, 10); + PBD::ID id (prop->value()); if (use_diskstream (id)) { return -1; @@ -349,24 +258,12 @@ AudioTrack::set_state (const XMLNode& node) return 0; } -XMLNode& -AudioTrack::get_template () -{ - return state (false); -} - -XMLNode& -AudioTrack::get_state () -{ - return state (true); -} - XMLNode& AudioTrack::state(bool full_state) { XMLNode& root (Route::state(full_state)); XMLNode* freeze_node; - char buf[32]; + char buf[64]; if (_freeze_record.playlist) { XMLNode* inode; @@ -378,7 +275,7 @@ AudioTrack::state(bool full_state) for (vector<FreezeRecordInsertInfo*>::iterator i = _freeze_record.insert_info.begin(); i != _freeze_record.insert_info.end(); ++i) { inode = new XMLNode (X_("insert")); - snprintf (buf, sizeof (buf), "%" PRIu64, (*i)->id); + (*i)->id.print (buf); inode->add_property (X_("id"), buf); inode->add_child_copy ((*i)->state); @@ -391,7 +288,7 @@ AudioTrack::state(bool full_state) /* Alignment: act as a proxy for the diskstream */ XMLNode* align_node = new XMLNode (X_("alignment")); - switch (diskstream->alignment_style()) { + switch (_diskstream->alignment_style()) { case ExistingMaterial: snprintf (buf, sizeof (buf), X_("existing")); break; @@ -402,29 +299,6 @@ AudioTrack::state(bool full_state) align_node->add_property (X_("style"), buf); root.add_child_nocopy (*align_node); - /* MIDI control */ - - MIDI::channel_t chn; - MIDI::eventType ev; - MIDI::byte additional; - XMLNode* midi_node = 0; - XMLNode* child; - XMLNodeList midikids; - - midikids = root.children ("MIDI"); - if (!midikids.empty()) { - midi_node = midikids.front(); - } - else { - midi_node = root.add_child ("MIDI"); - } - - if (_midi_rec_enable_control.get_control_info (chn, ev, additional) && midi_node) { - - child = midi_node->add_child ("rec_enable"); - set_midi_node_info (child, ev, chn, additional); - } - XMLNode* remote_control_node = new XMLNode (X_("remote_control")); snprintf (buf, sizeof (buf), "%d", _remote_control_id); remote_control_node->add_property (X_("id"), buf); @@ -445,7 +319,7 @@ AudioTrack::state(bool full_state) diskstream. */ - snprintf (buf, sizeof (buf), "%" PRIu64, diskstream->id()); + _diskstream->id().print (buf); root.add_property ("diskstream-id", buf); return root; @@ -504,9 +378,9 @@ AudioTrack::set_state_part_two () continue; } - FreezeRecordInsertInfo* frii = new FreezeRecordInsertInfo (*((*citer)->children().front())); - frii->insert = 0; - sscanf (prop->value().c_str(), "%" PRIu64, &frii->id); + FreezeRecordInsertInfo* frii = new FreezeRecordInsertInfo (*((*citer)->children().front()), + boost::shared_ptr<Insert>()); + frii->id = prop->value (); _freeze_record.insert_info.push_back (frii); } } @@ -517,9 +391,9 @@ AudioTrack::set_state_part_two () if ((prop = fnode->property (X_("style"))) != 0) { if (prop->value() == "existing") { - diskstream->set_persistent_align_style (ExistingMaterial); + _diskstream->set_persistent_align_style (ExistingMaterial); } else if (prop->value() == "capture") { - diskstream->set_persistent_align_style (CaptureTime); + _diskstream->set_persistent_align_style (CaptureTime); } } } @@ -529,7 +403,7 @@ AudioTrack::set_state_part_two () uint32_t AudioTrack::n_process_buffers () { - return max ((uint32_t) diskstream->n_channels(), redirect_max_outs); + return max ((uint32_t) _diskstream->n_channels(), redirect_max_outs); } void @@ -560,7 +434,7 @@ AudioTrack::no_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nf return 0; } - diskstream->check_record_status (start_frame, nframes, can_record); + audio_diskstream().check_record_status (start_frame, nframes, can_record); bool send_silence; @@ -579,7 +453,7 @@ AudioTrack::no_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nf send_silence = true; } } else { - if (diskstream->record_enabled()) { + if (_diskstream->record_enabled()) { if (Config->get_use_sw_monitoring()) { send_silence = false; } else { @@ -627,7 +501,8 @@ AudioTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nfram Sample* b; Sample* tmpb; jack_nframes_t transport_frame; - + AudioDiskstream& diskstream = audio_diskstream(); + { Glib::RWLock::ReaderLock lm (redirect_lock, Glib::TRY_LOCK); if (lm.locked()) { @@ -653,13 +528,13 @@ AudioTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nfram playback distance to zero, thus causing diskstream::commit to do nothing. */ - return diskstream->process (transport_frame, 0, 0, can_record, rec_monitors_input); + return diskstream.process (transport_frame, 0, 0, can_record, rec_monitors_input); } _silent = false; apply_gain_automation = false; - if ((dret = diskstream->process (transport_frame, nframes, offset, can_record, rec_monitors_input)) != 0) { + if ((dret = diskstream.process (transport_frame, nframes, offset, can_record, rec_monitors_input)) != 0) { silence (nframes, offset); @@ -672,7 +547,7 @@ AudioTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nfram just_meter_input (start_frame, end_frame, nframes, offset); } - if (diskstream->record_enabled() && !can_record && !_session.get_auto_input()) { + if (diskstream.record_enabled() && !can_record && !_session.get_auto_input()) { /* not actually recording, but we want to hear the input material anyway, at least potentially (depending on monitoring options) @@ -680,7 +555,7 @@ AudioTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nfram passthru (start_frame, end_frame, nframes, offset, 0, true); - } else if ((b = diskstream->playback_buffer(0)) != 0) { + } else if ((b = diskstream.playback_buffer(0)) != 0) { /* XXX is it true that the earlier test on n_outputs() @@ -702,8 +577,8 @@ AudioTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nfram for (i = 0, n = 1; i < limit; ++i, ++n) { memcpy (bufs[i], b, sizeof (Sample) * nframes); - if (n < diskstream->n_channels()) { - tmpb = diskstream->playback_buffer(n); + if (n < diskstream.n_channels()) { + tmpb = diskstream.playback_buffer(n); if (tmpb!=0) { b = tmpb; } @@ -712,7 +587,7 @@ AudioTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nfram /* don't waste time with automation if we're recording or we've just stopped (yes it can happen) */ - if (!diskstream->record_enabled() && _session.transport_rolling()) { + if (!diskstream.record_enabled() && _session.transport_rolling()) { Glib::Mutex::Lock am (automation_lock, Glib::TRY_LOCK); if (am.locked() && gain_automation_playback()) { @@ -748,37 +623,7 @@ AudioTrack::silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jac silence (nframes, offset); - return diskstream->process (_session.transport_frame() + offset, nframes, offset, can_record, rec_monitors_input); -} - -void -AudioTrack::toggle_monitor_input () -{ - for (vector<Port*>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { - (*i)->request_monitor_input(!(*i)->monitoring_input()); - } -} - -int -AudioTrack::set_name (string str, void *src) -{ - int ret; - - if (record_enabled() && _session.actively_recording()) { - /* this messes things up if done while recording */ - return -1; - } - - if (diskstream->set_name (str, src)) { - return -1; - } - - /* save state so that the statefile fully reflects any filename changes */ - - if ((ret = IO::set_name (str, src)) == 0) { - _session.save_state (""); - } - return ret; + return audio_diskstream().process (_session.transport_frame() + offset, nframes, offset, can_record, rec_monitors_input); } int @@ -792,10 +637,15 @@ AudioTrack::export_stuff (vector<Sample*>& buffers, char * workbuf, uint32_t nbu gain_t this_gain = _gain; vector<Sample*>::iterator bi; Sample * b; + AudioDiskstream& diskstream = audio_diskstream(); Glib::RWLock::ReaderLock rlock (redirect_lock); - - if (diskstream->playlist()->read (buffers[0], mix_buffer, gain_buffer, workbuf, start, nframes) != nframes) { + + // FIXME + AudioPlaylist* const apl = dynamic_cast<AudioPlaylist*>(diskstream.playlist()); + assert(apl); + + if (apl->read (buffers[0], mix_buffer, gain_buffer, workbuf, start, nframes) != nframes) { return -1; } @@ -804,8 +654,8 @@ AudioTrack::export_stuff (vector<Sample*>& buffers, char * workbuf, uint32_t nbu b = buffers[0]; ++bi; for (; bi != buffers.end(); ++bi, ++n) { - if (n < diskstream->n_channels()) { - if (diskstream->playlist()->read ((*bi), mix_buffer, gain_buffer, workbuf, start, nframes, n) != nframes) { + if (n < diskstream.n_channels()) { + if (apl->read ((*bi), mix_buffer, gain_buffer, workbuf, start, nframes, n) != nframes) { return -1; } b = (*bi); @@ -822,9 +672,9 @@ AudioTrack::export_stuff (vector<Sample*>& buffers, char * workbuf, uint32_t nbu */ for (i = _redirects.begin(); i != _redirects.end(); ++i) { - Insert *insert; + boost::shared_ptr<Insert> insert; - if ((insert = dynamic_cast<Insert*>(*i)) != 0) { + if ((insert = boost::dynamic_pointer_cast<Insert>(*i)) != 0) { switch (insert->placement()) { case PreFader: insert->run (buffers, nbufs, nframes, 0); @@ -860,9 +710,9 @@ AudioTrack::export_stuff (vector<Sample*>& buffers, char * workbuf, uint32_t nbu if (post_fader_work) { for (i = _redirects.begin(); i != _redirects.end(); ++i) { - PluginInsert *insert; + boost::shared_ptr<PluginInsert> insert; - if ((insert = dynamic_cast<PluginInsert*>(*i)) != 0) { + if ((insert = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) { switch ((*i)->placement()) { case PreFader: break; @@ -878,29 +728,6 @@ AudioTrack::export_stuff (vector<Sample*>& buffers, char * workbuf, uint32_t nbu } void -AudioTrack::set_latency_delay (jack_nframes_t longest_session_latency) -{ - Route::set_latency_delay (longest_session_latency); - diskstream->set_roll_delay (_roll_delay); -} - -jack_nframes_t -AudioTrack::update_total_latency () -{ - _own_latency = 0; - - for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) { - if ((*i)->active ()) { - _own_latency += (*i)->latency (); - } - } - - set_port_latency (_own_latency); - - return _own_latency; -} - -void AudioTrack::bounce (InterThreadInfo& itt) { vector<AudioSource*> srcs; @@ -918,15 +745,15 @@ AudioTrack::bounce_range (jack_nframes_t start, jack_nframes_t end, InterThreadI void AudioTrack::freeze (InterThreadInfo& itt) { - Insert* insert; vector<AudioSource*> srcs; string new_playlist_name; Playlist* new_playlist; string dir; AudioRegion* region; string region_name; + AudioDiskstream& diskstream = audio_diskstream(); - if ((_freeze_record.playlist = diskstream->playlist()) == 0) { + if ((_freeze_record.playlist = dynamic_cast<AudioPlaylist*>(diskstream.playlist())) == 0) { return; } @@ -948,7 +775,7 @@ AudioTrack::freeze (InterThreadInfo& itt) } if (n == (UINT_MAX-1)) { - error << string_compose (X_("There Are too many frozen versions of playlist \"%1\"" + error << string_compose (X_("There are too many frozen versions of playlist \"%1\"" " to create another one"), _freeze_record.playlist->name()) << endmsg; return; @@ -966,11 +793,12 @@ AudioTrack::freeze (InterThreadInfo& itt) for (RedirectList::iterator r = _redirects.begin(); r != _redirects.end(); ++r) { - if ((insert = dynamic_cast<Insert*>(*r)) != 0) { + boost::shared_ptr<Insert> insert; + + if ((insert = boost::dynamic_pointer_cast<Insert>(*r)) != 0) { - FreezeRecordInsertInfo* frii = new FreezeRecordInsertInfo ((*r)->get_state()); + FreezeRecordInsertInfo* frii = new FreezeRecordInsertInfo ((*r)->get_state(), insert); - frii->insert = insert; frii->id = insert->id(); frii->memento = (*r)->get_memento(); @@ -993,13 +821,13 @@ AudioTrack::freeze (InterThreadInfo& itt) (AudioRegion::Flag) (AudioRegion::WholeFile|AudioRegion::DefaultFlags), false); - new_playlist->set_orig_diskstream_id (diskstream->id()); + new_playlist->set_orig_diskstream_id (diskstream.id()); new_playlist->add_region (*region, 0); new_playlist->set_frozen (true); region->set_locked (true); - diskstream->use_playlist (dynamic_cast<AudioPlaylist*>(new_playlist)); - diskstream->set_record_enabled (false, this); + diskstream.use_playlist (dynamic_cast<AudioPlaylist*>(new_playlist)); + diskstream.set_record_enabled (false); _freeze_record.state = Frozen; FreezeChange(); /* EMIT SIGNAL */ @@ -1009,7 +837,7 @@ void AudioTrack::unfreeze () { if (_freeze_record.playlist) { - diskstream->use_playlist (_freeze_record.playlist); + audio_diskstream().use_playlist (_freeze_record.playlist); if (_freeze_record.have_mementos) { @@ -1037,116 +865,3 @@ AudioTrack::unfreeze () FreezeChange (); /* EMIT SIGNAL */ } -AudioTrack::FreezeRecord::~FreezeRecord () -{ - for (vector<FreezeRecordInsertInfo*>::iterator i = insert_info.begin(); i != insert_info.end(); ++i) { - delete *i; - } -} - -AudioTrack::FreezeState -AudioTrack::freeze_state() const -{ - return _freeze_record.state; -} - - -void -AudioTrack::reset_midi_control (MIDI::Port* port, bool on) -{ - MIDI::channel_t chn; - MIDI::eventType ev; - MIDI::byte extra; - - Route::reset_midi_control (port, on); - - _midi_rec_enable_control.get_control_info (chn, ev, extra); - if (!on) { - chn = -1; - } - _midi_rec_enable_control.midi_rebind (port, chn); -} - -void -AudioTrack::send_all_midi_feedback () -{ - if (_session.get_midi_feedback()) { - - Route::send_all_midi_feedback(); - - _midi_rec_enable_control.send_feedback (record_enabled()); - } -} - - -AudioTrack::MIDIRecEnableControl::MIDIRecEnableControl (AudioTrack& s, MIDI::Port* port) - : MIDI::Controllable (port, 0), track (s), setting(false) -{ - last_written = false; /* XXX need a good out of bound value */ -} - -void -AudioTrack::MIDIRecEnableControl::set_value (float val) -{ - bool bval = ((val >= 0.5f) ? true: false); - - setting = true; - track.set_record_enable (bval, this); - setting = false; -} - -void -AudioTrack::MIDIRecEnableControl::send_feedback (bool value) -{ - - if (!setting && get_midi_feedback()) { - MIDI::byte val = (MIDI::byte) (value ? 127: 0); - MIDI::channel_t ch = 0; - MIDI::eventType ev = MIDI::none; - MIDI::byte additional = 0; - MIDI::EventTwoBytes data; - - if (get_control_info (ch, ev, additional)) { - data.controller_number = additional; - data.value = val; - - track._session.send_midi_message (get_port(), ev, ch, data); - } - } - -} - -MIDI::byte* -AudioTrack::MIDIRecEnableControl::write_feedback (MIDI::byte* buf, int32_t& bufsize, bool val, bool force) -{ - if (get_midi_feedback()) { - - MIDI::channel_t ch = 0; - MIDI::eventType ev = MIDI::none; - MIDI::byte additional = 0; - - if (get_control_info (ch, ev, additional)) { - if (val != last_written || force) { - *buf++ = ev & ch; - *buf++ = additional; /* controller number */ - *buf++ = (MIDI::byte) (val ? 127: 0); - last_written = val; - bufsize -= 3; - } - } - } - - return buf; -} - -void -AudioTrack::set_mode (TrackMode m) -{ - if (diskstream) { - if (_mode != m) { - _mode = m; - diskstream->set_destructive (m == Destructive); - ModeChanged(); - } - } -} diff --git a/libs/ardour/audio_unit.cc b/libs/ardour/audio_unit.cc new file mode 100644 index 0000000000..0756f55a59 --- /dev/null +++ b/libs/ardour/audio_unit.cc @@ -0,0 +1,362 @@ +/* + Copyright (C) 2006 Paul Davis + Written by 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. + +*/ + +#include <pbd/transmitter.h> +#include <pbd/xml++.h> + +#include <ardour/audioengine.h> +#include <ardour/audio_unit.h> +#include <ardour/session.h> +#include <ardour/utils.h> + +#include <appleutility/CAAudioUnit.h> + +#include <CoreServices/CoreServices.h> +#include <AudioUnit/AudioUnit.h> + +#include "i18n.h" + +using namespace std; +using namespace PBD; +using namespace ARDOUR; + +AUPlugin::AUPlugin (AudioEngine& engine, Session& session, CAComponent* _comp) + : + Plugin (engine, session), + comp (_comp), + unit (new CAAudioUnit) +{ + OSErr err = CAAudioUnit::Open (*comp, *unit); + if (err != noErr) { + error << _("AudioUnit: Could not convert CAComponent to CAAudioUnit") << endmsg; + delete unit; + delete comp; + throw failed_constructor (); + } + + unit->Initialize (); +} + +AUPlugin::~AUPlugin () +{ + if (unit) { + unit->Uninitialize (); + delete unit; + } + + if (comp) { + delete comp; + } +} + +AUPluginInfo::~AUPluginInfo () +{ + if (desc) { + delete desc; + } +} + +uint32_t +AUPlugin::unique_id () const +{ + return 0; +} + +const char * +AUPlugin::label () const +{ + return ""; +} + +const char * +AUPlugin::maker () const +{ + return ""; +} + +uint32_t +AUPlugin::parameter_count () const +{ + return 0; +} + +float +AUPlugin::default_value (uint32_t port) +{ + return 0.0; +} + +jack_nframes_t +AUPlugin::latency () const +{ + return 0; +} + +void +AUPlugin::set_parameter (uint32_t which, float val) +{ + +} + +float +AUPlugin::get_parameter (uint32_t which) const +{ + return 0.0; +} + +int +AUPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const +{ + return -1; +} + +uint32_t +AUPlugin::nth_parameter (uint32_t which, bool& ok) const +{ + return 0; +} + +void +AUPlugin::activate () +{ + +} + +void +AUPlugin::deactivate () +{ + +} + +void +AUPlugin::set_block_size (jack_nframes_t nframes) +{ + +} + +int +AUPlugin::connect_and_run (vector<Sample*>& bufs, uint32_t maxbuf, int32_t& in, int32_t& out, jack_nframes_t nframes, jack_nframes_t offset) +{ + return -1; +} + +set<uint32_t> +AUPlugin::automatable() const +{ + set<uint32_t> automates; + + return automates; +} + +void +AUPlugin::store_state (ARDOUR::PluginState&) +{ + +} + +void +AUPlugin::restore_state (ARDOUR::PluginState&) +{ + +} + +string +AUPlugin::describe_parameter (uint32_t) +{ + return ""; +} + +void +AUPlugin::print_parameter (uint32_t, char*, uint32_t len) const +{ + +} + +bool +AUPlugin::parameter_is_audio (uint32_t) const +{ + return false; +} + +bool +AUPlugin::parameter_is_control (uint32_t) const +{ + return false; +} + +bool +AUPlugin::parameter_is_input (uint32_t) const +{ + return false; +} + +bool +AUPlugin::parameter_is_output (uint32_t) const +{ + return false; +} + +XMLNode& +AUPlugin::get_state() +{ + XMLNode* root = new XMLNode (state_node_name()); + + return *root; +} + +int +AUPlugin::set_state(const XMLNode& node) +{ + return -1; +} + +bool +AUPlugin::save_preset (string name) +{ + return false; +} + +bool +AUPlugin::load_preset (const string preset_label) +{ + return false; +} + +vector<string> +AUPlugin::get_presets () +{ + vector<string> presets; + + return presets; +} + +bool +AUPlugin::has_editor () const +{ + return false; +} + +PluginPtr +AUPluginInfo::load (Session& session) +{ + try { + PluginPtr plugin; + + CAComponent* comp = new CAComponent(*desc); + + if (!comp->IsValid()) { + error << ("AudioUnit: not a valid Component") << endmsg; + } else { + plugin.reset (new AUPlugin (session.engine(), session, comp)); + } + + plugin->set_info(PluginInfoPtr(new AUPluginInfo(*this))); + return plugin; + } + + catch (failed_constructor &err) { + return PluginPtr ((Plugin*) 0); + } +} + +PluginInfoList +AUPluginInfo::discover () +{ + PluginInfoList plugs; + + int numTypes = 2; // this magic number was retrieved from the apple AUHost example. + + CAComponentDescription desc; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + desc.componentSubType = 0; + desc.componentManufacturer = 0; + + for (int i = 0; i < numTypes; ++i) { + if (i == 1) { + desc.componentType = kAudioUnitType_MusicEffect; + } else { + desc.componentType = kAudioUnitType_Effect; + } + + Component comp = 0; + + comp = FindNextComponent (NULL, &desc); + while (comp != NULL) { + CAComponentDescription temp; + GetComponentInfo (comp, &temp, NULL, NULL, NULL); + + AUPluginInfoPtr plug(new AUPluginInfo); + plug->name = AUPluginInfo::get_name (temp); + plug->type = PluginInfo::AudioUnit; + plug->n_inputs = 0; + plug->n_outputs = 0; + plug->category = "AudioUnit"; + plug->desc = new CAComponentDescription(temp); + + plugs.push_back(plug); + + comp = FindNextComponent (comp, &desc); + } + } + + return plugs; +} + +string +AUPluginInfo::get_name (CAComponentDescription& comp_desc) +{ + CFStringRef itemName = NULL; + // Marc Poirier -style item name + CAComponent auComponent (comp_desc); + if (auComponent.IsValid()) { + CAComponentDescription dummydesc; + Handle nameHandle = NewHandle(sizeof(void*)); + if (nameHandle != NULL) { + OSErr err = GetComponentInfo(auComponent.Comp(), &dummydesc, nameHandle, NULL, NULL); + if (err == noErr) { + ConstStr255Param nameString = (ConstStr255Param) (*nameHandle); + if (nameString != NULL) { + itemName = CFStringCreateWithPascalString(kCFAllocatorDefault, nameString, CFStringGetSystemEncoding()); + } + } + DisposeHandle(nameHandle); + } + } + + // if Marc-style fails, do the original way + if (itemName == NULL) { + CFStringRef compTypeString = UTCreateStringForOSType(comp_desc.componentType); + CFStringRef compSubTypeString = UTCreateStringForOSType(comp_desc.componentSubType); + CFStringRef compManufacturerString = UTCreateStringForOSType(comp_desc.componentManufacturer); + + itemName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ - %@ - %@"), + compTypeString, compManufacturerString, compSubTypeString); + + if (compTypeString != NULL) + CFRelease(compTypeString); + if (compSubTypeString != NULL) + CFRelease(compSubTypeString); + if (compManufacturerString != NULL) + CFRelease(compManufacturerString); + } + + return CFStringRefToStdString(itemName); +} diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 5a5e200531..982a7c5971 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -26,6 +26,7 @@ #include <pbd/pthread_utils.h> #include <ardour/audioengine.h> +#include <ardour/buffer.h> #include <ardour/port.h> #include <ardour/session.h> #include <ardour/cycle_timer.h> @@ -42,8 +43,8 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -jack_nframes_t Port::short_over_length = 2; -jack_nframes_t Port::long_over_length = 10; +jack_nframes_t Port::_short_over_length = 2; +jack_nframes_t Port::_long_over_length = 10; AudioEngine::AudioEngine (string client_name) { @@ -274,8 +275,8 @@ AudioEngine::process_callback (jack_nframes_t nframes) Port *port = (*i); bool x; - if (port->last_monitor != (x = port->monitoring_input ())) { - port->last_monitor = x; + if (port->_last_monitor != (x = port->monitoring_input ())) { + port->_last_monitor = x; /* XXX I think this is dangerous, due to a likely mutex in the signal handlers ... */ @@ -388,18 +389,19 @@ AudioEngine::remove_session () } Port * -AudioEngine::register_audio_input_port (const string& portname) +AudioEngine::register_input_port (DataType type, const string& portname) { if (!_running) { if (!_has_run) { - fatal << _("register audio input port called before engine was started") << endmsg; + fatal << _("register input port called before engine was started") << endmsg; /*NOTREACHED*/ } else { return 0; } } - jack_port_t *p = jack_port_register (_jack, portname.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); + jack_port_t *p = jack_port_register (_jack, portname.c_str(), + type.to_jack_type(), JackPortIsInput, 0); if (p) { @@ -419,11 +421,11 @@ AudioEngine::register_audio_input_port (const string& portname) } Port * -AudioEngine::register_audio_output_port (const string& portname) +AudioEngine::register_output_port (DataType type, const string& portname) { if (!_running) { if (!_has_run) { - fatal << _("register audio output port called before engine was started") << endmsg; + fatal << _("register output port called before engine was started") << endmsg; /*NOTREACHED*/ } else { return 0; @@ -432,7 +434,8 @@ AudioEngine::register_audio_output_port (const string& portname) jack_port_t *p; - if ((p = jack_port_register (_jack, portname.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) != 0) { + if ((p = jack_port_register (_jack, portname.c_str(), + type.to_jack_type(), JackPortIsOutput, 0)) != 0) { Port *newport = new Port (p); ports.insert (ports.begin(), newport); return newport; @@ -446,6 +449,7 @@ AudioEngine::register_audio_output_port (const string& portname) return 0; } + int AudioEngine::unregister_port (Port *port) { @@ -458,7 +462,7 @@ AudioEngine::unregister_port (Port *port) if (port) { - int ret = jack_port_unregister (_jack, port->port); + int ret = jack_port_unregister (_jack, port->_port); if (ret == 0) { @@ -549,7 +553,7 @@ AudioEngine::disconnect (Port *port) } } - int ret = jack_port_disconnect (_jack, port->port); + int ret = jack_port_disconnect (_jack, port->_port); if (ret == 0) { remove_connections_for (port); @@ -699,7 +703,6 @@ AudioEngine::n_physical_inputs () const } string - AudioEngine::get_nth_physical (uint32_t n, int flag) { const char ** ports; @@ -747,7 +750,7 @@ AudioEngine::get_port_total_latency (const Port& port) } } - return jack_port_get_total_latency (_jack, port.port); + return jack_port_get_total_latency (_jack, port._port); } void @@ -825,7 +828,7 @@ AudioEngine::remove_all_ports () if (_jack) { for (Ports::iterator i = ports.begin(); i != ports.end(); ++i) { - jack_port_unregister (_jack, (*i)->port); + jack_port_unregister (_jack, (*i)->_port); } } @@ -948,7 +951,7 @@ AudioEngine::reconnect_to_jack () short_name = long_name.substr (long_name.find_last_of (':') + 1); - if (((*i)->port = jack_port_register (_jack, short_name.c_str(), (*i)->type(), (*i)->flags(), 0)) == 0) { + if (((*i)->_port = jack_port_register (_jack, short_name.c_str(), (*i)->type(), (*i)->flags(), 0)) == 0) { error << string_compose (_("could not reregister %1"), (*i)->name()) << endmsg; break; } else { @@ -963,7 +966,7 @@ AudioEngine::reconnect_to_jack () if (i != ports.end()) { for (Ports::iterator i = ports.begin(); i != ports.end(); ++i) { - jack_port_unregister (_jack, (*i)->port); + jack_port_unregister (_jack, (*i)->_port); } return -1; } diff --git a/libs/ardour/audiofilesource.cc b/libs/ardour/audiofilesource.cc index 0663f5f9b1..ee35f3068a 100644 --- a/libs/ardour/audiofilesource.cc +++ b/libs/ardour/audiofilesource.cc @@ -56,8 +56,7 @@ string AudioFileSource::peak_dir = ""; string AudioFileSource::search_path; sigc::signal<void> AudioFileSource::HeaderPositionOffsetChanged; -bool AudioFileSource::header_position_negative; -uint64_t AudioFileSource::header_position_offset; +uint64_t AudioFileSource::header_position_offset = 0; char AudioFileSource::bwf_country_code[3] = "US"; char AudioFileSource::bwf_organization_code[4] = "LAS"; @@ -214,6 +213,10 @@ AudioFileSource::create (const string& idstr, Flag flags) { AudioFileSource* es = 0; + if (flags & Destructive) { + return new DestructiveFileSource (idstr, flags); + } + try { es = new CoreAudioSource (idstr, flags); } @@ -235,25 +238,6 @@ AudioFileSource::create (const string& idstr, Flag flags) #endif // HAVE_COREAUDIO -#ifdef HAVE_COREAUDIO -std::string -CFStringRefToStdString(CFStringRef stringRef) -{ - CFIndex size = - CFStringGetMaximumSizeForEncoding(CFStringGetLength(stringRef) , - kCFStringEncodingASCII); - char *buf = new char[size]; - - std::string result; - - if(CFStringGetCString(stringRef, buf, size, kCFStringEncodingASCII)) { - result = buf; - } - delete [] buf; - return result; -} -#endif // HAVE_COREAUDIO - bool AudioFileSource::get_soundfile_info (string path, SoundFileInfo& _info, string& error_msg) { @@ -592,23 +576,13 @@ AudioFileSource::set_search_path (string p) } void -AudioFileSource::set_header_position_offset (jack_nframes_t offset, bool negative) +AudioFileSource::set_header_position_offset (jack_nframes_t offset) { header_position_offset = offset; - header_position_negative = negative; - + cerr << "hpo set to " << offset << endl; HeaderPositionOffsetChanged (); } -void -AudioFileSource::handle_header_position_change () -{ - if (writable()) { - set_header_timeline_position (); - flush_header (); - } -} - void AudioFileSource::set_timeline_position (jack_nframes_t pos) { @@ -635,6 +609,12 @@ AudioFileSource::set_name (string newname, bool destructive) return -1; } + // Test whether newpath exists, if yes notify the user but continue. + if (access(newpath.c_str(),F_OK) == 0) { + error << _("Programming error! Ardour tried to rename a file over another file! It's safe to continue working, but please report this to the developers.") << endmsg; + return -1; + } + if (rename (oldpath.c_str(), newpath.c_str()) != 0) { error << string_compose (_("cannot rename audio file for %1 to %2"), _name, newpath) << endmsg; return -1; diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index 6b118faa51..20d1dbfbd6 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -48,13 +48,13 @@ using namespace ARDOUR; /* a Session will reset these to its chosen defaults by calling AudioRegion::set_default_fade() */ -Change AudioRegion::FadeInChanged = ARDOUR::new_change(); -Change AudioRegion::FadeOutChanged = ARDOUR::new_change(); -Change AudioRegion::FadeInActiveChanged = ARDOUR::new_change(); -Change AudioRegion::FadeOutActiveChanged = ARDOUR::new_change(); +Change AudioRegion::FadeInChanged = ARDOUR::new_change(); +Change AudioRegion::FadeOutChanged = ARDOUR::new_change(); +Change AudioRegion::FadeInActiveChanged = ARDOUR::new_change(); +Change AudioRegion::FadeOutActiveChanged = ARDOUR::new_change(); Change AudioRegion::EnvelopeActiveChanged = ARDOUR::new_change(); Change AudioRegion::ScaleAmplitudeChanged = ARDOUR::new_change(); -Change AudioRegion::EnvelopeChanged = ARDOUR::new_change(); +Change AudioRegion::EnvelopeChanged = ARDOUR::new_change(); AudioRegionState::AudioRegionState (string why) : RegionState (why), @@ -267,8 +267,6 @@ AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node) _fade_out (0.0, 2.0, 1.0, false), _envelope (0.0, 2.0, 1.0, false) { - /* basic AudioRegion constructor */ - set<AudioSource*> unique_srcs; for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) { @@ -636,12 +634,6 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff } XMLNode& -AudioRegion::get_state () -{ - return state (true); -} - -XMLNode& AudioRegion::state (bool full) { XMLNode& node (Region::state (full)); @@ -652,12 +644,12 @@ AudioRegion::state (bool full) snprintf (buf, sizeof (buf), "0x%x", (int) _flags); node.add_property ("flags", buf); - snprintf (buf, sizeof(buf), "%f", _scale_amplitude); + snprintf (buf, sizeof(buf), "%.12g", _scale_amplitude); node.add_property ("scale-gain", buf); for (uint32_t n=0; n < sources.size(); ++n) { snprintf (buf2, sizeof(buf2), "source-%d", n); - snprintf (buf, sizeof(buf), "%" PRIu64, sources[n]->id()); + sources[n]->id().print (buf); node.add_property (buf2, buf); } @@ -1141,24 +1133,22 @@ AudioRegion::master_source_names () } bool -AudioRegion::region_list_equivalent (const AudioRegion& other) const +AudioRegion::source_equivalent (const Region& o) const { - return size_equivalent (other) && source_equivalent (other) && _name == other._name; -} + const AudioRegion* other = dynamic_cast<const AudioRegion*>(&o); + if (!other) + return false; -bool -AudioRegion::source_equivalent (const AudioRegion& other) const -{ SourceList::const_iterator i; SourceList::const_iterator io; - for (i = sources.begin(), io = other.sources.begin(); i != sources.end() && io != other.sources.end(); ++i, ++io) { + for (i = sources.begin(), io = other->sources.begin(); i != sources.end() && io != other->sources.end(); ++i, ++io) { if ((*i)->id() != (*io)->id()) { return false; } } - for (i = master_sources.begin(), io = other.master_sources.begin(); i != master_sources.end() && io != other.master_sources.end(); ++i, ++io) { + for (i = master_sources.begin(), io = other->master_sources.begin(); i != master_sources.end() && io != other->master_sources.end(); ++i, ++io) { if ((*i)->id() != (*io)->id()) { return false; } @@ -1167,27 +1157,6 @@ AudioRegion::source_equivalent (const AudioRegion& other) const return true; } -bool -AudioRegion::overlap_equivalent (const AudioRegion& other) const -{ - return coverage (other.first_frame(), other.last_frame()) != OverlapNone; -} - -bool -AudioRegion::equivalent (const AudioRegion& other) const -{ - return _start == other._start && - _position == other._position && - _length == other._length; -} - -bool -AudioRegion::size_equivalent (const AudioRegion& other) const -{ - return _start == other._start && - _length == other._length; -} - int AudioRegion::apply (AudioFilter& filter) { @@ -1289,7 +1258,7 @@ AudioRegion::set_scale_amplitude (gain_t g) void AudioRegion::normalize_to (float target_dB) { - const jack_nframes_t blocksize = 256 * 1048; + const jack_nframes_t blocksize = 64 * 1024; Sample buf[blocksize]; char workbuf[blocksize * 4]; jack_nframes_t fpos; @@ -1410,7 +1379,7 @@ AudioRegion::speed_mismatch (float sr) const float fsr = sources.front()->sample_rate(); - return fsr == sr; + return fsr != sr; } extern "C" { diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc index add9364cad..bf7a32c885 100644 --- a/libs/ardour/audiosource.cc +++ b/libs/ardour/audiosource.cc @@ -640,7 +640,7 @@ AudioSource::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t to_read = min (chunksize, (_length - current_frame)); - if ((frames_read = read_unlocked (raw_staging, current_frame, to_read, workbuf)) < 0) { + if ((frames_read = read_unlocked (raw_staging, current_frame, to_read, workbuf)) == 0) { error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3") , _name, to_read, current_frame) << endmsg; diff --git a/libs/ardour/auditioner.cc b/libs/ardour/auditioner.cc index 2f0b943c0e..e48f103b9f 100644 --- a/libs/ardour/auditioner.cc +++ b/libs/ardour/auditioner.cc @@ -27,6 +27,7 @@ #include <ardour/auditioner.h> #include <ardour/audioplaylist.h> #include <ardour/panner.h> +#include <ardour/data_type.h> using namespace std; using namespace ARDOUR; @@ -44,12 +45,12 @@ Auditioner::Auditioner (Session& s) defer_pan_reset (); if (left.length()) { - add_output_port (left, this); + add_output_port (left, this, DataType::AUDIO); } if (right.length()) { - disk_stream().add_channel(); - add_output_port (right, this); + audio_diskstream().add_channel(); + add_output_port (right, this, DataType::AUDIO); } allow_pan_reset (); @@ -67,8 +68,12 @@ Auditioner::~Auditioner () AudioPlaylist& Auditioner::prepare_playlist () { - diskstream->playlist()->clear (false, false); - return *diskstream->playlist(); + // FIXME auditioner is still audio-only + AudioPlaylist* const apl = dynamic_cast<AudioPlaylist*>(_diskstream->playlist()); + assert(apl); + + apl->clear (false, false); + return *apl; } void @@ -82,13 +87,13 @@ Auditioner::audition_current_playlist () } Glib::Mutex::Lock lm (lock); - diskstream->seek (0); - length = diskstream->playlist()->get_maximum_extent(); + _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()); + _panner->reset (n_outputs(), _diskstream->n_channels()); g_atomic_int_set (&_active, 1); } @@ -108,23 +113,23 @@ Auditioner::audition_region (AudioRegion& region) 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); + _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()) { + audio_diskstream().add_channel (); } - while (diskstream->n_channels() > the_region->n_channels()) { - diskstream->remove_channel (); + while (_diskstream->n_channels() > the_region->n_channels()) { + audio_diskstream().remove_channel (); } /* force a panner reset now that we have all channels */ - _panner->reset (n_outputs(), diskstream->n_channels()); + _panner->reset (n_outputs(), _diskstream->n_channels()); length = the_region->length(); - diskstream->seek (0); + _diskstream->seek (0); current_frame = 0; g_atomic_int_set (&_active, 1); } @@ -143,14 +148,14 @@ Auditioner::play_audition (jack_nframes_t nframes) this_nframes = min (nframes, length - current_frame); - diskstream->prepare (); + _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); + need_butler = _diskstream->commit (this_nframes); current_frame += this_nframes; if (current_frame >= length) { diff --git a/libs/ardour/automation_event.cc b/libs/ardour/automation_event.cc index a9e76ac55c..dc1767d1e7 100644 --- a/libs/ardour/automation_event.cc +++ b/libs/ardour/automation_event.cc @@ -1211,7 +1211,7 @@ AutomationList::store_state (XMLNode& node) const snprintf (buf, sizeof (buf), "%" PRIu32, (jack_nframes_t) floor ((*i)->when)); pointnode->add_property ("x", buf); - snprintf (buf, sizeof (buf), "%f", (*i)->value); + snprintf (buf, sizeof (buf), "%.12g", (*i)->value); pointnode->add_property ("y", buf); node.add_child_nocopy (*pointnode); diff --git a/libs/ardour/configuration.cc b/libs/ardour/configuration.cc index fc708f805d..58da77f933 100644 --- a/libs/ardour/configuration.cc +++ b/libs/ardour/configuration.cc @@ -25,6 +25,7 @@ #include <pbd/xml++.h> #include <ardour/ardour.h> +#include <ardour/audio_library.h> #include <ardour/configuration.h> #include <ardour/audio_diskstream.h> #include <ardour/destructive_filesource.h> @@ -178,6 +179,7 @@ Configuration::state (bool user_only) } root->add_child_nocopy (ControlProtocolManager::instance().get_state()); + root->add_child_nocopy (Library->get_state()); return *root; } @@ -229,6 +231,8 @@ Configuration::set_state (const XMLNode& root) } else if (node->name() == ControlProtocolManager::state_node_name) { _control_protocol_state = new XMLNode (*node); + } else if (node->name() == AudioLibrary::state_node_name) { + Library->set_state (*node); } } diff --git a/libs/ardour/control_protocol_manager.cc b/libs/ardour/control_protocol_manager.cc index c2fb188953..0370886a35 100644 --- a/libs/ardour/control_protocol_manager.cc +++ b/libs/ardour/control_protocol_manager.cc @@ -49,6 +49,10 @@ ControlProtocolManager::set_session (Session& s) if ((*i)->requested || (*i)->mandatory) { instantiate (**i); (*i)->requested = false; + + if ((*i)->state) { + (*i)->protocol->set_state (*(*i)->state); + } } } } @@ -181,6 +185,7 @@ ControlProtocolManager::control_protocol_discover (string path) cpi->protocol = 0; cpi->requested = false; cpi->mandatory = descriptor->mandatory; + cpi->state = 0; control_protocol_info.push_back (cpi); diff --git a/libs/ardour/coreaudiosource.cc b/libs/ardour/coreaudiosource.cc index 55409a8524..5e9de225d4 100644 --- a/libs/ardour/coreaudiosource.cc +++ b/libs/ardour/coreaudiosource.cc @@ -68,13 +68,13 @@ CoreAudioSource::init (const string& idstr) FSRef fsr; err = FSPathMakeRef ((UInt8*)file.c_str(), &fsr, 0); if (err != noErr) { - cerr << "FSPathMakeRef " << err << endl; + error << string_compose (_("Could not make reference to file: %1"), name()) << endmsg; throw failed_constructor(); } err = ExtAudioFileOpen (&fsr, &af); if (err != noErr) { - cerr << "ExtAudioFileOpen " << err << endl; + error << string_compose (_("Could not open file: %1"), name()) << endmsg; ExtAudioFileDispose (af); throw failed_constructor(); } @@ -85,7 +85,7 @@ CoreAudioSource::init (const string& idstr) err = ExtAudioFileGetProperty(af, kExtAudioFileProperty_FileDataFormat, &asbd_size, &file_asbd); if (err != noErr) { - cerr << "ExtAudioFileGetProperty1 " << err << endl; + error << string_compose (_("Could not get file data format for file: %1"), name()) << endmsg; ExtAudioFileDispose (af); throw failed_constructor(); } @@ -104,7 +104,7 @@ CoreAudioSource::init (const string& idstr) err = ExtAudioFileGetProperty(af, kExtAudioFileProperty_FileLengthFrames, &prop_size, &ca_frames); if (err != noErr) { - cerr << "ExtAudioFileGetProperty2 " << err << endl; + error << string_compose (_("Could not get file length for file: %1"), name()) << endmsg; ExtAudioFileDispose (af); throw failed_constructor(); } @@ -125,14 +125,14 @@ CoreAudioSource::init (const string& idstr) err = ExtAudioFileSetProperty (af, kExtAudioFileProperty_ClientDataFormat, asbd_size, &client_asbd); if (err != noErr) { - cerr << "ExtAudioFileSetProperty3 " << err << endl; + error << string_compose (_("Could not set client data format for file: %1"), name()) << endmsg; ExtAudioFileDispose (af); throw failed_constructor (); } if (_build_peakfiles) { if (initialize_peakfile (false, file)) { - error << "initialize peakfile failed" << endmsg; + error << string_compose(_("initialize peakfile failed for file %1"), name()) << endmsg; ExtAudioFileDispose (af); throw failed_constructor (); } @@ -212,7 +212,24 @@ CoreAudioSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_ float CoreAudioSource::sample_rate() const { - /* XXX taybin fill me in please */ + AudioStreamBasicDescription client_asbd; + memset(&client_asbd, 0, sizeof(AudioStreamBasicDescription)); - return 44100.0f; + OSStatus err = noErr; + size_t asbd_size = sizeof(AudioStreamBasicDescription); + + err = ExtAudioFileSetProperty (af, kExtAudioFileProperty_ClientDataFormat, asbd_size, &client_asbd); + if (err != noErr) { + error << string_compose(_("Could not detect samplerate for: %1"), name()) << endmsg; + return 0.0; + } + + return client_asbd.mSampleRate; } + +int +CoreAudioSource::update_header (jack_nframes_t when, struct tm&, time_t) +{ + return 0; +} + diff --git a/libs/ardour/crossfade.cc b/libs/ardour/crossfade.cc index 5d36c63f01..dc4c074844 100644 --- a/libs/ardour/crossfade.cc +++ b/libs/ardour/crossfade.cc @@ -112,7 +112,6 @@ Crossfade::Crossfade (const Playlist& playlist, XMLNode& node) { 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 */ @@ -122,7 +121,7 @@ Crossfade::Crossfade (const Playlist& playlist, XMLNode& node) throw failed_constructor(); } - sscanf (prop->value().c_str(), "%" PRIu64, &id); + PBD::ID id (prop->value()); if ((r = playlist.find_region (id)) == 0) { error << string_compose (_("Crossfade: no \"in\" region %1 found in playlist %2"), id, playlist.name()) @@ -139,10 +138,10 @@ Crossfade::Crossfade (const Playlist& playlist, XMLNode& node) throw failed_constructor(); } - sscanf (prop->value().c_str(), "%" PRIu64, &id); + PBD::ID id2 (prop->value()); - if ((r = playlist.find_region (id)) == 0) { - error << string_compose (_("Crossfade: no \"out\" region %1 found in playlist %2"), id, playlist.name()) + if ((r = playlist.find_region (id2)) == 0) { + error << string_compose (_("Crossfade: no \"out\" region %1 found in playlist %2"), id2, playlist.name()) << endmsg; throw failed_constructor(); } @@ -680,9 +679,9 @@ Crossfade::get_state () char buf[64]; LocaleGuard lg (X_("POSIX")); - snprintf (buf, sizeof(buf), "%" PRIu64, _out->id()); + _out->id().print (buf); node->add_property ("out", buf); - snprintf (buf, sizeof(buf), "%" PRIu64, _in->id()); + _in->id().print (buf); node->add_property ("in", buf); node->add_property ("active", (_active ? "yes" : "no")); node->add_property ("follow-overlap", (_follow_overlap ? "yes" : "no")); @@ -703,7 +702,7 @@ Crossfade::get_state () snprintf (buf, sizeof (buf), "%" PRIu32, (jack_nframes_t) floor ((*ii)->when)); pnode->add_property ("x", buf); - snprintf (buf, sizeof (buf), "%f", (*ii)->value); + snprintf (buf, sizeof (buf), "%.12g", (*ii)->value); pnode->add_property ("y", buf); child->add_child_nocopy (*pnode); } @@ -717,7 +716,7 @@ Crossfade::get_state () snprintf (buf, sizeof (buf), "%" PRIu32, (jack_nframes_t) floor ((*ii)->when)); pnode->add_property ("x", buf); - snprintf (buf, sizeof (buf), "%f", (*ii)->value); + snprintf (buf, sizeof (buf), "%.12g", (*ii)->value); pnode->add_property ("y", buf); child->add_child_nocopy (*pnode); } diff --git a/libs/ardour/destructive_filesource.cc b/libs/ardour/destructive_filesource.cc index cce757509a..43fafff30a 100644 --- a/libs/ardour/destructive_filesource.cc +++ b/libs/ardour/destructive_filesource.cc @@ -70,21 +70,33 @@ jack_nframes_t DestructiveFileSource::xfade_frames = 64; DestructiveFileSource::DestructiveFileSource (string path, SampleFormat samp_format, HeaderFormat hdr_format, jack_nframes_t rate, Flag flags) : SndFileSource (path, samp_format, hdr_format, rate, flags) { - xfade_buf = new Sample[xfade_frames]; + init (); +} - _capture_start = false; - _capture_end = false; - file_pos = 0; + +DestructiveFileSource::DestructiveFileSource (string path, Flag flags) + : SndFileSource (path, flags) +{ + init (); } DestructiveFileSource::DestructiveFileSource (const XMLNode& node) : SndFileSource (node) { + init (); +} + +void +DestructiveFileSource::init () +{ xfade_buf = new Sample[xfade_frames]; _capture_start = false; _capture_end = false; file_pos = 0; + + timeline_position = header_position_offset; + AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &DestructiveFileSource::handle_header_position_change)); } DestructiveFileSource::~DestructiveFileSource() @@ -124,8 +136,12 @@ DestructiveFileSource::setup_standard_crossfades (jack_nframes_t rate) void DestructiveFileSource::mark_capture_start (jack_nframes_t pos) { - _capture_start = true; - capture_start_frame = pos; + if (pos < timeline_position) { + _capture_start = false; + } else { + _capture_start = true; + capture_start_frame = pos; + } } void @@ -265,6 +281,11 @@ DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t cnt, char * } if (_capture_start && _capture_end) { + + /* start and end of capture both occur within the data we are writing, + so do both crossfades. + */ + _capture_start = false; _capture_end = false; @@ -290,8 +311,12 @@ DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t cnt, char * } file_pos = ofilepos; // adjusted below - } - else if (_capture_start) { + + } else if (_capture_start) { + + /* start of capture both occur within the data we are writing, + so do the fade in + */ _capture_start = false; _capture_end = false; @@ -305,6 +330,10 @@ DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t cnt, char * } else if (_capture_end) { + /* end of capture both occur within the data we are writing, + so do the fade out + */ + _capture_start = false; _capture_end = false; @@ -314,6 +343,8 @@ DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t cnt, char * } else { + /* in the middle of recording */ + if (write_float (data, file_pos, cnt) != cnt) { return 0; } @@ -366,8 +397,19 @@ DestructiveFileSource::get_state () } void +DestructiveFileSource::handle_header_position_change () +{ + if ( _length != 0 ) { + error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg; + //in the future, pop up a dialog here that allows user to regenerate file with new start offset + } else if (writable()) { + timeline_position = header_position_offset; + set_header_timeline_position (); //this will get flushed if/when the file is recorded to + } +} + +void DestructiveFileSource::set_timeline_position (jack_nframes_t pos) { - /* destructive tracks always start at where our reference frame zero is */ - timeline_position = 0; + //destructive track timeline postion does not change except at instantion or when header_position_offset (session start) changes } diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc new file mode 100644 index 0000000000..9312de5bf1 --- /dev/null +++ b/libs/ardour/diskstream.cc @@ -0,0 +1,401 @@ +/* + Copyright (C) 2000-2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: diskstream.cc 567 2006-06-07 14:54:12Z trutkin $ +*/ + +#include <fstream> +#include <cstdio> +#include <unistd.h> +#include <cmath> +#include <cerrno> +#include <string> +#include <climits> +#include <fcntl.h> +#include <cstdlib> +#include <ctime> +#include <sys/stat.h> +#include <sys/mman.h> + +#include <pbd/error.h> +#include <pbd/basename.h> +#include <glibmm/thread.h> +#include <pbd/xml++.h> + +#include <ardour/ardour.h> +#include <ardour/audioengine.h> +#include <ardour/diskstream.h> +#include <ardour/utils.h> +#include <ardour/configuration.h> +#include <ardour/audiofilesource.h> +#include <ardour/destructive_filesource.h> +#include <ardour/send.h> +#include <ardour/playlist.h> +#include <ardour/cycle_timer.h> +#include <ardour/region.h> + +#include "i18n.h" +#include <locale.h> + +using namespace std; +using namespace ARDOUR; +using namespace PBD; + +jack_nframes_t Diskstream::disk_io_chunk_frames = 0; + +sigc::signal<void,Diskstream*> Diskstream::DiskstreamCreated; +sigc::signal<void,list<Source*>*> Diskstream::DeleteSources; +sigc::signal<void> Diskstream::DiskOverrun; +sigc::signal<void> Diskstream::DiskUnderrun; + +Diskstream::Diskstream (Session &sess, const string &name, Flag flag) + : _name (name) + , _session (sess) + , _playlist(NULL) +{ + init (flag); +} + +Diskstream::Diskstream (Session& sess, const XMLNode& node) + : _session (sess) + , _playlist(NULL) +{ + init (Recordable); +} + +void +Diskstream::init (Flag f) +{ + _refcnt = 0; + _flags = f; + _io = 0; + _alignment_style = ExistingMaterial; + _persistent_alignment_style = ExistingMaterial; + first_input_change = true; + i_am_the_modifier = 0; + g_atomic_int_set (&_record_enabled, 0); + was_recording = false; + capture_start_frame = 0; + capture_captured = 0; + _visible_speed = 1.0f; + _actual_speed = 1.0f; + _buffer_reallocation_required = false; + _seek_required = false; + first_recordable_frame = max_frames; + last_recordable_frame = max_frames; + _roll_delay = 0; + _capture_offset = 0; + _processed = false; + _slaved = false; + adjust_capture_position = 0; + last_possibly_recording = 0; + loop_location = 0; + wrap_buffer_size = 0; + speed_buffer_size = 0; + last_phase = 0; + phi = (uint64_t) (0x1000000); + file_frame = 0; + playback_sample = 0; + playback_distance = 0; + _read_data_count = 0; + _write_data_count = 0; + + pending_overwrite = false; + overwrite_frame = 0; + overwrite_queued = false; + input_change_pending = NoChange; + + _n_channels = 0; +} + +Diskstream::~Diskstream () +{ + // Taken by derived class destrctors.. should assure locked here somehow? + //Glib::Mutex::Lock lm (state_lock); + + if (_playlist) + _playlist->unref (); +} + +void +Diskstream::set_io (IO& io) +{ + _io = &io; + set_align_style_from_io (); +} + +void +Diskstream::handle_input_change (IOChange change, void *src) +{ + Glib::Mutex::Lock lm (state_lock); + + if (!(input_change_pending & change)) { + input_change_pending = IOChange (input_change_pending|change); + _session.request_input_change_handling (); + } +} + +void +Diskstream::non_realtime_set_speed () +{ + if (_buffer_reallocation_required) + { + Glib::Mutex::Lock lm (state_lock); + allocate_temporary_buffers (); + + _buffer_reallocation_required = false; + } + + if (_seek_required) { + if (speed() != 1.0f || speed() != -1.0f) { + seek ((jack_nframes_t) (_session.transport_frame() * (double) speed()), true); + } + else { + seek (_session.transport_frame(), true); + } + + _seek_required = false; + } +} + +bool +Diskstream::realtime_set_speed (double sp, bool global) +{ + bool changed = false; + double new_speed = sp * _session.transport_speed(); + + if (_visible_speed != sp) { + _visible_speed = sp; + changed = true; + } + + if (new_speed != _actual_speed) { + + jack_nframes_t required_wrap_size = (jack_nframes_t) floor (_session.get_block_size() * + fabs (new_speed)) + 1; + + if (required_wrap_size > wrap_buffer_size) { + _buffer_reallocation_required = true; + } + + _actual_speed = new_speed; + phi = (uint64_t) (0x1000000 * fabs(_actual_speed)); + } + + if (changed) { + if (!global) { + _seek_required = true; + } + SpeedChanged (); /* EMIT SIGNAL */ + } + + return _buffer_reallocation_required || _seek_required; +} + +void +Diskstream::prepare () +{ + _processed = false; + playback_distance = 0; +} + +void +Diskstream::recover () +{ + state_lock.unlock(); + _processed = false; +} + +void +Diskstream::set_capture_offset () +{ + if (_io == 0) { + /* can't capture, so forget it */ + return; + } + + _capture_offset = _io->input_latency(); +} + +void +Diskstream::set_align_style (AlignStyle a) +{ + if (record_enabled() && _session.actively_recording()) { + return; + } + + if (a != _alignment_style) { + _alignment_style = a; + AlignmentStyleChanged (); + } +} + +int +Diskstream::set_loop (Location *location) +{ + if (location) { + if (location->start() >= location->end()) { + error << string_compose(_("Location \"%1\" not valid for track loop (start >= end)"), location->name()) << endl; + return -1; + } + } + + loop_location = location; + + LoopSet (location); /* EMIT SIGNAL */ + return 0; +} + +jack_nframes_t +Diskstream::get_capture_start_frame (uint32_t n) +{ + Glib::Mutex::Lock lm (capture_info_lock); + + if (capture_info.size() > n) { + return capture_info[n]->start; + } + else { + return capture_start_frame; + } +} + +jack_nframes_t +Diskstream::get_captured_frames (uint32_t n) +{ + Glib::Mutex::Lock lm (capture_info_lock); + + if (capture_info.size() > n) { + return capture_info[n]->frames; + } + else { + return capture_captured; + } +} + +void +Diskstream::set_roll_delay (jack_nframes_t nframes) +{ + _roll_delay = nframes; +} + +void +Diskstream::set_speed (double sp) +{ + _session.request_diskstream_speed (*this, sp); + + /* to force a rebuffering at the right place */ + playlist_modified(); +} + +int +Diskstream::use_playlist (Playlist* playlist) +{ + { + Glib::Mutex::Lock lm (state_lock); + + if (playlist == _playlist) { + return 0; + } + + plstate_connection.disconnect(); + plmod_connection.disconnect (); + plgone_connection.disconnect (); + + if (_playlist) { + _playlist->unref(); + } + + _playlist = playlist; + _playlist->ref(); + + if (!in_set_state && recordable()) { + reset_write_sources (false); + } + + plstate_connection = _playlist->StateChanged.connect (mem_fun (*this, &Diskstream::playlist_changed)); + plmod_connection = _playlist->Modified.connect (mem_fun (*this, &Diskstream::playlist_modified)); + plgone_connection = _playlist->GoingAway.connect (mem_fun (*this, &Diskstream::playlist_deleted)); + } + + if (!overwrite_queued) { + _session.request_overwrite_buffer (this); + overwrite_queued = true; + } + + PlaylistChanged (); /* EMIT SIGNAL */ + _session.set_dirty (); + + return 0; +} + +void +Diskstream::playlist_changed (Change ignored) +{ + playlist_modified (); +} + +void +Diskstream::playlist_modified () +{ + if (!i_am_the_modifier && !overwrite_queued) { + _session.request_overwrite_buffer (this); + overwrite_queued = true; + } +} + +void +Diskstream::playlist_deleted (Playlist* pl) +{ + /* this catches an ordering issue with session destruction. playlists + are destroyed before diskstreams. we have to invalidate any handles + we have to the playlist. + */ + + _playlist = 0; +} + +int +Diskstream::set_name (string str) +{ + if (str != _name) { + assert(playlist()); + playlist()->set_name (str); + _name = str; + + if (!in_set_state && recordable()) { + /* rename existing capture files so that they have the correct name */ + return rename_write_sources (); + } else { + return -1; + } + } + + return 0; +} + +void +Diskstream::set_destructive (bool yn) +{ + if (yn != destructive()) { + reset_write_sources (true, true); + if (yn) { + _flags |= Destructive; + } else { + _flags &= ~Destructive; + } + } +} diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index f80c9dc287..1342c0147b 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -32,6 +32,7 @@ #include <lrdf.h> #include <pbd/error.h> +#include <pbd/id.h> #include <pbd/strsplit.h> #include <midi++/port.h> @@ -189,12 +190,17 @@ setup_midi () } int -ARDOUR::init (AudioEngine& engine, bool use_vst, bool try_optimization) +ARDOUR::init (bool use_vst, bool try_optimization) { bool generic_mix_functions = true; (void) bindtextdomain(PACKAGE, LOCALEDIR); + PBD::ID::init (); + + lrdf_init(); + Library = new AudioLibrary; + Config = new Configuration; if (Config->load_state ()) { @@ -292,12 +298,9 @@ ARDOUR::init (AudioEngine& engine, bool use_vst, bool try_optimization) info << "No H/W specific optimizations in use" << endmsg; } - - lrdf_init(); - Library = new AudioLibrary; /* singleton - first object is "it" */ - new PluginManager (engine); + new PluginManager (); /* singleton - first object is "it" */ new ControlProtocolManager (); @@ -322,10 +325,15 @@ ARDOUR::cleanup () return 0; } -ARDOUR::id_t -ARDOUR::new_id () + +microseconds_t +ARDOUR::get_microseconds () { - return get_uid(); + /* XXX need JACK to export its functionality */ + + struct timeval now; + gettimeofday (&now, 0); + return now.tv_sec * 1000000ULL + now.tv_usec; } ARDOUR::Change diff --git a/libs/ardour/insert.cc b/libs/ardour/insert.cc index fc05355d4a..a057fef931 100644 --- a/libs/ardour/insert.cc +++ b/libs/ardour/insert.cc @@ -62,12 +62,12 @@ Insert::Insert(Session& s, string name, Placement p) const string PluginInsert::port_automation_node_name = "PortAutomation"; -PluginInsert::PluginInsert (Session& s, Plugin& plug, Placement placement) - : Insert (s, plug.name(), placement) +PluginInsert::PluginInsert (Session& s, boost::shared_ptr<Plugin> plug, Placement placement) + : Insert (s, plug->name(), placement) { /* the first is the master */ - _plugins.push_back(&plug); + _plugins.push_back (plug); _plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed)); @@ -103,13 +103,13 @@ PluginInsert::PluginInsert (Session& s, const XMLNode& node) } PluginInsert::PluginInsert (const PluginInsert& other) - : Insert (other._session, other.plugin().name(), other.placement()) + : Insert (other._session, other.plugin()->name(), other.placement()) { uint32_t count = other._plugins.size(); /* make as many copies as requested */ for (uint32_t n = 0; n < count; ++n) { - _plugins.push_back (plugin_factory (other.plugin())); + _plugins.push_back (plugin_factory (other.plugin (n))); } @@ -137,7 +137,7 @@ PluginInsert::set_count (uint32_t num) uint32_t diff = num - _plugins.size(); for (uint32_t n = 0; n < diff; ++n) { - _plugins.push_back (plugin_factory (*_plugins[0])); + _plugins.push_back (plugin_factory (_plugins[0])); if (require_state) { /* XXX do something */ @@ -147,9 +147,7 @@ PluginInsert::set_count (uint32_t num) } else if (num < _plugins.size()) { uint32_t diff = _plugins.size() - num; for (uint32_t n= 0; n < diff; ++n) { - Plugin * plug = _plugins.back(); _plugins.pop_back(); - delete plug; } } @@ -167,12 +165,6 @@ PluginInsert::init () PluginInsert::~PluginInsert () { GoingAway (this); /* EMIT SIGNAL */ - - while (!_plugins.empty()) { - Plugin* p = _plugins.back(); - _plugins.pop_back(); - delete p; - } } void @@ -194,25 +186,25 @@ PluginInsert::auto_state_changed (uint32_t which) uint32_t PluginInsert::output_streams() const { - return _plugins[0]->get_info().n_outputs * _plugins.size(); + return _plugins[0]->get_info()->n_outputs * _plugins.size(); } uint32_t PluginInsert::input_streams() const { - return _plugins[0]->get_info().n_inputs * _plugins.size(); + return _plugins[0]->get_info()->n_inputs * _plugins.size(); } uint32_t PluginInsert::natural_output_streams() const { - return _plugins[0]->get_info().n_outputs; + return _plugins[0]->get_info()->n_outputs; } uint32_t PluginInsert::natural_input_streams() const { - return _plugins[0]->get_info().n_inputs; + return _plugins[0]->get_info()->n_inputs; } bool @@ -222,7 +214,7 @@ PluginInsert::is_generator() const a specific "instrument" flag, for example. */ - return _plugins[0]->get_info().n_inputs == 0; + return _plugins[0]->get_info()->n_inputs == 0; } void @@ -240,7 +232,7 @@ PluginInsert::set_automatable () void PluginInsert::parameter_changed (uint32_t which, float val) { - vector<Plugin*>::iterator i = _plugins.begin(); + vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); /* don't set the first plugin, just all the slaves */ @@ -255,7 +247,7 @@ PluginInsert::parameter_changed (uint32_t which, float val) void PluginInsert::set_block_size (jack_nframes_t nframes) { - for (vector<Plugin*>::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { + for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { (*i)->set_block_size (nframes); } } @@ -263,7 +255,7 @@ PluginInsert::set_block_size (jack_nframes_t nframes) void PluginInsert::activate () { - for (vector<Plugin*>::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { + for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { (*i)->activate (); } } @@ -271,7 +263,7 @@ PluginInsert::activate () void PluginInsert::deactivate () { - for (vector<Plugin*>::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { + for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { (*i)->deactivate (); } } @@ -309,7 +301,7 @@ PluginInsert::connect_and_run (vector<Sample*>& bufs, uint32_t nbufs, jack_nfram } } - for (vector<Plugin*>::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { + for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { (*i)->connect_and_run (bufs, nbufs, in_index, out_index, nframes, offset); } @@ -357,8 +349,8 @@ PluginInsert::silence (jack_nframes_t nframes, jack_nframes_t offset) uint32_t n; if (active()) { - for (vector<Plugin*>::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { - n = (*i) -> get_info().n_inputs; + for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { + n = (*i) -> get_info()->n_inputs; (*i)->connect_and_run (_session.get_silent_buffers (n), n, in_index, out_index, nframes, offset); } } @@ -375,8 +367,8 @@ PluginInsert::run (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframe connect_and_run (bufs, nbufs, nframes, offset, false); } } else { - uint32_t in = _plugins[0]->get_info().n_inputs; - uint32_t out = _plugins[0]->get_info().n_outputs; + uint32_t in = _plugins[0]->get_info()->n_inputs; + uint32_t out = _plugins[0]->get_info()->n_outputs; if (out > in) { @@ -506,19 +498,19 @@ PluginInsert::protect_automation () } } -Plugin* -PluginInsert::plugin_factory (Plugin& other) +boost::shared_ptr<Plugin> +PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other) { - LadspaPlugin* lp; + boost::shared_ptr<LadspaPlugin> lp; #ifdef VST_SUPPORT - VSTPlugin* vp; + boost::shared_ptr<VSTPlugin> vp; #endif - if ((lp = dynamic_cast<LadspaPlugin*> (&other)) != 0) { - return new LadspaPlugin (*lp); + if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) { + return boost::shared_ptr<Plugin> (new LadspaPlugin (*lp)); #ifdef VST_SUPPORT - } else if ((vp = dynamic_cast<VSTPlugin*> (&other)) != 0) { - return new VSTPlugin (*vp); + } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) { + return boost::shared_ptr<Plugin> (new VSTPlugin (*vp)); #endif } @@ -526,13 +518,13 @@ PluginInsert::plugin_factory (Plugin& other) X_("unknown plugin type in PluginInsert::plugin_factory")) << endmsg; /*NOTREACHED*/ - return 0; + return boost::shared_ptr<Plugin> ((Plugin*) 0); } int32_t PluginInsert::compute_output_streams (int32_t cnt) const { - return _plugins[0]->get_info().n_outputs * cnt; + return _plugins[0]->get_info()->n_outputs * cnt; } int32_t @@ -544,8 +536,8 @@ PluginInsert::configure_io (int32_t magic, int32_t in, int32_t out) int32_t PluginInsert::can_support_input_configuration (int32_t in) const { - int32_t outputs = _plugins[0]->get_info().n_outputs; - int32_t inputs = _plugins[0]->get_info().n_inputs; + int32_t outputs = _plugins[0]->get_info()->n_outputs; + int32_t inputs = _plugins[0]->get_info()->n_inputs; if (inputs == 0) { @@ -599,7 +591,7 @@ PluginInsert::state (bool full) node->add_property("id", string(buf)); if (_plugins[0]->state_node_name() == "ladspa") { char buf[32]; - snprintf (buf, 31, "%ld", _plugins[0]->get_info().unique_id); + snprintf (buf, sizeof (buf), "%ld", _plugins[0]->get_info()->unique_id); node->add_property("unique-id", string(buf)); } node->add_property("count", string_compose("%1", _plugins.size())); @@ -666,7 +658,7 @@ PluginInsert::set_state(const XMLNode& node) return -1; } - Plugin* plugin; + boost::shared_ptr<Plugin> plugin; if (unique != 0) { plugin = find_plugin (_session, "", unique, type); @@ -692,13 +684,13 @@ PluginInsert::set_state(const XMLNode& node) _plugins.push_back (plugin); for (uint32_t n=1; n < count; ++n) { - _plugins.push_back (plugin_factory (*plugin)); + _plugins.push_back (plugin_factory (plugin)); } } for (niter = nlist.begin(); niter != nlist.end(); ++niter) { if ((*niter)->name() == plugin->state_node_name()) { - for (vector<Plugin*>::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { + for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { (*i)->set_state (**niter); } break; @@ -769,7 +761,7 @@ PluginInsert::set_state(const XMLNode& node) } // The name of the PluginInsert comes from the plugin, nothing else - set_name(plugin->get_info().name,this); + set_name(plugin->get_info()->name,this); return 0; } @@ -780,18 +772,6 @@ PluginInsert::describe_parameter (uint32_t what) return _plugins[0]->describe_parameter (what); } -void -PluginInsert::reset_midi_control (MIDI::Port* port, bool on) -{ - _plugins[0]->reset_midi_control (port, on); -} - -void -PluginInsert::send_all_midi_feedback () -{ - _plugins[0]->send_all_midi_feedback(); -} - jack_nframes_t PluginInsert::latency() { diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index 87c03c6b70..2dfd735a6b 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -74,17 +74,17 @@ sigc::signal<int> IO::PortsCreated; Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT; -/* this is a default mapper of MIDI control values to a gain coefficient. - others can be imagined. see IO::set_midi_to_gain_function(). +/* this is a default mapper of [0 .. 1.0] control values to a gain coefficient. + others can be imagined. */ -static gain_t direct_midi_to_gain (double fract) { +static gain_t direct_control_to_gain (double fract) { /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */ /* this maxes at +6dB */ return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0); } -static double direct_gain_to_midi (gain_t gain) { +static double direct_gain_to_control (gain_t gain) { /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */ if (gain == 0) return 0.0; @@ -97,19 +97,22 @@ static bool sort_ports_by_name (Port* a, Port* b) } +/** @param default_type The type of port that will be created by ensure_io + * and friends if no type is explicitly requested (to avoid breakage). + */ IO::IO (Session& s, string name, - - int input_min, int input_max, int output_min, int output_max) + int input_min, int input_max, int output_min, int output_max, + DataType default_type) : _session (s), _name (name), - _midi_gain_control (*this, _session.midi_port()), + _default_type(default_type), + _gain_control (*this), _gain_automation_curve (0.0, 2.0, 1.0), _input_minimum (input_min), _input_maximum (input_max), _output_minimum (output_min), _output_maximum (output_max) { - _id = new_id(); _panner = new Panner (name, _session); _gain = 1.0; _desired_gain = 1.0; @@ -121,9 +124,6 @@ IO::IO (Session& s, string name, no_panner_reset = false; deferred_state = 0; - _midi_gain_control.midi_to_gain = direct_midi_to_gain; - _midi_gain_control.gain_to_midi = direct_gain_to_midi; - apply_gain_automation = false; last_automation_snapshot = 0; @@ -785,11 +785,20 @@ IO::remove_output_port (Port* port, void* src) return -1; } +/** Add an output port. + * + * @param destination Name of input port to connect new port to. + * @param src Source for emitted ConfigurationChanged signal. + * @param type Data type of port. Default value (NIL) will use this IO's default type. + */ int -IO::add_output_port (string destination, void* src) +IO::add_output_port (string destination, void* src, DataType type) { Port* our_port; - char buf[64]; + char name[64]; + + if (type == DataType::NIL) + type = _default_type; { Glib::Mutex::Lock em(_session.engine().process_lock()); @@ -803,14 +812,15 @@ IO::add_output_port (string destination, void* src) /* Create a new output port */ + // FIXME: naming scheme for differently typed ports? if (_output_maximum == 1) { - snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str()); + snprintf (name, sizeof (name), _("%s/out"), _name.c_str()); } else { - snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole()); + snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole()); } - if ((our_port = _session.engine().register_audio_output_port (buf)) == 0) { - error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg; + if ((our_port = _session.engine().register_output_port (type, name)) == 0) { + error << string_compose(_("IO: cannot register output port %1"), name) << endmsg; return -1; } @@ -886,11 +896,21 @@ IO::remove_input_port (Port* port, void* src) return -1; } + +/** Add an input port. + * + * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created. + * @param destination Name of input port to connect new port to. + * @param src Source for emitted ConfigurationChanged signal. + */ int -IO::add_input_port (string source, void* src) +IO::add_input_port (string source, void* src, DataType type) { Port* our_port; - char buf[64]; + char name[64]; + + if (type == DataType::NIL) + type = _default_type; { Glib::Mutex::Lock em (_session.engine().process_lock()); @@ -904,14 +924,15 @@ IO::add_input_port (string source, void* src) /* Create a new input port */ + // FIXME: naming scheme for differently typed ports? if (_input_maximum == 1) { - snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str()); + snprintf (name, sizeof (name), _("%s/in"), _name.c_str()); } else { - snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole()); + snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole()); } - if ((our_port = _session.engine().register_audio_input_port (buf)) == 0) { - error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg; + if ((our_port = _session.engine().register_input_port (type, name)) == 0) { + error << string_compose(_("IO: cannot register input port %1"), name) << endmsg; return -1; } @@ -1005,7 +1026,7 @@ IO::ensure_inputs_locked (uint32_t n, bool clear, void* src) char buf[64]; - /* Create a new input port */ + /* Create a new input port (of the default type) */ if (_input_maximum == 1) { snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str()); @@ -1016,7 +1037,7 @@ IO::ensure_inputs_locked (uint32_t n, bool clear, void* src) try { - if ((input_port = _session.engine().register_audio_input_port (buf)) == 0) { + if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) { error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg; return -1; } @@ -1105,7 +1126,7 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src) out_changed = true; } - /* create any necessary new ports */ + /* create any necessary new ports (of the default type) */ while (_ninputs < nin) { @@ -1121,7 +1142,7 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src) } try { - if ((port = _session.engine().register_audio_input_port (buf)) == 0) { + if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) { error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg; return -1; } @@ -1154,7 +1175,7 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src) } try { - if ((port = _session.engine().register_audio_output_port (buf)) == 0) { + if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) { error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg; return -1; } @@ -1279,7 +1300,7 @@ IO::ensure_outputs_locked (uint32_t n, bool clear, void* src) snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole()); } - if ((output_port = _session.engine().register_audio_output_port (buf)) == 0) { + if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) { error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg; return -1; } @@ -1397,7 +1418,7 @@ XMLNode& IO::state (bool full_state) { XMLNode* node = new XMLNode (state_node_name); - char buf[32]; + char buf[64]; string str; bool need_ins = true; bool need_outs = true; @@ -1405,7 +1426,7 @@ IO::state (bool full_state) Glib::Mutex::Lock lm (io_lock); node->add_property("name", _name); - snprintf (buf, sizeof(buf), "%" PRIu64, id()); + id().print (buf); node->add_property("id", buf); str = ""; @@ -1499,22 +1520,6 @@ IO::state (bool full_state) node->add_property ("iolimits", buf); - /* MIDI control */ - - MIDI::channel_t chn; - MIDI::eventType ev; - MIDI::byte additional; - XMLNode* midi_node = 0; - XMLNode* child; - - if (_midi_gain_control.get_control_info (chn, ev, additional)) { - - midi_node = node->add_child ("MIDI"); - - child = midi_node->add_child ("gain"); - set_midi_node_info (child, ev, chn, additional); - } - /* automation */ if (full_state) { @@ -1583,7 +1588,6 @@ IO::set_state (const XMLNode& node) { const XMLProperty* prop; XMLNodeConstIterator iter; - XMLNodeList midi_kids; LocaleGuard lg (X_("POSIX")); /* force use of non-localized representation of decimal point, @@ -1601,7 +1605,7 @@ IO::set_state (const XMLNode& node) } if ((prop = node.property ("id")) != 0) { - sscanf (prop->value().c_str(), "%" PRIu64, &_id); + _id = prop->value (); } if ((prop = node.property ("iolimits")) != 0) { @@ -1623,35 +1627,6 @@ IO::set_state (const XMLNode& node) } } - midi_kids = node.children ("MIDI"); - - for (iter = midi_kids.begin(); iter != midi_kids.end(); ++iter) { - - XMLNodeList kids; - XMLNodeConstIterator miter; - XMLNode* child; - - kids = (*iter)->children (); - - for (miter = kids.begin(); miter != kids.end(); ++miter) { - - child =* miter; - - if (child->name() == "gain") { - - MIDI::eventType ev = MIDI::on; /* initialize to keep gcc happy */ - MIDI::byte additional = 0; /* ditto */ - MIDI::channel_t chn = 0; /* ditto */ - - if (get_midi_node_info (child, ev, chn, additional)) { - _midi_gain_control.set_control_type (chn, ev, additional); - } else { - error << string_compose(_("MIDI gain control specification for %1 is incomplete, so it has been ignored"), _name) << endmsg; - } - } - } - } - if ((prop = node.property ("automation-state")) != 0) { long int x; @@ -1769,50 +1744,6 @@ IO::create_ports (const XMLNode& node) return 0; } -bool -IO::get_midi_node_info (XMLNode * node, MIDI::eventType & ev, MIDI::channel_t & chan, MIDI::byte & additional) -{ - bool ok = true; - const XMLProperty* prop; - int xx; - - if ((prop = node->property ("event")) != 0) { - sscanf (prop->value().c_str(), "0x%x", &xx); - ev = (MIDI::eventType) xx; - } else { - ok = false; - } - - if (ok && ((prop = node->property ("channel")) != 0)) { - sscanf (prop->value().c_str(), "%d", &xx); - chan = (MIDI::channel_t) xx; - } else { - ok = false; - } - - if (ok && ((prop = node->property ("additional")) != 0)) { - sscanf (prop->value().c_str(), "0x%x", &xx); - additional = (MIDI::byte) xx; - } - - return ok; -} - -bool -IO::set_midi_node_info (XMLNode * node, MIDI::eventType ev, MIDI::channel_t chan, MIDI::byte additional) -{ - char buf[32]; - - snprintf (buf, sizeof(buf), "0x%x", ev); - node->add_property ("event", buf); - snprintf (buf, sizeof(buf), "%d", chan); - node->add_property ("channel", buf); - snprintf (buf, sizeof(buf), "0x%x", additional); - node->add_property ("additional", buf); - - return true; -} - int IO::make_connections (const XMLNode& node) @@ -2339,69 +2270,16 @@ IO::output_connection_configuration_changed () use_output_connection (*_output_connection, this); } -IO::MIDIGainControl::MIDIGainControl (IO& i, MIDI::Port* port) - : MIDI::Controllable (port, 0), io (i), setting(false) -{ - midi_to_gain = 0; - gain_to_midi = 0; - setting = false; - last_written = 0; /* XXX need a good out-of-bound-value */ -} - void -IO::MIDIGainControl::set_value (float val) +IO::GainControllable::set_value (float val) { - if (midi_to_gain == 0) return; - - setting = true; - io.set_gain (midi_to_gain (val), this); - setting = false; + io.set_gain (direct_control_to_gain (val), this); } -void -IO::MIDIGainControl::send_feedback (gain_t gain) -{ - if (!setting && get_midi_feedback() && gain_to_midi) { - MIDI::byte val = (MIDI::byte) (gain_to_midi (gain) * 127.0); - MIDI::channel_t ch = 0; - MIDI::eventType ev = MIDI::none; - MIDI::byte additional = 0; - MIDI::EventTwoBytes data; - - if (get_control_info (ch, ev, additional)) { - data.controller_number = additional; - data.value = val; - last_written = val; - - io._session.send_midi_message (get_port(), ev, ch, data); - } - //send_midi_feedback (gain_to_midi (gain)); - } -} - -MIDI::byte* -IO::MIDIGainControl::write_feedback (MIDI::byte* buf, int32_t& bufsize, gain_t val, bool force) +float +IO::GainControllable::get_value (void) const { - if (get_midi_feedback() && gain_to_midi && bufsize > 2) { - MIDI::channel_t ch = 0; - MIDI::eventType ev = MIDI::none; - MIDI::byte additional = 0; - MIDI::byte gm; - - if (get_control_info (ch, ev, additional)) { - gm = (MIDI::byte) (gain_to_midi (val) * 127.0); - - if (gm != last_written) { - *buf++ = (0xF0 & ev) | (0xF & ch); - *buf++ = additional; /* controller number */ - *buf++ = gm; - last_written = gm; - bufsize -= 3; - } - } - } - - return buf; + return direct_gain_to_control (io.effective_gain()); } void @@ -2493,23 +2371,6 @@ IO::meter () } } -void -IO::reset_midi_control (MIDI::Port* port, bool on) -{ - MIDI::channel_t chn; - MIDI::eventType ev; - MIDI::byte extra; - - _midi_gain_control.get_control_info (chn, ev, extra); - if (!on) { - chn = -1; - } - _midi_gain_control.midi_rebind (port, chn); - - _panner->reset_midi_control (port, on); -} - - int IO::save_automation (const string& path) { @@ -2699,10 +2560,7 @@ IO::set_gain (gain_t val, void *src) } gain_changed (src); - - if (_session.get_midi_feedback()) { - _midi_gain_control.send_feedback (_desired_gain); - } + _gain_control.Changed (); /* EMIT SIGNAL */ if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) { _gain_automation_curve.add (_session.transport_frame(), val); @@ -2713,30 +2571,6 @@ IO::set_gain (gain_t val, void *src) } void -IO::send_all_midi_feedback () -{ - if (_session.get_midi_feedback()) { - _midi_gain_control.send_feedback (_effective_gain); - - // panners - _panner->send_all_midi_feedback(); - } -} - -MIDI::byte* -IO::write_midi_feedback (MIDI::byte* buf, int32_t& bufsize) -{ - if (_session.get_midi_feedback()) { - if (gain_automation_playback ()) { - buf = _midi_gain_control.write_feedback (buf, bufsize, _effective_gain); - } - buf = _panner->write_midi_feedback (buf, bufsize); - } - - return buf; -} - -void IO::start_gain_touch () { _gain_automation_curve.start_touch (); diff --git a/libs/ardour/ladspa_plugin.cc b/libs/ardour/ladspa_plugin.cc index 11001655d2..6b773b9e0b 100644 --- a/libs/ardour/ladspa_plugin.cc +++ b/libs/ardour/ladspa_plugin.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2002 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -133,20 +133,9 @@ LadspaPlugin::init (void *mod, uint32_t index, jack_nframes_t rate) } } - Plugin::setup_midi_controls (); + Plugin::setup_controls (); latency_compute_run (); - - MIDI::Controllable *mcontrol; - - for (uint32_t i = 0; i < parameter_count(); ++i) { - if (LADSPA_IS_PORT_INPUT(port_descriptor (i)) && - LADSPA_IS_PORT_CONTROL(port_descriptor (i))) { - if ((mcontrol = get_nth_midi_control (i)) != 0) { - mcontrol->midi_rebind (_session.midi_port(), 0); - } - } - } } LadspaPlugin::~LadspaPlugin () @@ -318,17 +307,14 @@ LadspaPlugin::set_parameter (uint32_t which, float val) shadow_data[which] = (LADSPA_Data) val; ParameterChanged (which, val); /* EMIT SIGNAL */ - if (session().get_midi_feedback()) { - - if (which < parameter_count() && midi_controls[which]) { - midi_controls[which]->send_feedback (val); - } + if (which < parameter_count() && controls[which]) { + controls[which]->Changed (); } - + } else { warning << string_compose (_("illegal parameter number used with plugin \"%1\". This may" - "indicate a change in the plugin design, and presets may be" - "invalid"), name()) + "indicate a change in the plugin design, and presets may be" + "invalid"), name()) << endmsg; } } @@ -380,28 +366,6 @@ LadspaPlugin::get_state() snprintf(buf, sizeof(buf), "%+f", shadow_data[i]); child->add_property("value", string(buf)); root->add_child_nocopy (*child); - - MIDI::Controllable *pcontrol = get_nth_midi_control (i); - - if (pcontrol) { - - MIDI::eventType ev; - MIDI::byte additional; - MIDI::channel_t chn; - XMLNode* midi_node; - - if (pcontrol->get_control_info (chn, ev, additional)) { - - midi_node = child->add_child ("midi-control"); - - snprintf (buf, sizeof(buf), "0x%x", ev); - midi_node->add_property ("event", buf); - snprintf (buf, sizeof(buf), "%d", chn); - midi_node->add_property ("channel", buf); - snprintf (buf, sizeof(buf), "0x%x", additional); - midi_node->add_property ("additional", buf); - } - } } } @@ -452,52 +416,6 @@ LadspaPlugin::set_state(const XMLNode& node) sscanf (port, "%" PRIu32, &port_id); set_parameter (port_id, atof(data)); - - XMLNodeList midi_kids; - XMLNodeConstIterator iter; - - midi_kids = child->children ("midi-control"); - - for (iter = midi_kids.begin(); iter != midi_kids.end(); ++iter) { - - child = *iter; - - MIDI::eventType ev = MIDI::on; /* initialize to keep gcc happy */ - MIDI::byte additional = 0; /* initialize to keep gcc happy */ - MIDI::channel_t chn = 0; /* initialize to keep gcc happy */ - bool ok = true; - int xx; - - if ((prop = child->property ("event")) != 0) { - sscanf (prop->value().c_str(), "0x%x", &xx); - ev = (MIDI::eventType) xx; - } else { - ok = false; - } - - if (ok && ((prop = child->property ("channel")) != 0)) { - sscanf (prop->value().c_str(), "%d", &xx); - chn = (MIDI::channel_t) xx; - } else { - ok = false; - } - - if (ok && ((prop = child->property ("additional")) != 0)) { - sscanf (prop->value().c_str(), "0x%x", &xx); - additional = (MIDI::byte) xx; - } - - if (ok) { - MIDI::Controllable* pcontrol = get_nth_midi_control (port_id); - - if (pcontrol) { - pcontrol->set_control_type (chn, ev, additional); - } - - } else { - error << string_compose(_("LADSPA LadspaPlugin MIDI control specification for port %1 is incomplete, so it has been ignored"), port) << endl; - } - } } latency_compute_run (); @@ -723,3 +641,26 @@ LadspaPlugin::latency_compute_run () run (bufsize); deactivate (); } + +PluginPtr +LadspaPluginInfo::load (Session& session) +{ + try { + PluginPtr plugin; + void *module; + + if ((module = dlopen (path.c_str(), RTLD_NOW)) == 0) { + error << string_compose(_("LADSPA: cannot load module from \"%1\""), path) << endmsg; + error << dlerror() << endmsg; + } else { + plugin.reset (new LadspaPlugin (module, session.engine(), session, index, session.frame_rate())); + } + + plugin->set_info(PluginInfoPtr(new LadspaPluginInfo(*this))); + return plugin; + } + + catch (failed_constructor &err) { + return PluginPtr ((Plugin*) 0); + } +} diff --git a/libs/ardour/location.cc b/libs/ardour/location.cc index b2af52284e..5b5f733138 100644 --- a/libs/ardour/location.cc +++ b/libs/ardour/location.cc @@ -30,6 +30,7 @@ #include <pbd/xml++.h> #include <ardour/location.h> +#include <ardour/audiofilesource.h> #include "i18n.h" @@ -44,6 +45,10 @@ Location::Location (const Location& other) _end (other._end), _flags (other._flags) { + /* start and end flags can never be copied, because there can only ever be one of each */ + + _flags = Flags (_flags & ~IsStart); + _flags = Flags (_flags & ~IsEnd); } Location* @@ -71,6 +76,9 @@ Location::set_start (jack_nframes_t s) _start = s; _end = s; start_changed(this); /* EMIT SIGNAL */ + if ( is_start() ) { + AudioFileSource::set_header_position_offset ( s ); + } } return 0; } diff --git a/libs/ardour/mix.cc b/libs/ardour/mix.cc index ab0d1dde59..c6e234d87b 100644 --- a/libs/ardour/mix.cc +++ b/libs/ardour/mix.cc @@ -22,6 +22,7 @@ #include <ardour/types.h> #include <ardour/utils.h> #include <ardour/mix.h> +#include <stdint.h> #if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS) @@ -119,8 +120,9 @@ mix_buffers_no_gain (ARDOUR::Sample *dst, ARDOUR::Sample *src, jack_nframes_t nf float veclib_compute_peak (ARDOUR::Sample *buf, jack_nframes_t nsamples, float current) { - vDSP_maxv(buf, 1, ¤t, nsamples); - return current; + float tmpmax = 0.0f; + vDSP_maxmgv(buf, 1, &tmpmax, nsamples); + return f_max(current, tmpmax); } void diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc index 83c9e6eb4d..8336c4697c 100644 --- a/libs/ardour/panner.cc +++ b/libs/ardour/panner.cc @@ -53,21 +53,21 @@ float Panner::current_automation_version_number = 1.0; string EqualPowerStereoPanner::name = "Equal Power Stereo"; string Multi2dPanner::name = "Multiple (2D)"; -/* this is a default mapper of MIDI control values to a pan position - others can be imagined. see Panner::set_midi_to_pan_function(). +/* this is a default mapper of control values to a pan position + others can be imagined. */ -static pan_t direct_midi_to_pan (double fract) { +static pan_t direct_control_to_pan (double fract) { return fract; } -static double direct_pan_to_midi (pan_t val) { +static double direct_pan_to_control (pan_t val) { return val; } StreamPanner::StreamPanner (Panner& p) : parent (p), - _midi_control (*this, (MIDI::Port*) 0) + _control (*this) { _muted = false; @@ -80,84 +80,30 @@ StreamPanner::~StreamPanner () { } -StreamPanner::MIDIControl::MIDIControl (StreamPanner& s, MIDI::Port* port) - : MIDI::Controllable (port, 0), sp (s), setting(false) -{ - midi_to_pan = direct_midi_to_pan; - pan_to_midi = direct_pan_to_midi; - last_written = 0; /* XXX need a good out-of-bound-value */ -} - void -StreamPanner::MIDIControl::set_value (float val) +StreamPanner::PanControllable::set_value (float val) { - setting = true; - sp.set_position (midi_to_pan (val)); - setting = false; -} - -void -StreamPanner::MIDIControl::send_feedback (pan_t value) -{ - - if (!setting && get_midi_feedback() && pan_to_midi) { - MIDI::byte val = (MIDI::byte) (pan_to_midi (value) * 127.0f); - MIDI::channel_t ch = 0; - MIDI::eventType ev = MIDI::none; - MIDI::byte additional = 0; - MIDI::EventTwoBytes data; - - if (get_control_info (ch, ev, additional)) { - data.controller_number = additional; - data.value = val; - last_written = val; - - sp.get_parent().session().send_midi_message (get_port(), ev, ch, data); - } - - // send_midi_feedback (pan_to_midi (val)); - } - + panner.set_position (direct_control_to_pan (val)); } -MIDI::byte* -StreamPanner::MIDIControl::write_feedback (MIDI::byte* buf, int32_t& bufsize, pan_t val, bool force) +float +StreamPanner::PanControllable::get_value (void) const { - if (get_midi_feedback() && pan_to_midi && bufsize > 2) { - MIDI::channel_t ch = 0; - MIDI::eventType ev = MIDI::none; - MIDI::byte additional = 0; - MIDI::byte pm; - if (get_control_info (ch, ev, additional)) { - - pm = (MIDI::byte) (pan_to_midi (val) * 127.0); - - if (pm != last_written || force) { - *buf++ = (0xF0 & ev) | (0xF & ch); - *buf++ = additional; /* controller number */ - *buf++ = pm; - last_written = pm; - bufsize -= 3; - } - } - } - - return buf; + float xpos; + panner.get_effective_position (xpos); + return direct_pan_to_control (xpos); } - -void -StreamPanner::reset_midi_control (MIDI::Port* port, bool on) +bool +StreamPanner::PanControllable::can_send_feedback () const { - MIDI::channel_t chn; - MIDI::eventType ev; - MIDI::byte extra; + AutoState astate = panner.get_parent().automation_state (); - _midi_control.get_control_info (chn, ev, extra); - if (!on) { - chn = -1; + if ((astate == Play) || (astate == Touch && !panner.get_parent().touching())) { + return true; } - _midi_control.midi_rebind (port, chn); + + return false; } void @@ -180,10 +126,7 @@ StreamPanner::set_position (float xpos, bool link_call) x = xpos; update (); Changed (); - - if (parent.session().get_midi_feedback()) { - _midi_control.send_feedback (x); - } + _control.Changed (); } } @@ -224,42 +167,11 @@ StreamPanner::set_state (const XMLNode& node) { const XMLProperty* prop; XMLNodeConstIterator iter; - XMLNodeList midi_kids; if ((prop = node.property (X_("muted")))) { set_muted (prop->value() == "yes"); } - midi_kids = node.children ("MIDI"); - - for (iter = midi_kids.begin(); iter != midi_kids.end(); ++iter) { - - XMLNodeList kids; - XMLNodeConstIterator miter; - XMLNode* child; - - kids = (*iter)->children (); - - for (miter = kids.begin(); miter != kids.end(); ++miter) { - - child =* miter; - - if (child->name() == "pan") { - - MIDI::eventType ev = MIDI::on; /* initialize to keep gcc happy */ - MIDI::byte additional = 0; /* ditto */ - MIDI::channel_t chn = 0; /* ditto */ - - if (get_midi_node_info (child, ev, chn, additional)) { - _midi_control.set_control_type (chn, ev, additional); - } else { - error << _("MIDI pan control specification is incomplete, so it has been ignored") << endmsg; - } - } - } - } - - return 0; } @@ -267,68 +179,6 @@ void StreamPanner::add_state (XMLNode& node) { node.add_property (X_("muted"), (muted() ? "yes" : "no")); - - /* MIDI control */ - - MIDI::channel_t chn; - MIDI::eventType ev; - MIDI::byte additional; - XMLNode* midi_node = 0; - XMLNode* child; - - if (_midi_control.get_control_info (chn, ev, additional)) { - - midi_node = node.add_child ("MIDI"); - - child = midi_node->add_child ("pan"); - set_midi_node_info (child, ev, chn, additional); - } - -} - - -bool -StreamPanner::get_midi_node_info (XMLNode * node, MIDI::eventType & ev, MIDI::channel_t & chan, MIDI::byte & additional) -{ - bool ok = true; - const XMLProperty* prop; - int xx; - - if ((prop = node->property ("event")) != 0) { - sscanf (prop->value().c_str(), "0x%x", &xx); - ev = (MIDI::eventType) xx; - } else { - ok = false; - } - - if (ok && ((prop = node->property ("channel")) != 0)) { - sscanf (prop->value().c_str(), "%d", &xx); - chan = (MIDI::channel_t) xx; - } else { - ok = false; - } - - if (ok && ((prop = node->property ("additional")) != 0)) { - sscanf (prop->value().c_str(), "0x%x", &xx); - additional = (MIDI::byte) xx; - } - - return ok; -} - -bool -StreamPanner::set_midi_node_info (XMLNode * node, MIDI::eventType ev, MIDI::channel_t chan, MIDI::byte additional) -{ - char buf[32]; - - snprintf (buf, sizeof(buf), "0x%x", ev); - node->add_property ("event", buf); - snprintf (buf, sizeof(buf), "%d", chan); - node->add_property ("channel", buf); - snprintf (buf, sizeof(buf), "0x%x", additional); - node->add_property ("additional", buf); - - return true; } /*---------------------------------------------------------------------- */ @@ -679,7 +529,7 @@ EqualPowerStereoPanner::state (bool full_state) char buf[64]; LocaleGuard lg (X_("POSIX")); - snprintf (buf, sizeof (buf), "%f", x); + snprintf (buf, sizeof (buf), "%.12g", x); root->add_property (X_("x"), buf); root->add_property (X_("type"), EqualPowerStereoPanner::name); if (full_state) { @@ -913,9 +763,9 @@ Multi2dPanner::state (bool full_state) char buf[64]; LocaleGuard lg (X_("POSIX")); - snprintf (buf, sizeof (buf), "%f", x); + snprintf (buf, sizeof (buf), "%.12g", x); root->add_property (X_("x"), buf); - snprintf (buf, sizeof (buf), "%f", y); + snprintf (buf, sizeof (buf), "%.12g", y); root->add_property (X_("y"), buf); root->add_property (X_("type"), Multi2dPanner::name); @@ -959,8 +809,6 @@ Panner::Panner (string name, Session& s) _linked = false; _link_direction = SameDirection; _bypassed = false; - - reset_midi_control (_session.mmc_port(), _session.get_mmc_control()); } Panner::~Panner () @@ -1107,8 +955,6 @@ Panner::reset (uint32_t nouts, uint32_t npans) (*x)->update (); } - reset_midi_control (_session.mmc_port(), _session.get_mmc_control()); - /* force hard left/right panning in a common case: 2in/2out */ @@ -1333,7 +1179,7 @@ struct PanPlugins { PanPlugins pan_plugins[] = { { EqualPowerStereoPanner::name, 2, EqualPowerStereoPanner::factory }, { Multi2dPanner::name, 3, Multi2dPanner::factory }, - { string (""), 0 } + { string (""), 0, 0 } }; XMLNode& @@ -1361,9 +1207,9 @@ Panner::state (bool full) for (vector<Panner::Output>::iterator o = outputs.begin(); o != outputs.end(); ++o) { XMLNode* onode = new XMLNode (X_("Output")); - snprintf (buf, sizeof (buf), "%f", (*o).x); + snprintf (buf, sizeof (buf), "%.12g", (*o).x); onode->add_property (X_("x"), buf); - snprintf (buf, sizeof (buf), "%f", (*o).y); + snprintf (buf, sizeof (buf), "%.12g", (*o).y); onode->add_property (X_("y"), buf); root->add_child_nocopy (*onode); } @@ -1412,10 +1258,10 @@ Panner::set_state (const XMLNode& node) float x, y; prop = (*niter)->property (X_("x")); - sscanf (prop->value().c_str(), "%f", &x); + sscanf (prop->value().c_str(), "%.12g", &x); prop = (*niter)->property (X_("y")); - sscanf (prop->value().c_str(), "%f", &y); + sscanf (prop->value().c_str(), "%.12g", &y); outputs.push_back (Output (x, y)); } @@ -1490,14 +1336,6 @@ Panner::touching () const } void -Panner::reset_midi_control (MIDI::Port* port, bool on) -{ - for (vector<StreamPanner*>::const_iterator i = begin(); i != end(); ++i) { - (*i)->reset_midi_control (port, on); - } -} - -void Panner::set_position (float xpos, StreamPanner& orig) { float xnow; @@ -1639,42 +1477,3 @@ Panner::set_position (float xpos, float ypos, float zpos, StreamPanner& orig) } } } - -void -Panner::send_all_midi_feedback () -{ - if (_session.get_midi_feedback()) { - float xpos; - - // do feedback for all panners - for (vector<StreamPanner*>::iterator i = begin(); i != end(); ++i) { - (*i)->get_effective_position (xpos); - - (*i)->midi_control().send_feedback (xpos); - } - - } -} - -MIDI::byte* -Panner::write_midi_feedback (MIDI::byte* buf, int32_t& bufsize) -{ - AutoState astate = automation_state (); - - if (_session.get_midi_feedback() && - (astate == Play || (astate == Touch && !touching()))) { - - float xpos; - - // do feedback for all panners - for (vector<StreamPanner*>::iterator i = begin(); i != end(); ++i) { - (*i)->get_effective_position (xpos); - - buf = (*i)->midi_control().write_feedback (buf, bufsize, xpos); - } - - } - - return buf; -} - diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc index 7dee866767..6d5e8f7847 100644 --- a/libs/ardour/playlist.cc +++ b/libs/ardour/playlist.cc @@ -77,7 +77,6 @@ Playlist::Playlist (Session& sess, string nom, bool hide) { init (hide); _name = nom; - _orig_diskstream_id = 0; } @@ -86,7 +85,6 @@ Playlist::Playlist (Session& sess, const XMLNode& node, bool hide) { init (hide); _name = "unnamed"; /* reset by set_state */ - _orig_diskstream_id = 0; if (set_state (node)) { throw failed_constructor(); @@ -601,6 +599,31 @@ Playlist::remove_region_internal (Region *region, bool delay_sort) } void +Playlist::get_equivalent_regions (const Region& other, vector<Region*>& results) +{ + for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { + if (Config->get_use_overlap_equivalency()) { + if ((*i)->overlap_equivalent (other)) { + results.push_back ((*i)); + } else if ((*i)->equivalent (other)) { + results.push_back ((*i)); + } + } + } +} + +void +Playlist::get_region_list_equivalent_regions (const Region& other, vector<Region*>& results) +{ + for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { + + if ((*i) && (*i)->region_list_equivalent (other)) { + results.push_back (*i); + } + } +} + +void Playlist::partition (jack_nframes_t start, jack_nframes_t end, bool just_top_level) { RegionList thawlist; @@ -1343,7 +1366,7 @@ Playlist::set_state (const XMLNode& node) if (prop->name() == X_("name")) { _name = prop->value(); } else if (prop->name() == X_("orig_diskstream_id")) { - sscanf (prop->value().c_str(), "%" PRIu64, &_orig_diskstream_id); + _orig_diskstream_id = prop->value (); } else if (prop->name() == X_("frozen")) { _frozen = (prop->value() == X_("yes")); } @@ -1404,7 +1427,7 @@ Playlist::state (bool full_state) node->add_property (X_("name"), _name); - snprintf (buf, sizeof(buf), "%" PRIu64, _orig_diskstream_id); + _orig_diskstream_id.print (buf); node->add_property (X_("orig_diskstream_id"), buf); node->add_property (X_("frozen"), _frozen ? "yes" : "no"); @@ -1725,7 +1748,7 @@ Playlist::nudge_after (jack_nframes_t start, jack_nframes_t distance, bool forwa } Region* -Playlist::find_region (id_t id) const +Playlist::find_region (const ID& id) const { RegionLock rlock (const_cast<Playlist*> (this)); RegionList::const_iterator i; diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc index 2d1f8ffcbd..8ea95b8903 100644 --- a/libs/ardour/plugin.cc +++ b/libs/ardour/plugin.cc @@ -35,12 +35,12 @@ #include <pbd/pathscanner.h> #include <pbd/xml++.h> -#include <midi++/manager.h> - #include <ardour/ardour.h> #include <ardour/session.h> #include <ardour/audioengine.h> #include <ardour/plugin.h> +#include <ardour/ladspa_plugin.h> +#include <ardour/plugin_manager.h> #include <pbd/stl_delete.h> @@ -61,64 +61,59 @@ Plugin::Plugin (const Plugin& other) } void -Plugin::setup_midi_controls () +Plugin::setup_controls () { - uint32_t port_cnt; - - port_cnt = parameter_count(); + uint32_t port_cnt = parameter_count(); - /* set up a vector of null pointers for the MIDI controls. + /* set up a vector of null pointers for the controls. we'll fill this in on an as-needed basis. */ for (uint32_t i = 0; i < port_cnt; ++i) { - midi_controls.push_back (0); + controls.push_back (0); } } Plugin::~Plugin () { - for (vector<MIDIPortControl*>::iterator i = midi_controls.begin(); i != midi_controls.end(); ++i) { + for (vector<PortControllable*>::iterator i = controls.begin(); i != controls.end(); ++i) { if (*i) { delete *i; } } } -MIDI::Controllable * -Plugin::get_nth_midi_control (uint32_t n) +Controllable * +Plugin::get_nth_control (uint32_t n) { if (n >= parameter_count()) { return 0; } - if (midi_controls[n] == 0) { + if (controls[n] == 0) { Plugin::ParameterDescriptor desc; get_parameter_descriptor (n, desc); - - midi_controls[n] = new MIDIPortControl (*this, n, _session.midi_port(), desc.lower, desc.upper, desc.toggled, desc.logarithmic); + + controls[n] = new PortControllable (*this, n, desc.lower, desc.upper, desc.toggled, desc.logarithmic); } - return midi_controls[n]; + return controls[n]; } -Plugin::MIDIPortControl::MIDIPortControl (Plugin& p, uint32_t port_id, MIDI::Port *port, - float low, float up, bool t, bool loga) - : MIDI::Controllable (port, 0), plugin (p), absolute_port (port_id) +Plugin::PortControllable::PortControllable (Plugin& p, uint32_t port_id, float low, float up, bool t, bool loga) + : plugin (p), absolute_port (port_id) { toggled = t; logarithmic = loga; lower = low; upper = up; range = upper - lower; - last_written = 0; /* XXX need a good out-of-bound-value */ - setting = false; } void -Plugin::MIDIPortControl::set_value (float value) +Plugin::PortControllable::set_value (float value) { if (toggled) { if (value > 0.5) { @@ -127,145 +122,40 @@ Plugin::MIDIPortControl::set_value (float value) value = 0.0; } } else { - value = lower + (range * value); - - if (logarithmic) { - value = exp(value); - } - } - setting = true; - plugin.set_parameter (absolute_port, value); - setting = false; -} - -void -Plugin::MIDIPortControl::send_feedback (float value) -{ - - if (!setting && get_midi_feedback()) { - MIDI::byte val; - MIDI::channel_t ch = 0; - MIDI::eventType ev = MIDI::none; - MIDI::byte additional = 0; - MIDI::EventTwoBytes data; - - if (toggled) { - val = (MIDI::byte) (value * 127.0f); + if (!logarithmic) { + value = lower + (range * value); } else { - if (logarithmic) { - value = log(value); - } - - val = (MIDI::byte) (((value - lower) / range) * 127.0f); - } - - if (get_control_info (ch, ev, additional)) { - data.controller_number = additional; - data.value = val; - last_written = val; - - plugin.session().send_midi_message (get_port(), ev, ch, data); - } - } - -} - -MIDI::byte* -Plugin::MIDIPortControl::write_feedback (MIDI::byte* buf, int32_t& bufsize, float value, bool force) -{ - if (get_midi_feedback() && bufsize > 2) { - MIDI::channel_t ch = 0; - MIDI::eventType ev = MIDI::none; - MIDI::byte additional = 0; - - if (get_control_info (ch, ev, additional)) { - - MIDI::byte val; - - if (toggled) { - - val = (MIDI::byte) (value * 127.0f); - - } else { - - if (logarithmic) { - value = log(value); - } - - val = (MIDI::byte) (((value - lower) / range) * 127.0f); + float _lower = 0.0f; + if (lower > 0.0f) { + _lower = log(lower); } - if (val != last_written || force) { - *buf++ = MIDI::controller & ch; - *buf++ = additional; /* controller number */ - *buf++ = val; - last_written = val; - bufsize -= 3; - } + value = exp(_lower + log(range) * value); } } - return buf; + plugin.set_parameter (absolute_port, value); } - -void -Plugin::reset_midi_control (MIDI::Port* port, bool on) +float +Plugin::PortControllable::get_value (void) const { - MIDI::channel_t chn; - MIDI::eventType ev; - MIDI::byte extra; - - for (vector<MIDIPortControl*>::iterator i = midi_controls.begin(); i != midi_controls.end(); ++i) { - if (*i == 0) - continue; - (*i)->get_control_info (chn, ev, extra); - if (!on) { - chn = -1; - } - (*i)->midi_rebind (port, chn); - } -} + float val = plugin.get_parameter (absolute_port); -void -Plugin::send_all_midi_feedback () -{ - if (_session.get_midi_feedback()) { - float val = 0.0; - uint32_t n = 0; + if (toggled) { - for (vector<MIDIPortControl*>::iterator i = midi_controls.begin(); i != midi_controls.end(); ++i, ++n) { - if (*i == 0) { - continue; - } - - val = (*i)->plugin.get_parameter (n); - (*i)->send_feedback (val); - } + return val; - } -} - -MIDI::byte* -Plugin::write_midi_feedback (MIDI::byte* buf, int32_t& bufsize) -{ - if (_session.get_midi_feedback()) { - float val = 0.0; - uint32_t n = 0; + } else { - for (vector<MIDIPortControl*>::iterator i = midi_controls.begin(); i != midi_controls.end(); ++i, ++n) { - if (*i == 0) { - continue; - } - - val = (*i)->plugin.get_parameter (n); - buf = (*i)->write_feedback (buf, bufsize, val); + if (logarithmic) { + val = log(val); } + + return ((val - lower) / range); } - - return buf; -} +} vector<string> Plugin::get_presets() @@ -352,3 +242,43 @@ Plugin::save_preset (string name, string domain) return true; } + +PluginPtr +ARDOUR::find_plugin(Session& session, string name, long unique_id, PluginInfo::Type type) +{ + PluginManager *mgr = PluginManager::the_manager(); + PluginInfoList plugs; + + switch (type) { + case PluginInfo::LADSPA: + plugs = mgr->ladspa_plugin_info(); + break; + +#ifdef VST_SUPPORT + case PluginInfo::VST: + plugs = mgr->vst_plugin_info(); + unique_id = 0; // VST plugins don't have a unique id. + break; +#endif + +#ifdef HAVE_COREAUDIO + case PluginInfo::AudioUnit: + plugs = AUPluginInfo::discover (); + unique_id = 0; // Neither do AU. + break; +#endif + + default: + return PluginPtr ((Plugin *) 0); + } + + PluginInfoList::iterator i; + for (i = plugs.begin(); i != plugs.end(); ++i) { + if ((name == "" || (*i)->name == name) && + (unique_id == 0 || (*i)->unique_id == unique_id)) { + return (*i)->load (session); + } + } + + return PluginPtr ((Plugin*) 0); +} diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc index b096e81785..096696aca5 100644 --- a/libs/ardour/plugin_manager.cc +++ b/libs/ardour/plugin_manager.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2004 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,7 +27,7 @@ #include <fst.h> #include <pbd/basename.h> #include <string.h> -#endif +#endif // VST_SUPPORT #include <pbd/pathscanner.h> @@ -36,7 +36,10 @@ #include <ardour/plugin_manager.h> #include <ardour/plugin.h> #include <ardour/ladspa_plugin.h> + +#ifdef VST_SUPPORT #include <ardour/vst_plugin.h> +#endif #include <pbd/error.h> #include <pbd/stl_delete.h> @@ -48,8 +51,7 @@ using namespace PBD; PluginManager* PluginManager::_manager = 0; -PluginManager::PluginManager (AudioEngine& e) - : _engine (e) +PluginManager::PluginManager () { char* s; string lrdf_path; @@ -95,16 +97,12 @@ PluginManager::refresh () if (Config->get_use_vst()) { vst_refresh (); } -#endif +#endif // VST_SUPPORT } void PluginManager::ladspa_refresh () { - for (std::list<PluginInfo*>::iterator i = _ladspa_plugin_info.begin(); i != _ladspa_plugin_info.end(); ++i) { - delete *i; - } - _ladspa_plugin_info.clear (); if (ladspa_path.length() == 0) { @@ -225,7 +223,6 @@ PluginManager::add_lrdf_data (const string &path) int PluginManager::ladspa_discover (string path) { - PluginInfo *info; void *module; const LADSPA_Descriptor *descriptor; LADSPA_Descriptor_Function dfunc; @@ -250,7 +247,7 @@ PluginManager::ladspa_discover (string path) break; } - info = new PluginInfo; + PluginInfoPtr info(new LadspaPluginInfo); info->name = descriptor->Name; info->category = get_ladspa_category(descriptor->UniqueID); info->path = path; @@ -280,82 +277,6 @@ PluginManager::ladspa_discover (string path) return 0; } -Plugin * -PluginManager::load (Session& session, PluginInfo *info) -{ - void *module; - Plugin *plugin = 0; - - try { - if (info->type == PluginInfo::VST) { - -#ifdef VST_SUPPORT - if (Config->get_use_vst()) { - FSTHandle* handle; - - if ((handle = fst_load (info->path.c_str())) == 0) { - error << string_compose(_("VST: cannot load module from \"%1\""), info->path) << endmsg; - } else { - plugin = new VSTPlugin (_engine, session, handle); - } - } else { - error << _("You asked ardour to not use any VST plugins") << endmsg; - } -#else - error << _("This version of ardour has no support for VST plugins") << endmsg; - return 0; -#endif - - } else { - - if ((module = dlopen (info->path.c_str(), RTLD_NOW)) == 0) { - error << string_compose(_("LADSPA: cannot load module from \"%1\""), info->path) << endmsg; - error << dlerror() << endmsg; - } else { - plugin = new LadspaPlugin (module, _engine, session, info->index, session.frame_rate()); - } - } - - plugin->set_info(*info); - } - - catch (failed_constructor &err) { - plugin = 0; - } - - return plugin; -} - -Plugin * -ARDOUR::find_plugin(Session& session, string name, long unique_id, PluginInfo::Type type) -{ - PluginManager *mgr = PluginManager::the_manager(); - list<PluginInfo *>::iterator i; - list<PluginInfo *>* plugs = 0; - - switch (type) { - case PluginInfo::LADSPA: - plugs = &mgr->ladspa_plugin_info(); - break; - case PluginInfo::VST: - plugs = &mgr->vst_plugin_info(); - unique_id = 0; // VST plugins don't have a unique id. - break; - case PluginInfo::AudioUnit: - default: - return 0; - } - - for (i = plugs->begin(); i != plugs->end(); ++i) { - if ((name == "" || (*i)->name == name) && - (unique_id == 0 || (*i)->unique_id == unique_id)) { - return mgr->load (session, *i); - } - } - - return 0; -} - string PluginManager::get_ladspa_category (uint32_t plugin_id) { @@ -397,10 +318,6 @@ PluginManager::get_ladspa_category (uint32_t plugin_id) void PluginManager::vst_refresh () { - for (std::list<PluginInfo*>::iterator i = _vst_plugin_info.begin(); i != _vst_plugin_info.end(); ++i) { - delete *i; - } - _vst_plugin_info.clear (); if (vst_path.length() == 0) { @@ -454,7 +371,6 @@ int PluginManager::vst_discover (string path) { FSTInfo* finfo; - PluginInfo* info; if ((finfo = fst_get_info (const_cast<char *> (path.c_str()))) == 0) { return -1; @@ -466,7 +382,7 @@ PluginManager::vst_discover (string path) << endl; } - info = new PluginInfo; + PluginInfoPtr info(new PluginInfo); /* what a goddam joke freeware VST is */ @@ -489,4 +405,4 @@ PluginManager::vst_discover (string path) return 0; } -#endif +#endif // VST_SUPPORT diff --git a/libs/ardour/po/el_GR.po b/libs/ardour/po/el_GR.po index 33c1bb6e85..5d8adef7d0 100644 --- a/libs/ardour/po/el_GR.po +++ b/libs/ardour/po/el_GR.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: libardour 0.664.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2006-06-27 13:00-0400\n" +"POT-Creation-Date: 2006-06-29 21:03-0400\n" "PO-Revision-Date: 2003-05-21 12:50+0500\n" "Last-Translator: Muadibas\n" "Language-Team: Hellenic(Greek)\n" @@ -56,47 +56,47 @@ msgid "AudioDiskstream \"%1\": cannot flush captured data to disk!" msgstr "" "DiskStream \"%1\": δεν γίνεται να αποÏÏιφθοÏν δειγματοληψίες στο δίσκο!" -#: libs/ardour/audio_diskstream.cc:1795 +#: libs/ardour/audio_diskstream.cc:1796 msgid "%1: could not create region for complete audio file" msgstr "%1: δεν μπόÏεσα να δημιουÏγήσω πεÏιοχή για ολόκληÏο audio file" -#: libs/ardour/audio_diskstream.cc:1818 +#: libs/ardour/audio_diskstream.cc:1819 #, fuzzy msgid "AudioDiskstream: could not create region for captured audio!" msgstr "DiskStream: δεν μπόÏεσα να δημιουÏγήσω πεÏιοχή για δειγματοληψίες!" -#: libs/ardour/audio_diskstream.cc:1873 +#: libs/ardour/audio_diskstream.cc:1874 #, fuzzy msgid "programmer error: %1" msgstr "σφάλμα Ï€ÏογÏαμματισμοÏ: %1" -#: libs/ardour/audio_diskstream.cc:2145 +#: libs/ardour/audio_diskstream.cc:2146 #, fuzzy msgid "AudioDiskstream: channel %1 out of range" msgstr "DiskStream: κανάλι εκτός διαστήματος" -#: libs/ardour/audio_diskstream.cc:2170 +#: libs/ardour/audio_diskstream.cc:2171 msgid "%1:%2 new capture file not initialized correctly" msgstr "%1:%2 νÎα δειγματοληψία δεν εκκινήθη σωστά" -#: libs/ardour/audio_diskstream.cc:2403 +#: libs/ardour/audio_diskstream.cc:2404 msgid "Location \"%1\" not valid for track loop (start >= end)" msgstr "Η Τοποθεσία \"%1\" δεν είναι ικανή για track loop (αÏχή >= Ï„Îλος)" -#: libs/ardour/audio_diskstream.cc:2484 +#: libs/ardour/audio_diskstream.cc:2485 #, fuzzy msgid "%1: cannot restore pending capture source file %2" msgstr "Εισαγωγή: δεν μποÏÏŽ να ανοίξω το εισαγμÎνο αÏχείο ήχου \"%1\"" -#: libs/ardour/audio_diskstream.cc:2506 +#: libs/ardour/audio_diskstream.cc:2507 msgid "%1: incorrect number of pending sources listed - ignoring them all" msgstr "" -#: libs/ardour/audio_diskstream.cc:2522 +#: libs/ardour/audio_diskstream.cc:2523 msgid "%1: cannot create whole-file region from pending capture sources" msgstr "" -#: libs/ardour/audio_diskstream.cc:2534 +#: libs/ardour/audio_diskstream.cc:2535 #, fuzzy msgid "%1: cannot create region from pending capture sources" msgstr "%1: δεν μπόÏεσα να δημιουÏγήσω πεÏιοχή για ολόκληÏο audio file" @@ -155,36 +155,36 @@ msgstr "αλλαγή xfade" msgid "region modified" msgstr "η πεÏιοχή μετεβλήθη" -#: libs/ardour/audio_track.cc:133 libs/ardour/io.cc:1716 +#: libs/ardour/audio_track.cc:125 libs/ardour/io.cc:1716 #: libs/ardour/io.cc:1826 msgid "Unknown connection \"%1\" listed for input of %2" msgstr "Άγνωστη σÏνδεση \"%1\" στη λίστα εισόδου του %2" -#: libs/ardour/audio_track.cc:135 libs/ardour/io.cc:1718 +#: libs/ardour/audio_track.cc:127 libs/ardour/io.cc:1718 #: libs/ardour/io.cc:1828 #, fuzzy msgid "in 1" msgstr "in %lu" -#: libs/ardour/audio_track.cc:136 libs/ardour/io.cc:1719 +#: libs/ardour/audio_track.cc:128 libs/ardour/io.cc:1719 #: libs/ardour/io.cc:1829 msgid "No input connections available as a replacement" msgstr "" -#: libs/ardour/audio_track.cc:140 libs/ardour/io.cc:1723 +#: libs/ardour/audio_track.cc:132 libs/ardour/io.cc:1723 #: libs/ardour/io.cc:1833 msgid "Connection %1 was not available - \"in 1\" used instead" msgstr "" -#: libs/ardour/audio_track.cc:149 libs/ardour/io.cc:1842 +#: libs/ardour/audio_track.cc:141 libs/ardour/io.cc:1842 msgid "improper input channel list in XML node (%1)" msgstr "ακατάλληλη λίστα καναλιών εισόδου στον κόμβο XML (%1)" -#: libs/ardour/audio_track.cc:194 libs/ardour/audio_track.cc:207 +#: libs/ardour/audio_track.cc:186 libs/ardour/audio_track.cc:199 msgid "AudioTrack: diskstream \"%1\" not known by session" msgstr "AudioTrack: το diskstream \"%1\" είναι μή αναγνωÏίσιμο από τη συνεδÏία" -#: libs/ardour/audio_track.cc:305 +#: libs/ardour/audio_track.cc:297 #, fuzzy msgid "" "MIDI rec_enable control specification for %1 is incomplete, so it has been " @@ -193,7 +193,7 @@ msgstr "" "Η Ï€ÏοδιαγÏαφή ελÎγχου του MIDI gain για το %1 είναι ημιτελής, με αποτÎλεσμα " "να αγνοηθεί" -#: libs/ardour/audio_track.cc:317 +#: libs/ardour/audio_track.cc:309 msgid "programming error: AudioTrack given state without diskstream!" msgstr "" "σφάλμα Ï€ÏογÏαμματισμοÏ: εδόθη κατάσταση στην AudioTrack δίχως diskstream!" @@ -272,24 +272,24 @@ msgstr "Σφάλμα: δεν μπόÏεσα να γÏάψω %1" msgid "could not reconnect %1 and %2 (err = %3)" msgstr "" -#: libs/ardour/audiofilesource.cc:445 libs/ardour/session_state.cc:3095 +#: libs/ardour/audiofilesource.cc:444 libs/ardour/session_state.cc:3095 msgid "" "there are already 1000 files with names like %1; versioning discontinued" msgstr "ΥπάÏχουν ήδη 1000 αÏχεία με ονόματα όπως %1; μη-συνεχÎÏ‚ versioning" -#: libs/ardour/audiofilesource.cc:459 libs/ardour/session_state.cc:3109 +#: libs/ardour/audiofilesource.cc:458 libs/ardour/session_state.cc:3109 msgid "cannot rename audio file source from %1 to %2 (%3)" msgstr "δεν μποÏÏŽ να μετονομάσω την πηγή του audio file από %1 σε %2 (%3)" -#: libs/ardour/audiofilesource.cc:466 libs/ardour/session_state.cc:3124 +#: libs/ardour/audiofilesource.cc:465 libs/ardour/session_state.cc:3124 msgid "cannot remove peakfile %1 for %2 (%3)" msgstr "δεν μποÏÏŽ να απαλοίψω το peakfile %1 για %2 (%3)" -#: libs/ardour/audiofilesource.cc:510 +#: libs/ardour/audiofilesource.cc:509 msgid "FileSource: search path not set" msgstr "FileSource: μονοπάτι αναζητήσεως δεν ετÎθη" -#: libs/ardour/audiofilesource.cc:534 +#: libs/ardour/audiofilesource.cc:533 msgid "" "FileSource: \"%1\" is ambigous when searching %2\n" "\t" @@ -297,25 +297,25 @@ msgstr "" "FileSource: \"%1\" είναι αμφίβολο κατά την αναζήτηση του %2\n" "\t" -#: libs/ardour/audiofilesource.cc:540 +#: libs/ardour/audiofilesource.cc:539 #, fuzzy msgid "Filesource: cannot find required file (%1): while searching %2" msgstr "Filesource: δεν ευÏÎθη το απαιτοÏμενο αÏχείο (%1): %2" -#: libs/ardour/audiofilesource.cc:563 +#: libs/ardour/audiofilesource.cc:562 msgid "Filesource: cannot find required file (%1): %2" msgstr "Filesource: δεν ευÏÎθη το απαιτοÏμενο αÏχείο (%1): %2" -#: libs/ardour/audiofilesource.cc:568 +#: libs/ardour/audiofilesource.cc:567 msgid "Filesource: cannot check for existing file (%1): %2" msgstr "Filesource: δεν μποÏÏŽ να ελÎγξω για το υπάÏχον αÏχείο (%1): %2" -#: libs/ardour/audiofilesource.cc:640 libs/ardour/insert.cc:525 -#: libs/ardour/sndfilesource.cc:112 +#: libs/ardour/audiofilesource.cc:636 libs/ardour/insert.cc:525 +#: libs/ardour/sndfilesource.cc:113 msgid "programming error: %1" msgstr "σφάλμα Ï€ÏογÏαμματισμοÏ: %1" -#: libs/ardour/audiofilesource.cc:645 +#: libs/ardour/audiofilesource.cc:641 #, fuzzy msgid "cannot rename audio file for %1 to %2" msgstr "δεν μποÏÏŽ να μετονομάσω την πηγή του audio file από %1 σε %2 (%3)" @@ -1837,7 +1837,7 @@ msgstr "" msgid "cannot remove dead sound file %1 (%2)" msgstr "δεν μποÏÏŽ να απαλοίψω το 'νεκÏο' ηχο-αÏχείο %1 (%2)" -#: libs/ardour/session_time.cc:375 +#: libs/ardour/session_time.cc:374 msgid "Unknown JACK transport state %1 in sync callback" msgstr "Άγνωστη κατάσταση του JACK transport %1 στην ανάκληση sync" @@ -1979,24 +1979,24 @@ msgstr "Little-endian (Intel)" msgid "Big-endian (Mac)" msgstr "Big-endian (Mac)" -#: libs/ardour/sndfilesource.cc:146 +#: libs/ardour/sndfilesource.cc:147 msgid "FileSource: cannot get host information for BWF header (%1)" msgstr "" "FileSource: δεν μποÏÏŽ να βÏÏŽ πληÏοφοÏίες οικοδεσπότη(host) για επικεφαλίδα " "BWF (%1)" -#: libs/ardour/sndfilesource.cc:168 +#: libs/ardour/sndfilesource.cc:169 msgid "" "cannot set broadcast info for audio file %1 (%2); dropping broadcast info " "for this file" msgstr "" -#: libs/ardour/sndfilesource.cc:224 +#: libs/ardour/sndfilesource.cc:220 #, fuzzy msgid "SndFileSource: cannot open file \"%1\" for %2 (%3)" msgstr "SndFileSource: δεν μποÏÏŽ να ανοίξω το αÏχείο \"%1\" (%2)" -#: libs/ardour/sndfilesource.cc:230 +#: libs/ardour/sndfilesource.cc:226 msgid "" "SndFileSource: file only contains %1 channels; %2 is invalid as a channel " "number" @@ -2004,22 +2004,22 @@ msgstr "" "SndFileSource: το αÏχείο πεÏιÎχει μόνο %1 κανάλια; %2 δεν Îχει αξία σαν " "κανάλι number" -#: libs/ardour/sndfilesource.cc:307 +#: libs/ardour/sndfilesource.cc:327 msgid "SndFileSource: could not seek to frame %1 within %2 (%3)" msgstr "SndFileSource: δεν μποÏοÏσα να αναζητήσω στο frame %1 μÎσα στο %2 (%3)" -#: libs/ardour/sndfilesource.cc:358 +#: libs/ardour/sndfilesource.cc:378 #, fuzzy msgid "programming error: %1 %2" msgstr "σφάλμα Ï€ÏογÏαμματισμοÏ: %1" -#: libs/ardour/sndfilesource.cc:458 +#: libs/ardour/sndfilesource.cc:487 libs/ardour/sndfilesource.cc:533 msgid "" "cannot set broadcast info for audio file %1; Dropping broadcast info for " "this file" msgstr "" -#: libs/ardour/sndfilesource.cc:500 +#: libs/ardour/sndfilesource.cc:544 #, fuzzy msgid "%1: cannot seek to %2" msgstr "%1: δεν μποÏÏŽ να αναζητήσω στο %2 για εξαγωγή" @@ -2166,7 +2166,7 @@ msgid "no support for presets using chunks at this time" msgstr "" "καμμία υποστήÏιξη αυτή τη στιγμή για Ïυθμίσεις που χÏησιμοποιοÏν κομμάτια" -#: libs/ardour/coreaudio_source.cc:99 +#: libs/ardour/coreaudiosource.cc:97 #, fuzzy msgid "" "CoreAudioSource: file only contains %1 channels; %2 is invalid as a channel " @@ -2175,7 +2175,7 @@ msgstr "" "SndFileSource: το αÏχείο πεÏιÎχει μόνο %1 κανάλια; %2 δεν Îχει αξία σαν " "κανάλι number" -#: libs/ardour/coreaudio_source.cc:164 +#: libs/ardour/coreaudiosource.cc:162 #, fuzzy msgid "CoreAudioSource: could not seek to frame %1 within %2 (%3)" msgstr "SndFileSource: δεν μποÏοÏσα να αναζητήσω στο frame %1 μÎσα στο %2 (%3)" diff --git a/libs/ardour/po/it_IT.po b/libs/ardour/po/it_IT.po index 63089ea77f..2ce02827bd 100644 --- a/libs/ardour/po/it_IT.po +++ b/libs/ardour/po/it_IT.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: libardour 0.664.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2006-06-27 13:00-0400\n" +"POT-Creation-Date: 2006-06-29 21:03-0400\n" "PO-Revision-Date: 2003-05-21 12:50+0500\n" "Last-Translator: Filippo Pappalardo <filippo@email.it>\n" "Language-Team: Italian\n" @@ -50,48 +50,48 @@ msgstr "DiskStream %1: impossibile scrivere sul disco" msgid "AudioDiskstream \"%1\": cannot flush captured data to disk!" msgstr "DiskStream \"%1\": impossibile scaricare i dati acquisiti sul disco!" -#: libs/ardour/audio_diskstream.cc:1795 +#: libs/ardour/audio_diskstream.cc:1796 msgid "%1: could not create region for complete audio file" msgstr "%1: impossibile creare una regione per il file audio completo" -#: libs/ardour/audio_diskstream.cc:1818 +#: libs/ardour/audio_diskstream.cc:1819 #, fuzzy msgid "AudioDiskstream: could not create region for captured audio!" msgstr "DiskStream: impossibile creare una regione per l'audio registrato!" -#: libs/ardour/audio_diskstream.cc:1873 +#: libs/ardour/audio_diskstream.cc:1874 #, fuzzy msgid "programmer error: %1" msgstr "errore di programmazione: %1" -#: libs/ardour/audio_diskstream.cc:2145 +#: libs/ardour/audio_diskstream.cc:2146 #, fuzzy msgid "AudioDiskstream: channel %1 out of range" msgstr "DiskStream: canale fuori margine" -#: libs/ardour/audio_diskstream.cc:2170 +#: libs/ardour/audio_diskstream.cc:2171 msgid "%1:%2 new capture file not initialized correctly" msgstr "%1:%2 nuovo file di registrazione non è stato avviato correttamente" -#: libs/ardour/audio_diskstream.cc:2403 +#: libs/ardour/audio_diskstream.cc:2404 msgid "Location \"%1\" not valid for track loop (start >= end)" msgstr "La Location \"%1\" non valida per il loop (inizio >= fine)" -#: libs/ardour/audio_diskstream.cc:2484 +#: libs/ardour/audio_diskstream.cc:2485 #, fuzzy msgid "%1: cannot restore pending capture source file %2" msgstr "Import: impossibile aprire il file audio di input \"%1\"" -#: libs/ardour/audio_diskstream.cc:2506 +#: libs/ardour/audio_diskstream.cc:2507 msgid "%1: incorrect number of pending sources listed - ignoring them all" msgstr "" -#: libs/ardour/audio_diskstream.cc:2522 +#: libs/ardour/audio_diskstream.cc:2523 #, fuzzy msgid "%1: cannot create whole-file region from pending capture sources" msgstr "Playlist: impossibile creare la Regione dal file di stato" -#: libs/ardour/audio_diskstream.cc:2534 +#: libs/ardour/audio_diskstream.cc:2535 #, fuzzy msgid "%1: cannot create region from pending capture sources" msgstr "Playlist: impossibile creare la Regione dal file di stato" @@ -145,41 +145,41 @@ msgstr "cambio dello smorzamento incrociato" msgid "region modified" msgstr "regione modificata" -#: libs/ardour/audio_track.cc:133 libs/ardour/io.cc:1716 +#: libs/ardour/audio_track.cc:125 libs/ardour/io.cc:1716 #: libs/ardour/io.cc:1826 msgid "Unknown connection \"%1\" listed for input of %2" msgstr "Connessione sconosciuta \"%1\" come input di %2" -#: libs/ardour/audio_track.cc:135 libs/ardour/io.cc:1718 +#: libs/ardour/audio_track.cc:127 libs/ardour/io.cc:1718 #: libs/ardour/io.cc:1828 msgid "in 1" msgstr "" -#: libs/ardour/audio_track.cc:136 libs/ardour/io.cc:1719 +#: libs/ardour/audio_track.cc:128 libs/ardour/io.cc:1719 #: libs/ardour/io.cc:1829 msgid "No input connections available as a replacement" msgstr "" -#: libs/ardour/audio_track.cc:140 libs/ardour/io.cc:1723 +#: libs/ardour/audio_track.cc:132 libs/ardour/io.cc:1723 #: libs/ardour/io.cc:1833 msgid "Connection %1 was not available - \"in 1\" used instead" msgstr "" -#: libs/ardour/audio_track.cc:149 libs/ardour/io.cc:1842 +#: libs/ardour/audio_track.cc:141 libs/ardour/io.cc:1842 msgid "improper input channel list in XML node (%1)" msgstr "" -#: libs/ardour/audio_track.cc:194 libs/ardour/audio_track.cc:207 +#: libs/ardour/audio_track.cc:186 libs/ardour/audio_track.cc:199 msgid "AudioTrack: diskstream \"%1\" not known by session" msgstr "AudioTrack: diskstream \"%1\" non riconosciuto dalla sessione" -#: libs/ardour/audio_track.cc:305 +#: libs/ardour/audio_track.cc:297 msgid "" "MIDI rec_enable control specification for %1 is incomplete, so it has been " "ignored" msgstr "" -#: libs/ardour/audio_track.cc:317 +#: libs/ardour/audio_track.cc:309 msgid "programming error: AudioTrack given state without diskstream!" msgstr "" @@ -268,25 +268,25 @@ msgstr "Esportazione: impossibile scrivere dati sul file di output (%1)" msgid "could not reconnect %1 and %2 (err = %3)" msgstr "" -#: libs/ardour/audiofilesource.cc:445 libs/ardour/session_state.cc:3095 +#: libs/ardour/audiofilesource.cc:444 libs/ardour/session_state.cc:3095 msgid "" "there are already 1000 files with names like %1; versioning discontinued" msgstr "" "ci sono gia' 1000 file con nomi come %1; tracciamento di versione interrotto" -#: libs/ardour/audiofilesource.cc:459 libs/ardour/session_state.cc:3109 +#: libs/ardour/audiofilesource.cc:458 libs/ardour/session_state.cc:3109 msgid "cannot rename audio file source from %1 to %2 (%3)" msgstr "impossibile rinominare file audio sorgente da %1 a %2 (%3)" -#: libs/ardour/audiofilesource.cc:466 libs/ardour/session_state.cc:3124 +#: libs/ardour/audiofilesource.cc:465 libs/ardour/session_state.cc:3124 msgid "cannot remove peakfile %1 for %2 (%3)" msgstr "impossibile eliminare il peakfile %1 per %2 (%3)" -#: libs/ardour/audiofilesource.cc:510 +#: libs/ardour/audiofilesource.cc:509 msgid "FileSource: search path not set" msgstr "FileSource: percorso di ricerca non specificato" -#: libs/ardour/audiofilesource.cc:534 +#: libs/ardour/audiofilesource.cc:533 msgid "" "FileSource: \"%1\" is ambigous when searching %2\n" "\t" @@ -294,25 +294,25 @@ msgstr "" "FileSource: \"%1\" è risultato ambiguo nel cercare %2\n" "\t" -#: libs/ardour/audiofilesource.cc:540 +#: libs/ardour/audiofilesource.cc:539 #, fuzzy msgid "Filesource: cannot find required file (%1): while searching %2" msgstr "FileSource: impossibile trovare il file richiesto (%1): %2" -#: libs/ardour/audiofilesource.cc:563 +#: libs/ardour/audiofilesource.cc:562 msgid "Filesource: cannot find required file (%1): %2" msgstr "FileSource: impossibile trovare il file richiesto (%1): %2" -#: libs/ardour/audiofilesource.cc:568 +#: libs/ardour/audiofilesource.cc:567 msgid "Filesource: cannot check for existing file (%1): %2" msgstr "FileSource: impossibile controllare il file esistente (%1): %2" -#: libs/ardour/audiofilesource.cc:640 libs/ardour/insert.cc:525 -#: libs/ardour/sndfilesource.cc:112 +#: libs/ardour/audiofilesource.cc:636 libs/ardour/insert.cc:525 +#: libs/ardour/sndfilesource.cc:113 msgid "programming error: %1" msgstr "errore di programmazione: %1" -#: libs/ardour/audiofilesource.cc:645 +#: libs/ardour/audiofilesource.cc:641 #, fuzzy msgid "cannot rename audio file for %1 to %2" msgstr "impossibile rinominare file audio sorgente da %1 a %2 (%3)" @@ -1782,7 +1782,7 @@ msgstr "Nodo sconosciuto \"%1\" trovato in Connections list dal file di stato" msgid "cannot remove dead sound file %1 (%2)" msgstr "impossibile accedere al file audio per il click %1 (%2)" -#: libs/ardour/session_time.cc:375 +#: libs/ardour/session_time.cc:374 msgid "Unknown JACK transport state %1 in sync callback" msgstr "" @@ -1915,22 +1915,22 @@ msgstr "" msgid "Big-endian (Mac)" msgstr "" -#: libs/ardour/sndfilesource.cc:146 +#: libs/ardour/sndfilesource.cc:147 msgid "FileSource: cannot get host information for BWF header (%1)" msgstr "FileSource: impossibile ottenere info sull'host dall'header BWF (%1)" -#: libs/ardour/sndfilesource.cc:168 +#: libs/ardour/sndfilesource.cc:169 msgid "" "cannot set broadcast info for audio file %1 (%2); dropping broadcast info " "for this file" msgstr "" -#: libs/ardour/sndfilesource.cc:224 +#: libs/ardour/sndfilesource.cc:220 #, fuzzy msgid "SndFileSource: cannot open file \"%1\" for %2 (%3)" msgstr "SndFileSource: impossibile accedere al file \"%1\" (%2)" -#: libs/ardour/sndfilesource.cc:230 +#: libs/ardour/sndfilesource.cc:226 msgid "" "SndFileSource: file only contains %1 channels; %2 is invalid as a channel " "number" @@ -1938,22 +1938,22 @@ msgstr "" "SndFileSource: il file contiene solo %1 canali; %2 non è valido come numero " "di canale" -#: libs/ardour/sndfilesource.cc:307 +#: libs/ardour/sndfilesource.cc:327 msgid "SndFileSource: could not seek to frame %1 within %2 (%3)" msgstr "" -#: libs/ardour/sndfilesource.cc:358 +#: libs/ardour/sndfilesource.cc:378 #, fuzzy msgid "programming error: %1 %2" msgstr "errore di programmazione: %1" -#: libs/ardour/sndfilesource.cc:458 +#: libs/ardour/sndfilesource.cc:487 libs/ardour/sndfilesource.cc:533 msgid "" "cannot set broadcast info for audio file %1; Dropping broadcast info for " "this file" msgstr "" -#: libs/ardour/sndfilesource.cc:500 +#: libs/ardour/sndfilesource.cc:544 msgid "%1: cannot seek to %2" msgstr "" @@ -2100,7 +2100,7 @@ msgstr "" msgid "no support for presets using chunks at this time" msgstr "" -#: libs/ardour/coreaudio_source.cc:99 +#: libs/ardour/coreaudiosource.cc:97 #, fuzzy msgid "" "CoreAudioSource: file only contains %1 channels; %2 is invalid as a channel " @@ -2109,7 +2109,7 @@ msgstr "" "SndFileSource: il file contiene solo %1 canali; %2 non è valido come numero " "di canale" -#: libs/ardour/coreaudio_source.cc:164 +#: libs/ardour/coreaudiosource.cc:162 msgid "CoreAudioSource: could not seek to frame %1 within %2 (%3)" msgstr "" diff --git a/libs/ardour/po/ru_RU.po b/libs/ardour/po/ru_RU.po index 2ca30cba55..aeeb1bf547 100644 --- a/libs/ardour/po/ru_RU.po +++ b/libs/ardour/po/ru_RU.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: libardour 0.716.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2006-06-27 13:00-0400\n" +"POT-Creation-Date: 2006-06-29 21:03-0400\n" "PO-Revision-Date: 2004-03-31 00:55+0300\n" "Last-Translator: Igor Blinov pitstop@nm.ru\n" "Language-Team: Russian\n" @@ -43,44 +43,44 @@ msgstr "" msgid "AudioDiskstream \"%1\": cannot flush captured data to disk!" msgstr "" -#: libs/ardour/audio_diskstream.cc:1795 +#: libs/ardour/audio_diskstream.cc:1796 msgid "%1: could not create region for complete audio file" msgstr "" -#: libs/ardour/audio_diskstream.cc:1818 +#: libs/ardour/audio_diskstream.cc:1819 msgid "AudioDiskstream: could not create region for captured audio!" msgstr "" -#: libs/ardour/audio_diskstream.cc:1873 +#: libs/ardour/audio_diskstream.cc:1874 #, fuzzy msgid "programmer error: %1" msgstr "ÏÛÉÂËÁ ÐÒÏÇÒÁÍÍÙ: " -#: libs/ardour/audio_diskstream.cc:2145 +#: libs/ardour/audio_diskstream.cc:2146 msgid "AudioDiskstream: channel %1 out of range" msgstr "" -#: libs/ardour/audio_diskstream.cc:2170 +#: libs/ardour/audio_diskstream.cc:2171 msgid "%1:%2 new capture file not initialized correctly" msgstr "" -#: libs/ardour/audio_diskstream.cc:2403 +#: libs/ardour/audio_diskstream.cc:2404 msgid "Location \"%1\" not valid for track loop (start >= end)" msgstr "" -#: libs/ardour/audio_diskstream.cc:2484 +#: libs/ardour/audio_diskstream.cc:2485 msgid "%1: cannot restore pending capture source file %2" msgstr "" -#: libs/ardour/audio_diskstream.cc:2506 +#: libs/ardour/audio_diskstream.cc:2507 msgid "%1: incorrect number of pending sources listed - ignoring them all" msgstr "" -#: libs/ardour/audio_diskstream.cc:2522 +#: libs/ardour/audio_diskstream.cc:2523 msgid "%1: cannot create whole-file region from pending capture sources" msgstr "" -#: libs/ardour/audio_diskstream.cc:2534 +#: libs/ardour/audio_diskstream.cc:2535 msgid "%1: cannot create region from pending capture sources" msgstr "" @@ -133,41 +133,41 @@ msgstr "" msgid "region modified" msgstr "" -#: libs/ardour/audio_track.cc:133 libs/ardour/io.cc:1716 +#: libs/ardour/audio_track.cc:125 libs/ardour/io.cc:1716 #: libs/ardour/io.cc:1826 msgid "Unknown connection \"%1\" listed for input of %2" msgstr "" -#: libs/ardour/audio_track.cc:135 libs/ardour/io.cc:1718 +#: libs/ardour/audio_track.cc:127 libs/ardour/io.cc:1718 #: libs/ardour/io.cc:1828 msgid "in 1" msgstr "" -#: libs/ardour/audio_track.cc:136 libs/ardour/io.cc:1719 +#: libs/ardour/audio_track.cc:128 libs/ardour/io.cc:1719 #: libs/ardour/io.cc:1829 msgid "No input connections available as a replacement" msgstr "" -#: libs/ardour/audio_track.cc:140 libs/ardour/io.cc:1723 +#: libs/ardour/audio_track.cc:132 libs/ardour/io.cc:1723 #: libs/ardour/io.cc:1833 msgid "Connection %1 was not available - \"in 1\" used instead" msgstr "" -#: libs/ardour/audio_track.cc:149 libs/ardour/io.cc:1842 +#: libs/ardour/audio_track.cc:141 libs/ardour/io.cc:1842 msgid "improper input channel list in XML node (%1)" msgstr "" -#: libs/ardour/audio_track.cc:194 libs/ardour/audio_track.cc:207 +#: libs/ardour/audio_track.cc:186 libs/ardour/audio_track.cc:199 msgid "AudioTrack: diskstream \"%1\" not known by session" msgstr "" -#: libs/ardour/audio_track.cc:305 +#: libs/ardour/audio_track.cc:297 msgid "" "MIDI rec_enable control specification for %1 is incomplete, so it has been " "ignored" msgstr "" -#: libs/ardour/audio_track.cc:317 +#: libs/ardour/audio_track.cc:309 msgid "programming error: AudioTrack given state without diskstream!" msgstr "" @@ -243,48 +243,48 @@ msgstr "" msgid "could not reconnect %1 and %2 (err = %3)" msgstr "" -#: libs/ardour/audiofilesource.cc:445 libs/ardour/session_state.cc:3095 +#: libs/ardour/audiofilesource.cc:444 libs/ardour/session_state.cc:3095 msgid "" "there are already 1000 files with names like %1; versioning discontinued" msgstr "" -#: libs/ardour/audiofilesource.cc:459 libs/ardour/session_state.cc:3109 +#: libs/ardour/audiofilesource.cc:458 libs/ardour/session_state.cc:3109 msgid "cannot rename audio file source from %1 to %2 (%3)" msgstr "" -#: libs/ardour/audiofilesource.cc:466 libs/ardour/session_state.cc:3124 +#: libs/ardour/audiofilesource.cc:465 libs/ardour/session_state.cc:3124 msgid "cannot remove peakfile %1 for %2 (%3)" msgstr "" -#: libs/ardour/audiofilesource.cc:510 +#: libs/ardour/audiofilesource.cc:509 msgid "FileSource: search path not set" msgstr "" -#: libs/ardour/audiofilesource.cc:534 +#: libs/ardour/audiofilesource.cc:533 msgid "" "FileSource: \"%1\" is ambigous when searching %2\n" "\t" msgstr "" -#: libs/ardour/audiofilesource.cc:540 +#: libs/ardour/audiofilesource.cc:539 msgid "Filesource: cannot find required file (%1): while searching %2" msgstr "" -#: libs/ardour/audiofilesource.cc:563 +#: libs/ardour/audiofilesource.cc:562 msgid "Filesource: cannot find required file (%1): %2" msgstr "" -#: libs/ardour/audiofilesource.cc:568 +#: libs/ardour/audiofilesource.cc:567 msgid "Filesource: cannot check for existing file (%1): %2" msgstr "" -#: libs/ardour/audiofilesource.cc:640 libs/ardour/insert.cc:525 -#: libs/ardour/sndfilesource.cc:112 +#: libs/ardour/audiofilesource.cc:636 libs/ardour/insert.cc:525 +#: libs/ardour/sndfilesource.cc:113 #, fuzzy msgid "programming error: %1" msgstr "ÏÛÉÂËÁ ÐÒÏÇÒÁÍÍÙ: " -#: libs/ardour/audiofilesource.cc:645 +#: libs/ardour/audiofilesource.cc:641 msgid "cannot rename audio file for %1 to %2" msgstr "" @@ -1684,7 +1684,7 @@ msgstr "" msgid "cannot remove dead sound file %1 (%2)" msgstr "" -#: libs/ardour/session_time.cc:375 +#: libs/ardour/session_time.cc:374 msgid "Unknown JACK transport state %1 in sync callback" msgstr "" @@ -1816,42 +1816,42 @@ msgstr "" msgid "Big-endian (Mac)" msgstr "" -#: libs/ardour/sndfilesource.cc:146 +#: libs/ardour/sndfilesource.cc:147 msgid "FileSource: cannot get host information for BWF header (%1)" msgstr "" -#: libs/ardour/sndfilesource.cc:168 +#: libs/ardour/sndfilesource.cc:169 msgid "" "cannot set broadcast info for audio file %1 (%2); dropping broadcast info " "for this file" msgstr "" -#: libs/ardour/sndfilesource.cc:224 +#: libs/ardour/sndfilesource.cc:220 msgid "SndFileSource: cannot open file \"%1\" for %2 (%3)" msgstr "" -#: libs/ardour/sndfilesource.cc:230 +#: libs/ardour/sndfilesource.cc:226 msgid "" "SndFileSource: file only contains %1 channels; %2 is invalid as a channel " "number" msgstr "" -#: libs/ardour/sndfilesource.cc:307 +#: libs/ardour/sndfilesource.cc:327 msgid "SndFileSource: could not seek to frame %1 within %2 (%3)" msgstr "" -#: libs/ardour/sndfilesource.cc:358 +#: libs/ardour/sndfilesource.cc:378 #, fuzzy msgid "programming error: %1 %2" msgstr "ÏÛÉÂËÁ ÐÒÏÇÒÁÍÍÙ: " -#: libs/ardour/sndfilesource.cc:458 +#: libs/ardour/sndfilesource.cc:487 libs/ardour/sndfilesource.cc:533 msgid "" "cannot set broadcast info for audio file %1; Dropping broadcast info for " "this file" msgstr "" -#: libs/ardour/sndfilesource.cc:500 +#: libs/ardour/sndfilesource.cc:544 msgid "%1: cannot seek to %2" msgstr "" @@ -1989,12 +1989,12 @@ msgstr "" msgid "no support for presets using chunks at this time" msgstr "" -#: libs/ardour/coreaudio_source.cc:99 +#: libs/ardour/coreaudiosource.cc:97 msgid "" "CoreAudioSource: file only contains %1 channels; %2 is invalid as a channel " "number" msgstr "" -#: libs/ardour/coreaudio_source.cc:164 +#: libs/ardour/coreaudiosource.cc:162 msgid "CoreAudioSource: could not seek to frame %1 within %2 (%3)" msgstr "" diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc index c5c03d0a05..7ec0d5a05a 100644 --- a/libs/ardour/port.cc +++ b/libs/ardour/port.cc @@ -24,15 +24,15 @@ using namespace ARDOUR; using namespace std; Port::Port (jack_port_t *p) - : port (p) + : _port (p) { - if (port == 0) { + if (_port == 0) { throw failed_constructor(); } - _flags = JackPortFlags (jack_port_flags (port)); - _type = jack_port_type (port); - _name = jack_port_name (port); + _flags = JackPortFlags (jack_port_flags (_port)); + _type = jack_port_type (_port); + _name = jack_port_name (_port); reset (); } @@ -42,9 +42,9 @@ Port::reset () { reset_buffer (); - last_monitor = false; - silent = false; - metering = 0; + _last_monitor = false; + _silent = false; + _metering = 0; reset_meters (); } @@ -54,7 +54,7 @@ Port::set_name (string str) { int ret; - if ((ret = jack_port_set_name (port, str.c_str())) == 0) { + if ((ret = jack_port_set_name (_port, str.c_str())) == 0) { _name = str; } diff --git a/libs/ardour/redirect.cc b/libs/ardour/redirect.cc index 33fec5088f..1ab2f91cf0 100644 --- a/libs/ardour/redirect.cc +++ b/libs/ardour/redirect.cc @@ -60,25 +60,25 @@ Redirect::~Redirect () { } -Redirect* -Redirect::clone (const Redirect& other) +boost::shared_ptr<Redirect> +Redirect::clone (boost::shared_ptr<const Redirect> other) { - const Send *send; - const PortInsert *port_insert; - const PluginInsert *plugin_insert; - - if ((send = dynamic_cast<const Send*>(&other)) != 0) { - return new Send (*send); - } else if ((port_insert = dynamic_cast<const PortInsert*>(&other)) != 0) { - return new PortInsert (*port_insert); - } else if ((plugin_insert = dynamic_cast<const PluginInsert*>(&other)) != 0) { - return new PluginInsert (*plugin_insert); + boost::shared_ptr<const Send> send; + boost::shared_ptr<const PortInsert> port_insert; + boost::shared_ptr<const PluginInsert> plugin_insert; + + if ((send = boost::dynamic_pointer_cast<const Send>(other)) != 0) { + return boost::shared_ptr<Redirect> (new Send (*send)); + } else if ((port_insert = boost::dynamic_pointer_cast<const PortInsert>(other)) != 0) { + return boost::shared_ptr<Redirect> (new PortInsert (*port_insert)); + } else if ((plugin_insert = boost::dynamic_pointer_cast<const PluginInsert>(other)) != 0) { + return boost::shared_ptr<Redirect> (new PluginInsert (*plugin_insert)); } else { fatal << _("programming error: unknown Redirect type in Redirect::Clone!\n") << endmsg; /*NOTREACHED*/ } - return 0; + return boost::shared_ptr<Redirect>(); } void @@ -231,9 +231,9 @@ Redirect::state (bool full_state) string path; string legal_name; - snprintf (buf, sizeof(buf), "%" PRIu64, id()); path = _session.snap_name(); path += "-redirect-"; + id().print (buf); path += buf; path += ".automation"; diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index 8c27a3bebc..037c844324 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -39,13 +39,13 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -Change Region::FadeChanged = ARDOUR::new_change (); +Change Region::FadeChanged = ARDOUR::new_change (); Change Region::SyncOffsetChanged = ARDOUR::new_change (); -Change Region::MuteChanged = ARDOUR::new_change (); -Change Region::OpacityChanged = ARDOUR::new_change (); -Change Region::LockChanged = ARDOUR::new_change (); -Change Region::LayerChanged = ARDOUR::new_change (); -Change Region::HiddenChanged = ARDOUR::new_change (); +Change Region::MuteChanged = ARDOUR::new_change (); +Change Region::OpacityChanged = ARDOUR::new_change (); +Change Region::LockChanged = ARDOUR::new_change (); +Change Region::LayerChanged = ARDOUR::new_change (); +Change Region::HiddenChanged = ARDOUR::new_change (); sigc::signal<void,Region *> Region::CheckNewRegion; @@ -53,7 +53,6 @@ Region::Region (jack_nframes_t start, jack_nframes_t length, const string& name, { /* basic Region constructor */ - _id = ARDOUR::new_id(); _flags = flags; _playlist = 0; _read_data_count = 0; @@ -76,7 +75,6 @@ Region::Region (const Region& other, jack_nframes_t offset, jack_nframes_t lengt { /* create a new Region from part of an existing one */ - _id = ARDOUR::new_id(); _frozen = 0; pending_changed = Change (0); _playlist = 0; @@ -102,7 +100,6 @@ Region::Region (const Region &other) { /* Pure copy constructor */ - _id = ARDOUR::new_id(); _frozen = 0; pending_changed = Change (0); _playlist = 0; @@ -130,7 +127,6 @@ Region::Region (const Region &other) Region::Region (const XMLNode& node) { - _id = 0; _frozen = 0; pending_changed = Change (0); _playlist = 0; @@ -844,7 +840,7 @@ Region::state (bool full_state) XMLNode *node = new XMLNode ("Region"); char buf[64]; - snprintf (buf, sizeof (buf), "%" PRIu64, _id); + _id.print (buf); node->add_property ("id", buf); node->add_property ("name", _name); snprintf (buf, sizeof (buf), "%u", _start); @@ -886,7 +882,7 @@ Region::set_state (const XMLNode& node) return -1; } - sscanf (prop->value().c_str(), "%" PRIu64, &_id); + _id = prop->value(); if ((prop = node.property ("name")) == 0) { error << _("Session: XMLNode describing a Region is incomplete (no name)") << endmsg; @@ -994,3 +990,30 @@ Region::set_last_layer_op (uint64_t when) { _last_layer_op = when; } + +bool +Region::overlap_equivalent (const Region& other) const +{ + return coverage (other.first_frame(), other.last_frame()) != OverlapNone; +} + +bool +Region::equivalent (const Region& other) const +{ + return _start == other._start && + _position == other._position && + _length == other._length; +} + +bool +Region::size_equivalent (const Region& other) const +{ + return _start == other._start && + _length == other._length; +} + +bool +Region::region_list_equivalent (const Region& other) const +{ + return size_equivalent (other) && source_equivalent (other) && _name == other._name; +} diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 3f51b2f140..b47981a47e 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -20,11 +20,13 @@ #include <cmath> #include <fstream> +#include <cassert> #include <sigc++/bind.h> #include <pbd/xml++.h> #include <ardour/timestamps.h> +#include <ardour/buffer.h> #include <ardour/audioengine.h> #include <ardour/route.h> #include <ardour/insert.h> @@ -50,19 +52,19 @@ using namespace PBD; uint32_t Route::order_key_cnt = 0; -Route::Route (Session& sess, string name, int input_min, int input_max, int output_min, int output_max, Flag flg) - : IO (sess, name, input_min, input_max, output_min, output_max), +Route::Route (Session& sess, string name, int input_min, int input_max, int output_min, int output_max, Flag flg, DataType default_type) + : IO (sess, name, input_min, input_max, output_min, output_max, default_type), _flags (flg), - _midi_solo_control (*this, MIDIToggleControl::SoloControl, _session.midi_port()), - _midi_mute_control (*this, MIDIToggleControl::MuteControl, _session.midi_port()) + _solo_control (*this, ToggleControllable::SoloControl), + _mute_control (*this, ToggleControllable::MuteControl) { init (); } Route::Route (Session& sess, const XMLNode& node) : IO (sess, "route"), - _midi_solo_control (*this, MIDIToggleControl::SoloControl, _session.midi_port()), - _midi_mute_control (*this, MIDIToggleControl::MuteControl, _session.midi_port()) + _solo_control (*this, ToggleControllable::SoloControl), + _mute_control (*this, ToggleControllable::MuteControl) { init (); set_state (node); @@ -105,8 +107,6 @@ Route::init () input_changed.connect (mem_fun (this, &Route::input_change_handler)); output_changed.connect (mem_fun (this, &Route::output_change_handler)); - - reset_midi_control (_session.midi_port(), _session.get_midi_control()); } Route::~Route () @@ -712,11 +712,8 @@ Route::set_solo (bool yn, void *src) if (_soloed != yn) { _soloed = yn; - solo_changed (src); /* EMIT SIGNAL */ - - if (_session.get_midi_feedback()) { - _midi_solo_control.send_feedback (_soloed); - } + solo_changed (src); /* EMIT SIGNAL */ + _solo_control.Changed (); /* EMIT SIGNAL */ } } @@ -753,9 +750,7 @@ Route::set_mute (bool yn, void *src) _muted = yn; mute_changed (src); /* EMIT SIGNAL */ - if (_session.get_midi_feedback()) { - _midi_mute_control.send_feedback (_muted); - } + _mute_control.Changed (); /* EMIT SIGNAL */ Glib::Mutex::Lock lm (declick_lock); desired_mute_gain = (yn?0.0f:1.0f); @@ -763,7 +758,7 @@ Route::set_mute (bool yn, void *src) } int -Route::add_redirect (Redirect *redirect, void *src, uint32_t* err_streams) +Route::add_redirect (boost::shared_ptr<Redirect> redirect, void *src, uint32_t* err_streams) { uint32_t old_rmo = redirect_max_outs; @@ -774,12 +769,12 @@ Route::add_redirect (Redirect *redirect, void *src, uint32_t* err_streams) { Glib::RWLock::WriterLock lm (redirect_lock); - PluginInsert* pi; - PortInsert* porti; + boost::shared_ptr<PluginInsert> pi; + boost::shared_ptr<PortInsert> porti; uint32_t potential_max_streams = 0; - if ((pi = dynamic_cast<PluginInsert*>(redirect)) != 0) { + if ((pi = boost::dynamic_pointer_cast<PluginInsert>(redirect)) != 0) { pi->set_count (1); if (pi->input_streams() == 0) { @@ -788,8 +783,8 @@ Route::add_redirect (Redirect *redirect, void *src, uint32_t* err_streams) } potential_max_streams = max(pi->input_streams(), pi->output_streams()); - - } else if ((porti = dynamic_cast<PortInsert*>(redirect)) != 0) { + + } else if ((porti = boost::dynamic_pointer_cast<PortInsert>(redirect)) != 0) { /* force new port inserts to start out with an i/o configuration that matches this route's i/o configuration. @@ -854,9 +849,9 @@ Route::add_redirects (const RedirectList& others, void *src, uint32_t* err_strea for (RedirectList::const_iterator i = others.begin(); i != others.end(); ++i) { - PluginInsert* pi; + boost::shared_ptr<PluginInsert> pi; - if ((pi = dynamic_cast<PluginInsert*>(*i)) != 0) { + if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) { pi->set_count (1); uint32_t m = max(pi->input_streams(), pi->output_streams()); @@ -905,11 +900,6 @@ Route::clear_redirects (void *src) { Glib::RWLock::WriterLock lm (redirect_lock); - - for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) { - delete *i; - } - _redirects.clear (); } @@ -923,7 +913,7 @@ Route::clear_redirects (void *src) } int -Route::remove_redirect (Redirect *redirect, void *src, uint32_t* err_streams) +Route::remove_redirect (boost::shared_ptr<Redirect> redirect, void *src, uint32_t* err_streams) { uint32_t old_rmo = redirect_max_outs; @@ -955,13 +945,13 @@ Route::remove_redirect (Redirect *redirect, void *src, uint32_t* err_streams) run. */ - Send* send; - PortInsert* port_insert; + boost::shared_ptr<Send> send; + boost::shared_ptr<PortInsert> port_insert; - if ((send = dynamic_cast<Send*> (*i)) != 0) { + if ((send = boost::dynamic_pointer_cast<Send> (*i)) != 0) { send->disconnect_inputs (this); send->disconnect_outputs (this); - } else if ((port_insert = dynamic_cast<PortInsert*> (*i)) != 0) { + } else if ((port_insert = boost::dynamic_pointer_cast<PortInsert> (*i)) != 0) { port_insert->disconnect_inputs (this); port_insert->disconnect_outputs (this); } @@ -990,9 +980,9 @@ Route::remove_redirect (Redirect *redirect, void *src, uint32_t* err_streams) bool foo = false; for (i = _redirects.begin(); i != _redirects.end(); ++i) { - PluginInsert* pi; - - if ((pi = dynamic_cast<PluginInsert*>(*i)) != 0) { + boost::shared_ptr<PluginInsert> pi; + + if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) { if (pi->is_generator()) { foo = true; } @@ -1039,7 +1029,7 @@ Route::_reset_plugin_counts (uint32_t* err_streams) for (r = _redirects.begin(); r != _redirects.end(); ++r) { - Insert *insert; + boost::shared_ptr<Insert> insert; /* do this here in case we bomb out before we get to the end of this function. @@ -1047,22 +1037,22 @@ Route::_reset_plugin_counts (uint32_t* err_streams) redirect_max_outs = max ((*r)->output_streams (), redirect_max_outs); - if ((insert = dynamic_cast<Insert*>(*r)) != 0) { + if ((insert = boost::dynamic_pointer_cast<Insert>(*r)) != 0) { ++i_cnt; - insert_map[insert->placement()].push_back (InsertCount (*insert)); + insert_map[insert->placement()].push_back (InsertCount (insert)); /* reset plugin counts back to one for now so that we have a predictable, controlled state to try to configure. */ - PluginInsert* pi; + boost::shared_ptr<PluginInsert> pi; - if ((pi = dynamic_cast<PluginInsert*>(insert)) != 0) { + if ((pi = boost::dynamic_pointer_cast<PluginInsert>(insert)) != 0) { pi->set_count (1); } - } else if (dynamic_cast<Send*> (*r) != 0) { + } else if (boost::dynamic_pointer_cast<Send> (*r) != 0) { ++s_cnt; } } @@ -1089,7 +1079,7 @@ Route::_reset_plugin_counts (uint32_t* err_streams) if (!insert_map[PreFader].empty()) { InsertCount& ic (insert_map[PreFader].back()); - initial_streams = ic.insert.compute_output_streams (ic.cnt); + initial_streams = ic.insert->compute_output_streams (ic.cnt); } else { initial_streams = n_inputs (); } @@ -1113,9 +1103,9 @@ Route::_reset_plugin_counts (uint32_t* err_streams) RedirectList::iterator prev = _redirects.end(); for (r = _redirects.begin(); r != _redirects.end(); prev = r, ++r) { - Send* s; + boost::shared_ptr<Send> s; - if ((s = dynamic_cast<Send*> (*r)) != 0) { + if ((s = boost::dynamic_pointer_cast<Send> (*r)) != 0) { if (r == _redirects.begin()) { s->expect_inputs (n_inputs()); } else { @@ -1138,11 +1128,11 @@ Route::apply_some_plugin_counts (list<InsertCount>& iclist) for (i = iclist.begin(); i != iclist.end(); ++i) { - if ((*i).insert.configure_io ((*i).cnt, (*i).in, (*i).out)) { + if ((*i).insert->configure_io ((*i).cnt, (*i).in, (*i).out)) { return -1; } /* make sure that however many we have, they are all active */ - (*i).insert.activate (); + (*i).insert->activate (); } return 0; @@ -1155,7 +1145,7 @@ Route::check_some_plugin_counts (list<InsertCount>& iclist, int32_t required_inp for (i = iclist.begin(); i != iclist.end(); ++i) { - if (((*i).cnt = (*i).insert.can_support_input_configuration (required_inputs)) < 0) { + if (((*i).cnt = (*i).insert->can_support_input_configuration (required_inputs)) < 0) { if (err_streams) { *err_streams = required_inputs; } @@ -1163,7 +1153,7 @@ Route::check_some_plugin_counts (list<InsertCount>& iclist, int32_t required_inp } (*i).in = required_inputs; - (*i).out = (*i).insert.compute_output_streams ((*i).cnt); + (*i).out = (*i).insert->compute_output_streams ((*i).cnt); required_inputs = (*i).out; } @@ -1207,7 +1197,7 @@ Route::copy_redirects (const Route& other, Placement placement, uint32_t* err_st for (RedirectList::const_iterator i = other._redirects.begin(); i != other._redirects.end(); ++i) { if ((*i)->placement() == placement) { - _redirects.push_back (Redirect::clone (**i)); + _redirects.push_back (Redirect::clone (*i)); } } @@ -1225,7 +1215,6 @@ Route::copy_redirects (const Route& other, Placement placement, uint32_t* err_st ++tmp; if ((*i)->placement() == placement) { - delete *i; _redirects.erase (i); } @@ -1244,10 +1233,7 @@ Route::copy_redirects (const Route& other, Placement placement, uint32_t* err_st } else { /* SUCCESSFUL COPY ATTEMPT: delete the redirects we removed pre-copy */ - - for (RedirectList::iterator i = to_be_deleted.begin(); i != to_be_deleted.end(); ++i) { - delete *i; - } + to_be_deleted.clear (); } } @@ -1290,7 +1276,7 @@ Route::all_redirects_active (bool state) } struct RedirectSorter { - bool operator() (const Redirect *a, const Redirect *b) { + bool operator() (boost::shared_ptr<const Redirect> a, boost::shared_ptr<const Redirect> b) { return a->sort_key() < b->sort_key(); } }; @@ -1346,6 +1332,9 @@ Route::state(bool full_state) snprintf (buf, sizeof (buf), "0x%x", _flags); node->add_property("flags", buf); } + + node->add_property("default-type", _default_type.to_string()); + node->add_property("active", _active?"yes":"no"); node->add_property("muted", _muted?"yes":"no"); node->add_property("soloed", _soloed?"yes":"no"); @@ -1362,26 +1351,6 @@ Route::state(bool full_state) node->add_property("mix-group", _mix_group->name()); } - /* MIDI control */ - - MIDI::channel_t chn; - MIDI::eventType ev; - MIDI::byte additional; - XMLNode* midi_node = 0; - XMLNode* child; - - midi_node = node->add_child ("MIDI"); - - if (_midi_mute_control.get_control_info (chn, ev, additional)) { - child = midi_node->add_child ("mute"); - set_midi_node_info (child, ev, chn, additional); - } - if (_midi_solo_control.get_control_info (chn, ev, additional)) { - child = midi_node->add_child ("solo"); - set_midi_node_info (child, ev, chn, additional); - } - - string order_string; OrderKeys::iterator x = order_keys.begin(); @@ -1469,13 +1438,13 @@ void Route::add_redirect_from_xml (const XMLNode& node) { const XMLProperty *prop; - Insert *insert = 0; - Send *send = 0; if (node.name() == "Send") { + try { - send = new Send (_session, node); + boost::shared_ptr<Send> send (new Send (_session, node)); + add_redirect (send, this); } catch (failed_constructor &err) { @@ -1483,21 +1452,21 @@ Route::add_redirect_from_xml (const XMLNode& node) return; } - add_redirect (send, this); - } else if (node.name() == "Insert") { try { if ((prop = node.property ("type")) != 0) { + boost::shared_ptr<Insert> insert; + if (prop->value() == "ladspa" || prop->value() == "Ladspa" || prop->value() == "vst") { - insert = new PluginInsert(_session, node); + insert.reset (new PluginInsert(_session, node)); } else if (prop->value() == "port") { - insert = new PortInsert (_session, node); + insert.reset (new PortInsert (_session, node)); } else { @@ -1526,8 +1495,6 @@ Route::set_state (const XMLNode& node) XMLNode *child; XMLPropertyList plist; const XMLProperty *prop; - XMLNodeList midi_kids; - if (node.name() != "Route"){ error << string_compose(_("Bad node sent to Route::set_state() [%1]"), node.name()) << endmsg; @@ -1541,6 +1508,11 @@ Route::set_state (const XMLNode& node) } else { _flags = Flag (0); } + + if ((prop = node.property ("default-type")) != 0) { + _default_type = DataType(prop->value()); + assert(_default_type != DataType::NIL); + } if ((prop = node.property ("phase-invert")) != 0) { set_phase_invert(prop->value()=="yes"?true:false, this); @@ -1716,45 +1688,6 @@ Route::set_state (const XMLNode& node) } } - midi_kids = node.children ("MIDI"); - - for (niter = midi_kids.begin(); niter != midi_kids.end(); ++niter) { - - XMLNodeList kids; - XMLNodeConstIterator miter; - XMLNode* child; - - kids = (*niter)->children (); - - for (miter = kids.begin(); miter != kids.end(); ++miter) { - - child =* miter; - - MIDI::eventType ev = MIDI::on; /* initialize to keep gcc happy */ - MIDI::byte additional = 0; /* ditto */ - MIDI::channel_t chn = 0; /* ditto */ - - if (child->name() == "mute") { - - if (get_midi_node_info (child, ev, chn, additional)) { - _midi_mute_control.set_control_type (chn, ev, additional); - } else { - error << string_compose(_("MIDI mute control specification for %1 is incomplete, so it has been ignored"), _name) << endmsg; - } - } - else if (child->name() == "solo") { - - if (get_midi_node_info (child, ev, chn, additional)) { - _midi_solo_control.set_control_type (chn, ev, additional); - } else { - error << string_compose(_("MIDI mute control specification for %1 is incomplete, so it has been ignored"), _name) << endmsg; - } - } - - } - } - - return 0; } @@ -1783,8 +1716,8 @@ Route::silence (jack_nframes_t nframes, jack_nframes_t offset) if (lm.locked()) { for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) { - PluginInsert* pi; - if (!_active && (pi = dynamic_cast<PluginInsert*> (*i)) != 0) { + boost::shared_ptr<PluginInsert> pi; + if (!_active && (pi = boost::dynamic_pointer_cast<PluginInsert> (*i)) != 0) { // skip plugins, they don't need anything when we're not active continue; } @@ -1895,18 +1828,17 @@ Route::set_comment (string cmt, void *src) } bool -Route::feeds (Route *o) +Route::feeds (boost::shared_ptr<Route> other) { uint32_t i, j; - IO& other = *o; IO& self = *this; uint32_t no = self.n_outputs(); - uint32_t ni = other.n_inputs (); + uint32_t ni = other->n_inputs (); for (i = 0; i < no; ++i) { for (j = 0; j < ni; ++j) { - if (self.output(i)->connected_to (other.input(j)->name())) { + if (self.output(i)->connected_to (other->input(j)->name())) { return true; } } @@ -1920,7 +1852,7 @@ Route::feeds (Route *o) for (i = 0; i < no; ++i) { for (j = 0; j < ni; ++j) { - if ((*r)->output(i)->connected_to (other.input (j)->name())) { + if ((*r)->output(i)->connected_to (other->input (j)->name())) { return true; } } @@ -1935,7 +1867,7 @@ Route::feeds (Route *o) for (i = 0; i < no; ++i) { for (j = 0; j < ni; ++j) { - if (_control_outs->output(i)->connected_to (other.input (j)->name())) { + if (_control_outs->output(i)->connected_to (other->input (j)->name())) { return true; } } @@ -2186,10 +2118,10 @@ Route::toggle_monitor_input () bool Route::has_external_redirects () const { - const PortInsert* pi; + boost::shared_ptr<const PortInsert> pi; for (RedirectList::const_iterator i = _redirects.begin(); i != _redirects.end(); ++i) { - if ((pi = dynamic_cast<const PortInsert*>(*i)) != 0) { + if ((pi = boost::dynamic_pointer_cast<const PortInsert>(*i)) != 0) { uint32_t no = pi->n_outputs(); @@ -2211,67 +2143,6 @@ Route::has_external_redirects () const } void -Route::reset_midi_control (MIDI::Port* port, bool on) -{ - MIDI::channel_t chn; - MIDI::eventType ev; - MIDI::byte extra; - - for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) { - (*i)->reset_midi_control (port, on); - } - - IO::reset_midi_control (port, on); - - _midi_solo_control.get_control_info (chn, ev, extra); - if (!on) { - chn = -1; - } - _midi_solo_control.midi_rebind (port, chn); - - _midi_mute_control.get_control_info (chn, ev, extra); - if (!on) { - chn = -1; - } - _midi_mute_control.midi_rebind (port, chn); -} - -void -Route::send_all_midi_feedback () -{ - if (_session.get_midi_feedback()) { - - { - Glib::RWLock::ReaderLock lm (redirect_lock); - for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) { - (*i)->send_all_midi_feedback (); - } - } - - IO::send_all_midi_feedback(); - - _midi_solo_control.send_feedback (_soloed); - _midi_mute_control.send_feedback (_muted); - } -} - -MIDI::byte* -Route::write_midi_feedback (MIDI::byte* buf, int32_t& bufsize) -{ - buf = _midi_solo_control.write_feedback (buf, bufsize, _soloed); - buf = _midi_mute_control.write_feedback (buf, bufsize, _muted); - - { - Glib::RWLock::ReaderLock lm (redirect_lock); - for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) { - buf = (*i)->write_midi_feedback (buf, bufsize); - } - } - - return IO::write_midi_feedback (buf, bufsize); -} - -void Route::flush_redirects () { /* XXX shouldn't really try to take this lock, since @@ -2341,106 +2212,46 @@ Route::automation_snapshot (jack_nframes_t now) } } -Route::MIDIToggleControl::MIDIToggleControl (Route& s, ToggleType tp, MIDI::Port* port) - : MIDI::Controllable (port, true), route (s), type(tp), setting(false) +Route::ToggleControllable::ToggleControllable (Route& s, ToggleType tp) + : route (s), type(tp) { - last_written = false; /* XXX need a good out-of-bound-value */ + } void -Route::MIDIToggleControl::set_value (float val) +Route::ToggleControllable::set_value (float val) { - MIDI::eventType et; - MIDI::channel_t chn; - MIDI::byte additional; - - get_control_info (chn, et, additional); - - setting = true; - -#ifdef HOLD_TOGGLE_VALUES - if (et == MIDI::off || et == MIDI::on) { - - /* literal toggle */ - - switch (type) { - case MuteControl: - route.set_mute (!route.muted(), this); - break; - case SoloControl: - route.set_solo (!route.soloed(), this); - break; - default: - break; - } - - } else { -#endif - - /* map full control range to a boolean */ - - bool bval = ((val >= 0.5f) ? true: false); - - switch (type) { - case MuteControl: - route.set_mute (bval, this); - break; - case SoloControl: - route.set_solo (bval, this); - break; - default: - break; - } - -#ifdef HOLD_TOGGLE_VALUES + bool bval = ((val >= 0.5f) ? true: false); + + switch (type) { + case MuteControl: + route.set_mute (bval, this); + break; + case SoloControl: + route.set_solo (bval, this); + break; + default: + break; } -#endif - - setting = false; } -void -Route::MIDIToggleControl::send_feedback (bool value) +float +Route::ToggleControllable::get_value (void) const { - - if (!setting && get_midi_feedback()) { - MIDI::byte val = (MIDI::byte) (value ? 127: 0); - MIDI::channel_t ch = 0; - MIDI::eventType ev = MIDI::none; - MIDI::byte additional = 0; - MIDI::EventTwoBytes data; - - if (get_control_info (ch, ev, additional)) { - data.controller_number = additional; - data.value = val; - last_written = value; - - route._session.send_midi_message (get_port(), ev, ch, data); - } - } + float val = 0.0f; -} - -MIDI::byte* -Route::MIDIToggleControl::write_feedback (MIDI::byte* buf, int32_t& bufsize, bool val, bool force) -{ - if (get_midi_feedback() && bufsize > 2) { - MIDI::channel_t ch = 0; - MIDI::eventType ev = MIDI::none; - MIDI::byte additional = 0; - - if (get_control_info (ch, ev, additional)) { - if (val != last_written || force) { - *buf++ = (0xF0 & ev) | (0xF & ch); - *buf++ = additional; /* controller number */ - *buf++ = (MIDI::byte) (val ? 127 : 0); - bufsize -= 3; - last_written = val; - } - } + switch (type) { + case MuteControl: + val = route.muted() ? 1.0f : 0.0f; + break; + case SoloControl: + val = route.soloed() ? 1.0f : 0.0f; + break; + default: + break; } - return buf; + return val; } void @@ -2479,8 +2290,8 @@ Route::protect_automation () } for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) { - PluginInsert* pi; - if ((pi = dynamic_cast<PluginInsert*> (*i)) != 0) { + boost::shared_ptr<PluginInsert> pi; + if ((pi = boost::dynamic_pointer_cast<PluginInsert> (*i)) != 0) { pi->protect_automation (); } } diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 864e6178d2..806ec3b17f 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -64,6 +64,7 @@ #include <ardour/crossfade.h> #include <ardour/playlist.h> #include <ardour/click.h> +#include <ardour/data_type.h> #ifdef HAVE_LIBLO #include <ardour/osc.h> @@ -74,6 +75,7 @@ using namespace std; using namespace ARDOUR; using namespace PBD; +using boost::shared_ptr; const char* Session::_template_suffix = X_(".template"); const char* Session::_statefile_suffix = X_(".ardour"); @@ -90,6 +92,8 @@ Session::mix_buffers_no_gain_t Session::mix_buffers_no_gain = 0; sigc::signal<int> Session::AskAboutPendingState; sigc::signal<void> Session::SMPTEOffsetChanged; +sigc::signal<void> Session::SendFeedback; + int Session::find_session (string str, string& path, string& snapshot, bool& isnew) @@ -252,6 +256,9 @@ Session::Session (AudioEngine &eng, _midi_port (default_midi_port), pending_events (2048), midi_requests (128), // the size of this should match the midi request pool size + routes (new RouteList), + auditioner ((Auditioner*) 0), + _click_io ((IO*) 0), main_outs (0) { bool new_session; @@ -299,6 +306,7 @@ Session::Session (AudioEngine &eng, _midi_port (default_midi_port), pending_events (2048), midi_requests (16), + routes (new RouteList), main_outs (0) { @@ -316,15 +324,13 @@ Session::Session (AudioEngine &eng, } if (control_out_channels) { - Route* r; - r = new Route (*this, _("monitor"), -1, control_out_channels, -1, control_out_channels, Route::ControlOut); + shared_ptr<Route> r (new Route (*this, _("monitor"), -1, control_out_channels, -1, control_out_channels, Route::ControlOut)); add_route (r); _control_out = r; } if (master_out_channels) { - Route* r; - r = new Route (*this, _("master"), -1, master_out_channels, -1, master_out_channels, Route::MasterOut); + shared_ptr<Route> r (new Route (*this, _("master"), -1, master_out_channels, -1, master_out_channels, Route::MasterOut)); add_route (r); _master_out = r; } else { @@ -376,15 +382,6 @@ Session::~Session () clear_clicks (); - if (_click_io) { - delete _click_io; - } - - - if (auditioner) { - delete auditioner; - } - for (vector<Sample*>::iterator i = _passthru_buffers.begin(); i != _passthru_buffers.end(); ++i) { free(*i); } @@ -401,6 +398,8 @@ Session::~Session () delete [] (i->second); } + AudioDiskstream::free_working_buffers(); + #undef TRACK_DESTRUCTION #ifdef TRACK_DESTRUCTION cerr << "delete named selections\n"; @@ -438,27 +437,16 @@ Session::~Session () tmp =i; ++tmp; - delete (*i).second; + delete i->second; i = tmp; } #ifdef TRACK_DESTRUCTION - cerr << "delete routes\n"; -#endif /* TRACK_DESTRUCTION */ - for (RouteList::iterator i = routes.begin(); i != routes.end(); ) { - RouteList::iterator tmp; - tmp = i; - ++tmp; - delete *i; - i = tmp; - } - -#ifdef TRACK_DESTRUCTION - cerr << "delete audio_diskstreams\n"; + cerr << "delete diskstreams\n"; #endif /* TRACK_DESTRUCTION */ - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ) { - AudioDiskstreamList::iterator tmp; + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ) { + DiskstreamList::iterator tmp; tmp = i; ++tmp; @@ -477,7 +465,7 @@ Session::~Session () tmp = i; ++tmp; - delete (*i).second; + delete i->second; i = tmp; } @@ -544,7 +532,7 @@ Session::~Session () } void -Session::set_worst_io_latencies (bool take_lock) +Session::set_worst_io_latencies () { _worst_output_latency = 0; _worst_input_latency = 0; @@ -553,18 +541,12 @@ Session::set_worst_io_latencies (bool take_lock) return; } - if (take_lock) { - route_lock.reader_lock (); - } + boost::shared_ptr<RouteList> r = routes.reader (); - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { _worst_output_latency = max (_worst_output_latency, (*i)->output_latency()); _worst_input_latency = max (_worst_input_latency, (*i)->input_latency()); } - - if (take_lock) { - route_lock.reader_unlock (); - } } void @@ -581,7 +563,7 @@ Session::when_engine_running () /* every time we reconnect, recompute worst case output latencies */ - _engine.Running.connect (sigc::bind (mem_fun (*this, &Session::set_worst_io_latencies), true)); + _engine.Running.connect (mem_fun (*this, &Session::set_worst_io_latencies)); if (synced_to_jack()) { _engine.transport_stop (); @@ -596,7 +578,7 @@ Session::when_engine_running () try { XMLNode* child = 0; - _click_io = new ClickIO (*this, "click", 0, 0, -1, -1); + _click_io.reset (new ClickIO (*this, "click", 0, 0, -1, -1)); if (state_tree && (child = find_named_node (*state_tree->root(), "Click")) != 0) { @@ -632,7 +614,7 @@ Session::when_engine_running () error << _("cannot setup Click I/O") << endmsg; } - set_worst_io_latencies (true); + set_worst_io_latencies (); if (_clicking) { ControlChanged (Clicking); /* EMIT SIGNAL */ @@ -647,7 +629,7 @@ Session::when_engine_running () */ try { - auditioner = new Auditioner (*this); + auditioner.reset (new Auditioner (*this)); } catch (failed_constructor& err) { @@ -881,7 +863,7 @@ Session::playlist_length_changed (Playlist* pl) } void -Session::diskstream_playlist_changed (AudioDiskstream* dstream) +Session::diskstream_playlist_changed (Diskstream* dstream) { Playlist *playlist; @@ -961,7 +943,7 @@ Session::set_auto_input (bool yn) The rarity and short potential lock duration makes this "OK" */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (!auto_input); @@ -979,7 +961,7 @@ Session::reset_input_monitor_state () { if (transport_rolling()) { Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (Config->get_use_hardware_monitoring() && !auto_input); @@ -987,7 +969,7 @@ Session::reset_input_monitor_state () } } else { Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (Config->get_use_hardware_monitoring()); @@ -1068,7 +1050,7 @@ Session::auto_loop_changed (Location* location) } else if (seamless_loop && !loop_changing) { - // schedule a locate-roll to refill the audio_diskstreams at the + // schedule a locate-roll to refill the diskstreams at the // previous loop end loop_changing = true; @@ -1265,7 +1247,7 @@ Session::enable_record () */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { (*i)->monitor_input (true); } @@ -1300,7 +1282,7 @@ Session::disable_record (bool rt_context, bool force) */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { (*i)->monitor_input (false); } @@ -1327,7 +1309,7 @@ Session::step_back_from_record () */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (auto_input && (*i)->record_enabled ()) { //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (false); @@ -1450,7 +1432,6 @@ Session::set_block_size (jack_nframes_t nframes) */ { - Glib::RWLock::ReaderLock lm (route_lock); Glib::RWLock::ReaderLock dsm (diskstream_lock); vector<Sample*>::iterator i; uint32_t np; @@ -1492,15 +1473,17 @@ Session::set_block_size (jack_nframes_t nframes) allocate_pan_automation_buffers (nframes, _npan_buffers, true); - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + boost::shared_ptr<RouteList> r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { (*i)->set_block_size (nframes); } - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->set_block_size (nframes); } - set_worst_io_latencies (false); + set_worst_io_latencies (); } } @@ -1542,7 +1525,7 @@ Session::set_default_fade (float steepness, float fade_msecs) } struct RouteSorter { - bool operator() (Route* r1, Route* r2) { + bool operator() (boost::shared_ptr<Route> r1, boost::shared_ptr<Route> r2) { if (r1->fed_by.find (r2) != r1->fed_by.end()) { return false; } else if (r2->fed_by.find (r1) != r2->fed_by.end()) { @@ -1564,9 +1547,9 @@ struct RouteSorter { }; static void -trace_terminal (Route* r1, Route* rbase) +trace_terminal (shared_ptr<Route> r1, shared_ptr<Route> rbase) { - Route* r2; + shared_ptr<Route> r2; if ((r1->fed_by.find (rbase) != r1->fed_by.end()) && (rbase->fed_by.find (r1) != rbase->fed_by.end())) { info << string_compose(_("feedback loop setup between %1 and %2"), r1->name(), rbase->name()) << endmsg; @@ -1575,13 +1558,13 @@ trace_terminal (Route* r1, Route* rbase) /* make a copy of the existing list of routes that feed r1 */ - set<Route *> existing = r1->fed_by; + set<shared_ptr<Route> > existing = r1->fed_by; /* for each route that feeds r1, recurse, marking it as feeding rbase as well. */ - for (set<Route *>::iterator i = existing.begin(); i != existing.end(); ++i) { + for (set<shared_ptr<Route> >::iterator i = existing.begin(); i != existing.end(); ++i) { r2 =* i; /* r2 is a route that feeds r1 which somehow feeds base. mark @@ -1611,7 +1594,7 @@ trace_terminal (Route* r1, Route* rbase) } void -Session::resort_routes (void* src) +Session::resort_routes () { /* don't do anything here with signals emitted by Routes while we are being destroyed. @@ -1621,54 +1604,64 @@ Session::resort_routes (void* src) return; } - /* Caller MUST hold the route_lock */ - RouteList::iterator i, j; + { - for (i = routes.begin(); i != routes.end(); ++i) { + RCUWriter<RouteList> writer (routes); + shared_ptr<RouteList> r = writer.get_copy (); + resort_routes_using (r); + /* writer goes out of scope and forces update */ + } +} +void +Session::resort_routes_using (shared_ptr<RouteList> r) +{ + RouteList::iterator i, j; + + for (i = r->begin(); i != r->end(); ++i) { + (*i)->fed_by.clear (); - for (j = routes.begin(); j != routes.end(); ++j) { - + for (j = r->begin(); j != r->end(); ++j) { + /* although routes can feed themselves, it will cause an endless recursive descent if we detect it. so don't bother checking for self-feeding. */ - + if (*j == *i) { continue; } - + if ((*j)->feeds (*i)) { (*i)->fed_by.insert (*j); } } } - for (i = routes.begin(); i != routes.end(); ++i) { + for (i = r->begin(); i != r->end(); ++i) { trace_terminal (*i, *i); } - + RouteSorter cmp; - routes.sort (cmp); - + r->sort (cmp); + #if 0 cerr << "finished route resort\n"; - for (i = routes.begin(); i != routes.end(); ++i) { + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { cerr << " " << (*i)->name() << " signal order = " << (*i)->order_key ("signal") << endl; } cerr << endl; #endif - + } -AudioTrack* +shared_ptr<AudioTrack> Session::new_audio_track (int input_channels, int output_channels, TrackMode mode) { - AudioTrack *track; char track_name[32]; uint32_t n = 0; uint32_t channels_used = 0; @@ -1679,9 +1672,10 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod /* count existing audio tracks */ { - Glib::RWLock::ReaderLock lm (route_lock); - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { - if (dynamic_cast<AudioTrack*>(*i) != 0) { + shared_ptr<RouteList> r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + if (dynamic_cast<AudioTrack*>((*i).get()) != 0) { if (!(*i)->hidden()) { n++; channels_used += (*i)->n_inputs(); @@ -1718,7 +1712,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod } try { - track = new AudioTrack (*this, track_name, Route::Flag (0), mode); + shared_ptr<AudioTrack> track (new AudioTrack (*this, track_name, Route::Flag (0), mode)); if (track->ensure_io (input_channels, output_channels, false, this)) { error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"), @@ -1769,25 +1763,23 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod track->set_control_outs (cports); } - track->diskstream_changed.connect (mem_fun (this, &Session::resort_routes)); + track->DiskstreamChanged.connect (mem_fun (this, &Session::resort_routes)); add_route (track); track->set_remote_control_id (ntracks()); + return track; } catch (failed_constructor &err) { error << _("Session: could not create new audio track.") << endmsg; - return 0; + return shared_ptr<AudioTrack> ((AudioTrack*) 0); } - - return track; } -Route* +shared_ptr<Route> Session::new_audio_route (int input_channels, int output_channels) { - Route *bus; char bus_name[32]; uint32_t n = 0; string port; @@ -1795,9 +1787,10 @@ Session::new_audio_route (int input_channels, int output_channels) /* count existing audio busses */ { - Glib::RWLock::ReaderLock lm (route_lock); - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { - if (dynamic_cast<AudioTrack*>(*i) == 0) { + shared_ptr<RouteList> r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + if (dynamic_cast<AudioTrack*>((*i).get()) == 0) { if (!(*i)->hidden()) { n++; } @@ -1815,7 +1808,7 @@ Session::new_audio_route (int input_channels, int output_channels) } while (n < (UINT_MAX-1)); try { - bus = new Route (*this, bus_name, -1, -1, -1, -1); + shared_ptr<Route> bus (new Route (*this, bus_name, -1, -1, -1, -1, Route::Flag(0), DataType::AUDIO)); if (bus->ensure_io (input_channels, output_channels, false, this)) { error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"), @@ -1864,23 +1857,23 @@ Session::new_audio_route (int input_channels, int output_channels) } add_route (bus); + return bus; } catch (failed_constructor &err) { - error << _("Session: could not create new route.") << endmsg; - return 0; + error << _("Session: could not create new audio route.") << endmsg; + return shared_ptr<Route> ((Route*) 0); } - - return bus; } void -Session::add_route (Route* route) +Session::add_route (shared_ptr<Route> route) { { - Glib::RWLock::WriterLock lm (route_lock); - routes.push_front (route); - resort_routes(0); + RCUWriter<RouteList> writer (routes); + shared_ptr<RouteList> r = writer.get_copy (); + r->push_front (route); + resort_routes_using (r); } route->solo_changed.connect (sigc::bind (mem_fun (*this, &Session::route_solo_changed), route)); @@ -1903,14 +1896,14 @@ Session::add_route (Route* route) } void -Session::add_diskstream (AudioDiskstream* dstream) +Session::add_diskstream (Diskstream* dstream) { /* need to do this in case we're rolling at the time, to prevent false underruns */ - dstream->do_refill(0, 0, 0); + dstream->do_refill_with_alloc(); { Glib::RWLock::WriterLock lm (diskstream_lock); - audio_diskstreams.push_back (dstream); + diskstreams.push_back (dstream); } /* take a reference to the diskstream, preventing it from @@ -1930,52 +1923,56 @@ Session::add_diskstream (AudioDiskstream* dstream) set_dirty(); save_state (_current_snapshot_name); - AudioDiskstreamAdded (dstream); /* EMIT SIGNAL */ + DiskstreamAdded (dstream); /* EMIT SIGNAL */ } void -Session::remove_route (Route& route) +Session::remove_route (shared_ptr<Route> route) { { - Glib::RWLock::WriterLock lm (route_lock); - routes.remove (&route); + RCUWriter<RouteList> writer (routes); + shared_ptr<RouteList> rs = writer.get_copy (); + rs->remove (route); /* deleting the master out seems like a dumb idea, but its more of a UI policy issue than our concern. */ - if (&route == _master_out) { - _master_out = 0; + if (route == _master_out) { + _master_out = shared_ptr<Route> ((Route*) 0); } - if (&route == _control_out) { - _control_out = 0; + if (route == _control_out) { + _control_out = shared_ptr<Route> ((Route*) 0); /* cancel control outs for all routes */ vector<string> empty; - for (RouteList::iterator r = routes.begin(); r != routes.end(); ++r) { + for (RouteList::iterator r = rs->begin(); r != rs->end(); ++r) { (*r)->set_control_outs (empty); } } update_route_solo_state (); + + /* writer goes out of scope, forces route list update */ } + // FIXME: audio specific AudioTrack* at; AudioDiskstream* ds = 0; - if ((at = dynamic_cast<AudioTrack*>(&route)) != 0) { - ds = &at->disk_stream(); + if ((at = dynamic_cast<AudioTrack*>(route.get())) != 0) { + ds = &at->audio_diskstream(); } if (ds) { { Glib::RWLock::WriterLock lm (diskstream_lock); - audio_diskstreams.remove (ds); + diskstreams.remove (ds); } ds->unref (); @@ -1990,7 +1987,7 @@ Session::remove_route (Route& route) save_state (_current_snapshot_name); - delete &route; + /* all shared ptrs to route should go out of scope here */ } void @@ -2000,19 +1997,20 @@ Session::route_mute_changed (void* src) } void -Session::route_solo_changed (void* src, Route* route) +Session::route_solo_changed (void* src, shared_ptr<Route> route) { if (solo_update_disabled) { // We know already return; } - Glib::RWLock::ReaderLock lm (route_lock); bool is_track; - is_track = (dynamic_cast<AudioTrack*>(route) != 0); + is_track = (dynamic_cast<AudioTrack*>(route.get()) != 0); - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + shared_ptr<RouteList> r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { /* soloing a track mutes all other tracks, soloing a bus mutes all other busses */ @@ -2020,7 +2018,7 @@ Session::route_solo_changed (void* src, Route* route) /* don't mess with busses */ - if (dynamic_cast<AudioTrack*>(*i) == 0) { + if (dynamic_cast<AudioTrack*>((*i).get()) == 0) { continue; } @@ -2028,7 +2026,7 @@ Session::route_solo_changed (void* src, Route* route) /* don't mess with tracks */ - if (dynamic_cast<AudioTrack*>(*i) != 0) { + if (dynamic_cast<AudioTrack*>((*i).get()) != 0) { continue; } } @@ -2061,10 +2059,10 @@ Session::route_solo_changed (void* src, Route* route) bool same_thing_soloed = false; bool signal = false; - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if ((*i)->soloed()) { something_soloed = true; - if (dynamic_cast<AudioTrack*>(*i)) { + if (dynamic_cast<AudioTrack*>((*i).get())) { if (is_track) { same_thing_soloed = true; break; @@ -2115,11 +2113,13 @@ Session::update_route_solo_state () /* this is where we actually implement solo by changing the solo mute setting of each track. */ - - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + + shared_ptr<RouteList> r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if ((*i)->soloed()) { mute = true; - if (dynamic_cast<AudioTrack*>(*i)) { + if (dynamic_cast<AudioTrack*>((*i).get())) { is_track = true; } break; @@ -2135,7 +2135,7 @@ Session::update_route_solo_state () /* nothing is soloed */ - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { (*i)->set_solo_mute (false); } @@ -2156,13 +2156,15 @@ Session::update_route_solo_state () void Session::modify_solo_mute (bool is_track, bool mute) { - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + shared_ptr<RouteList> r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (is_track) { /* only alter track solo mute */ - if (dynamic_cast<AudioTrack*>(*i)) { + if (dynamic_cast<AudioTrack*>((*i).get())) { if ((*i)->soloed()) { (*i)->set_solo_mute (!mute); } else { @@ -2174,7 +2176,7 @@ Session::modify_solo_mute (bool is_track, bool mute) /* only alter bus solo mute */ - if (!dynamic_cast<AudioTrack*>(*i)) { + if (!dynamic_cast<AudioTrack*>((*i).get())) { if ((*i)->soloed()) { @@ -2206,36 +2208,35 @@ Session::catch_up_on_solo () basis, but needs the global overview that only the session has. */ - Glib::RWLock::ReaderLock lm (route_lock); update_route_solo_state(); } -Route * +shared_ptr<Route> Session::route_by_name (string name) { - Glib::RWLock::ReaderLock lm (route_lock); + shared_ptr<RouteList> r = routes.reader (); - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if ((*i)->name() == name) { - return* i; + return *i; } } - return 0; + return shared_ptr<Route> ((Route*) 0); } -Route * +shared_ptr<Route> Session::route_by_remote_id (uint32_t id) { - Glib::RWLock::ReaderLock lm (route_lock); + shared_ptr<RouteList> r = routes.reader (); - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if ((*i)->remote_control_id() == id) { - return* i; + return *i; } } - return 0; + return shared_ptr<Route> ((Route*) 0); } void @@ -2264,7 +2265,7 @@ Session::get_maximum_extent () const ensure atomicity. */ - for (AudioDiskstreamList::const_iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::const_iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { Playlist* pl = (*i)->playlist(); if ((me = pl->get_maximum_extent()) > max) { max = me; @@ -2274,12 +2275,12 @@ Session::get_maximum_extent () const return max; } -AudioDiskstream * +Diskstream * Session::diskstream_by_name (string name) { Glib::RWLock::ReaderLock lm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->name() == name) { return* i; } @@ -2288,12 +2289,12 @@ Session::diskstream_by_name (string name) return 0; } -AudioDiskstream * -Session::diskstream_by_id (id_t id) +Diskstream * +Session::diskstream_by_id (const PBD::ID& id) { Glib::RWLock::ReaderLock lm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->id() == id) { return *i; } @@ -2337,7 +2338,7 @@ Session::new_region_name (string old) sbuf = buf; for (i = audio_regions.begin(); i != audio_regions.end(); ++i) { - if ((*i).second->name() == sbuf) { + if (i->second->name() == sbuf) { break; } } @@ -2402,7 +2403,7 @@ Session::region_name (string& result, string base, bool newlevel) const name_taken = false; for (AudioRegionList::const_iterator i = audio_regions.begin(); i != audio_regions.end(); ++i) { - if ((*i).second->name() == result) { + if (i->second->name() == result) { name_taken = true; break; } @@ -2447,8 +2448,8 @@ Session::add_region (Region* region) if (x == audio_regions.end()) { - pair<AudioRegionList::key_type, AudioRegionList::mapped_type> entry; - + pair<AudioRegionList::key_type,AudioRegionList::mapped_type> entry; + entry.first = region->id(); entry.second = ar; @@ -2505,16 +2506,18 @@ Session::remove_region (Region* region) AudioRegionList::iterator i; AudioRegion* ar = 0; bool removed = false; - + { Glib::Mutex::Lock lm (region_lock); - if ((ar = dynamic_cast<AudioRegion*> (region)) != 0) { + if ((ar = dynamic_cast<AudioRegion*> (region)) != 0) { if ((i = audio_regions.find (region->id())) != audio_regions.end()) { audio_regions.erase (i); removed = true; - } + } + } else { + fatal << _("programming error: ") << X_("unknown region type passed to Session::remove_region()") << endmsg; @@ -2542,7 +2545,7 @@ Session::find_whole_file_parent (AudioRegion& child) for (i = audio_regions.begin(); i != audio_regions.end(); ++i) { - region = (*i).second; + region = i->second; if (region->whole_file()) { @@ -2556,18 +2559,10 @@ Session::find_whole_file_parent (AudioRegion& child) } void -Session::find_equivalent_playlist_regions (AudioRegion& region, vector<AudioRegion*>& result) +Session::find_equivalent_playlist_regions (Region& region, vector<Region*>& result) { - for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) { - - AudioPlaylist* pl; - - if ((pl = dynamic_cast<AudioPlaylist*>(*i)) == 0) { - continue; - } - - pl->get_region_list_equivalent_regions (region, result); - } + for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) + (*i)->get_region_list_equivalent_regions (region, result); } int @@ -2619,7 +2614,7 @@ Session::remove_last_capture () Glib::RWLock::ReaderLock lm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { list<Region*>& l = (*i)->last_capture_regions(); if (!l.empty()) { @@ -2646,12 +2641,12 @@ Session::add_audio_source (AudioSource* source) { pair<AudioSourceList::key_type, AudioSourceList::mapped_type> entry; - { - Glib::Mutex::Lock lm (audio_source_lock); + { + Glib::Mutex::Lock lm (audio_source_lock); entry.first = source->id(); entry.second = source; audio_sources.insert (entry); - } + } source->GoingAway.connect (mem_fun (this, &Session::remove_source)); set_dirty(); @@ -2669,7 +2664,7 @@ Session::remove_source (Source* source) if ((i = audio_sources.find (source->id())) != audio_sources.end()) { audio_sources.erase (i); - } + } } if (!_state_of_the_state & InCleanup) { @@ -2685,23 +2680,19 @@ Session::remove_source (Source* source) } Source * -Session::get_source (ARDOUR::id_t id) +Session::source_by_id (const PBD::ID& id) { Glib::Mutex::Lock lm (audio_source_lock); AudioSourceList::iterator i; Source* source = 0; if ((i = audio_sources.find (id)) != audio_sources.end()) { - source = (*i).second; - } - - if (source) { - return source; + source = i->second; } /* XXX search MIDI or other searches here */ - return 0; + return source; } string @@ -2776,12 +2767,13 @@ Session::change_audio_path_by_name (string path, string oldname, string newname, the task here is to replace NAME with the new name. */ - /* find last slash */ - string dir; string suffix; string::size_type slash; string::size_type dash; + string::size_type postfix; + + /* find last slash */ if ((slash = path.find_last_of ('/')) == string::npos) { return ""; @@ -2795,11 +2787,41 @@ Session::change_audio_path_by_name (string path, string oldname, string newname, return ""; } - suffix = path.substr (dash); + suffix = path.substr (dash+1); + + // Suffix is now everything after the dash. Now we need to eliminate + // the nnnnn part, which is done by either finding a '%' or a '.' + + postfix = suffix.find_last_of ("%"); + if (postfix == string::npos) { + postfix = suffix.find_last_of ('.'); + } + + if (postfix != string::npos) { + suffix = suffix.substr (postfix); + } else { + error << "Logic error in Session::change_audio_path_by_name(), please report to the developers" << endl; + return ""; + } + + const uint32_t limit = 10000; + char buf[PATH_MAX+1]; + + for (uint32_t cnt = 1; cnt <= limit; ++cnt) { + + snprintf (buf, sizeof(buf), "%s%s-%u%s", dir.c_str(), newname.c_str(), cnt, suffix.c_str()); + + if (access (buf, F_OK) != 0) { + path = buf; + break; + } + path = ""; + } + + if (path == "") { + error << "FATAL ERROR! Could not find a " << endl; + } - path = dir; - path += new_legalized; - path += suffix; } return path; @@ -2822,20 +2844,20 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool */ for (cnt = (destructive ? ++destructive_index : 1); cnt <= limit; ++cnt) { - + vector<space_and_path>::iterator i; uint32_t existing = 0; - + for (i = session_dirs.begin(); i != session_dirs.end(); ++i) { - + spath = (*i).path; - + if (destructive) { spath += tape_dir_name; } else { spath += sound_dir_name; } - + if (destructive) { if (nchan < 2) { snprintf (buf, sizeof(buf), "%s/T%04d-%s.wav", spath.c_str(), cnt, legalized.c_str()); @@ -2851,10 +2873,10 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool snprintf (buf, sizeof(buf), "%s/T%04d-%s.wav", spath.c_str(), cnt, legalized.c_str()); } } else { - + spath += '/'; spath += legalized; - + if (nchan < 2) { snprintf (buf, sizeof(buf), "%s-%u.wav", spath.c_str(), cnt); } else if (nchan == 2) { @@ -2874,7 +2896,7 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool existing++; } } - + if (existing == 0) { break; } @@ -2931,18 +2953,6 @@ Session::create_audio_source_for_session (AudioDiskstream& ds, uint32_t chan, bo /* Playlist management */ Playlist * -Session::get_playlist (string name) -{ - Playlist* ret = 0; - - if ((ret = playlist_by_name (name)) == 0) { - ret = new AudioPlaylist (*this, name); - } - - return ret; -} - -Playlist * Session::playlist_by_name (string name) { Glib::Mutex::Lock lm (playlist_lock); @@ -3071,11 +3081,14 @@ Session::audition_playlist () } void -Session::audition_region (AudioRegion& r) +Session::audition_region (Region& r) { - Event* ev = new Event (Event::Audition, Event::Add, Event::Immediate, 0, 0.0); - ev->set_ptr (&r); - queue_event (ev); + AudioRegion* ar = dynamic_cast<AudioRegion*>(&r); + if (ar) { + Event* ev = new Event (Event::Audition, Event::Add, Event::Immediate, 0, 0.0); + ev->set_ptr (ar); + queue_event (ev); + } } void @@ -3088,7 +3101,7 @@ Session::cancel_audition () } bool -Session::RoutePublicOrderSorter::operator() (Route* a, Route* b) +Session::RoutePublicOrderSorter::operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) { return a->order_key(N_("signal")) < b->order_key(N_("signal")); } @@ -3134,13 +3147,11 @@ Session::is_auditioning () const void Session::set_all_solo (bool yn) { - { - Glib::RWLock::ReaderLock lm (route_lock); - - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { - if (!(*i)->hidden()) { - (*i)->set_solo (yn, this); - } + shared_ptr<RouteList> r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + if (!(*i)->hidden()) { + (*i)->set_solo (yn, this); } } @@ -3150,13 +3161,11 @@ Session::set_all_solo (bool yn) void Session::set_all_mute (bool yn) { - { - Glib::RWLock::ReaderLock lm (route_lock); - - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { - if (!(*i)->hidden()) { - (*i)->set_mute (yn, this); - } + shared_ptr<RouteList> r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + if (!(*i)->hidden()) { + (*i)->set_mute (yn, this); } } @@ -3164,12 +3173,12 @@ Session::set_all_mute (bool yn) } uint32_t -Session::n_audio_diskstreams () const +Session::n_diskstreams () const { Glib::RWLock::ReaderLock lm (diskstream_lock); uint32_t n = 0; - for (AudioDiskstreamList::const_iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::const_iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (!(*i)->hidden()) { n++; } @@ -3177,17 +3186,6 @@ Session::n_audio_diskstreams () const return n; } -void -Session::foreach_audio_diskstream (void (AudioDiskstream::*func)(void)) -{ - Glib::RWLock::ReaderLock lm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { - if (!(*i)->hidden()) { - ((*i)->*func)(); - } - } -} - void Session::graph_reordered () { @@ -3199,16 +3197,15 @@ Session::graph_reordered () return; } - Glib::RWLock::WriterLock lm1 (route_lock); Glib::RWLock::ReaderLock lm2 (diskstream_lock); - resort_routes (0); + resort_routes (); /* force all diskstreams to update their capture offset values to reflect any changes in latencies within the graph. */ - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->set_capture_offset (); } } @@ -3228,12 +3225,12 @@ Session::record_enable_all () void Session::record_enable_change_all (bool yn) { - Glib::RWLock::ReaderLock lm1 (route_lock); + shared_ptr<RouteList> r = routes.reader (); - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { AudioTrack* at; - if ((at = dynamic_cast<AudioTrack*>(*i)) != 0) { + if ((at = dynamic_cast<AudioTrack*>((*i).get())) != 0) { at->set_record_enable (yn, this); } } @@ -3491,7 +3488,7 @@ Session::reset_native_file_format () //RWLockMonitor lm1 (route_lock, true, __LINE__, __FILE__); Glib::RWLock::ReaderLock lm2 (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->reset_write_sources (false); } } @@ -3499,9 +3496,9 @@ Session::reset_native_file_format () bool Session::route_name_unique (string n) const { - Glib::RWLock::ReaderLock lm (route_lock); + shared_ptr<RouteList> r = routes.reader (); - for (RouteList::const_iterator i = routes.begin(); i != routes.end(); ++i) { + for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) { if ((*i)->name() == n) { return false; } @@ -3558,23 +3555,16 @@ Session::allocate_pan_automation_buffers (jack_nframes_t nframes, uint32_t howma _npan_buffers = howmany; } -void -Session::add_instant_xml (XMLNode& node, const std::string& dir) -{ - Stateful::add_instant_xml (node, dir); - Config->add_instant_xml (node, get_user_ardour_path()); -} - int Session::freeze (InterThreadInfo& itt) { - Glib::RWLock::ReaderLock lm (route_lock); + shared_ptr<RouteList> r = routes.reader (); - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { AudioTrack *at; - if ((at = dynamic_cast<AudioTrack*>(*i)) != 0) { + if ((at = dynamic_cast<AudioTrack*>((*i).get())) != 0) { /* XXX this is wrong because itt.progress will keep returning to zero at the start of every track. */ @@ -3609,7 +3599,7 @@ Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nf /* call tree *MUST* hold route_lock */ - if ((playlist = track.disk_stream().playlist()) == 0) { + if ((playlist = track.diskstream().playlist()) == 0) { goto out; } @@ -3619,7 +3609,7 @@ Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nf goto out; } - nchans = track.disk_stream().n_channels(); + nchans = track.audio_diskstream().n_channels(); dir = discover_best_sound_dir (); @@ -3763,10 +3753,10 @@ uint32_t Session::ntracks () const { uint32_t n = 0; - Glib::RWLock::ReaderLock lm (route_lock); + shared_ptr<RouteList> r = routes.reader (); - for (RouteList::const_iterator i = routes.begin(); i != routes.end(); ++i) { - if (dynamic_cast<AudioTrack*> (*i)) { + for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) { + if (dynamic_cast<AudioTrack*> ((*i).get())) { ++n; } } @@ -3778,10 +3768,10 @@ uint32_t Session::nbusses () const { uint32_t n = 0; - Glib::RWLock::ReaderLock lm (route_lock); + shared_ptr<RouteList> r = routes.reader (); - for (RouteList::const_iterator i = routes.begin(); i != routes.end(); ++i) { - if (dynamic_cast<AudioTrack*> (*i) == 0) { + for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) { + if (dynamic_cast<AudioTrack*> ((*i).get()) == 0) { ++n; } } diff --git a/libs/ardour/session_butler.cc b/libs/ardour/session_butler.cc index 4613bfccf9..6509a783bb 100644 --- a/libs/ardour/session_butler.cc +++ b/libs/ardour/session_butler.cc @@ -168,15 +168,9 @@ Session::butler_thread_work () struct timeval begin, end; struct pollfd pfd[1]; bool disk_work_outstanding = false; - AudioDiskstreamList::iterator i; - - butler_mixdown_buffer = new Sample[AudioDiskstream::disk_io_frames()]; - butler_gain_buffer = new gain_t[AudioDiskstream::disk_io_frames()]; - // this buffer is used for temp conversion purposes in filesources - char * conv_buffer = conversion_buffer(ButlerContext); + DiskstreamList::iterator i; while (true) { - pfd[0].fd = butler_request_pipe[0]; pfd[0].events = POLLIN|POLLERR|POLLHUP; @@ -198,14 +192,13 @@ Session::butler_thread_work () } if (pfd[0].revents & POLLIN) { - + char req; /* empty the pipe of all current requests */ while (1) { size_t nread = ::read (butler_request_pipe[0], &req, sizeof (req)); - if (nread == 1) { switch ((ButlerRequest::Type) req) { @@ -240,10 +233,10 @@ Session::butler_thread_work () } } } - - for (i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + + //for (i = diskstreams.begin(); i != diskstreams.end(); ++i) { // cerr << "BEFORE " << (*i)->name() << ": pb = " << (*i)->playback_buffer_load() << " cp = " << (*i)->capture_buffer_load() << endl; - } + //} if (transport_work_requested()) { butler_transport_work (); @@ -257,16 +250,16 @@ Session::butler_thread_work () Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (i = audio_diskstreams.begin(); !transport_work_requested() && butler_should_run && i != audio_diskstreams.end(); ++i) { - - // cerr << "rah fondr " << (*i)->io()->name () << endl; + for (i = diskstreams.begin(); !transport_work_requested() && butler_should_run && i != diskstreams.end(); ++i) { + + Diskstream* const ds = *i; - switch ((*i)->do_refill (butler_mixdown_buffer, butler_gain_buffer, conv_buffer)) { + switch (ds->do_refill ()) { case 0: - bytes += (*i)->read_data_count(); + bytes += ds->read_data_count(); break; case 1: - bytes += (*i)->read_data_count(); + bytes += ds->read_data_count(); disk_work_outstanding = true; break; @@ -278,7 +271,7 @@ Session::butler_thread_work () } - if (i != audio_diskstreams.end()) { + if (i != diskstreams.end()) { /* we didn't get to all the streams */ disk_work_outstanding = true; } @@ -299,12 +292,11 @@ Session::butler_thread_work () bytes = 0; compute_io = true; gettimeofday (&begin, 0); - - for (i = audio_diskstreams.begin(); !transport_work_requested() && butler_should_run && i != audio_diskstreams.end(); ++i) { - + + for (i = diskstreams.begin(); !transport_work_requested() && butler_should_run && i != diskstreams.end(); ++i) { // cerr << "write behind for " << (*i)->name () << endl; - switch ((*i)->do_flush (conv_buffer)) { + switch ((*i)->do_flush (Session::ButlerContext)) { case 0: bytes += (*i)->write_data_count(); break; @@ -330,7 +322,7 @@ Session::butler_thread_work () request_stop (); } - if (i != audio_diskstreams.end()) { + if (i != diskstreams.end()) { /* we didn't get to all the streams */ disk_work_outstanding = true; } @@ -357,7 +349,7 @@ Session::butler_thread_work () Glib::Mutex::Lock lm (butler_request_lock); if (butler_should_run && (disk_work_outstanding || transport_work_requested())) { -// for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { +// for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { // cerr << "AFTER " << (*i)->name() << ": pb = " << (*i)->playback_buffer_load() << " cp = " << (*i)->capture_buffer_load() << endl; // } @@ -375,18 +367,17 @@ Session::butler_thread_work () void -Session::request_overwrite_buffer (AudioDiskstream* stream) +Session::request_overwrite_buffer (Diskstream* stream) { Event *ev = new Event (Event::Overwrite, Event::Add, Event::Immediate, 0, 0, 0.0); ev->set_ptr (stream); queue_event (ev); } +/** Process thread. */ void -Session::overwrite_some_buffers (AudioDiskstream* ds) +Session::overwrite_some_buffers (Diskstream* ds) { - /* executed by the audio thread */ - if (actively_recording()) { return; } @@ -398,7 +389,7 @@ Session::overwrite_some_buffers (AudioDiskstream* ds) } else { Glib::RWLock::ReaderLock dm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->set_pending_overwrite (true); } } diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc index ddced9cc5f..b39c4f2218 100644 --- a/libs/ardour/session_export.cc +++ b/libs/ardour/session_export.cc @@ -485,8 +485,9 @@ Session::prepare_to_export (AudioExportSpecification& spec) /* take everyone out of awrite to avoid disasters */ { - Glib::RWLock::ReaderLock lm (route_lock); - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + boost::shared_ptr<RouteList> r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { (*i)->protect_automation (); } } @@ -495,7 +496,7 @@ Session::prepare_to_export (AudioExportSpecification& spec) { Glib::RWLock::ReaderLock lm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)-> seek (spec.start_frame, true)) { error << string_compose (_("%1: cannot seek to %2 for export"), (*i)->name(), spec.start_frame) diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc index 60bd95464f..821f894eeb 100644 --- a/libs/ardour/session_midi.cc +++ b/libs/ardour/session_midi.cc @@ -109,13 +109,6 @@ Session::set_midi_control (bool yn) set_dirty(); poke_midi_thread (); - if (_midi_port) { - Glib::RWLock::ReaderLock guard (route_lock); - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { - (*i)->reset_midi_control (_midi_port, midi_control); - } - } - ControlChanged (MidiControl); /* EMIT SIGNAL */ } @@ -783,12 +776,12 @@ Session::mmc_record_enable (MIDI::MachineControl &mmc, size_t trk, bool enabled) if (mmc_control) { RouteList::iterator i; - Glib::RWLock::ReaderLock guard (route_lock); + boost::shared_ptr<RouteList> r = routes.reader(); - for (i = routes.begin(); i != routes.end(); ++i) { + for (i = r->begin(); i != r->end(); ++i) { AudioTrack *at; - if ((at = dynamic_cast<AudioTrack*>(*i)) != 0) { + if ((at = dynamic_cast<AudioTrack*>((*i).get())) != 0) { if (trk == at->remote_control_id()) { at->set_record_enable (enabled, &mmc); break; diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc index ad4e9a64bb..88b111a1fb 100644 --- a/libs/ardour/session_process.cc +++ b/libs/ardour/session_process.cc @@ -59,12 +59,14 @@ Session::process (jack_nframes_t nframes) } (this->*process_function) (nframes); + + SendFeedback (); /* EMIT SIGNAL */ } void Session::prepare_diskstreams () { - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->prepare (); } } @@ -75,23 +77,20 @@ Session::no_roll (jack_nframes_t nframes, jack_nframes_t offset) jack_nframes_t end_frame = _transport_frame + nframes; int ret = 0; bool declick = get_transport_declick_required(); + boost::shared_ptr<RouteList> r = routes.reader (); if (_click_io) { _click_io->silence (nframes, offset); } - /* XXX we're supposed to have the route_lock while doing this. - this is really bad ... - */ - if (g_atomic_int_get (&processing_prohibited)) { - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { (*i)->silence (nframes, offset); } return 0; } - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if ((*i)->hidden()) { continue; @@ -116,6 +115,7 @@ Session::process_routes (jack_nframes_t nframes, jack_nframes_t offset) bool record_active; int declick = get_transport_declick_required(); bool rec_monitors = get_rec_monitors_input(); + boost::shared_ptr<RouteList> r = routes.reader (); if (transport_sub_state & StopPendingCapture) { /* force a declick out */ @@ -124,7 +124,7 @@ Session::process_routes (jack_nframes_t nframes, jack_nframes_t offset) record_active = actively_recording(); // || (get_record_enabled() && get_punch_in()); - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { int ret; @@ -141,7 +141,7 @@ Session::process_routes (jack_nframes_t nframes, jack_nframes_t offset) call path, so make sure we release any outstanding locks here before we return failure. */ - for (AudioDiskstreamList::iterator ids = audio_diskstreams.begin(); ids != audio_diskstreams.end(); ++ids) { + for (DiskstreamList::iterator ids = diskstreams.begin(); ids != diskstreams.end(); ++ids) { (*ids)->recover (); } @@ -159,13 +159,14 @@ Session::silent_process_routes (jack_nframes_t nframes, jack_nframes_t offset) bool record_active = actively_recording(); int declick = get_transport_declick_required(); bool rec_monitors = get_rec_monitors_input(); + boost::shared_ptr<RouteList> r = routes.reader (); if (transport_sub_state & StopPendingCapture) { /* force a declick out */ declick = -1; } - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { int ret; @@ -180,7 +181,7 @@ Session::silent_process_routes (jack_nframes_t nframes, jack_nframes_t offset) call path, so make sure we release any outstanding locks here before we return failure. */ - for (AudioDiskstreamList::iterator ids = audio_diskstreams.begin(); ids != audio_diskstreams.end(); ++ids) { + for (DiskstreamList::iterator ids = diskstreams.begin(); ids != diskstreams.end(); ++ids) { (*ids)->recover (); } @@ -199,7 +200,7 @@ Session::commit_diskstreams (jack_nframes_t nframes, bool &needs_butler) float pworst = 1.0f; float cworst = 1.0f; - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->hidden()) { continue; @@ -247,10 +248,14 @@ Session::process_with_events (jack_nframes_t nframes) jack_nframes_t stop_limit; long frames_moved; + /* make sure the auditioner is silent */ + if (auditioner) { auditioner->silence (nframes, 0); } + /* handle any pending events */ + while (pending_events.read (&ev, 1) == 1) { merge_event (ev); } @@ -279,13 +284,12 @@ Session::process_with_events (jack_nframes_t nframes) end_frame = _transport_frame + nframes; { - Glib::RWLock::ReaderLock rm (route_lock, Glib::TRY_LOCK); Glib::RWLock::ReaderLock dsm (diskstream_lock, Glib::TRY_LOCK); Event* this_event; Events::iterator the_next_one; - - if (!rm.locked() || !dsm.locked() || (post_transport_work & (PostTransportLocate|PostTransportStop))) { + + if (!dsm.locked() || (post_transport_work & (PostTransportLocate|PostTransportStop))) { no_roll (nframes, 0); return; } @@ -566,7 +570,7 @@ Session::follow_slave (jack_nframes_t nframes, jack_nframes_t offset) bool ok = true; jack_nframes_t frame_delta = slave_transport_frame - _transport_frame; - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (!(*i)->can_internal_playback_seek (frame_delta)) { ok = false; break; @@ -574,7 +578,7 @@ Session::follow_slave (jack_nframes_t nframes, jack_nframes_t offset) } if (ok) { - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->internal_playback_seek (frame_delta); } _transport_frame += frame_delta; @@ -692,7 +696,7 @@ Session::follow_slave (jack_nframes_t nframes, jack_nframes_t offset) summon_butler (); } - jack_nframes_t frames_moved = (long) floor (_transport_speed * nframes); + int32_t frames_moved = (int32_t) floor (_transport_speed * nframes); if (frames_moved < 0) { decrement_transport_position (-frames_moved); @@ -729,10 +733,9 @@ Session::process_without_events (jack_nframes_t nframes) long frames_moved; { - Glib::RWLock::ReaderLock rm (route_lock, Glib::TRY_LOCK); Glib::RWLock::ReaderLock dsm (diskstream_lock, Glib::TRY_LOCK); - if (!rm.locked() || !dsm.locked() || (post_transport_work & (PostTransportLocate|PostTransportStop))) { + if (!dsm.locked() || (post_transport_work & (PostTransportLocate|PostTransportStop))) { no_roll (nframes, 0); return; } @@ -801,21 +804,23 @@ Session::process_without_events (jack_nframes_t nframes) void Session::process_audition (jack_nframes_t nframes) { - Glib::RWLock::ReaderLock rm (route_lock, Glib::TRY_LOCK); Event* ev; + boost::shared_ptr<RouteList> r = routes.reader (); - if (rm.locked()) { - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { - if (!(*i)->hidden()) { - (*i)->silence (nframes, 0); - } + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + if (!(*i)->hidden()) { + (*i)->silence (nframes, 0); } } + + /* run the auditioner, and if it says we need butler service, ask for it */ if (auditioner->play_audition (nframes) > 0) { summon_butler (); } + /* handle pending events */ + while (pending_events.read (&ev, 1) == 1) { merge_event (ev); } diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 0ae73291e0..9619e77ad1 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -165,7 +165,6 @@ Session::first_stage_init (string fullpath, string snapshot_name) _slave_type = None; butler_mixdown_buffer = 0; butler_gain_buffer = 0; - auditioner = 0; mmc_control = false; midi_control = true; mmc = 0; @@ -180,8 +179,6 @@ Session::first_stage_init (string fullpath, string snapshot_name) _edit_mode = Slide; pending_edit_mode = _edit_mode; _play_range = false; - _control_out = 0; - _master_out = 0; input_auto_connect = AutoConnectOption (0); output_auto_connect = AutoConnectOption (0); waiting_to_start = false; @@ -197,6 +194,7 @@ Session::first_stage_init (string fullpath, string snapshot_name) /* allocate conversion buffers */ _conversion_buffers[ButlerContext] = new char[AudioDiskstream::disk_io_frames() * 4]; _conversion_buffers[TransportContext] = new char[AudioDiskstream::disk_io_frames() * 4]; + AudioDiskstream::allocate_working_buffers(); /* default short fade = 15ms */ @@ -216,7 +214,6 @@ Session::first_stage_init (string fullpath, string snapshot_name) waveforms for clicks. */ - _click_io = 0; _clicking = false; click_requested = false; click_data = 0; @@ -270,9 +267,12 @@ Session::first_stage_init (string fullpath, string snapshot_name) AudioSource::AudioSourceCreated.connect (mem_fun (*this, &Session::add_audio_source)); Playlist::PlaylistCreated.connect (mem_fun (*this, &Session::add_playlist)); Redirect::RedirectCreated.connect (mem_fun (*this, &Session::add_redirect)); - AudioDiskstream::AudioDiskstreamCreated.connect (mem_fun (*this, &Session::add_diskstream)); + AudioDiskstream::DiskstreamCreated.connect (mem_fun (*this, &Session::add_diskstream)); NamedSelection::NamedSelectionCreated.connect (mem_fun (*this, &Session::add_named_selection)); + Controllable::Created.connect (mem_fun (*this, &Session::add_controllable)); + Controllable::GoingAway.connect (mem_fun (*this, &Session::remove_controllable)); + IO::MoreOutputs.connect (mem_fun (*this, &Session::ensure_passthru_buffers)); /* stop IO objects from doing stuff until we're ready for them */ @@ -1330,6 +1330,13 @@ Session::state(bool full_state) } } + /* save the ID counter */ + + snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter()); + node->add_property ("id-counter", buf); + + /* various options */ + node->add_child_nocopy (get_options()); child = node->add_child ("Sources"); @@ -1343,7 +1350,7 @@ Session::state(bool full_state) AudioFileSource* fs; - if ((fs = dynamic_cast<AudioFileSource*> ((*siter).second)) != 0) { + if ((fs = dynamic_cast<AudioFileSource*> (siter->second)) != 0) { DestructiveFileSource* dfs = dynamic_cast<DestructiveFileSource*> (fs); /* destructive file sources are OK if they are empty, because @@ -1357,7 +1364,7 @@ Session::state(bool full_state) } } - child->add_child_nocopy ((*siter).second->get_state()); + child->add_child_nocopy (siter->second->get_state()); } } @@ -1370,7 +1377,7 @@ Session::state(bool full_state) /* only store regions not attached to playlists */ - if ((*i).second->playlist() == 0) { + if (i->second->playlist() == 0) { child->add_child_nocopy (i->second->state (true)); } } @@ -1380,7 +1387,7 @@ Session::state(bool full_state) { Glib::RWLock::ReaderLock dl (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (!(*i)->hidden()) { child->add_child_nocopy ((*i)->get_state()); } @@ -1401,10 +1408,10 @@ Session::state(bool full_state) child = node->add_child ("Routes"); { - Glib::RWLock::ReaderLock lm (route_lock); + boost::shared_ptr<RouteList> r = routes.reader (); RoutePublicOrderSorter cmp; - RouteList public_order(routes); + RouteList public_order (*r); public_order.sort (cmp); for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) { @@ -1489,7 +1496,7 @@ Session::set_state (const XMLNode& node) _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave); - if (node.name() != "Session"){ + if (node.name() != X_("Session")){ fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg; return -1; } @@ -1499,6 +1506,21 @@ Session::set_state (const XMLNode& node) if ((prop = node.property ("name")) != 0) { _name = prop->value (); } + + if ((prop = node.property (X_("id-counter"))) != 0) { + uint64_t x; + sscanf (prop->value().c_str(), "%" PRIu64, &x); + ID::init_counter (x); + } else { + /* old sessions used a timebased counter, so fake + the startup ID counter based on a standard + timestamp. + */ + time_t now; + time (&now); + ID::init_counter (now); + } + IO::disable_ports (); IO::disable_connecting (); @@ -1685,7 +1707,6 @@ Session::load_routes (const XMLNode& node) { XMLNodeList nlist; XMLNodeConstIterator niter; - Route *route; nlist = node.children(); @@ -1693,7 +1714,9 @@ Session::load_routes (const XMLNode& node) for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - if ((route = XMLRouteFactory (**niter)) == 0) { + boost::shared_ptr<Route> route (XMLRouteFactory (**niter)); + + if (route == 0) { error << _("Session: cannot create Route from XML description.") << endmsg; return -1; } @@ -1704,17 +1727,19 @@ Session::load_routes (const XMLNode& node) return 0; } -Route * +boost::shared_ptr<Route> Session::XMLRouteFactory (const XMLNode& node) { if (node.name() != "Route") { - return 0; + return boost::shared_ptr<Route> ((Route*) 0); } if (node.property ("diskstream") != 0 || node.property ("diskstream-id") != 0) { - return new AudioTrack (*this, node); + boost::shared_ptr<Route> x (new AudioTrack (*this, node)); + return x; } else { - return new Route (*this, node); + boost::shared_ptr<Route> x (new Route (*this, node)); + return x; } } @@ -1730,12 +1755,10 @@ Session::load_regions (const XMLNode& node) set_dirty(); for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - if ((region = XMLRegionFactory (**niter, false)) == 0) { error << _("Session: cannot create Region from XML description.") << endmsg; } } - return 0; } @@ -1743,7 +1766,6 @@ AudioRegion * Session::XMLRegionFactory (const XMLNode& node, bool full) { const XMLProperty* prop; - id_t s_id; Source* source; AudioSource* as; AudioRegion::SourceList sources; @@ -1766,9 +1788,9 @@ Session::XMLRegionFactory (const XMLNode& node, bool full) } } - sscanf (prop->value().c_str(), "%" PRIu64, &s_id); + PBD::ID s_id (prop->value()); - if ((source = get_source (s_id)) == 0) { + if ((source = source_by_id (s_id)) == 0) { error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg; return 0; } @@ -1786,23 +1808,23 @@ Session::XMLRegionFactory (const XMLNode& node, bool full) for (uint32_t n=1; n < nchans; ++n) { snprintf (buf, sizeof(buf), X_("source-%d"), n); if ((prop = node.property (buf)) != 0) { - sscanf (prop->value().c_str(), "%" PRIu64, &s_id); - if ((source = get_source (s_id)) == 0) { - error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg; + PBD::ID id2 (prop->value()); + + if ((source = source_by_id (id2)) == 0) { + error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg; return 0; } as = dynamic_cast<AudioSource*>(source); if (!as) { - error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg; + error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg; return 0; } sources.push_back (as); } } - try { return new AudioRegion (sources, node); } @@ -1820,7 +1842,7 @@ Session::get_sources_as_xml () Glib::Mutex::Lock lm (audio_source_lock); for (AudioSourceList::iterator i = audio_sources.begin(); i != audio_sources.end(); ++i) { - node->add_child_nocopy ((*i).second->get_state()); + node->add_child_nocopy (i->second->get_state()); } /* XXX get MIDI and other sources here */ @@ -2401,23 +2423,6 @@ Session::load_route_groups (const XMLNode& node, bool edit) return 0; } -void -Session::swap_configuration(Configuration** new_config) -{ - Glib::RWLock::WriterLock lm (route_lock); // jlc - WHY? - Configuration* tmp = *new_config; - *new_config = Config; - Config = tmp; - set_dirty(); -} - -void -Session::copy_configuration(Configuration* new_config) -{ - Glib::RWLock::WriterLock lm (route_lock); - new_config = new Configuration(*Config); -} - static bool state_file_filter (const string &str, void *arg) { @@ -2441,7 +2446,7 @@ remove_end(string* state) statename = statename.substr (start+1); } - if ((end = statename.rfind(".ardour")) < 0) { + if ((end = statename.rfind(".ardour")) == string::npos) { end = statename.length(); } @@ -2589,14 +2594,15 @@ Session::GlobalRouteBooleanState Session::get_global_route_boolean (bool (Route::*method)(void) const) { GlobalRouteBooleanState s; - Glib::RWLock::ReaderLock lm (route_lock); + boost::shared_ptr<RouteList> r = routes.reader (); - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (!(*i)->hidden()) { RouteBooleanState v; v.first =* i; - v.second = ((*i)->*method)(); + Route* r = (*i).get(); + v.second = (r->*method)(); s.push_back (v); } @@ -2609,9 +2615,9 @@ Session::GlobalRouteMeterState Session::get_global_route_metering () { GlobalRouteMeterState s; - Glib::RWLock::ReaderLock lm (route_lock); + boost::shared_ptr<RouteList> r = routes.reader (); - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (!(*i)->hidden()) { RouteMeterState v; @@ -2637,7 +2643,8 @@ void Session::set_global_route_boolean (GlobalRouteBooleanState s, void (Route::*method)(bool, void*), void* arg) { for (GlobalRouteBooleanState::iterator i = s.begin(); i != s.end(); ++i) { - (i->first->*method) (i->second, arg); + Route* r = i->first.get(); + (r->*method) (i->second, arg); } } @@ -2944,7 +2951,7 @@ Session::cleanup_sources (Session::cleanup_report& rep) capture files. */ - if ((*i).second->use_cnt() == 0 && (*i).second->length() > 0) { + if (i->second->use_cnt() == 0 && i->second->length() > 0) { dead_sources.push_back (i->second); /* remove this source from our own list to avoid us @@ -2971,7 +2978,7 @@ Session::cleanup_sources (Session::cleanup_report& rep) tmp = r; ++tmp; - ar = (*r).second; + ar = r->second; for (uint32_t n = 0; n < ar->n_channels(); ++n) { if (&ar->source (n) == (*i)) { @@ -3024,7 +3031,7 @@ Session::cleanup_sources (Session::cleanup_report& rep) for (AudioSourceList::iterator i = audio_sources.begin(); i != audio_sources.end(); ++i) { AudioFileSource* fs; - if ((fs = dynamic_cast<AudioFileSource*> ((*i).second)) != 0) { + if ((fs = dynamic_cast<AudioFileSource*> (i->second)) != 0) { all_sources.insert (fs->path()); } } @@ -3233,3 +3240,41 @@ Session::set_clean () } } +void +Session::add_controllable (Controllable* c) +{ + Glib::Mutex::Lock lm (controllables_lock); + controllables.push_back (c); +} + +void +Session::remove_controllable (Controllable* c) +{ + if (_state_of_the_state | Deletion) { + return; + } + + Glib::Mutex::Lock lm (controllables_lock); + controllables.remove (c); +} + +Controllable* +Session::controllable_by_id (const PBD::ID& id) +{ + Glib::Mutex::Lock lm (controllables_lock); + + for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) { + if ((*i)->id() == id) { + return *i; + } + } + + return 0; +} + +void +Session::add_instant_xml (XMLNode& node, const std::string& dir) +{ + Stateful::add_instant_xml (node, dir); + Config->add_instant_xml (node, get_user_ardour_path()); +} diff --git a/libs/ardour/session_time.cc b/libs/ardour/session_time.cc index 0e52c926fe..bd2c992ff5 100644 --- a/libs/ardour/session_time.cc +++ b/libs/ardour/session_time.cc @@ -32,7 +32,6 @@ #include <ardour/audioengine.h> #include <ardour/session.h> #include <ardour/tempo.h> -#include <ardour/audiofilesource.h> #include "i18n.h" @@ -93,8 +92,6 @@ Session::set_smpte_offset (jack_nframes_t off) _smpte_offset = off; last_smpte_valid = false; - AudioFileSource::set_header_position_offset (_smpte_offset, _smpte_offset_negative); - SMPTEOffsetChanged (); /* EMIT SIGNAL */ } @@ -104,8 +101,6 @@ Session::set_smpte_offset_negative (bool neg) _smpte_offset_negative = neg; last_smpte_valid = false; - AudioFileSource::set_header_position_offset (_smpte_offset, _smpte_offset_negative); - SMPTEOffsetChanged (); /* EMIT SIGNAL */ } diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 55bdac064b..3bd54aa69c 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -80,7 +80,7 @@ Session::request_transport_speed (float speed) } void -Session::request_diskstream_speed (AudioDiskstream& ds, float speed) +Session::request_diskstream_speed (Diskstream& ds, float speed) { Event* ev = new Event (Event::SetDiskstreamSpeed, Event::Add, Event::Immediate, 0, speed); ev->set_ptr (&ds); @@ -192,17 +192,17 @@ Session::realtime_stop (bool abort) void Session::butler_transport_work () { - Glib::RWLock::ReaderLock rm (route_lock); Glib::RWLock::ReaderLock dsm (diskstream_lock); - + boost::shared_ptr<RouteList> r = routes.reader (); + if (post_transport_work & PostTransportCurveRealloc) { - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { (*i)->curve_reallocate(); } } if (post_transport_work & PostTransportInputChange) { - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->non_realtime_input_change (); } } @@ -218,7 +218,7 @@ Session::butler_transport_work () cumulative_rf_motion = 0; reset_rf_scale (0); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (!(*i)->hidden()) { if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) { (*i)->seek ((jack_nframes_t) (_transport_frame * (double) (*i)->speed())); @@ -250,7 +250,7 @@ Session::non_realtime_set_speed () { Glib::RWLock::ReaderLock lm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->non_realtime_set_speed (); } } @@ -260,7 +260,7 @@ Session::non_realtime_overwrite () { Glib::RWLock::ReaderLock lm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->pending_overwrite) { (*i)->overwrite_existing_buffers (); } @@ -276,7 +276,7 @@ Session::non_realtime_stop (bool abort) did_record = false; - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->get_captured_frames () != 0) { did_record = true; break; @@ -331,11 +331,13 @@ Session::non_realtime_stop (bool abort) _have_captured = true; } - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->transport_stopped (*now, xnow, abort); } - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + boost::shared_ptr<RouteList> r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (!(*i)->hidden()) { (*i)->set_pending_declick (0); } @@ -368,7 +370,7 @@ Session::non_realtime_stop (bool abort) } #endif - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (!(*i)->hidden()) { if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) { (*i)->seek ((jack_nframes_t) (_transport_frame * (double) (*i)->speed())); @@ -495,7 +497,7 @@ Session::set_auto_loop (bool yn) if (seamless_loop) { // set all diskstreams to use internal looping - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (!(*i)->hidden()) { (*i)->set_loop (loc); } @@ -503,7 +505,7 @@ Session::set_auto_loop (bool yn) } else { // set all diskstreams to NOT use internal looping - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (!(*i)->hidden()) { (*i)->set_loop (0); } @@ -533,7 +535,7 @@ Session::set_auto_loop (bool yn) clear_events (Event::AutoLoop); // set all diskstreams to NOT use internal looping - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (!(*i)->hidden()) { (*i)->set_loop (0); } @@ -547,7 +549,9 @@ Session::set_auto_loop (bool yn) void Session::flush_all_redirects () { - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + boost::shared_ptr<RouteList> r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { (*i)->flush_redirects (); } } @@ -649,7 +653,7 @@ Session::locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, b The rarity and short potential lock duration makes this "OK" */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (!auto_input); @@ -664,7 +668,7 @@ Session::locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, b The rarity and short potential lock duration makes this "OK" */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (true); @@ -708,7 +712,7 @@ Session::set_transport_speed (float speed, bool abort) The rarity and short potential lock duration makes this "OK" */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (true); @@ -734,7 +738,7 @@ Session::set_transport_speed (float speed, bool abort) The rarity and short potential lock duration makes this "OK" */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (auto_input && (*i)->record_enabled ()) { //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (false); @@ -785,7 +789,7 @@ Session::set_transport_speed (float speed, bool abort) _last_transport_speed = _transport_speed; _transport_speed = speed; - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->realtime_set_speed ((*i)->speed(), true)) { post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed); } @@ -875,7 +879,7 @@ Session::actually_start_transport () transport_sub_state |= PendingDeclickIn; _transport_speed = 1.0; - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->realtime_set_speed ((*i)->speed(), true); } @@ -1005,7 +1009,7 @@ Session::set_slave_source (SlaveSource src, jack_nframes_t frame) _slave_type = src; - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (!(*i)->hidden()) { if ((*i)->realtime_set_speed ((*i)->speed(), true)) { non_rt_required = true; @@ -1037,7 +1041,7 @@ Session::reverse_diskstream_buffers () } void -Session::set_diskstream_speed (AudioDiskstream* stream, float speed) +Session::set_diskstream_speed (Diskstream* stream, float speed) { if (stream->realtime_set_speed (speed, false)) { post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed); @@ -1196,11 +1200,12 @@ Session::update_latency_compensation (bool with_stop, bool abort) return; } - Glib::RWLock::ReaderLock lm (route_lock); Glib::RWLock::ReaderLock lm2 (diskstream_lock); _worst_track_latency = 0; - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + boost::shared_ptr<RouteList> r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (with_stop) { (*i)->handle_transport_stopped (abort, (post_transport_work & PostTransportLocate), (!(post_transport_work & PostTransportLocate) || pending_locate_flush)); @@ -1218,7 +1223,7 @@ Session::update_latency_compensation (bool with_stop, bool abort) } } - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { (*i)->set_latency_delay (_worst_track_latency); } @@ -1228,12 +1233,12 @@ Session::update_latency_compensation (bool with_stop, bool abort) _engine.update_total_latencies (); } - set_worst_io_latencies (false); + set_worst_io_latencies (); /* reflect any changes in latencies into capture offsets */ - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->set_capture_offset (); } } diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc index 443a24e3c2..5936f62570 100644 --- a/libs/ardour/sndfilesource.cc +++ b/libs/ardour/sndfilesource.cc @@ -156,6 +156,8 @@ SndFileSource::SndFileSource (string idstr, SampleFormat sfmt, HeaderFormat hf, utsinfo.version); _broadcast_info->version = 1; + _broadcast_info->time_reference_low = 0; + _broadcast_info->time_reference_high = 0; /* XXX do something about this field */ @@ -183,6 +185,7 @@ SndFileSource::SndFileSource (string idstr, SampleFormat sfmt, HeaderFormat hf, } AudioSourceCreated (this); /* EMIT SIGNAL */ + } void @@ -246,21 +249,19 @@ SndFileSource::open () _flags = Flag (_flags & ~Broadcast); } + set_timeline_position (header_position_offset); + } else { /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits of the time reference. */ - - set_timeline_position (_broadcast_info->time_reference_low); + + set_timeline_position ( _broadcast_info->time_reference_low ); } if (writable()) { sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE); - - /* update header if header offset info changes */ - - AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &AudioFileSource::handle_header_position_change)); } return 0; @@ -280,7 +281,7 @@ SndFileSource::~SndFileSource () } if (_broadcast_info) { - free (_broadcast_info); + delete _broadcast_info; } } @@ -472,7 +473,7 @@ SndFileSource::setup_broadcast_info (jack_nframes_t when, struct tm& now, time_t now.tm_mon, now.tm_mday); - snprintf (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d-%02d-%02d", + snprintf (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d", now.tm_hour, now.tm_min, now.tm_sec); @@ -495,33 +496,12 @@ SndFileSource::setup_broadcast_info (jack_nframes_t when, struct tm& now, time_t void SndFileSource::set_header_timeline_position () { - uint64_t pos; - if (!(_flags & Broadcast)) { return; } - _broadcast_info->time_reference_high = 0; - - if (header_position_negative) { - - if (ULONG_LONG_MAX - header_position_offset < timeline_position) { - pos = ULONG_LONG_MAX; // impossible - } else { - pos = timeline_position + header_position_offset; - } - - } else { - - if (timeline_position < header_position_offset) { - pos = 0; - } else { - pos = timeline_position - header_position_offset; - } - } - - _broadcast_info->time_reference_high = (pos >> 32); - _broadcast_info->time_reference_low = (pos & 0xffffffff); + _broadcast_info->time_reference_high = (timeline_position >> 32); + _broadcast_info->time_reference_low = (timeline_position & 0xffffffff); if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) { error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg; @@ -545,3 +525,9 @@ SndFileSource::write_float (Sample* data, jack_nframes_t frame_pos, jack_nframes return cnt; } + +jack_nframes_t +SndFileSource::natural_position() const +{ + return timeline_position; +} diff --git a/libs/ardour/source.cc b/libs/ardour/source.cc index 0d32ea4a21..eebc64d463 100644 --- a/libs/ardour/source.cc +++ b/libs/ardour/source.cc @@ -45,7 +45,6 @@ using namespace ARDOUR; Source::Source (string name) { _name = name; - _id = ARDOUR::new_id(); _use_cnt = 0; _timestamp = 0; } @@ -71,7 +70,7 @@ Source::get_state () char buf[64]; node->add_property ("name", _name); - snprintf (buf, sizeof(buf)-1, "%" PRIu64, _id); + _id.print (buf); node->add_property ("id", buf); if (_timestamp != 0) { @@ -94,7 +93,7 @@ Source::set_state (const XMLNode& node) } if ((prop = node.property ("id")) != 0) { - sscanf (prop->value().c_str(), "%" PRIu64, &_id); + _id = prop->value (); } else { return -1; } diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc new file mode 100644 index 0000000000..3b3b705a87 --- /dev/null +++ b/libs/ardour/track.cc @@ -0,0 +1,219 @@ +/* + Copyright (C) 2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include <pbd/error.h> +#include <sigc++/retype.h> +#include <sigc++/retype_return.h> +#include <sigc++/bind.h> + +#include <ardour/track.h> +#include <ardour/diskstream.h> +#include <ardour/session.h> +#include <ardour/redirect.h> +#include <ardour/audioregion.h> +#include <ardour/audiosource.h> +#include <ardour/route_group_specialized.h> +#include <ardour/insert.h> +#include <ardour/audioplaylist.h> +#include <ardour/panner.h> +#include <ardour/utils.h> + +#include "i18n.h" + +using namespace std; +using namespace ARDOUR; +using namespace PBD; + +Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, DataType default_type) + : Route (sess, name, 1, -1, -1, -1, flag, default_type) + , _diskstream (0) + , _rec_enable_control (*this) +{ + _declickable = true; + _freeze_record.state = NoFreeze; + _saved_meter_point = _meter_point; + _mode = mode; +} + +Track::Track (Session& sess, const XMLNode& node, DataType default_type) + : Route (sess, "to be renamed", 0, 0, -1, -1, Route::Flag(0), default_type) + , _diskstream (0) + , _rec_enable_control (*this) +{ + _freeze_record.state = NoFreeze; + _declickable = true; + _saved_meter_point = _meter_point; +} + +Track::~Track () +{ + if (_diskstream) { + _diskstream->unref(); + } +} + +void +Track::set_meter_point (MeterPoint p, void *src) +{ + Route::set_meter_point (p, src); +} + +XMLNode& +Track::get_state () +{ + return state (true); +} + +XMLNode& +Track::get_template () +{ + return state (false); +} + +void +Track::toggle_monitor_input () +{ + for (vector<Port*>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { + (*i)->request_monitor_input(!(*i)->monitoring_input()); + } +} + +jack_nframes_t +Track::update_total_latency () +{ + _own_latency = 0; + + for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) { + if ((*i)->active ()) { + _own_latency += (*i)->latency (); + } + } + + set_port_latency (_own_latency); + + return _own_latency; +} + + +Track::FreezeRecord::~FreezeRecord () +{ + for (vector<FreezeRecordInsertInfo*>::iterator i = insert_info.begin(); i != insert_info.end(); ++i) { + delete *i; + } +} + +Track::FreezeState +Track::freeze_state() const +{ + return _freeze_record.state; +} + +Track::RecEnableControllable::RecEnableControllable (Track& s) + : track (s) +{ +} + +void +Track::RecEnableControllable::set_value (float val) +{ + bool bval = ((val >= 0.5f) ? true: false); + track.set_record_enable (bval, this); +} + +float +Track::RecEnableControllable::get_value (void) const +{ + if (track.record_enabled()) { return 1.0f; } + return 0.0f; +} + +bool +Track::record_enabled () const +{ + return _diskstream->record_enabled (); +} + +void +Track::set_record_enable (bool yn, void *src) +{ + if (_freeze_record.state == Frozen) { + return; + } + + if (_mix_group && src != _mix_group && _mix_group->is_active()) { + _mix_group->apply (&Track::set_record_enable, yn, _mix_group); + return; + } + + /* keep track of the meter point as it was before we rec-enabled */ + + if (!_diskstream->record_enabled()) { + _saved_meter_point = _meter_point; + } + + _diskstream->set_record_enabled (yn); + + if (_diskstream->record_enabled()) { + set_meter_point (MeterInput, this); + } else { + set_meter_point (_saved_meter_point, this); + } + + _rec_enable_control.Changed (); +} + +void +Track::set_mode (TrackMode m) +{ + if (_diskstream) { + if (_mode != m) { + _mode = m; + _diskstream->set_destructive (m == Destructive); + ModeChanged(); + } + } +} + +int +Track::set_name (string str, void *src) +{ + int ret; + + if (record_enabled() && _session.actively_recording()) { + /* this messes things up if done while recording */ + return -1; + } + + if (_diskstream->set_name (str)) { + return -1; + } + + /* save state so that the statefile fully reflects any filename changes */ + + if ((ret = IO::set_name (str, src)) == 0) { + _session.save_state (""); + } + return ret; +} + +void +Track::set_latency_delay (jack_nframes_t longest_session_latency) +{ + Route::set_latency_delay (longest_session_latency); + _diskstream->set_roll_delay (_roll_delay); +} + diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc index 9adc7c72cd..78e5572a3d 100644 --- a/libs/ardour/utils.cc +++ b/libs/ardour/utils.cc @@ -186,15 +186,6 @@ touch_file (string path) return 1; } -uint32_t long -get_uid() -{ - struct timeval tv; - gettimeofday(&tv, 0); - - return (uint32_t long) tv.tv_sec * 1000000 + tv.tv_usec; -} - string placement_as_string (Placement p) { @@ -262,3 +253,21 @@ path_expand (string path) #endif } +#ifdef HAVE_COREAUDIO +string +CFStringRefToStdString(CFStringRef stringRef) +{ + CFIndex size = + CFStringGetMaximumSizeForEncoding(CFStringGetLength(stringRef) , + kCFStringEncodingUTF8); + char *buf = new char[size]; + + std::string result; + + if(CFStringGetCString(stringRef, buf, size, kCFStringEncodingUTF8)) { + result = buf; + } + delete [] buf; + return result; +} +#endif // HAVE_COREAUDIO diff --git a/libs/ardour/vst_plugin.cc b/libs/ardour/vst_plugin.cc index 80c36dab95..a551a15d28 100644 --- a/libs/ardour/vst_plugin.cc +++ b/libs/ardour/vst_plugin.cc @@ -41,8 +41,6 @@ #include <vst/aeffectx.h> -#include <midi++/manager.h> - #include <ardour/ardour.h> #include <ardour/session.h> #include <ardour/audioengine.h> @@ -81,7 +79,7 @@ VSTPlugin::VSTPlugin (AudioEngine& e, Session& session, FSTHandle* h) _plugin->dispatcher (_plugin, effSetProgram, 0, 0, NULL, 0.0f); - Plugin::setup_midi_controls (); + Plugin::setup_controls (); } VSTPlugin::VSTPlugin (const VSTPlugin &other) @@ -94,7 +92,7 @@ VSTPlugin::VSTPlugin (const VSTPlugin &other) } _plugin = _fst->plugin; - Plugin::setup_midi_controls (); + Plugin::setup_controls (); } VSTPlugin::~VSTPlugin () @@ -133,13 +131,6 @@ VSTPlugin::set_parameter (uint32_t which, float val) { _plugin->setParameter (_plugin, which, val); ParameterChanged (which, val); /* EMIT SIGNAL */ - - if (session().get_midi_feedback()) { - - if (which < parameter_count() && midi_controls[which]) { - midi_controls[which]->send_feedback (val); - } - } } float @@ -488,3 +479,31 @@ VSTPlugin::print_parameter (uint32_t param, char *buf, uint32_t len) const memmove (buf, first_nonws, strlen (buf) - (first_nonws - buf) + 1); } + +PluginPtr +VSTPluginInfo::load (Session& session) +{ + try { + PluginPtr plugin; + + if (Config->get_use_vst()) { + FSTHandle* handle; + + if ((handle = fst_load (info->path.c_str())) == 0) { + error << string_compose(_("VST: cannot load module from \"%1\""), info->path) << endmsg; + } else { + plugin.reset (new VSTPlugin (session.engine(), session, handle)); + } + } else { + error << _("You asked ardour to not use any VST plugins") << endmsg; + return PluginPtr ((Plugin*) 0); + } + + plugin->set_info(PluginInfoPtr(new VSTPluginInfo(*this))); + return plugin; + } + + catch (failed_constructor &err) { + return PluginPtr ((Plugin*) 0); + } +} diff --git a/libs/gtkmm2ext/SConscript b/libs/gtkmm2ext/SConscript index b70aea3d40..cf513eb5a1 100644 --- a/libs/gtkmm2ext/SConscript +++ b/libs/gtkmm2ext/SConscript @@ -9,8 +9,7 @@ Import('env final_prefix install_prefix libraries i18n') gtkmm2ext = env.Copy() gtkmm2ext.Merge ([ libraries['sigc2'], - libraries['pbd3'], - libraries['midi++2'], + libraries['pbd'], libraries['gtk2'], libraries['glibmm2'], libraries['pangomm'], @@ -25,24 +24,25 @@ gtkmm2ext.Merge ([ domain = 'libgtkmm2ext' -gtkmm2ext.Append(DOMAIN=domain,MAJOR=0,MINOR=8,MICRO=2) +gtkmm2ext.Append(DOMAIN=domain,MAJOR=0,MINOR=8,MICRO=3) gtkmm2ext.Append(CXXFLAGS="-DPACKAGE=\\\"" + domain + "\\\"") gtkmm2ext.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED") +#gtkmm2ext.Append(CPPPATH='#libs/surfaces/control_protocol') gtkmm2ext.Append(PACKAGE=domain) gtkmm2ext.Append(POTFILE=domain + '.pot') gtkmm2ext_files = Split(""" auto_spin.cc barcontroller.cc -bindable_button.cc +binding_proxy.cc choice.cc click_box.cc -controller.cc dndtreeview.cc fastmeter.cc gtk_ui.cc hexentry.cc idle_adjustment.cc +pathlist.cc pixscroller.cc popup.cc prompter.cc diff --git a/libs/gtkmm2ext/barcontroller.cc b/libs/gtkmm2ext/barcontroller.cc index c977f3e5f7..eefe6ca843 100644 --- a/libs/gtkmm2ext/barcontroller.cc +++ b/libs/gtkmm2ext/barcontroller.cc @@ -23,7 +23,7 @@ #include <cmath> #include <algorithm> -#include <midi++/controllable.h> +#include <pbd/controllable.h> #include <gtkmm2ext/gtk_ui.h> #include <gtkmm2ext/utils.h> @@ -36,16 +36,13 @@ using namespace Gtk; using namespace Gtkmm2ext; BarController::BarController (Gtk::Adjustment& adj, - MIDI::Controllable *mc, + PBD::Controllable& mc, sigc::slot<void,char*,unsigned int> lc) : adjustment (adj), - prompter (Gtk::WIN_POS_MOUSE, 30000, false), - midi_control (mc), + binding_proxy (mc), label_callback (lc), - spinner (adjustment), - bind_button (2), - bind_statemask (Gdk::CONTROL_MASK) + spinner (adjustment) { _style = LeftToRight; @@ -77,16 +74,6 @@ BarController::BarController (Gtk::Adjustment& adj, darea.signal_button_release_event().connect (mem_fun (*this, &BarController::button_release)); darea.signal_scroll_event().connect (mem_fun (*this, &BarController::scroll)); - prompter.signal_unmap_event().connect (mem_fun (*this, &BarController::prompter_hiding)); - - prompting = false; - unprompting = false; - - if (mc) { - mc->learning_started.connect (mem_fun (*this, &BarController::midicontrol_prompt)); - mc->learning_stopped.connect (mem_fun (*this, &BarController::midicontrol_unprompt)); - } - spinner.signal_activate().connect (mem_fun (*this, &BarController::entry_activated)); spinner.signal_focus_out_event().connect (mem_fun (*this, &BarController::entry_focus_out)); spinner.set_digits (3); @@ -95,24 +82,13 @@ BarController::BarController (Gtk::Adjustment& adj, show_all (); } -void -BarController::set_bind_button_state (guint button, guint statemask) -{ - bind_button = button; - bind_statemask = statemask; -} - -void -BarController::get_bind_button_state (guint &button, guint &statemask) -{ - button = bind_button; - statemask = bind_statemask; -} - - bool BarController::button_press (GdkEventButton* ev) { + if (binding_proxy.button_press_handler (ev)) { + return true; + } + switch (ev->button) { case 1: if (ev->type == GDK_2BUTTON_PRESS) { @@ -174,8 +150,8 @@ BarController::button_release (GdkEventButton* ev) break; case 2: - if ((ev->state & bind_statemask) && bind_button == 2) { - midi_learn (); + if (true) { // XXX FIX ME + /* relax */ } else { double fract; fract = ev->x / (darea.get_width() - 2.0); @@ -185,10 +161,6 @@ BarController::button_release (GdkEventButton* ev) return true; case 3: - if ((ev->state & bind_statemask) && bind_button == 3) { - midi_learn (); - return TRUE; - } return false; default: @@ -408,61 +380,6 @@ BarController::set_with_text (bool yn) } void -BarController::midicontrol_set_tip () -{ - if (midi_control) { - // Gtkmm2ext::UI::instance()->set_tip (&darea, midi_control->control_description()); - } -} - -void -BarController::midi_learn() -{ - if (midi_control) { - prompting = true; - midi_control->learn_about_external_control (); - } -} - - -void -BarController::midicontrol_prompt () -{ - if (prompting) { - string prompt = _("operate MIDI controller now"); - prompter.set_text (prompt); - Gtkmm2ext::UI::instance()->touch_display (&prompter); - - unprompting = true; - prompting = false; - } -} - -void -BarController::midicontrol_unprompt () -{ - if (unprompting) { - Gtkmm2ext::UI::instance()->touch_display (&prompter); - - unprompting = false; - } -} - -gint -BarController::prompter_hiding (GdkEventAny *ev) -{ - if (unprompting) { - if (midi_control) { - midi_control->stop_learning(); - } - unprompting = false; - } - - return FALSE; -} - - -void BarController::set_style (Style s) { _style = s; diff --git a/libs/gtkmm2ext/binding_proxy.cc b/libs/gtkmm2ext/binding_proxy.cc new file mode 100644 index 0000000000..3a2f5bbbc8 --- /dev/null +++ b/libs/gtkmm2ext/binding_proxy.cc @@ -0,0 +1,89 @@ +/* + Copyright (C) 2006 Paul Davis + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <string> +#include <climits> +#include <iostream> + +#include <pbd/controllable.h> + +#include <gtkmm2ext/binding_proxy.h> + +#include "i18n.h" + +using namespace Gtkmm2ext; +using namespace std; +using namespace PBD; + +BindingProxy::BindingProxy (Controllable& c) + : prompter (Gtk::WIN_POS_MOUSE, 30000, false), + controllable (c), + bind_button (2), + bind_statemask (Gdk::CONTROL_MASK) + +{ + prompter.signal_unmap_event().connect (mem_fun (*this, &BindingProxy::prompter_hiding)); +} + +void +BindingProxy::set_bind_button_state (guint button, guint statemask) +{ + bind_button = button; + bind_statemask = statemask; +} + +void +BindingProxy::get_bind_button_state (guint &button, guint &statemask) +{ + button = bind_button; + statemask = bind_statemask; +} + +bool +BindingProxy::button_press_handler (GdkEventButton *ev) +{ + if ((ev->state & bind_statemask) && ev->button == bind_button) { + if (Controllable::StartLearning (&controllable)) { + string prompt = _("operate controller now"); + prompter.set_text (prompt); + prompter.touch (); // shows popup + learning_connection = controllable.LearningFinished.connect (mem_fun (*this, &BindingProxy::learning_finished)); + } + return true; + } + + return false; +} + +void +BindingProxy::learning_finished () +{ + learning_connection.disconnect (); + prompter.touch (); // hides popup +} + + +bool +BindingProxy::prompter_hiding (GdkEventAny *ev) +{ + learning_connection.disconnect (); + Controllable::StopLearning (&controllable); + return false; +} + diff --git a/libs/gtkmm2ext/controller.cc b/libs/gtkmm2ext/controller.cc deleted file mode 100644 index 98d5566c69..0000000000 --- a/libs/gtkmm2ext/controller.cc +++ /dev/null @@ -1,92 +0,0 @@ -/* - Copyright (C) 1998-99 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 <string> -#include <climits> - -#include <midi++/channel.h> -#include <gtkmm2ext/gtk_ui.h> -#include <gtkmm2ext/controller.h> - -#include "i18n.h" - -using namespace Gtkmm2ext; - -Controller::Controller (Gtk::Adjustment *adj, MIDI::Port *p) - : MIDI::Controllable (p), - adjustment (adj), - prompter (Gtk::WIN_POS_MOUSE, 30000, false) -{ - new_value_pending = false; - - /* hear about MIDI control learning */ - - learning_started.connect - (mem_fun (*this, &Controller::midicontrol_prompt)); - learning_stopped.connect - (mem_fun (*this, &Controller::midicontrol_unprompt)); -} - -void -Controller::midicontrol_prompt () - -{ - string prompt = _("operate MIDI controller now"); - - prompter.set_text (prompt); - Gtkmm2ext::UI::instance()->touch_display (&prompter); -} - -void -Controller::midicontrol_unprompt () - -{ - Gtkmm2ext::UI::instance()->touch_display (&prompter); -} - -int -Controller::update_controller_value (void *arg) - -{ - Controller *c = (Controller *) arg; - - c->adjustment->set_value (c->new_value); - c->new_value_pending = false; - - return FALSE; -} - -void -Controller::set_value (float v) - -{ - /* This is called from a MIDI callback. It could happen - a thousand times a second, or more. Therefore, instead - of going straight to the X server, which may not work for - thread-related reasons, simply request an update whenever - the GTK main loop is idle. - */ - - new_value = v; - - if (!new_value_pending) { - new_value_pending = true; - Gtkmm2ext::UI::instance()->idle_add (update_controller_value, this); - } -} diff --git a/libs/gtkmm2ext/gtkmm2ext/barcontroller.h b/libs/gtkmm2ext/gtkmm2ext/barcontroller.h index 67c8221a55..ebce4e2de9 100644 --- a/libs/gtkmm2ext/gtkmm2ext/barcontroller.h +++ b/libs/gtkmm2ext/gtkmm2ext/barcontroller.h @@ -21,9 +21,9 @@ #define __gtkmm2ext_bar_controller_h__ #include <gtkmm.h> -#include <gtkmm2ext/popup.h> +#include <gtkmm2ext/binding_proxy.h> -namespace MIDI { +namespace ARDOUR { class Controllable; } @@ -32,14 +32,9 @@ namespace Gtkmm2ext { class BarController : public Gtk::Frame { public: - BarController (Gtk::Adjustment& adj, MIDI::Controllable*, sigc::slot<void,char*,unsigned int>); + BarController (Gtk::Adjustment& adj, PBD::Controllable&, sigc::slot<void,char*,unsigned int>); virtual ~BarController () {} - void set_bind_button_state (guint button, guint statemask); - void get_bind_button_state (guint &button, guint &statemask); - void midicontrol_set_tip (); - void midi_learn (); - void set_sensitive (bool yn) { darea.set_sensitive (yn); } @@ -69,9 +64,8 @@ class BarController : public Gtk::Frame protected: Gtk::Adjustment& adjustment; + BindingProxy binding_proxy; Gtk::DrawingArea darea; - Gtkmm2ext::PopUp prompter; - MIDI::Controllable* midi_control; sigc::slot<void,char*,unsigned int> label_callback; Glib::RefPtr<Pango::Layout> layout; Style _style; @@ -85,10 +79,6 @@ class BarController : public Gtk::Frame Gtk::SpinButton spinner; bool use_parent; - guint bind_button; - guint bind_statemask; - bool prompting, unprompting; - bool button_press (GdkEventButton *); bool button_release (GdkEventButton *); bool motion (GdkEventMotion *); @@ -98,11 +88,6 @@ class BarController : public Gtk::Frame gint mouse_control (double x, GdkWindow* w, double scaling); - gint prompter_hiding (GdkEventAny *); - void midicontrol_prompt (); - void midicontrol_unprompt (); - void update_midi_control (); - gint switch_to_bar (); gint switch_to_spinner (); diff --git a/libs/gtkmm2ext/gtkmm2ext/bindable_button.h b/libs/gtkmm2ext/gtkmm2ext/bindable_button.h index 7400cf15d0..1936125405 100644 --- a/libs/gtkmm2ext/gtkmm2ext/bindable_button.h +++ b/libs/gtkmm2ext/gtkmm2ext/bindable_button.h @@ -18,59 +18,31 @@ $Id$ */ -#ifndef __pbd_gtkmm_bindable_button_h__ -#define __pbd_gtkmm_bindable_button_h__ +#ifndef __bindable_button_h__ +#define __bindable_button_h__ #include <string> #include <gtkmm2ext/stateful_button.h> -#include <gtkmm2ext/popup.h> +#include "binding_proxy.h" -namespace MIDI { +namespace PBD { class Controllable; } -namespace Gtkmm2ext { - class BindableToggleButton : public Gtk::ToggleButton { public: - BindableToggleButton(MIDI::Controllable *); - - //: Create a check button with a label. - //- You won't be able - //- to add a widget in this button since it already has a {\class Gtk_Label} - //- in it. - explicit BindableToggleButton(MIDI::Controllable *, const std::string &label); - + BindableToggleButton (PBD::Controllable& c) : binding_proxy (c) {} + explicit BindableToggleButton (PBD::Controllable& c, const std::string &label) : Gtk::ToggleButton (label), binding_proxy (c) {} virtual ~BindableToggleButton() {} - void set_bind_button_state (guint button, guint statemask); - void get_bind_button_state (guint &button, guint &statemask); - - void midicontrol_set_tip (); - - void midi_learn (); - - protected: - - Gtkmm2ext::PopUp prompter; - - MIDI::Controllable* midi_control; - - guint bind_button; - guint bind_statemask; - - bool prompting, unprompting; - - void init_events (); - bool prompter_hiding (GdkEventAny *); - void midicontrol_prompt (); - void midicontrol_unprompt (); - - bool on_button_press_event (GdkEventButton *); -}; + bool on_button_press_event (GdkEventButton *ev) { + return binding_proxy.button_press_handler (ev); + } + private: + BindingProxy binding_proxy; }; #endif diff --git a/libs/ardour/ardour/session_diskstream.h b/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h index 33fc5419ba..a26c8ace2a 100644 --- a/libs/ardour/ardour/session_diskstream.h +++ b/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2002 Paul Davis + Copyright (C) 2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,25 +18,37 @@ $Id$ */ -#ifndef __ardour_session_diskstream_h__ -#define __ardour_session_diskstream_h__ +#ifndef __binding_proxy__ +#define __binding_proxy__ -#include <ardour/session.h> -#include <ardour/audio_diskstream.h> +#include <string> -namespace ARDOUR { +#include <gtkmm2ext/popup.h> -template<class T> void -Session::foreach_audio_diskstream (T *obj, void (T::*func)(AudioDiskstream&)) -{ - Glib::RWLock::ReaderLock lm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); i++) { - if (!(*i)->hidden()) { - (obj->*func) (**i); - } - } +namespace PBD { + class Controllable; } -} /* namespace */ - -#endif /* __ardour_session_diskstream_h__ */ +class BindingProxy : public sigc::trackable +{ + public: + BindingProxy (PBD::Controllable&); + virtual ~BindingProxy() {} + + void set_bind_button_state (guint button, guint statemask); + void get_bind_button_state (guint &button, guint &statemask); + + bool button_press_handler (GdkEventButton *); + + protected: + + Gtkmm2ext::PopUp prompter; + PBD::Controllable& controllable; + guint bind_button; + guint bind_statemask; + sigc::connection learning_connection; + void learning_finished (); + bool prompter_hiding (GdkEventAny *); +}; + +#endif diff --git a/libs/gtkmm2ext/gtkmm2ext/controller.h b/libs/gtkmm2ext/gtkmm2ext/pathlist.h index b72f6c7ed7..f4a5973d5a 100644 --- a/libs/gtkmm2ext/gtkmm2ext/controller.h +++ b/libs/gtkmm2ext/gtkmm2ext/pathlist.h @@ -1,5 +1,6 @@ /* - Copyright (C) 1998-99 Paul Davis + Copyright (C) 2006 Paul Davis + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -14,46 +15,49 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ */ -#ifndef __gtkmm2ext_controller_h__ -#define __gtkmm2ext_controller_h__ +#ifndef __gtkmm2ext_pathlist_h__ +#define __gtkmm2ext_pathlist_h__ + +#include <vector> +#include <string> #include <gtkmm.h> -#include <gtkmm2ext/popup.h> -#include <midi++/controllable.h> namespace Gtkmm2ext { -class Controller : public MIDI::Controllable - +class PathList : public Gtk::VBox { public: - Controller (Gtk::Adjustment *, MIDI::Port *); - virtual ~Controller () {} + PathList (); + ~PathList () {}; + + std::vector<std::string> get_paths (); + void set_paths (std::vector<std::string> paths); + + sigc::signal<void> PathsUpdated; - void set_value (float); - float lower () { return adjustment->get_lower(); } - float upper () { return adjustment->get_upper(); } - float range () { return upper() - lower() /* XXX +1 ??? */ ; } - - void midicontrol_prompt (); - void midicontrol_unprompt (); - protected: - Gtk::Adjustment *adjustment; + Gtk::Button add_btn; + Gtk::Button subtract_btn; - private: - Gtkmm2ext::PopUp prompter; - gfloat new_value; - bool new_value_pending; + void add_btn_clicked (); + void subtract_btn_clicked (); - static gint update_controller_value (void *); + private: + struct PathColumns : public Gtk::TreeModel::ColumnRecord { + PathColumns() { add (paths); } + Gtk::TreeModelColumn<std::string> paths; + }; + PathColumns path_columns; + + Glib::RefPtr<Gtk::ListStore> _store; + Gtk::TreeView _view; + + void selection_changed (); }; -}; /* namespace */ - -#endif // __gtkmm2ext_controller_h__ - +} // namespace Gtkmm2ext +#endif // __gtkmm2ext_pathlist_h__ diff --git a/libs/gtkmm2ext/gtkmm2ext/slider_controller.h b/libs/gtkmm2ext/gtkmm2ext/slider_controller.h index 7abaf285d1..f0f645eab7 100644 --- a/libs/gtkmm2ext/gtkmm2ext/slider_controller.h +++ b/libs/gtkmm2ext/gtkmm2ext/slider_controller.h @@ -1,5 +1,5 @@ /* - Copyright (C) 1998-99 Paul Davis + Copyright (C) 1998-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -17,18 +17,19 @@ $Id$ */ -#ifndef __gtkmm2ext_motion_controller_h__ -#define __gtkmm2ext_motion_controller_h__ +#ifndef __gtkmm2ext_slider_controller_h__ +#define __gtkmm2ext_slider_controller_h__ #include <gtkmm.h> #include <gtkmm2ext/popup.h> #include <gtkmm2ext/pixscroller.h> +#include <gtkmm2ext/binding_proxy.h> namespace Gtkmm2ext { class Pix; } -namespace MIDI { +namespace PBD { class Controllable; } @@ -40,41 +41,24 @@ class SliderController : public Gtkmm2ext::PixScroller SliderController (Glib::RefPtr<Gdk::Pixbuf> slider, Glib::RefPtr<Gdk::Pixbuf> rail, Gtk::Adjustment* adj, - MIDI::Controllable*, + PBD::Controllable&, bool with_numeric = true); virtual ~SliderController () {} - void set_bind_button_state (guint button, guint statemask); - void get_bind_button_state (guint &button, guint &statemask); - void midicontrol_set_tip (); - void midi_learn (); - void set_value (float); - // void set_sensitive (bool yn) { - // spin.set_sensitive (yn); - // } - Gtk::SpinButton & get_spin_button () { return spin; } + Gtk::SpinButton& get_spin_button () { return spin; } + bool on_button_press_event (GdkEventButton *ev); + protected: + BindingProxy binding_proxy; Glib::RefPtr<Gdk::Pixbuf> slider; Glib::RefPtr<Gdk::Pixbuf> rail; Gtk::SpinButton spin; Gtk::Frame spin_frame; Gtk::HBox spin_hbox; - Gtkmm2ext::PopUp prompter; - MIDI::Controllable* midi_control; - - guint bind_button; - guint bind_statemask; - bool prompting, unprompting; - - bool button_press (GdkEventButton *); - bool prompter_hiding (GdkEventAny *); - void midicontrol_prompt (); - void midicontrol_unprompt (); - void update_midi_control (); }; class VSliderController : public SliderController @@ -83,7 +67,7 @@ class VSliderController : public SliderController VSliderController (Glib::RefPtr<Gdk::Pixbuf> slider, Glib::RefPtr<Gdk::Pixbuf> rail, Gtk::Adjustment *adj, - MIDI::Controllable *, + PBD::Controllable&, bool with_numeric = true); }; @@ -93,11 +77,11 @@ class HSliderController : public SliderController HSliderController (Glib::RefPtr<Gdk::Pixbuf> slider, Glib::RefPtr<Gdk::Pixbuf> rail, Gtk::Adjustment *adj, - MIDI::Controllable *, + PBD::Controllable&, bool with_numeric = true); }; }; /* namespace */ -#endif // __gtkmm2ext_motion_controller_h__ +#endif // __gtkmm2ext_slider_controller_h__ diff --git a/libs/gtkmm2ext/pathlist.cc b/libs/gtkmm2ext/pathlist.cc new file mode 100644 index 0000000000..7b3448ed5f --- /dev/null +++ b/libs/gtkmm2ext/pathlist.cc @@ -0,0 +1,124 @@ +/* + Copyright (C) 2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <gtkmm2ext/pathlist.h> + +#include "i18n.h" + +using namespace std; +using namespace Gtkmm2ext; + +PathList::PathList () + : + add_btn(_("+")), + subtract_btn(_("-")), + path_columns(), + _store(Gtk::ListStore::create(path_columns)), + _view(_store) +{ + _view.append_column(_("Paths"), path_columns.paths); + _view.set_size_request(-1, 100); + _view.set_headers_visible (false); + + Gtk::ScrolledWindow* scroll = manage(new Gtk::ScrolledWindow); + scroll->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + scroll->add(_view); + + add (*scroll); + + Gtk::HBox* btn_box = manage(new Gtk::HBox); + btn_box->add(add_btn); + btn_box->add(subtract_btn); + + add (*btn_box); + + add_btn.signal_clicked().connect (mem_fun(*this, &PathList::add_btn_clicked)); + subtract_btn.signal_clicked().connect (mem_fun(*this, &PathList::subtract_btn_clicked)); + _view.get_selection()->signal_changed().connect (mem_fun(*this, &PathList::selection_changed)); +} + +vector<string> +PathList::get_paths () +{ + vector<string> paths; + + Gtk::TreeModel::Children children(_store->children()); + + for (Gtk::TreeIter iter = children.begin(); iter != children.end(); ++iter) { + Gtk::ListStore::Row row = *iter; + + paths.push_back(row[path_columns.paths]); + } + + return paths; +} + +void +PathList::set_paths (vector<string> paths) +{ + _store->clear(); + + for (vector<string>::iterator i = paths.begin(); i != paths.end(); ++i) { + Gtk::ListStore::iterator iter = _store->append(); + Gtk::ListStore::Row row = *iter; + row[path_columns.paths] = *i; + } +} + +void +PathList::add_btn_clicked () +{ + Gtk::FileChooserDialog path_chooser (_("Path Chooser"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); + + path_chooser.add_button (Gtk::Stock::ADD, Gtk::RESPONSE_OK); + path_chooser.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + + int result = path_chooser.run (); + + if (result == Gtk::RESPONSE_OK) { + string pathname = path_chooser.get_filename(); + + if (pathname.length ()) { + Gtk::ListStore::iterator iter = _store->append (); + Gtk::ListStore::Row row = *iter; + row[path_columns.paths] = pathname; + + PathsUpdated (); // EMIT_SIGNAL + } + } +} + +void +PathList::subtract_btn_clicked () +{ + Gtk::ListStore::iterator iter = _view.get_selection()->get_selected(); + _store->erase (iter); + + PathsUpdated (); // EMIT_SIGNAL +} + +void +PathList::selection_changed () +{ + if (_view.get_selection()->count_selected_rows ()) { + subtract_btn.set_sensitive (true); + } else { + subtract_btn.set_sensitive (false); + } +} diff --git a/libs/gtkmm2ext/popup.cc b/libs/gtkmm2ext/popup.cc index 0a48ebfc59..a8ffc4af66 100644 --- a/libs/gtkmm2ext/popup.cc +++ b/libs/gtkmm2ext/popup.cc @@ -73,11 +73,12 @@ PopUp::remove () { hide (); + if (popdown_time != 0 && timeout != -1) { + gtk_timeout_remove (timeout); + } + if (delete_on_hide) { std::cerr << "deleting prompter\n"; - if (popdown_time != 0 && timeout != -1) { - gtk_timeout_remove (timeout); - } gtk_idle_add (idle_delete, this); } } @@ -125,11 +126,12 @@ PopUp::on_delete_event (GdkEventAny* ev) { hide(); + if (popdown_time != 0 && timeout != -1) { + gtk_timeout_remove (timeout); + } + if (delete_on_hide) { std::cerr << "deleting prompter\n" << endl; - if (popdown_time != 0 && timeout != -1) { - gtk_timeout_remove (timeout); - } gtk_idle_add (idle_delete, this); } diff --git a/libs/gtkmm2ext/slider_controller.cc b/libs/gtkmm2ext/slider_controller.cc index 734d5eb62f..e524eba1cb 100644 --- a/libs/gtkmm2ext/slider_controller.cc +++ b/libs/gtkmm2ext/slider_controller.cc @@ -18,47 +18,30 @@ */ #include <string> -#include <climits> - -#include <midi++/controllable.h> #include <gtkmm2ext/gtk_ui.h> -#include <gtkmm2ext/slider_controller.h> #include <gtkmm2ext/pixscroller.h> +#include <gtkmm2ext/slider_controller.h> #include "i18n.h" using namespace Gtkmm2ext; +using namespace PBD; SliderController::SliderController (Glib::RefPtr<Gdk::Pixbuf> slide, Glib::RefPtr<Gdk::Pixbuf> rail, Gtk::Adjustment *adj, - MIDI::Controllable *mc, + Controllable& c, bool with_numeric) : PixScroller (*adj, slide, rail), - spin (*adj, 0, 2), - prompter (Gtk::WIN_POS_MOUSE, 30000, false), - midi_control (mc), - bind_button (2), - bind_statemask (Gdk::CONTROL_MASK) - + binding_proxy (c), + spin (*adj, 0, 2) { - signal_button_press_event().connect (mem_fun (this, &SliderController::button_press)); spin.set_name ("SliderControllerValue"); spin.set_size_request (70,-1); // should be based on font size somehow spin.set_numeric (true); spin.set_snap_to_ticks (false); - - prompter.signal_unmap_event().connect (mem_fun (*this, &SliderController::prompter_hiding)); - - prompting = false; - unprompting = false; - - if (mc) { - mc->learning_started.connect (mem_fun (*this, &SliderController::midicontrol_prompt)); - mc->learning_stopped.connect (mem_fun (*this, &SliderController::midicontrol_unprompt)); - } } void @@ -67,95 +50,22 @@ SliderController::set_value (float v) adj.set_value (v); } -void -SliderController::set_bind_button_state (guint button, guint statemask) -{ - bind_button = button; - bind_statemask = statemask; -} - -void -SliderController::get_bind_button_state (guint &button, guint &statemask) -{ - button = bind_button; - statemask = bind_statemask; -} - -void -SliderController::midi_learn() -{ - if (midi_control) { - prompting = true; - midi_control->learn_about_external_control (); - } -} - -bool -SliderController::button_press (GdkEventButton *ev) +bool +SliderController::on_button_press_event (GdkEventButton *ev) { - if ((ev->state & bind_statemask) && ev->button == bind_button) { - midi_learn (); + if (binding_proxy.button_press_handler (ev)) { return true; } - - return false; -} - -void -SliderController::midicontrol_set_tip () - -{ - if (midi_control) { - // Gtkmm2ext::UI::instance()->set_tip (this, midi_control->control_description()); - } -} - -bool -SliderController::prompter_hiding (GdkEventAny *ev) -{ - if (unprompting) { - if (midi_control) { - midi_control->stop_learning(); - } - unprompting = false; - } - - return false; -} - -void -SliderController::midicontrol_prompt () - -{ - if (prompting) { - - string prompt = _("operate MIDI controller now"); - prompter.set_text (prompt); - Gtkmm2ext::UI::instance()->touch_display (&prompter); - - unprompting = true; - prompting = false; - } -} - -void -SliderController::midicontrol_unprompt () - -{ - if (unprompting) { - Gtkmm2ext::UI::instance()->touch_display (&prompter); - unprompting = false; - } + return PixScroller::on_button_press_event (ev); } - VSliderController::VSliderController (Glib::RefPtr<Gdk::Pixbuf> slide, Glib::RefPtr<Gdk::Pixbuf> rail, Gtk::Adjustment *adj, - MIDI::Controllable *mcontrol, + Controllable& control, bool with_numeric) - : SliderController (slide, rail, adj, mcontrol, with_numeric) + : SliderController (slide, rail, adj, control, with_numeric) { if (with_numeric) { spin_frame.add (spin); @@ -169,10 +79,10 @@ VSliderController::VSliderController (Glib::RefPtr<Gdk::Pixbuf> slide, HSliderController::HSliderController (Glib::RefPtr<Gdk::Pixbuf> slide, Glib::RefPtr<Gdk::Pixbuf> rail, Gtk::Adjustment *adj, - MIDI::Controllable *mcontrol, + Controllable& control, bool with_numeric) - : SliderController (slide, rail, adj, mcontrol, with_numeric) + : SliderController (slide, rail, adj, control, with_numeric) { if (with_numeric) { spin_frame.add (spin); diff --git a/libs/libgnomecanvasmm/SConscript b/libs/libgnomecanvasmm/SConscript index 1d5f3e0050..d9620dc378 100644 --- a/libs/libgnomecanvasmm/SConscript +++ b/libs/libgnomecanvasmm/SConscript @@ -8,7 +8,14 @@ gnomecanvasmm_files = glob.glob('libgnomecanvasmm/*.cc') Import('env libraries install_prefix') gnomecanvasmm = env.Copy() -gnomecanvasmm.Merge([libraries['glibmm2'], libraries['gtk2'], libraries['sigc2'], libraries['pangomm'], libraries['atkmm'], libraries['gdkmm2'], libraries['gtkmm2'], libraries['libgnomecanvas2'] ]) +gnomecanvasmm.Merge([libraries['glibmm2'], + libraries['gtk2'], + libraries['sigc2'], + libraries['pangomm'], + libraries['atkmm'], + libraries['gdkmm2'], + libraries['gtkmm2'], + libraries['libgnomecanvas2'] ]) libgnomecanvasmm = gnomecanvasmm.SharedLibrary('libgnomecanvasmm', gnomecanvasmm_files) Default(libgnomecanvasmm) diff --git a/libs/libsndfile/src/sndfile.c b/libs/libsndfile/src/sndfile.c index 47b74cfd7f..14586526e4 100644 --- a/libs/libsndfile/src/sndfile.c +++ b/libs/libsndfile/src/sndfile.c @@ -1065,20 +1065,19 @@ sf_command (SNDFILE *sndfile, int command, void *data, int datasize) memcpy (data, psf->loop_info, sizeof (SF_LOOP_INFO)) ; return SF_TRUE ; - case SFC_SET_BROADCAST_INFO : - { int format = psf->sf.format & SF_FORMAT_TYPEMASK ; + case SFC_SET_BROADCAST_INFO : { + int format = psf->sf.format & SF_FORMAT_TYPEMASK ; - /* Only WAV supports the BEXT (Broadcast) chunk. */ - if (format != SF_FORMAT_WAV && format != SF_FORMAT_WAVEX) - return SF_FALSE ; - } ; + /* Only WAV supports the BEXT (Broadcast) chunk. */ + if (format != SF_FORMAT_WAV && format != SF_FORMAT_WAVEX) + return SF_FALSE ; /* Can only do this is in SFM_RDWR or SFM_WRITE modes. */ if (psf->mode == SFM_READ) return SF_FALSE ; /* If data has already been written this must fail. */ - if (psf->broadcast_info == NULL && psf->have_written) + if (psf->broadcast_info == NULL && psf->have_written) return SF_FALSE ; if (psf->broadcast_info == NULL) @@ -1089,7 +1088,9 @@ sf_command (SNDFILE *sndfile, int command, void *data, int datasize) if (psf->auto_header && psf->write_header) psf->write_header (psf, SF_TRUE) ; + return SF_TRUE ; + } case SFC_GET_BROADCAST_INFO : if (datasize != sizeof (SF_BROADCAST_INFO) || data == NULL) diff --git a/libs/midi++2/SConscript b/libs/midi++2/SConscript index 928372909c..696fed6b5b 100644 --- a/libs/midi++2/SConscript +++ b/libs/midi++2/SConscript @@ -7,7 +7,7 @@ import glob Import('env libraries install_prefix') midi2 = env.Copy() -midi2.Merge([ libraries['sigc2'], libraries['xml'], libraries['glib2'], libraries['pbd3'] ]) +midi2.Merge([ libraries['sigc2'], libraries['xml'], libraries['glib2'], libraries['pbd'] ]) domain = 'midipp' @@ -18,7 +18,6 @@ fd_midiport.cc fifomidi.cc midi.cc midichannel.cc -midicontrollable.cc midifactory.cc midimanager.cc midiparser.cc diff --git a/libs/midi++2/midi++/channel.h b/libs/midi++2/midi++/channel.h index 1efde3cb93..f8dbb6e194 100644 --- a/libs/midi++2/midi++/channel.h +++ b/libs/midi++2/midi++/channel.h @@ -152,7 +152,7 @@ class Channel : public sigc::trackable { void process_reset (Parser &); }; -}; /* namespace MIDI */ +} // namespace MIDI #endif // __midichannel_h__ diff --git a/libs/midi++2/midi++/controllable.h b/libs/midi++2/midi++/controllable.h deleted file mode 100644 index 3fa108bb46..0000000000 --- a/libs/midi++2/midi++/controllable.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - Copyright (C) 1998-99 Paul Barton-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 __qm_midicontrollable_h__ -#define __qm_midicontrollable_h__ - -#include <string> - -#include <sigc++/sigc++.h> - -#include <midi++/types.h> - -namespace MIDI { - -class Channel; -class Port; -class Parser; - -class Controllable : public sigc::trackable -{ - public: - Controllable (Port *, bool bistate = false); - virtual ~Controllable (); - - void midi_rebind (Port *, channel_t channel=-1); - void midi_forget (); - void learn_about_external_control (); - void stop_learning (); - void drop_external_control (); - - virtual void set_value (float) = 0; - - sigc::signal<void> learning_started; - sigc::signal<void> learning_stopped; - - bool get_control_info (channel_t&, eventType&, byte&); - void set_control_type (channel_t, eventType, byte); - - bool get_midi_feedback () { return feedback; } - void set_midi_feedback (bool val) { feedback = val; } - - Port * get_port() { return port; } - - std::string control_description() const { return _control_description; } - - void send_midi_feedback (float); - - private: - bool bistate; - int midi_msg_id; /* controller ID or note number */ - sigc::connection midi_sense_connection[2]; - sigc::connection midi_learn_connection; - size_t connections; - Port* port; - eventType control_type; - byte control_additional; - channel_t control_channel; - std::string _control_description; - bool feedback; - - void midi_receiver (Parser &p, byte *, size_t); - void midi_sense_note (Parser &, EventTwoBytes *, bool is_on); - void midi_sense_note_on (Parser &p, EventTwoBytes *tb); - void midi_sense_note_off (Parser &p, EventTwoBytes *tb); - void midi_sense_controller (Parser &, EventTwoBytes *); - void midi_sense_program_change (Parser &, byte); - void midi_sense_pitchbend (Parser &, pitchbend_t); - - void bind_midi (channel_t, eventType, byte); -}; - -}; /* namespace MIDI */ - -#endif // __qm_midicontrollable_h__ - diff --git a/libs/midi++2/midi++/coremidi_midiport.h b/libs/midi++2/midi++/coremidi_midiport.h index e02a225784..d7df23aa04 100644 --- a/libs/midi++2/midi++/coremidi_midiport.h +++ b/libs/midi++2/midi++/coremidi_midiport.h @@ -62,6 +62,6 @@ namespace MIDI { bool firstrecv; }; -}; /* namespace MIDI */ +} // namespace MIDI #endif // __coremidi_midiport_h__ diff --git a/libs/midi++2/midi++/factory.h b/libs/midi++2/midi++/factory.h index 1543f68cdc..7b4122d791 100644 --- a/libs/midi++2/midi++/factory.h +++ b/libs/midi++2/midi++/factory.h @@ -35,6 +35,6 @@ class PortFactory { const std::string &reqstr); }; -}; /* namespace MIDI */ +} // namespace MIDI #endif // __midi_factory_h__ diff --git a/libs/midi++2/midi++/fd_midiport.h b/libs/midi++2/midi++/fd_midiport.h index 853af9d7b4..6a9b8f74d1 100644 --- a/libs/midi++2/midi++/fd_midiport.h +++ b/libs/midi++2/midi++/fd_midiport.h @@ -89,6 +89,6 @@ class FD_MidiPort : public Port int do_slow_write (byte *msg, unsigned int msglen); }; -}; /*namespace MIDI */ +} // namespace MIDI #endif // __fd_midiport_h__ diff --git a/libs/midi++2/midi++/fifomidi.h b/libs/midi++2/midi++/fifomidi.h index eb8778d4d5..200d90eda8 100644 --- a/libs/midi++2/midi++/fifomidi.h +++ b/libs/midi++2/midi++/fifomidi.h @@ -42,6 +42,6 @@ class FIFO_MidiPort : public MIDI::FD_MidiPort void open (PortRequest &req); }; -}; /* namespace MIDI */ +} // namespace MIDI #endif // __fifomidi_h__ diff --git a/libs/midi++2/midi++/manager.h b/libs/midi++2/midi++/manager.h index 4889aad8c9..1bf8dc7cbd 100644 --- a/libs/midi++2/midi++/manager.h +++ b/libs/midi++2/midi++/manager.h @@ -83,6 +83,6 @@ class Manager { void close_ports (); }; -}; /* namespace MIDI */ +} // namespace MIDI #endif // __midi_manager_h__ diff --git a/libs/midi++2/midi++/mmc.h b/libs/midi++2/midi++/mmc.h index 7b51b33a72..2d569f122c 100644 --- a/libs/midi++2/midi++/mmc.h +++ b/libs/midi++2/midi++/mmc.h @@ -82,7 +82,7 @@ class MachineControl : public sigc::trackable cmdRecordStrobeVariable = 0x55, cmdWait = 0x7C, - cmdResume = 0x7F, + cmdResume = 0x7F }; MachineControl (Port &port, @@ -256,6 +256,6 @@ class MachineControl : public sigc::trackable void write_track_record_ready (byte *, size_t len); }; -}; /* namespace MIDI */ +} // namespace MIDI #endif /* __midipp_mmc_h_h__ */ diff --git a/libs/midi++2/midi++/nullmidi.h b/libs/midi++2/midi++/nullmidi.h index a94b1015b0..a74e5e3d9b 100644 --- a/libs/midi++2/midi++/nullmidi.h +++ b/libs/midi++2/midi++/nullmidi.h @@ -57,6 +57,6 @@ class Null_MidiPort : public Port virtual int selectable() const { return -1; } }; -}; /* namespace MIDI */ +} // namespace MIDI #endif // __nullmidi_h__ diff --git a/libs/midi++2/midi++/parser.h b/libs/midi++2/midi++/parser.h index 4ac07cc15d..36d19f3da9 100644 --- a/libs/midi++2/midi++/parser.h +++ b/libs/midi++2/midi++/parser.h @@ -183,7 +183,7 @@ class Parser : public sigc::trackable { void process_mtc_quarter_frame (byte *msg); }; -}; /* namespace MIDI */ +} // namespace MIDI #endif // __midi_parse_h__ diff --git a/libs/midi++2/midi++/port.h b/libs/midi++2/midi++/port.h index a186f1fd5f..4a5319b120 100644 --- a/libs/midi++2/midi++/port.h +++ b/libs/midi++2/midi++/port.h @@ -40,7 +40,7 @@ class Port : public sigc::trackable { ALSA_Sequencer, CoreMidi_MidiPort, Null, - FIFO, + FIFO }; @@ -140,7 +140,6 @@ class Port : public sigc::trackable { static size_t nports; }; -}; /* namespace MIDI */ +} // namespace MIDI #endif // __libmidi_port_h__ - diff --git a/libs/midi++2/midi++/port_request.h b/libs/midi++2/midi++/port_request.h index 28a0d1d70b..86838dd04d 100644 --- a/libs/midi++2/midi++/port_request.h +++ b/libs/midi++2/midi++/port_request.h @@ -54,7 +54,7 @@ struct PortRequest { const std::string &xtype); }; -}; /* namespace MIDI */ +} // namespace MIDI #endif // __midi_port_request_h__ diff --git a/libs/midi++2/midi++/types.h b/libs/midi++2/midi++/types.h index b9d9bf33e7..218416d213 100644 --- a/libs/midi++2/midi++/types.h +++ b/libs/midi++2/midi++/types.h @@ -57,10 +57,10 @@ namespace MIDI { enum MTC_Status { MTC_Stopped = 0, MTC_Forward, - MTC_Backward, + MTC_Backward }; -}; /* namespace MIDI */ +} // namespace MIDI #endif // __midi_types_h__ diff --git a/libs/midi++2/midiparser.cc b/libs/midi++2/midiparser.cc index 04ac2728f1..424bfa04f8 100644 --- a/libs/midi++2/midiparser.cc +++ b/libs/midi++2/midiparser.cc @@ -101,7 +101,7 @@ Parser::midi_event_type_name (eventType t) default: return "unknow MIDI event type"; } -}; +} Parser::Parser (Port &p) : _port (p) diff --git a/libs/pbd3/.cvsignore b/libs/pbd/.cvsignore index e9a15e81e9..e9a15e81e9 100644 --- a/libs/pbd3/.cvsignore +++ b/libs/pbd/.cvsignore diff --git a/libs/pbd3/AUTHORS b/libs/pbd/AUTHORS index e69de29bb2..e69de29bb2 100644 --- a/libs/pbd3/AUTHORS +++ b/libs/pbd/AUTHORS diff --git a/libs/pbd3/COPYING b/libs/pbd/COPYING index d60c31a97a..d60c31a97a 100644 --- a/libs/pbd3/COPYING +++ b/libs/pbd/COPYING diff --git a/libs/pbd3/ChangeLog b/libs/pbd/ChangeLog index 59e92915ba..59e92915ba 100644 --- a/libs/pbd3/ChangeLog +++ b/libs/pbd/ChangeLog diff --git a/libs/pbd3/NEWS b/libs/pbd/NEWS index e69de29bb2..e69de29bb2 100644 --- a/libs/pbd3/NEWS +++ b/libs/pbd/NEWS diff --git a/libs/pbd3/README b/libs/pbd/README index e69de29bb2..e69de29bb2 100644 --- a/libs/pbd3/README +++ b/libs/pbd/README diff --git a/libs/pbd/SConscript b/libs/pbd/SConscript new file mode 100644 index 0000000000..4b15dd70d1 --- /dev/null +++ b/libs/pbd/SConscript @@ -0,0 +1,75 @@ +# -*- python -*- + +import os +import os.path +import glob + +Import('env libraries i18n install_prefix') + +pbd = env.Copy() + +domain = 'libpbd' + +pbd.Append(DOMAIN=domain,MAJOR=4,MINOR=1,MICRO=0) +pbd.Append(CXXFLAGS="-DPACKAGE=\\\"" + domain + "\\\"") +pbd.Append(CXXFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE") +pbd.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED") +pbd.Append(PACKAGE=domain) +pbd.Append(POTFILE=domain + '.pot') + +pbd_files = Split(""" +basename.cc +base_ui.cc +convert.cc +command.cc +controllable.cc +dmalloc.cc +error.cc +id.cc +mountpoint.cc +path.cc +pathscanner.cc +pool.cc +pthread_utils.cc +receiver.cc +stacktrace.cc +stateful.cc +strsplit.cc +textreceiver.cc +transmitter.cc +undo.cc +version.cc +whitespace.cc +xml++.cc +""") + +conf = Configure(pbd) +if conf.CheckFunc('getmntent'): + conf.env.Append(CCFLAGS="-DHAVE_GETMNTENT") +if conf.CheckCHeader('execinfo.h'): + conf.env.Append(CXXFLAGS="-DHAVE_EXECINFO") +pbd = conf.Finish() + +pbd.Merge ([ libraries['sigc2'], + libraries['xml'], + libraries['glibmm2'], + libraries['glib2'] ]) + +pbd.VersionBuild(['version.cc','pbd/version.h'], 'SConscript') + +libpbd = pbd.SharedLibrary('pbd', pbd_files) +Default(libpbd) + +mount_env = Environment(CCFLAGS='-DTEST_MOUNTPOINT -Ilibs/pbd') +mount_env.Program('mountpoint', 'mountpoint.cc') + +if env['NLS']: + i18n (pbd, pbd_files, env) + +env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libpbd)) + +env.Alias('tarball', env.Distribute (env['DISTTREE'], + [ 'SConscript', 'i18n.h', 'gettext.h', 'pbd/abstract_ui.cc' ] + + pbd_files + + glob.glob('po/*.po') + + glob.glob('pbd/*.h'))) diff --git a/libs/pbd3/base_ui.cc b/libs/pbd/base_ui.cc index d3c8d5e4c7..d3c8d5e4c7 100644 --- a/libs/pbd3/base_ui.cc +++ b/libs/pbd/base_ui.cc diff --git a/libs/pbd3/basename.cc b/libs/pbd/basename.cc index a51e393b78..a51e393b78 100644 --- a/libs/pbd3/basename.cc +++ b/libs/pbd/basename.cc diff --git a/libs/pbd3/command.cc b/libs/pbd/command.cc index 3f5aca8e51..3f5aca8e51 100644 --- a/libs/pbd3/command.cc +++ b/libs/pbd/command.cc diff --git a/libs/pbd/controllable.cc b/libs/pbd/controllable.cc new file mode 100644 index 0000000000..b1176c64a5 --- /dev/null +++ b/libs/pbd/controllable.cc @@ -0,0 +1,26 @@ +#include <pbd/controllable.h> +#include <pbd/xml++.h> + +#include "i18n.h" + +using namespace PBD; + +sigc::signal<void,Controllable*> Controllable::Created; +sigc::signal<void,Controllable*> Controllable::GoingAway; +sigc::signal<bool,Controllable*> Controllable::StartLearning; +sigc::signal<void,Controllable*> Controllable::StopLearning; + +Controllable::Controllable () +{ + Created (this); +} + +XMLNode& +Controllable::get_state () +{ + XMLNode* node = new XMLNode (X_("Controllable")); + char buf[64]; + _id.print (buf); + node->add_property (X_("id"), buf); + return *node; +} diff --git a/libs/pbd3/convert.cc b/libs/pbd/convert.cc index 60d39c91e2..60d39c91e2 100644 --- a/libs/pbd3/convert.cc +++ b/libs/pbd/convert.cc diff --git a/libs/pbd3/dmalloc.cc b/libs/pbd/dmalloc.cc index 0e730946c8..0e730946c8 100644 --- a/libs/pbd3/dmalloc.cc +++ b/libs/pbd/dmalloc.cc diff --git a/libs/pbd3/error.cc b/libs/pbd/error.cc index a6f8fb7f8f..a6f8fb7f8f 100644 --- a/libs/pbd3/error.cc +++ b/libs/pbd/error.cc diff --git a/libs/pbd3/gettext.h b/libs/pbd/gettext.h index 339c74ffe7..339c74ffe7 100644 --- a/libs/pbd3/gettext.h +++ b/libs/pbd/gettext.h diff --git a/libs/pbd3/i18n.h b/libs/pbd/i18n.h index 7c79d2eb53..7c79d2eb53 100644 --- a/libs/pbd3/i18n.h +++ b/libs/pbd/i18n.h diff --git a/libs/pbd/id.cc b/libs/pbd/id.cc new file mode 100644 index 0000000000..f9afa72c98 --- /dev/null +++ b/libs/pbd/id.cc @@ -0,0 +1,63 @@ +#include <ostream> +#include <iostream> +#include <stdio.h> + +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif +#include <inttypes.h> + +#include <pbd/id.h> + +using namespace std; +using namespace PBD; + +Glib::Mutex* ID::counter_lock = 0; +uint64_t ID::_counter = 0; + +void +ID::init () +{ + counter_lock = new Glib::Mutex; +} + +ID::ID () +{ + Glib::Mutex::Lock lm (*counter_lock); + id = _counter++; +} + +ID::ID (string str) +{ + string_assign (str); +} + +int +ID::string_assign (string str) +{ + return sscanf (str.c_str(), "%" PRIu64, &id) != 0; +} + +void +ID::print (char* buf) const +{ + /* XXX sizeof buf is unknown. bad API design */ + snprintf (buf, 16, "%" PRIu64, id); +} + +ID& +ID::operator= (string str) +{ + string_assign (str); + return *this; +} + +ostream& +operator<< (ostream& ostr, const ID& id) +{ + char buf[32]; + id.print (buf); + ostr << buf; + return ostr; +} + diff --git a/libs/pbd3/libpbd.pc.in b/libs/pbd/libpbd.pc.in index 14d0208845..14d0208845 100644 --- a/libs/pbd3/libpbd.pc.in +++ b/libs/pbd/libpbd.pc.in diff --git a/libs/pbd3/libpbd.spec.in b/libs/pbd/libpbd.spec.in index d50622d638..d50622d638 100644 --- a/libs/pbd3/libpbd.spec.in +++ b/libs/pbd/libpbd.spec.in diff --git a/libs/pbd3/mountpoint.cc b/libs/pbd/mountpoint.cc index 160f5e921c..c1bcb375f3 100644 --- a/libs/pbd3/mountpoint.cc +++ b/libs/pbd/mountpoint.cc @@ -88,7 +88,7 @@ mountpoint (string path) return best; } -#else // no getmntent() +#else // !HAVE_GETMNTENT #include <sys/param.h> #include <sys/ucred.h> @@ -97,10 +97,55 @@ mountpoint (string path) string mountpoint (string path) { -//XXX IMPLEMENT ME using getmntinfo() or getfsstat(). - return "/"; + struct statfs *mntbufp = 0; + int count; + unsigned int maxmatch = 0; + unsigned int matchlen; + const char *cpath = path.c_str(); + char best[PATH_MAX+1]; + + if ((count = getmntinfo(&mntbufp, MNT_NOWAIT)) == 0) { + free(mntbufp); + return "\0"; + } + + best[0] = '\0'; + + for (int i = 0; i < count; ++i) { + unsigned int n = 0; + matchlen = 0; + + /* note: strcmp's semantics are not + strict enough to use for this. + */ + + while (cpath[n] && mntbufp[i].f_mntonname[n]) { + if (cpath[n] != mntbufp[i].f_mntonname[n]) { + break; + } + matchlen++; + n++; + } + + if (cpath[matchlen] == '\0') { + snprintf(best, sizeof(best), "%s", mntbufp[i].f_mntonname); + free(mntbufp); + return best; + + } else { + + if (matchlen > maxmatch) { + snprintf (best, sizeof(best), "%s", mntbufp[i].f_mntonname); + maxmatch = matchlen; + } + } + } + + free(mntbufp); + + return best; } -#endif +#endif // HAVE_GETMNTENT #ifdef TEST_MOUNTPOINT @@ -110,4 +155,4 @@ main (int argc, char *argv[]) exit (0); } -#endif +#endif // TEST_MOUNTPOINT diff --git a/libs/pbd/path.cc b/libs/pbd/path.cc new file mode 100644 index 0000000000..80f916c9ae --- /dev/null +++ b/libs/pbd/path.cc @@ -0,0 +1,164 @@ +/* + Copyright (C) 2006 Paul Davis + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <cerrno> + +#include <glib.h> +#include <glib/gstdio.h> + +#include <glibmm/miscutils.h> +#include <glibmm/fileutils.h> + +#include <pbd/path.h> +#include <pbd/tokenizer.h> + +namespace PBD { + +Path::Path () +{ + +} + +Path::Path (const string& path) +{ + vector<string> tmp; + + if(!tokenize ( path, string(":;"), std::back_inserter (tmp))) { + g_warning ("%s : %s\n", G_STRLOC, G_STRFUNC); + return; + } + + add_readable_directories (tmp); +} + +Path::Path (const vector<string>& paths) +{ + add_readable_directories (paths); +} + +Path::Path (const Path& other) + : m_dirs(other.m_dirs) +{ + +} + +bool +Path::readable_directory (const string& directory_path) +{ + if (g_access (directory_path.c_str(), R_OK) == 0) { + if (Glib::file_test(directory_path, Glib::FILE_TEST_IS_DIR)) { + return true; + } else { + g_warning (" %s : Path exists but is not a directory\n", G_STRLOC); + } + } else { + g_warning ("%s : %s : %s\n", G_STRLOC, directory_path.c_str(), g_strerror(errno)); + } + return false; +} + +void +Path::add_readable_directory (const string& directory_path) +{ + if(readable_directory(directory_path)) { + m_dirs.push_back(directory_path); + } +} + +void +Path::add_readable_directories (const vector<string>& paths) +{ + for(vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) { + add_readable_directory (*i); + } +} + +const string +Path::path_string() const +{ + string path; + + for (vector<string>::const_iterator i = m_dirs.begin(); i != m_dirs.end(); ++i) { + path += (*i); + path += G_SEARCHPATH_SEPARATOR; + } + + g_message ("%s : %s", G_STRLOC, path.c_str()); + + return path.substr (0, path.length() - 1); // drop final colon +} + +const Path& +Path::operator= (const Path& path) +{ + m_dirs = path.m_dirs; + return *this; +} + +const Path& +Path::operator+= (const string& directory_path) +{ + add_readable_directory (directory_path); + return *this; +} + +const Path +operator+ (const Path& lhs_path, const Path& rhs_path) +{ + Path tmp_path(lhs_path); // does this do what I think it does. + // concatenate paths into new Path + tmp_path.m_dirs.insert(tmp_path.m_dirs.end(), rhs_path.m_dirs.begin(), rhs_path.m_dirs.end()); + return tmp_path; +} + +Path& +Path::add_subdirectory_to_path (const string& subdir) +{ + vector<string> tmp; + string directory_path; + + for (vector<string>::iterator i = m_dirs.begin(); i != m_dirs.end(); ++i) { + directory_path = Glib::build_filename (*i, subdir); + if(readable_directory(directory_path)) { + tmp.push_back(directory_path); + } + } + m_dirs = tmp; + return *this; +} + +bool +find_file_in_path (const Path& path, const string& filename, string& resulting_path) +{ + for (vector<string>::const_iterator i = path.dirs().begin(); i != path.dirs().end(); ++i) { + resulting_path = Glib::build_filename ((*i), filename); + if (g_access (resulting_path.c_str(), R_OK) == 0) { + g_message ("File %s found in Path : %s\n", resulting_path.c_str(), + path.path_string().c_str()); + return true; + } + } + + g_warning ("%s : Could not locate file %s in path %s\n", G_STRLOC, filename.c_str(), + path.path_string().c_str()); + + return false; +} + +} // namespace PBD + diff --git a/libs/pbd3/pathscanner.cc b/libs/pbd/pathscanner.cc index 2af227a3a0..2af227a3a0 100644 --- a/libs/pbd3/pathscanner.cc +++ b/libs/pbd/pathscanner.cc diff --git a/libs/pbd3/pbd/.DS_Store b/libs/pbd/pbd/.DS_Store Binary files differindex 5008ddfcf5..5008ddfcf5 100644 --- a/libs/pbd3/pbd/.DS_Store +++ b/libs/pbd/pbd/.DS_Store diff --git a/libs/pbd3/pbd/.cvsignore b/libs/pbd/pbd/.cvsignore index 67020331ba..67020331ba 100644 --- a/libs/pbd3/pbd/.cvsignore +++ b/libs/pbd/pbd/.cvsignore diff --git a/libs/pbd3/pbd/abstract_ui.cc b/libs/pbd/pbd/abstract_ui.cc index 0e34787a2d..0e34787a2d 100644 --- a/libs/pbd3/pbd/abstract_ui.cc +++ b/libs/pbd/pbd/abstract_ui.cc diff --git a/libs/pbd3/pbd/abstract_ui.h b/libs/pbd/pbd/abstract_ui.h index f80db7bf1a..f80db7bf1a 100644 --- a/libs/pbd3/pbd/abstract_ui.h +++ b/libs/pbd/pbd/abstract_ui.h diff --git a/libs/pbd3/pbd/base_ui.h b/libs/pbd/pbd/base_ui.h index b4570f8707..b4570f8707 100644 --- a/libs/pbd3/pbd/base_ui.h +++ b/libs/pbd/pbd/base_ui.h diff --git a/libs/pbd3/pbd/basename.h b/libs/pbd/pbd/basename.h index 35aebe166c..a7e36acff0 100644 --- a/libs/pbd3/pbd/basename.h +++ b/libs/pbd/pbd/basename.h @@ -8,6 +8,6 @@ namespace PBD extern std::string basename_nosuffix (const std::string&); -}; +} // namespace PBD #endif // __stupid_basename_h__ diff --git a/libs/pbd3/pbd/command.h b/libs/pbd/pbd/command.h index 35ae011530..35ae011530 100644 --- a/libs/pbd3/pbd/command.h +++ b/libs/pbd/pbd/command.h diff --git a/libs/pbd3/pbd/compose.h b/libs/pbd/pbd/compose.h index 0df9519aaf..0df9519aaf 100644 --- a/libs/pbd3/pbd/compose.h +++ b/libs/pbd/pbd/compose.h diff --git a/libs/pbd/pbd/controllable.h b/libs/pbd/pbd/controllable.h new file mode 100644 index 0000000000..c46e477b6e --- /dev/null +++ b/libs/pbd/pbd/controllable.h @@ -0,0 +1,46 @@ +#ifndef __pbd_controllable_h__ +#define __pbd_controllable_h__ + +#include <sigc++/trackable.h> +#include <sigc++/signal.h> + +#include <pbd/stateful.h> +#include <pbd/id.h> + +class XMLNode; + +namespace PBD { + +class Controllable : public virtual sigc::trackable, public Stateful { + public: + Controllable (); + virtual ~Controllable() { GoingAway (this); } + + virtual void set_value (float) = 0; + virtual float get_value (void) const = 0; + + virtual bool can_send_feedback() const { return true; } + + sigc::signal<void> LearningFinished; + + static sigc::signal<void,Controllable*> Created; + static sigc::signal<void,Controllable*> GoingAway; + + + static sigc::signal<bool,PBD::Controllable*> StartLearning; + static sigc::signal<void,PBD::Controllable*> StopLearning; + + sigc::signal<void> Changed; + + const PBD::ID& id() const { return _id; } + + int set_state (const XMLNode&) { return 0; } + XMLNode& get_state (); + + private: + PBD::ID _id; +}; + +} + +#endif /* __pbd_controllable_h__ */ diff --git a/libs/pbd3/pbd/convert.h b/libs/pbd/pbd/convert.h index 12e63ba6fc..12e63ba6fc 100644 --- a/libs/pbd3/pbd/convert.h +++ b/libs/pbd/pbd/convert.h diff --git a/libs/pbd3/pbd/error.h b/libs/pbd/pbd/error.h index 4136f02ee2..4136f02ee2 100644 --- a/libs/pbd3/pbd/error.h +++ b/libs/pbd/pbd/error.h diff --git a/libs/pbd3/pbd/failed_constructor.h b/libs/pbd/pbd/failed_constructor.h index 62eb6c0d71..62eb6c0d71 100644 --- a/libs/pbd3/pbd/failed_constructor.h +++ b/libs/pbd/pbd/failed_constructor.h diff --git a/libs/pbd3/pbd/fastlog.h b/libs/pbd/pbd/fastlog.h index 4269705a44..4269705a44 100644 --- a/libs/pbd3/pbd/fastlog.h +++ b/libs/pbd/pbd/fastlog.h diff --git a/libs/pbd3/pbd/forkexec.h b/libs/pbd/pbd/forkexec.h index 2af3711390..2af3711390 100644 --- a/libs/pbd3/pbd/forkexec.h +++ b/libs/pbd/pbd/forkexec.h diff --git a/libs/pbd/pbd/id.h b/libs/pbd/pbd/id.h new file mode 100644 index 0000000000..9a3f10478d --- /dev/null +++ b/libs/pbd/pbd/id.h @@ -0,0 +1,47 @@ +#ifndef __pbd_id_h__ +#define __pbd_id_h__ + +#include <stdint.h> +#include <string> + +#include <glibmm/thread.h> + +namespace PBD { + +class ID { + public: + ID (); + ID (std::string); + + bool operator== (const ID& other) const { + return id == other.id; + } + + bool operator!= (const ID& other) const { + return id != other.id; + } + + ID& operator= (std::string); + + bool operator< (const ID& other) const { + return id < other.id; + } + + void print (char* buf) const; + + static uint64_t counter() { return _counter; } + static void init_counter (uint64_t val) { _counter = val; } + static void init (); + + private: + uint64_t id; + int string_assign (std::string); + + static Glib::Mutex* counter_lock; + static uint64_t _counter; +}; + +} +std::ostream& operator<< (std::ostream& ostr, const PBD::ID&); + +#endif /* __pbd_id_h__ */ diff --git a/libs/pbd3/pbd/mathfix.h b/libs/pbd/pbd/mathfix.h index f0dc7e491e..f0dc7e491e 100644 --- a/libs/pbd3/pbd/mathfix.h +++ b/libs/pbd/pbd/mathfix.h diff --git a/libs/pbd3/pbd/memento_command.h b/libs/pbd/pbd/memento_command.h index c8bfe5de4c..c8bfe5de4c 100644 --- a/libs/pbd3/pbd/memento_command.h +++ b/libs/pbd/pbd/memento_command.h diff --git a/libs/pbd3/pbd/mountpoint.h b/libs/pbd/pbd/mountpoint.h index 86ccc58190..86ccc58190 100644 --- a/libs/pbd3/pbd/mountpoint.h +++ b/libs/pbd/pbd/mountpoint.h diff --git a/libs/pbd/pbd/path.h b/libs/pbd/pbd/path.h new file mode 100644 index 0000000000..0b77a7c237 --- /dev/null +++ b/libs/pbd/pbd/path.h @@ -0,0 +1,113 @@ +/* + Copyright (C) 2006 Paul Davis + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef PBD_PATH +#define PBD_PATH + +#include <string> +#include <vector> + +namespace PBD { + +using std::string; +using std::vector; + +/** + The Path class is a helper class for getting a vector of absolute + paths contained in a path string where a path string contains + absolute directory paths separated by a colon(:) or a semi-colon(;) + on windows. + */ +class Path { +public: + + /** + Create an empty Path. + */ + Path (); + + /** + Initialize Path from a string, each absolute path contained + in the "path" will be accessed to ensure it exists and is + readable. + \param path A path string. + */ + Path (const string& path); + + /** + Initialize Path from a vector of path strings, each absolute + path contained in paths will be accessed to ensure it + exists and is readable. + \param path A path string. + */ + Path (const vector<string>& paths); + + Path(const Path& path); + + /** + Indicate whether there are any directories in m_dirs, if Path is + initialized with an empty string as the result of for instance + calling Glib::getenv where the environment variable doesn't + exist or if none of the directories in the path string are + accessible then false is returned. + + \return true if there are any paths in m_paths. + */ + //operator bool () const { return !m_dirs.empty(); } + + /** + \return vector containing the absolute paths to the directories + contained + */ + operator const vector<string>& () const { return m_dirs; } + + /** + \return vector containing the absolute paths to the directories + contained + */ + const vector<string>& dirs () const { return m_dirs; } + + const string path_string() const; + + const Path& operator= (const Path& path); + + const Path& operator+= (const string& directory_path); + + Path& add_subdirectory_to_path (const string& subdirectory); + +protected: + + friend const Path operator+ (const Path&, const Path&); + + bool readable_directory (const string& directory_path); + + void add_readable_directory (const string& directory_path); + + void add_readable_directories (const vector<string>& paths); + + vector<string> m_dirs; + +}; + +bool find_file_in_path (const Path& path, const string& filename, string& resulting_path_to_file); + +} // namespace PBD + +#endif // PBD_PATH + + diff --git a/libs/pbd3/pbd/pathscanner.h b/libs/pbd/pbd/pathscanner.h index 346e7858c4..346e7858c4 100644 --- a/libs/pbd3/pbd/pathscanner.h +++ b/libs/pbd/pbd/pathscanner.h diff --git a/libs/pbd3/pbd/pool.h b/libs/pbd/pbd/pool.h index f8e19e72fb..f8e19e72fb 100644 --- a/libs/pbd3/pbd/pool.h +++ b/libs/pbd/pbd/pool.h diff --git a/libs/pbd3/pbd/pthread_utils.h b/libs/pbd/pbd/pthread_utils.h index 482b5b54cf..482b5b54cf 100644 --- a/libs/pbd3/pbd/pthread_utils.h +++ b/libs/pbd/pbd/pthread_utils.h diff --git a/libs/pbd/pbd/rcu.h b/libs/pbd/pbd/rcu.h new file mode 100644 index 0000000000..6d9586cb3c --- /dev/null +++ b/libs/pbd/pbd/rcu.h @@ -0,0 +1,120 @@ +#ifndef __pbd_rcu_h__ +#define __pbd_rcu_h__ + +#include "boost/shared_ptr.hpp" +#include "glibmm/thread.h" + +#include <list> + +template<class T> +class RCUManager +{ +public: + + RCUManager (T* new_rcu_value) + : m_rcu_value(new_rcu_value) + { + + } + + virtual ~RCUManager() { } + + boost::shared_ptr<T> reader () const { return m_rcu_value; } + + // should be private + virtual boost::shared_ptr<T> write_copy () = 0; + + // should be private + virtual void update (boost::shared_ptr<T> new_value) = 0; + +protected: + + boost::shared_ptr<T> m_rcu_value; + + +}; + + +template<class T> +class SerializedRCUManager : public RCUManager<T> +{ +public: + + SerializedRCUManager(T* new_rcu_value) + : RCUManager<T>(new_rcu_value) + { + + } + + virtual boost::shared_ptr<T> write_copy () + { + m_lock.lock(); + + // I hope this is doing what I think it is doing :) + boost::shared_ptr<T> new_copy(new T(*RCUManager<T>::m_rcu_value)); + + // XXX todo remove old copies with only 1 reference from the list. + + return new_copy; + } + + virtual void update (boost::shared_ptr<T> new_value) + { + // So a current reader doesn't hold the only reference to + // the existing value when we assign it a new value which + // should ensure that deletion of old values doesn't + // occur in a reader thread. + boost::shared_ptr<T> old_copy = RCUManager<T>::m_rcu_value; + + // we hold the lock at this point effectively blocking + // other writers. + RCUManager<T>::m_rcu_value = new_value; + + + // XXX add the old value to the list of old copies. + + m_lock.unlock(); + } + +private: + Glib::Mutex m_lock; + + std::list<boost::shared_ptr<T> > m_old_values; +}; + +template<class T> +class RCUWriter +{ +public: + + RCUWriter(RCUManager<T>& manager) + : m_manager(manager) + { + m_copy = m_manager.write_copy(); + } + + ~RCUWriter() + { + // we can check here that the refcount of m_copy is 1 + + if(m_copy.use_count() == 1) { + m_manager.update(m_copy); + } else { + + // critical error. + } + + } + + // or operator boost::shared_ptr<T> (); + boost::shared_ptr<T> get_copy() { return m_copy; } + +private: + + RCUManager<T>& m_manager; + + // preferably this holds a pointer to T + boost::shared_ptr<T> m_copy; +}; + +#endif /* __pbd_rcu_h__ */ diff --git a/libs/pbd3/pbd/receiver.h b/libs/pbd/pbd/receiver.h index 5ce238df63..5ce238df63 100644 --- a/libs/pbd3/pbd/receiver.h +++ b/libs/pbd/pbd/receiver.h diff --git a/libs/pbd3/pbd/restartable_rw.h b/libs/pbd/pbd/restartable_rw.h index ee84e4e295..ee84e4e295 100644 --- a/libs/pbd3/pbd/restartable_rw.h +++ b/libs/pbd/pbd/restartable_rw.h diff --git a/libs/pbd3/pbd/ringbuffer.h b/libs/pbd/pbd/ringbuffer.h index 1d9c9b04e3..1d9c9b04e3 100644 --- a/libs/pbd3/pbd/ringbuffer.h +++ b/libs/pbd/pbd/ringbuffer.h diff --git a/libs/pbd3/pbd/ringbufferNPT.h b/libs/pbd/pbd/ringbufferNPT.h index fee2efce3d..fee2efce3d 100644 --- a/libs/pbd3/pbd/ringbufferNPT.h +++ b/libs/pbd/pbd/ringbufferNPT.h diff --git a/libs/pbd3/pbd/selectable.h b/libs/pbd/pbd/selectable.h index 470bc3cfcc..470bc3cfcc 100644 --- a/libs/pbd3/pbd/selectable.h +++ b/libs/pbd/pbd/selectable.h diff --git a/libs/pbd3/pbd/serializable.h b/libs/pbd/pbd/serializable.h index f6ac4e92fb..f6ac4e92fb 100644 --- a/libs/pbd3/pbd/serializable.h +++ b/libs/pbd/pbd/serializable.h diff --git a/libs/pbd3/pbd/stacktrace.h b/libs/pbd/pbd/stacktrace.h index d7278bd35a..d7278bd35a 100644 --- a/libs/pbd3/pbd/stacktrace.h +++ b/libs/pbd/pbd/stacktrace.h diff --git a/libs/ardour/ardour/stateful.h b/libs/pbd/pbd/stateful.h index 4f4cb20b39..3038f16b4f 100644 --- a/libs/ardour/ardour/stateful.h +++ b/libs/pbd/pbd/stateful.h @@ -15,11 +15,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ + $Id: stateful.h 17 2005-09-24 19:13:41Z taybin $ */ -#ifndef __ardour_stateful_h__ -#define __ardour_stateful_h__ +#ifndef __pbd_stateful_h__ +#define __pbd_stateful_h__ #include <string> @@ -47,5 +47,5 @@ class Stateful { XMLNode *_instant_xml; }; -#endif /* __ardour_stateful_h__ */ +#endif /* __pbd_stateful_h__ */ diff --git a/libs/pbd3/pbd/stl_delete.h b/libs/pbd/pbd/stl_delete.h index 6e5bfa0734..6e5bfa0734 100644 --- a/libs/pbd3/pbd/stl_delete.h +++ b/libs/pbd/pbd/stl_delete.h diff --git a/libs/pbd3/pbd/stl_functors.h b/libs/pbd/pbd/stl_functors.h index 4a96e91a28..4a96e91a28 100644 --- a/libs/pbd3/pbd/stl_functors.h +++ b/libs/pbd/pbd/stl_functors.h diff --git a/libs/pbd3/pbd/strsplit.h b/libs/pbd/pbd/strsplit.h index e55ad1c825..e55ad1c825 100644 --- a/libs/pbd3/pbd/strsplit.h +++ b/libs/pbd/pbd/strsplit.h diff --git a/libs/pbd3/pbd/textreceiver.h b/libs/pbd/pbd/textreceiver.h index b8bfe5bc78..b8bfe5bc78 100644 --- a/libs/pbd3/pbd/textreceiver.h +++ b/libs/pbd/pbd/textreceiver.h diff --git a/libs/pbd3/pbd/thrown_error.h b/libs/pbd/pbd/thrown_error.h index 83cf8acfac..83cf8acfac 100644 --- a/libs/pbd3/pbd/thrown_error.h +++ b/libs/pbd/pbd/thrown_error.h diff --git a/libs/pbd/pbd/tokenizer.h b/libs/pbd/pbd/tokenizer.h new file mode 100644 index 0000000000..a976b79341 --- /dev/null +++ b/libs/pbd/pbd/tokenizer.h @@ -0,0 +1,49 @@ +#ifndef PBD_TOKENIZER +#define PBD_TOKENIZER + +#include <iterator> +#include <string> + +namespace PBD { + +/** + Tokenize string, this should work for standard + strings aswell as Glib::ustring. This is a bit of a hack, + there are much better string tokenizing patterns out there. +*/ +template<typename StringType, typename Iter> +unsigned int +tokenize(const StringType& str, + const StringType& delims, + Iter it) +{ + typename StringType::size_type start_pos = 0; + typename StringType::size_type end_pos = 0; + unsigned int token_count = 0; + + do { + start_pos = str.find_first_not_of(delims, start_pos); + end_pos = str.find_first_of(delims, start_pos); + if (start_pos != end_pos) { + if (end_pos == str.npos) { + end_pos = str.length(); + } + *it++ = str.substr(start_pos, end_pos - start_pos); + ++token_count; + start_pos = str.find_first_not_of(delims, end_pos + 1); + } + } while (start_pos != str.npos); + + if (start_pos != str.npos) { + *it++ = str.substr(start_pos, str.length() - start_pos); + ++token_count; + } + + return token_count; +} + +} // namespace PBD + +#endif // PBD_TOKENIZER + + diff --git a/libs/pbd3/pbd/touchable.h b/libs/pbd/pbd/touchable.h index 0298574dfa..0298574dfa 100644 --- a/libs/pbd3/pbd/touchable.h +++ b/libs/pbd/pbd/touchable.h diff --git a/libs/pbd3/pbd/transmitter.h b/libs/pbd/pbd/transmitter.h index 357cb9965f..357cb9965f 100644 --- a/libs/pbd3/pbd/transmitter.h +++ b/libs/pbd/pbd/transmitter.h diff --git a/libs/pbd3/pbd/undo.h b/libs/pbd/pbd/undo.h index 33577ed4d7..33577ed4d7 100644 --- a/libs/pbd3/pbd/undo.h +++ b/libs/pbd/pbd/undo.h diff --git a/libs/pbd3/pbd/whitespace.h b/libs/pbd/pbd/whitespace.h index 6620a8fb50..6620a8fb50 100644 --- a/libs/pbd3/pbd/whitespace.h +++ b/libs/pbd/pbd/whitespace.h diff --git a/libs/pbd3/pbd/xml++.h b/libs/pbd/pbd/xml++.h index afb896e1d5..5dcb4f084a 100644 --- a/libs/pbd3/pbd/xml++.h +++ b/libs/pbd/pbd/xml++.h @@ -37,7 +37,6 @@ private: string _filename; XMLNode *_root; int _compression; - bool _initialized; public: XMLTree(); @@ -45,9 +44,8 @@ public: XMLTree(const XMLTree *); ~XMLTree(); - bool initialized() const { return _initialized; }; XMLNode *root() const { return _root; }; - XMLNode *set_root(XMLNode *n) { _initialized = true; return _root = n; }; + XMLNode *set_root(XMLNode *n) { return _root = n; }; const string & filename() const { return _filename; }; const string & set_filename(const string &fn) { return _filename = fn; }; @@ -69,7 +67,6 @@ public: class XMLNode { private: - bool _initialized; string _name; bool _is_content; string _content; @@ -83,18 +80,17 @@ public: XMLNode(const XMLNode&); ~XMLNode(); - bool initialized() const { return _initialized; }; const string name() const { return _name; }; bool is_content() const { return _is_content; }; const string & content() const { return _content; }; - const string & set_content(const string &); + const string & set_content (const string &); XMLNode *add_content(const string & = string()); - const XMLNodeList & children(const string & = string()) const; - XMLNode *add_child(const char *); - XMLNode *add_child_copy(const XMLNode&); - void add_child_nocopy (XMLNode&); + const XMLNodeList & children (const string & = string()) const; + XMLNode *add_child (const char *); + XMLNode *add_child_copy (const XMLNode&); + void add_child_nocopy (XMLNode&); const XMLPropertyList & properties() const { return _proplist; }; XMLProperty *property(const char * ); diff --git a/libs/pbd3/pool.cc b/libs/pbd/pool.cc index 089766482d..be8032b7b6 100644 --- a/libs/pbd3/pool.cc +++ b/libs/pbd/pool.cc @@ -70,7 +70,7 @@ Pool::alloc () } else { return ptr; } -}; +} void Pool::release (void *ptr) diff --git a/libs/pbd3/pthread_utils.cc b/libs/pbd/pthread_utils.cc index db242cea7b..db242cea7b 100644 --- a/libs/pbd3/pthread_utils.cc +++ b/libs/pbd/pthread_utils.cc diff --git a/libs/pbd3/receiver.cc b/libs/pbd/receiver.cc index 5e7c10de70..5e7c10de70 100644 --- a/libs/pbd3/receiver.cc +++ b/libs/pbd/receiver.cc diff --git a/libs/pbd3/stacktrace.cc b/libs/pbd/stacktrace.cc index 1e7dfa08e9..1e7dfa08e9 100644 --- a/libs/pbd3/stacktrace.cc +++ b/libs/pbd/stacktrace.cc diff --git a/libs/ardour/stateful.cc b/libs/pbd/stateful.cc index b8e301b273..786410e817 100644 --- a/libs/ardour/stateful.cc +++ b/libs/pbd/stateful.cc @@ -15,15 +15,14 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ + $Id: stateful.cc 629 2006-06-21 23:01:03Z paul $ */ -#include <cstdio> #include <unistd.h> -#include <ardour/stateful.h> -#include <ardour/utils.h> +#include <pbd/stateful.h> #include <pbd/xml++.h> +#include <pbd/error.h> #include "i18n.h" @@ -39,7 +38,10 @@ Stateful::~Stateful () { // Do not delete _extra_xml. The use of add_child_nocopy() // means it needs to live on indefinately. - delete _instant_xml; + + if (_instant_xml) { + delete _instant_xml; + } } void @@ -132,4 +134,3 @@ Stateful::instant_xml (const string& str, const string& dir) return 0; } - diff --git a/libs/pbd3/strsplit.cc b/libs/pbd/strsplit.cc index 7f29a77887..7f29a77887 100644 --- a/libs/pbd3/strsplit.cc +++ b/libs/pbd/strsplit.cc diff --git a/libs/pbd3/textreceiver.cc b/libs/pbd/textreceiver.cc index 43620e9830..43620e9830 100644 --- a/libs/pbd3/textreceiver.cc +++ b/libs/pbd/textreceiver.cc diff --git a/libs/pbd3/transmitter.cc b/libs/pbd/transmitter.cc index 876a9d86e5..876a9d86e5 100644 --- a/libs/pbd3/transmitter.cc +++ b/libs/pbd/transmitter.cc diff --git a/libs/pbd3/undo.cc b/libs/pbd/undo.cc index aa27f95789..aa27f95789 100644 --- a/libs/pbd3/undo.cc +++ b/libs/pbd/undo.cc diff --git a/libs/pbd/whitespace.cc b/libs/pbd/whitespace.cc new file mode 100644 index 0000000000..e35a8a8c0e --- /dev/null +++ b/libs/pbd/whitespace.cc @@ -0,0 +1,44 @@ +#include <pbd/whitespace.h> + +using namespace std; + +void +strip_whitespace_edges (string& str) +{ + string::size_type i; + string::size_type len; + string::size_type s; + + len = str.length(); + + /* strip front */ + + for (i = 0; i < len; ++i) { + if (isgraph (str[i])) { + break; + } + } + + /* strip back */ + + if (len > 1) { + + s = i; + i = len - 1; + + do { + if (isgraph (str[i]) || i == 0) { + break; + } + + --i; + + } while (true); + + str = str.substr (s, (i - s) + 1); + + } else { + str = str.substr (s); + } +} + diff --git a/libs/pbd/xml++.cc b/libs/pbd/xml++.cc new file mode 100644 index 0000000000..03fa116279 --- /dev/null +++ b/libs/pbd/xml++.cc @@ -0,0 +1,420 @@ +/* xml++.cc + * libxml++ and this file are copyright (C) 2000 by Ari Johnson, and + * are covered by the GNU Lesser General Public License, which should be + * included with libxml++ as the file COPYING. + */ + +#include <pbd/xml++.h> +#include <libxml/debugXML.h> + +static XMLNode *readnode(xmlNodePtr); +static void writenode(xmlDocPtr, XMLNode *, xmlNodePtr, int); + +XMLTree::XMLTree() + : _filename(), + _root(0), + _compression(0) +{ +} + +XMLTree::XMLTree(const string &fn) + : _filename(fn), + _root(0), + _compression(0) +{ + read(); +} + +XMLTree::XMLTree(const XMLTree * from) +{ + _filename = from->filename(); + _root = new XMLNode(*from->root()); + _compression = from->compression(); +} + +XMLTree::~XMLTree() +{ + if (_root) { + delete _root; + } +} + +int +XMLTree::set_compression(int c) +{ + if (c > 9) { + c = 9; + } else if (c < 0) { + c = 0; + } + + _compression = c; + + return _compression; +} + +bool +XMLTree::read(void) +{ + xmlDocPtr doc; + + if (_root) { + delete _root; + _root = 0; + } + + xmlKeepBlanksDefault(0); + + doc = xmlParseFile(_filename.c_str()); + if (!doc) { + return false; + } + + _root = readnode(xmlDocGetRootElement(doc)); + xmlFreeDoc(doc); + + return true; +} + +bool +XMLTree::read_buffer(const string & buffer) +{ + xmlDocPtr doc; + + _filename = ""; + + if (_root) { + delete _root; + _root = 0; + } + + doc = xmlParseMemory((char *) buffer.c_str(), buffer.length()); + if (!doc) { + return false; + } + + _root = readnode(xmlDocGetRootElement(doc)); + xmlFreeDoc(doc); + + return true; +} + +bool +XMLTree::write(void) const +{ + xmlDocPtr doc; + XMLNodeList children; + int result; + + xmlKeepBlanksDefault(0); + doc = xmlNewDoc((xmlChar *) "1.0"); + xmlSetDocCompressMode(doc, _compression); + writenode(doc, _root, doc->children, 1); + result = xmlSaveFormatFile(_filename.c_str(), doc, 1); + xmlFreeDoc(doc); + + if (result == -1) { + return false; + } + + return true; +} + +void +XMLTree::debug(FILE* out) const +{ + xmlDocPtr doc; + XMLNodeList children; + + xmlKeepBlanksDefault(0); + doc = xmlNewDoc((xmlChar *) "1.0"); + xmlSetDocCompressMode(doc, _compression); + writenode(doc, _root, doc->children, 1); + xmlDebugDumpDocument (out, doc); + xmlFreeDoc(doc); +} + +const string & +XMLTree::write_buffer(void) const +{ + static string retval; + char *ptr; + int len; + xmlDocPtr doc; + XMLNodeList children; + + xmlKeepBlanksDefault(0); + doc = xmlNewDoc((xmlChar *) "1.0"); + xmlSetDocCompressMode(doc, _compression); + writenode(doc, _root, doc->children, 1); + xmlDocDumpMemory(doc, (xmlChar **) & ptr, &len); + xmlFreeDoc(doc); + + retval = ptr; + + free(ptr); + + return retval; +} + +XMLNode::XMLNode(const string & n) + : _name(n), _is_content(false), _content(string()) +{ +} + +XMLNode::XMLNode(const string & n, const string & c) + :_name(n), _is_content(true), _content(c) +{ +} + +XMLNode::XMLNode(const XMLNode& from) +{ + XMLPropertyList props; + XMLPropertyIterator curprop; + XMLNodeList nodes; + XMLNodeIterator curnode; + + _name = from.name(); + set_content(from.content()); + + props = from.properties(); + for (curprop = props.begin(); curprop != props.end(); ++curprop) { + add_property((*curprop)->name().c_str(), (*curprop)->value()); + } + + nodes = from.children(); + for (curnode = nodes.begin(); curnode != nodes.end(); ++curnode) { + add_child_copy(**curnode); + } +} + +XMLNode::~XMLNode() +{ + XMLNodeIterator curchild; + XMLPropertyIterator curprop; + + for (curchild = _children.begin(); curchild != _children.end(); ++curchild) { + delete *curchild; + } + + for (curprop = _proplist.begin(); curprop != _proplist.end(); ++curprop) { + delete *curprop; + } +} + +const string & +XMLNode::set_content(const string & c) +{ + if (c.empty()) { + _is_content = false; + } else { + _is_content = true; + } + + _content = c; + + return _content; +} + +const XMLNodeList & +XMLNode::children(const string & n) const +{ + static XMLNodeList retval; + XMLNodeConstIterator cur; + + if (n.length() == 0) { + return _children; + } + + retval.erase(retval.begin(), retval.end()); + + for (cur = _children.begin(); cur != _children.end(); ++cur) { + if ((*cur)->name() == n) { + retval.insert(retval.end(), *cur); + } + } + + return retval; +} + +XMLNode * +XMLNode::add_child(const char * n) +{ + return add_child_copy(XMLNode (n)); +} + +void +XMLNode::add_child_nocopy (XMLNode& n) +{ + _children.insert(_children.end(), &n); +} + +XMLNode * +XMLNode::add_child_copy(const XMLNode& n) +{ + XMLNode *copy = new XMLNode (n); + _children.insert(_children.end(), copy); + return copy; +} + +XMLNode * +XMLNode::add_content(const string & c) +{ + return add_child_copy(XMLNode (string(), c)); +} + +XMLProperty * +XMLNode::property(const char * n) +{ + string ns(n); + if (_propmap.find(ns) == _propmap.end()) { + return 0; + } + + return _propmap[ns]; +} + +XMLProperty * +XMLNode::add_property(const char * n, const string & v) +{ + string ns(n); + if(_propmap.find(ns) != _propmap.end()){ + remove_property(ns); + } + + XMLProperty *tmp = new XMLProperty(ns, v); + + if (!tmp) { + return 0; + } + + _propmap[tmp->name()] = tmp; + _proplist.insert(_proplist.end(), tmp); + + return tmp; +} + +XMLProperty * +XMLNode::add_property(const char * n, const char * v) +{ + string vs(v); + return add_property(n, vs); +} + +void +XMLNode::remove_property(const string & n) +{ + if (_propmap.find(n) != _propmap.end()) { + _proplist.remove(_propmap[n]); + _propmap.erase(n); + } +} + +void +XMLNode::remove_nodes(const string & n) +{ + XMLNodeIterator i = _children.begin(); + XMLNodeIterator tmp; + + while (i != _children.end()) { + tmp = i; + ++tmp; + if ((*i)->name() == n) { + _children.erase (i); + } + i = tmp; + } +} + +void +XMLNode::remove_nodes_and_delete(const string & n) +{ + XMLNodeIterator i = _children.begin(); + XMLNodeIterator tmp; + + while (i != _children.end()) { + tmp = i; + ++tmp; + if ((*i)->name() == n) { + delete *i; + _children.erase (i); + } + i = tmp; + } +} + +XMLProperty::XMLProperty(const string &n, const string &v) + : _name(n), + _value(v) +{ +} + +XMLProperty::~XMLProperty() +{ +} + +static XMLNode * +readnode(xmlNodePtr node) +{ + string name, content; + xmlNodePtr child; + XMLNode *tmp; + xmlAttrPtr attr; + + if (node->name) { + name = (char *) node->name; + } + + tmp = new XMLNode(name); + + for (attr = node->properties; attr; attr = attr->next) { + content = ""; + if (attr->children) { + content = (char *) attr->children->content; + } + tmp->add_property((char *) attr->name, content); + } + + if (node->content) { + tmp->set_content((char *) node->content); + } else { + tmp->set_content(string()); + } + + for (child = node->children; child; child = child->next) { + tmp->add_child_nocopy (*readnode(child)); + } + + return tmp; +} + +static void +writenode(xmlDocPtr doc, XMLNode * n, xmlNodePtr p, int root = 0) +{ + XMLPropertyList props; + XMLPropertyIterator curprop; + XMLNodeList children; + XMLNodeIterator curchild; + xmlNodePtr node; + + if (root) { + node = doc->children = xmlNewDocNode(doc, 0, (xmlChar *) n->name().c_str(), 0); + } else { + node = xmlNewChild(p, 0, (xmlChar *) n->name().c_str(), 0); + } + + if (n->is_content()) { + node->type = XML_TEXT_NODE; + xmlNodeSetContentLen(node, (const xmlChar *) n->content().c_str(), n->content().length()); + } + + props = n->properties(); + for (curprop = props.begin(); curprop != props.end(); ++curprop) { + xmlSetProp(node, (xmlChar *) (*curprop)->name().c_str(), (xmlChar *) (*curprop)->value().c_str()); + } + + children = n->children(); + for (curchild = children.begin(); curchild != children.end(); ++curchild) { + writenode(doc, *curchild, node); + } +} diff --git a/libs/pbd3/SConscript b/libs/pbd3/SConscript deleted file mode 100644 index fedb3cded4..0000000000 --- a/libs/pbd3/SConscript +++ /dev/null @@ -1,66 +0,0 @@ -# -*- python -*- - -import os -import os.path -import glob - -Import('env libraries i18n install_prefix') - -pbd3 = env.Copy() - -domain = 'libpbd' - -pbd3.Append(DOMAIN=domain,MAJOR=4,MINOR=0,MICRO=0) -pbd3.Append(CXXFLAGS="-DPACKAGE=\\\"" + domain + "\\\"") -pbd3.Append(CXXFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE") -pbd3.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED") -pbd3.Append(PACKAGE=domain) -pbd3.Append(POTFILE=domain + '.pot') - -pbd3_files = Split(""" -basename.cc -base_ui.cc -convert.cc -command.cc -dmalloc.cc -error.cc -mountpoint.cc -pathscanner.cc -pool.cc -pthread_utils.cc -receiver.cc -stacktrace.cc -strsplit.cc -textreceiver.cc -transmitter.cc -undo.cc -version.cc -whitespace.cc -xml++.cc -""") - -conf = Configure(pbd3) -if conf.CheckFunc('getmntent'): - conf.env.Append(CCFLAGS="-DHAVE_GETMNTENT") -if conf.CheckCHeader('execinfo.h'): - conf.env.Append(CXXFLAGS="-DHAVE_EXECINFO") -pbd3 = conf.Finish() - -pbd3.Merge ([ libraries['sigc2'], libraries['xml'], libraries['glibmm2'], libraries['glib2'] ]) - -pbd3.VersionBuild(['version.cc','pbd/version.h'], 'SConscript') - -libpbd3 = pbd3.SharedLibrary('pbd', pbd3_files) - -Default(libpbd3) - -if env['NLS']: - i18n (pbd3, pbd3_files, env) - -env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libpbd3)) - -env.Alias('tarball', env.Distribute (env['DISTTREE'], - [ 'SConscript', 'i18n.h', 'gettext.h', 'pbd/abstract_ui.cc' ] + - pbd3_files + - glob.glob('po/*.po') + - glob.glob('pbd/*.h'))) diff --git a/libs/pbd3/whitespace.cc b/libs/pbd3/whitespace.cc deleted file mode 100644 index 7f74940457..0000000000 --- a/libs/pbd3/whitespace.cc +++ /dev/null @@ -1,30 +0,0 @@ -#include <pbd/whitespace.h> - -using namespace std; - -void -strip_whitespace_edges (string& str) -{ - string::size_type i; - string::size_type len; - string::size_type s; - - len = str.length(); - - for (i = 0; i < len; ++i) { - if (isgraph (str[i])) { - break; - } - } - - s = i; - - for (i = len - 1; i >= 0; --i) { - if (isgraph (str[i])) { - break; - } - } - - str = str.substr (s, (i - s) + 1); -} - diff --git a/libs/pbd3/xml++.cc b/libs/pbd3/xml++.cc deleted file mode 100644 index e496d8b2fd..0000000000 --- a/libs/pbd3/xml++.cc +++ /dev/null @@ -1,422 +0,0 @@ -/* xml++.cc - * libxml++ and this file are copyright (C) 2000 by Ari Johnson, and - * are covered by the GNU Lesser General Public License, which should be - * included with libxml++ as the file COPYING. - */ - -#include <pbd/xml++.h> -#include <libxml/debugXML.h> - -static XMLNode *readnode(xmlNodePtr); -static void writenode(xmlDocPtr, XMLNode *, xmlNodePtr, int); - -XMLTree::XMLTree() - : _filename(), - _root(), - _compression(0), - _initialized(false) -{ -} - -XMLTree::XMLTree(const string &fn) - : _filename(fn), - _root(0), - _compression(0), - _initialized(false) -{ - read(); -} - -XMLTree::XMLTree(const XMLTree * from) -{ - _filename = from->filename(); - _root = new XMLNode(*from->root()); - _compression = from->compression(); - _initialized = true; -} - -XMLTree::~XMLTree() -{ - if (_initialized && _root) - delete _root; -} - -int -XMLTree::set_compression(int c) -{ - if (c > 9) - c = 9; - - if (c < 0) - c = 0; - - _compression = c; - - return _compression; -} - -bool -XMLTree::read(void) -{ - xmlDocPtr doc; - - if (_root) { - delete _root; - _root = 0; - } - - xmlKeepBlanksDefault(0); - - doc = xmlParseFile(_filename.c_str()); - if (!doc) { - _initialized = false; - return false; - } - - _root = readnode(xmlDocGetRootElement(doc)); - xmlFreeDoc(doc); - _initialized = true; - - return true; -} - -bool -XMLTree::read_buffer(const string & buffer) -{ - xmlDocPtr doc; - - _filename = ""; - - if (_root) { - delete _root; - _root = 0; - } - - doc = xmlParseMemory((char *) buffer.c_str(), buffer.length()); - if (!doc) { - _initialized = false; - return false; - } - - _root = readnode(xmlDocGetRootElement(doc)); - xmlFreeDoc(doc); - _initialized = true; - - return true; -} - -bool -XMLTree::write(void) const -{ - xmlDocPtr doc; - XMLNodeList children; - int result; - - xmlKeepBlanksDefault(0); - doc = xmlNewDoc((xmlChar *) "1.0"); - xmlSetDocCompressMode(doc, _compression); - writenode(doc, _root, doc->children, 1); - result = xmlSaveFormatFile(_filename.c_str(), doc, 1); - xmlFreeDoc(doc); - - if (result == -1) - return false; - - return true; -} - -void -XMLTree::debug(FILE* out) const -{ - xmlDocPtr doc; - XMLNodeList children; - - xmlKeepBlanksDefault(0); - doc = xmlNewDoc((xmlChar *) "1.0"); - xmlSetDocCompressMode(doc, _compression); - writenode(doc, _root, doc->children, 1); - xmlDebugDumpDocument (out, doc); - xmlFreeDoc(doc); -} - -const string & -XMLTree::write_buffer(void) const -{ - static string retval; - char *ptr; - int len; - xmlDocPtr doc; - XMLNodeList children; - - xmlKeepBlanksDefault(0); - doc = xmlNewDoc((xmlChar *) "1.0"); - xmlSetDocCompressMode(doc, _compression); - writenode(doc, _root, doc->children, 1); - xmlDocDumpMemory(doc, (xmlChar **) & ptr, &len); - xmlFreeDoc(doc); - - retval = ptr; - - free(ptr); - - return retval; -} - -XMLNode::XMLNode(const string & n) - : _name(n), _is_content(false), _content(string()) -{ - - if (_name.empty()) - _initialized = false; - else - _initialized = true; -} - -XMLNode::XMLNode(const string & n, const string & c) - :_name(string()), _is_content(true), _content(c) -{ - _initialized = true; -} - -XMLNode::XMLNode(const XMLNode& from) - : _initialized(false) -{ - XMLPropertyList props; - XMLPropertyIterator curprop; - XMLNodeList nodes; - XMLNodeIterator curnode; - - _name = from.name(); - set_content(from.content()); - - props = from.properties(); - for (curprop = props.begin(); curprop != props.end(); curprop++) - add_property((*curprop)->name().c_str(), (*curprop)->value()); - - nodes = from.children(); - for (curnode = nodes.begin(); curnode != nodes.end(); curnode++) - add_child_copy(**curnode); -} - -XMLNode::~XMLNode() -{ - XMLNodeIterator curchild; - XMLPropertyIterator curprop; - - for (curchild = _children.begin(); curchild != _children.end(); - curchild++) - delete *curchild; - - for (curprop = _proplist.begin(); curprop != _proplist.end(); - curprop++) - delete *curprop; -} - -const string & -XMLNode::set_content(const string & c) -{ - if (c.empty()) - _is_content = false; - else - _is_content = true; - - _content = c; - - return _content; -} - -const XMLNodeList & -XMLNode::children(const string & n) const -{ - static XMLNodeList retval; - XMLNodeConstIterator cur; - - if (n.length() == 0) - return _children; - - retval.erase(retval.begin(), retval.end()); - - for (cur = _children.begin(); cur != _children.end(); cur++) - if ((*cur)->name() == n) - retval.insert(retval.end(), *cur); - - return retval; -} - -XMLNode * -XMLNode::add_child(const char * n) -{ - return add_child_copy(XMLNode (n)); -} - -void -XMLNode::add_child_nocopy (XMLNode& n) -{ - _children.insert(_children.end(), &n); -} - -XMLNode * -XMLNode::add_child_copy(const XMLNode& n) -{ - XMLNode *copy = new XMLNode (n); - _children.insert(_children.end(), copy); - return copy; -} - -XMLNode * -XMLNode::add_content(const string & c) -{ - return add_child_copy(XMLNode (string(), c)); -} - -XMLProperty * -XMLNode::property(const char * n) -{ - string ns(n); - if (_propmap.find(ns) == _propmap.end()) - return 0; - return _propmap[ns]; -} - -XMLProperty * -XMLNode::add_property(const char * n, const string & v) -{ - string ns(n); - if(_propmap.find(ns) != _propmap.end()){ - remove_property(ns); - } - - XMLProperty *tmp = new XMLProperty(ns, v); - - if (!tmp) - return 0; - - _propmap[tmp->name()] = tmp; - _proplist.insert(_proplist.end(), tmp); - - return tmp; -} - -XMLProperty * -XMLNode::add_property(const char * n, const char * v) -{ - string vs(v); - return add_property(n, vs); -} - -void -XMLNode::remove_property(const string & n) -{ - if (_propmap.find(n) != _propmap.end()) { - _proplist.remove(_propmap[n]); - _propmap.erase(n); - } -} - -void -XMLNode::remove_nodes(const string & n) -{ - XMLNodeIterator i = _children.begin(); - XMLNodeIterator tmp; - - while (i != _children.end()) { - tmp = i; - ++tmp; - if ((*i)->name() == n) { - _children.erase (i); - } - i = tmp; - } -} - -void -XMLNode::remove_nodes_and_delete(const string & n) -{ - XMLNodeIterator i = _children.begin(); - XMLNodeIterator tmp; - - while (i != _children.end()) { - tmp = i; - ++tmp; - if ((*i)->name() == n) { - delete *i; - _children.erase (i); - } - i = tmp; - } -} - -XMLProperty::XMLProperty(const string &n, const string &v) - : _name(n), - _value(v) -{ -} - -XMLProperty::~XMLProperty() -{ -} - -static XMLNode * -readnode(xmlNodePtr node) -{ - string name, content; - xmlNodePtr child; - XMLNode *tmp; - xmlAttrPtr attr; - - if (node->name) - name = (char *) node->name; - - tmp = new XMLNode(name); - - for (attr = node->properties; attr; attr = attr->next) { - content = ""; - if (attr->children) - content = (char *) attr->children->content; - tmp->add_property((char *) attr->name, content); - } - - if (node->content) - tmp->set_content((char *) node->content); - else - tmp->set_content(string()); - - for (child = node->children; child; child = child->next) - tmp->add_child_nocopy (*readnode(child)); - - return tmp; -} - -static void -writenode(xmlDocPtr doc, XMLNode * n, xmlNodePtr p, int root = - 0) -{ - XMLPropertyList props; - XMLPropertyIterator curprop; - XMLNodeList children; - XMLNodeIterator curchild; - xmlNodePtr node; - - if (root) - node = doc->children = - xmlNewDocNode(doc, 0, (xmlChar *) n->name().c_str(), 0); - - else - node = xmlNewChild(p, 0, (xmlChar *) n->name().c_str(), 0); - - if (n->is_content()) { - node->type = XML_TEXT_NODE; - xmlNodeSetContentLen(node, (const xmlChar *) n->content().c_str(), - n->content().length()); - } - - props = n->properties(); - for (curprop = props.begin(); curprop != props.end(); curprop++) - xmlSetProp(node, (xmlChar *) (*curprop)->name().c_str(), - (xmlChar *) (*curprop)->value().c_str()); - - children = n->children(); - for (curchild = children.begin(); curchild != children.end(); - curchild++) - writenode(doc, *curchild, node); -} diff --git a/libs/soundtouch/STTypes.h b/libs/soundtouch/STTypes.h index dc6a97001a..c404675ecd 100644 --- a/libs/soundtouch/STTypes.h +++ b/libs/soundtouch/STTypes.h @@ -105,6 +105,6 @@ namespace soundtouch #endif #endif // INTEGER_SAMPLES -}; +} #endif diff --git a/libs/surfaces/control_protocol/SConscript b/libs/surfaces/control_protocol/SConscript index f8a7d574f5..ce59b1c67c 100644 --- a/libs/surfaces/control_protocol/SConscript +++ b/libs/surfaces/control_protocol/SConscript @@ -34,7 +34,7 @@ cp.Append(CXXFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"") cp.Merge ([ libraries['ardour'], libraries['sigc2'], - libraries['pbd3'], + libraries['pbd'], libraries['midi++2'], libraries['xml'], libraries['usb'], diff --git a/libs/surfaces/control_protocol/control_protocol.cc b/libs/surfaces/control_protocol/control_protocol.cc index 10295bc698..dd9adc206e 100644 --- a/libs/surfaces/control_protocol/control_protocol.cc +++ b/libs/surfaces/control_protocol/control_protocol.cc @@ -49,7 +49,7 @@ void ControlProtocol::next_track (uint32_t initial_id) { uint32_t limit = session->nroutes(); - Route* cr = route_table[0]; + boost::shared_ptr<Route> cr = route_table[0]; uint32_t id; if (cr) { @@ -88,7 +88,7 @@ void ControlProtocol::prev_track (uint32_t initial_id) { uint32_t limit = session->nroutes() - 1; - Route* cr = route_table[0]; + boost::shared_ptr<Route> cr = route_table[0]; uint32_t id; if (cr) { @@ -128,29 +128,32 @@ void ControlProtocol::set_route_table_size (uint32_t size) { while (route_table.size() < size) { - route_table.push_back (0); + route_table.push_back (boost::shared_ptr<Route> ((Route*) 0)); } } void -ControlProtocol::set_route_table (uint32_t table_index, ARDOUR::Route*) +ControlProtocol::set_route_table (uint32_t table_index, boost::shared_ptr<ARDOUR::Route> r) { + if (table_index >= route_table.size()) { + return; + } + + route_table[table_index] = r; + + // XXX SHAREDPTR need to handle r->GoingAway } bool ControlProtocol::set_route_table (uint32_t table_index, uint32_t remote_control_id) { - if (table_index >= route_table.size()) { - return false; - } - - Route* r = session->route_by_remote_id (remote_control_id); + boost::shared_ptr<Route> r = session->route_by_remote_id (remote_control_id); if (!r) { return false; } - - route_table[table_index] = r; + + set_route_table (table_index, r); return true; } @@ -162,9 +165,9 @@ ControlProtocol::route_set_rec_enable (uint32_t table_index, bool yn) return; } - Route* r = route_table[table_index]; + boost::shared_ptr<Route> r = route_table[table_index]; - AudioTrack* at = dynamic_cast<AudioTrack*>(r); + boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack>(r); if (at) { at->set_record_enable (yn, this); @@ -178,9 +181,9 @@ ControlProtocol::route_get_rec_enable (uint32_t table_index) return false; } - Route* r = route_table[table_index]; + boost::shared_ptr<Route> r = route_table[table_index]; - AudioTrack* at = dynamic_cast<AudioTrack*>(r); + boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack>(r); if (at) { return at->record_enabled (); @@ -197,7 +200,7 @@ ControlProtocol::route_get_gain (uint32_t table_index) return 0.0f; } - Route* r = route_table[table_index]; + boost::shared_ptr<Route> r = route_table[table_index]; if (r == 0) { return 0.0f; @@ -213,7 +216,7 @@ ControlProtocol::route_set_gain (uint32_t table_index, float gain) return; } - Route* r = route_table[table_index]; + boost::shared_ptr<Route> r = route_table[table_index]; if (r != 0) { r->set_gain (gain, this); @@ -227,7 +230,7 @@ ControlProtocol::route_get_effective_gain (uint32_t table_index) return 0.0f; } - Route* r = route_table[table_index]; + boost::shared_ptr<Route> r = route_table[table_index]; if (r == 0) { return 0.0f; @@ -244,7 +247,7 @@ ControlProtocol::route_get_peak_input_power (uint32_t table_index, uint32_t whic return 0.0f; } - Route* r = route_table[table_index]; + boost::shared_ptr<Route> r = route_table[table_index]; if (r == 0) { return 0.0f; @@ -261,7 +264,7 @@ ControlProtocol::route_get_muted (uint32_t table_index) return false; } - Route* r = route_table[table_index]; + boost::shared_ptr<Route> r = route_table[table_index]; if (r == 0) { return false; @@ -277,7 +280,7 @@ ControlProtocol::route_set_muted (uint32_t table_index, bool yn) return; } - Route* r = route_table[table_index]; + boost::shared_ptr<Route> r = route_table[table_index]; if (r != 0) { r->set_mute (yn, this); @@ -292,7 +295,7 @@ ControlProtocol::route_get_soloed (uint32_t table_index) return false; } - Route* r = route_table[table_index]; + boost::shared_ptr<Route> r = route_table[table_index]; if (r == 0) { return false; @@ -308,7 +311,7 @@ ControlProtocol::route_set_soloed (uint32_t table_index, bool yn) return; } - Route* r = route_table[table_index]; + boost::shared_ptr<Route> r = route_table[table_index]; if (r != 0) { r->set_solo (yn, this); @@ -322,7 +325,7 @@ ControlProtocol:: route_get_name (uint32_t table_index) return ""; } - Route* r = route_table[table_index]; + boost::shared_ptr<Route> r = route_table[table_index]; if (r == 0) { return ""; diff --git a/libs/surfaces/control_protocol/control_protocol/control_protocol.h b/libs/surfaces/control_protocol/control_protocol/control_protocol.h index 69135f2b4b..8be652b9df 100644 --- a/libs/surfaces/control_protocol/control_protocol/control_protocol.h +++ b/libs/surfaces/control_protocol/control_protocol/control_protocol.h @@ -25,8 +25,9 @@ #include <string> #include <vector> #include <list> +#include <boost/shared_ptr.hpp> #include <sigc++/sigc++.h> - +#include <pbd/stateful.h> #include <control_protocol/basic_ui.h> namespace ARDOUR { @@ -34,7 +35,7 @@ namespace ARDOUR { class Route; class Session; -class ControlProtocol : public sigc::trackable, public BasicUI { +class ControlProtocol : public sigc::trackable, public Stateful, public BasicUI { public: ControlProtocol (Session&, std::string name); virtual ~ControlProtocol(); @@ -73,7 +74,7 @@ class ControlProtocol : public sigc::trackable, public BasicUI { */ void set_route_table_size (uint32_t size); - void set_route_table (uint32_t table_index, ARDOUR::Route*); + void set_route_table (uint32_t table_index, boost::shared_ptr<ARDOUR::Route>); bool set_route_table (uint32_t table_index, uint32_t remote_control_id); void route_set_rec_enable (uint32_t table_index, bool yn); @@ -94,7 +95,7 @@ class ControlProtocol : public sigc::trackable, public BasicUI { std::string route_get_name (uint32_t table_index); protected: - std::vector<ARDOUR::Route*> route_table; + std::vector<boost::shared_ptr<ARDOUR::Route> > route_table; std::string _name; bool _active; diff --git a/libs/surfaces/generic_midi/SConscript b/libs/surfaces/generic_midi/SConscript index 1760eb24e9..f9c2de08f8 100644 --- a/libs/surfaces/generic_midi/SConscript +++ b/libs/surfaces/generic_midi/SConscript @@ -23,6 +23,7 @@ genericmidi.Append(POTFILE = domain + '.pot') genericmidi_files=Split(""" interface.cc generic_midi_control_protocol.cc +midicontrollable.cc """) genericmidi.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE") @@ -34,7 +35,7 @@ genericmidi.Merge ([ libraries['ardour'], libraries['ardour_cp'], libraries['midi++2'], - libraries['pbd3'], + libraries['pbd'], libraries['sigc2'], libraries['usb'], libraries['xml'], diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc index 95b9d22393..d905c0bc41 100644 --- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc @@ -1,20 +1,65 @@ +/* + Copyright (C) 2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <algorithm> + +#include <pbd/error.h> +#include <pbd/failed_constructor.h> + #include <midi++/port.h> +#include <midi++/manager.h> +#include <midi++/port_request.h> #include <ardour/route.h> #include <ardour/session.h> #include "generic_midi_control_protocol.h" +#include "midicontrollable.h" using namespace ARDOUR; +using namespace PBD; #include "i18n.h" GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s) : ControlProtocol (s, _("GenericMIDI")) { - _port = s.midi_port(); - s.MIDI_PortChanged.connect (mem_fun (*this, &GenericMidiControlProtocol::port_change)); + MIDI::Manager* mm = MIDI::Manager::instance(); + + /* XXX it might be nice to run "control" through i18n, but thats a bit tricky because + the name is defined in ardour.rc which is likely not internationalized. + */ + _port = mm->port (X_("control")); + + if (_port == 0) { + error << _("no MIDI port named \"control\" exists - generic MIDI control disabled") << endmsg; + throw failed_constructor(); + } + + _feedback_interval = 10000; // microseconds + last_feedback_time = 0; + + Controllable::StartLearning.connect (mem_fun (*this, &GenericMidiControlProtocol::start_learning)); + Controllable::StopLearning.connect (mem_fun (*this, &GenericMidiControlProtocol::stop_learning)); + Session::SendFeedback.connect (mem_fun (*this, &GenericMidiControlProtocol::send_feedback)); } GenericMidiControlProtocol::~GenericMidiControlProtocol () @@ -24,42 +69,165 @@ GenericMidiControlProtocol::~GenericMidiControlProtocol () int GenericMidiControlProtocol::set_active (bool yn) { - /* start delivery/outbound thread */ + /* start/stop delivery/outbound thread */ return 0; } void -GenericMidiControlProtocol::port_change () +GenericMidiControlProtocol::set_feedback_interval (microseconds_t ms) { - _port = session->midi_port (); + _feedback_interval = ms; } -void -GenericMidiControlProtocol::set_port (MIDI::Port* p) +void +GenericMidiControlProtocol::send_feedback () { - _port = p; + microseconds_t now = get_microseconds (); + + if (last_feedback_time != 0) { + if ((now - last_feedback_time) < _feedback_interval) { + return; + } + } + + _send_feedback (); + + last_feedback_time = now; } void -GenericMidiControlProtocol::send_route_feedback (list<Route*>& routes) +GenericMidiControlProtocol::_send_feedback () { - if (_port != 0) { - - const int32_t bufsize = 16 * 1024; - MIDI::byte buf[bufsize]; - int32_t bsize = bufsize; - MIDI::byte* end = buf; - - for (list<Route*>::iterator r = routes.begin(); r != routes.end(); ++r) { - end = (*r)->write_midi_feedback (end, bsize); + const int32_t bufsize = 16 * 1024; + MIDI::byte buf[bufsize]; + int32_t bsize = bufsize; + MIDI::byte* end = buf; + + for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) { + end = (*r)->write_feedback (end, bsize); + } + + if (end == buf) { + return; + } + + _port->write (buf, (int32_t) (end - buf)); +} + +bool +GenericMidiControlProtocol::start_learning (Controllable* c) +{ + if (c == 0) { + return false; + } + + MIDIControllable* mc = new MIDIControllable (*_port, *c); + + { + Glib::Mutex::Lock lm (pending_lock); + std::pair<MIDIControllables::iterator,bool> result; + result = pending_controllables.insert (mc); + if (result.second) { + c->LearningFinished.connect (bind (mem_fun (*this, &GenericMidiControlProtocol::learning_stopped), mc)); } - - if (end == buf) { - return; - } - - _port->write (buf, (int32_t) (end - buf)); - //cerr << "MIDI feedback: wrote " << (int32_t) (end - buf) << " to midi port\n"; } + + mc->learn_about_external_control (); + return true; } +void +GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc) +{ + Glib::Mutex::Lock lm (pending_lock); + Glib::Mutex::Lock lm2 (controllables_lock); + + MIDIControllables::iterator i = find (pending_controllables.begin(), pending_controllables.end(), mc); + + if (i != pending_controllables.end()) { + pending_controllables.erase (i); + } + + controllables.insert (mc); +} + +void +GenericMidiControlProtocol::stop_learning (Controllable* c) +{ + Glib::Mutex::Lock lm (pending_lock); + + /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the + relevant MIDIControllable and remove it from the pending list. + */ + + for (MIDIControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) { + if (&(*i)->get_controllable() == c) { + (*i)->stop_learning (); + delete (*i); + pending_controllables.erase (i); + break; + } + } +} + +XMLNode& +GenericMidiControlProtocol::get_state () +{ + XMLNode* node = new XMLNode (_name); /* node name must match protocol name */ + XMLNode* children = new XMLNode (X_("controls")); + + node->add_child_nocopy (*children); + + Glib::Mutex::Lock lm2 (controllables_lock); + for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) { + children->add_child_nocopy ((*i)->get_state()); + } + + return *node; +} + +int +GenericMidiControlProtocol::set_state (const XMLNode& node) +{ + XMLNodeList nlist; + XMLNodeConstIterator niter; + Controllable* c; + + { + Glib::Mutex::Lock lm (pending_lock); + pending_controllables.clear (); + } + + Glib::Mutex::Lock lm2 (controllables_lock); + + controllables.clear (); + + nlist = node.children(); + + if (nlist.empty()) { + return 0; + } + + nlist = nlist.front()->children (); + + for (niter = nlist.begin(); niter != nlist.end(); ++niter) { + + XMLProperty* prop; + + if ((prop = (*niter)->property ("id")) != 0) { + + ID id = prop->value (); + + c = session->controllable_by_id (id); + + if (c) { + MIDIControllable* mc = new MIDIControllable (*_port, *c); + if (mc->set_state (**niter) == 0) { + controllables.insert (mc); + } + } + } + } + + return 0; +} diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.h b/libs/surfaces/generic_midi/generic_midi_control_protocol.h index 70cbd181c8..5f5a470b13 100644 --- a/libs/surfaces/generic_midi/generic_midi_control_protocol.h +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.h @@ -1,34 +1,58 @@ #ifndef ardour_generic_midi_control_protocol_h #define ardour_generic_midi_control_protocol_h +#include <set> +#include <glibmm/thread.h> +#include <ardour/types.h> + #include <control_protocol/control_protocol.h> namespace MIDI { class Port; } +namespace PBD { + class Controllable; +} + namespace ARDOUR { + class Session; +} -class GenericMidiControlProtocol : public ControlProtocol { +class MIDIControllable; + +class GenericMidiControlProtocol : public ARDOUR::ControlProtocol { public: - GenericMidiControlProtocol (Session&); + GenericMidiControlProtocol (ARDOUR::Session&); virtual ~GenericMidiControlProtocol(); int set_active (bool yn); static bool probe() { return true; } - void set_port (MIDI::Port*); MIDI::Port* port () const { return _port; } + void set_feedback_interval (ARDOUR::microseconds_t); + + XMLNode& get_state (); + int set_state (const XMLNode&); - void send_route_feedback (std::list<Route*>&); - private: - void route_feedback (ARDOUR::Route&, bool); MIDI::Port* _port; + ARDOUR::microseconds_t _feedback_interval; + ARDOUR::microseconds_t last_feedback_time; - void port_change (); -}; + void _send_feedback (); + void send_feedback (); -} + typedef std::set<MIDIControllable*> MIDIControllables; + MIDIControllables controllables; + MIDIControllables pending_controllables; + Glib::Mutex controllables_lock; + Glib::Mutex pending_lock; + + bool start_learning (PBD::Controllable*); + void stop_learning (PBD::Controllable*); + + void learning_stopped (MIDIControllable*); +}; -#endif // ardour_generic_midi_control_protocol_h +#endif /* ardour_generic_midi_control_protocol_h */ diff --git a/libs/surfaces/generic_midi/interface.cc b/libs/surfaces/generic_midi/interface.cc index c6c59c6589..230be694f2 100644 --- a/libs/surfaces/generic_midi/interface.cc +++ b/libs/surfaces/generic_midi/interface.cc @@ -1,3 +1,5 @@ +#include <pbd/failed_constructor.h> + #include <control_protocol/control_protocol.h> #include "generic_midi_control_protocol.h" @@ -6,7 +8,13 @@ using namespace ARDOUR; ControlProtocol* new_generic_midi_protocol (ControlProtocolDescriptor* descriptor, Session* s) { - GenericMidiControlProtocol* gmcp = new GenericMidiControlProtocol (*s); + GenericMidiControlProtocol* gmcp; + + try { + gmcp = new GenericMidiControlProtocol (*s); + } catch (failed_constructor& err) { + return 0; + } if (gmcp->set_active (true)) { delete gmcp; diff --git a/libs/midi++2/midicontrollable.cc b/libs/surfaces/generic_midi/midicontrollable.cc index f0dbd9cb77..d6135fd2a8 100644 --- a/libs/midi++2/midicontrollable.cc +++ b/libs/surfaces/generic_midi/midicontrollable.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 1998-99 Paul Barton-Davis + Copyright (C) 1998-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,40 +15,48 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ + $Id: midicontrollable.cc 629 2006-06-21 23:01:03Z paul $ */ #include <cstdio> /* for sprintf, sigh */ +#include <climits> #include <pbd/error.h> +#include <pbd/xml++.h> #include <midi++/port.h> #include <midi++/channel.h> -#include <midi++/controllable.h> + +#include "midicontrollable.h" using namespace sigc; using namespace MIDI; using namespace PBD; +using namespace ARDOUR; + +bool MIDIControllable::_send_feedback = false; -Controllable::Controllable (Port *p, bool is_bistate) +MIDIControllable::MIDIControllable (Port& p, Controllable& c, bool is_bistate) + : controllable (c), _port (p), bistate (is_bistate) { + setting = false; + last_written = 0; // got a better idea ? control_type = none; _control_description = "MIDI Control: none"; control_additional = (byte) -1; - bistate = is_bistate; connections = 0; feedback = true; // for now /* use channel 0 ("1") as the initial channel */ - midi_rebind (p, 0); + midi_rebind (0); } -Controllable::~Controllable () +MIDIControllable::~MIDIControllable () { drop_external_control (); } void -Controllable::midi_forget () +MIDIControllable::midi_forget () { /* stop listening for incoming messages, but retain our existing event + type information. @@ -68,41 +76,30 @@ Controllable::midi_forget () } void -Controllable::midi_rebind (Port *p, channel_t c) +MIDIControllable::midi_rebind (channel_t c) { - if ((port = p) == 0) { - midi_forget (); + if (c >= 0) { + bind_midi (c, control_type, control_additional); } else { - if (c >= 0) { - bind_midi (c, control_type, control_additional); - } else { - midi_forget (); - } + midi_forget (); } } void -Controllable::learn_about_external_control () +MIDIControllable::learn_about_external_control () { drop_external_control (); - - if (port) { - midi_learn_connection = port->input()->any.connect (mem_fun (*this, &Controllable::midi_receiver)); - learning_started (); - - } else { - info << "No MIDI port specified - external control disabled" << endmsg; - } + midi_learn_connection = _port.input()->any.connect (mem_fun (*this, &MIDIControllable::midi_receiver)); } void -Controllable::stop_learning () +MIDIControllable::stop_learning () { midi_learn_connection.disconnect (); } void -Controllable::drop_external_control () +MIDIControllable::drop_external_control () { if (connections > 0) { midi_sense_connection[0].disconnect (); @@ -119,22 +116,22 @@ Controllable::drop_external_control () } void -Controllable::midi_sense_note_on (Parser &p, EventTwoBytes *tb) +MIDIControllable::midi_sense_note_on (Parser &p, EventTwoBytes *tb) { midi_sense_note (p, tb, true); } void -Controllable::midi_sense_note_off (Parser &p, EventTwoBytes *tb) +MIDIControllable::midi_sense_note_off (Parser &p, EventTwoBytes *tb) { midi_sense_note (p, tb, false); } void -Controllable::midi_sense_note (Parser &p, EventTwoBytes *msg, bool is_on) +MIDIControllable::midi_sense_note (Parser &p, EventTwoBytes *msg, bool is_on) { if (!bistate) { - set_value (msg->note_number/127.0); + controllable.set_value (msg->note_number/127.0); } else { /* Note: parser handles the use of zero velocity to @@ -143,49 +140,49 @@ Controllable::midi_sense_note (Parser &p, EventTwoBytes *msg, bool is_on) */ if (msg->note_number == control_additional) { - set_value (is_on ? 1 : 0); + controllable.set_value (is_on ? 1 : 0); } } } void -Controllable::midi_sense_controller (Parser &, EventTwoBytes *msg) +MIDIControllable::midi_sense_controller (Parser &, EventTwoBytes *msg) { if (control_additional == msg->controller_number) { if (!bistate) { - set_value (msg->value/127.0); + controllable.set_value (msg->value/127.0); } else { if (msg->value > 64.0) { - set_value (1); + controllable.set_value (1); } else { - set_value (0); + controllable.set_value (0); } } } } void -Controllable::midi_sense_program_change (Parser &p, byte msg) +MIDIControllable::midi_sense_program_change (Parser &p, byte msg) { /* XXX program change messages make no sense for bistates */ if (!bistate) { - set_value (msg/127.0); + controllable.set_value (msg/127.0); } } void -Controllable::midi_sense_pitchbend (Parser &p, pitchbend_t pb) +MIDIControllable::midi_sense_pitchbend (Parser &p, pitchbend_t pb) { /* pitchbend messages make no sense for bistates */ /* XXX gack - get rid of assumption about typeof pitchbend_t */ - set_value ((pb/(float) SHRT_MAX)); + controllable.set_value ((pb/(float) SHRT_MAX)); } void -Controllable::midi_receiver (Parser &p, byte *msg, size_t len) +MIDIControllable::midi_receiver (Parser &p, byte *msg, size_t len) { /* we only respond to channel messages */ @@ -195,17 +192,17 @@ Controllable::midi_receiver (Parser &p, byte *msg, size_t len) /* if the our port doesn't do input anymore, forget it ... */ - if (!port->input()) { + if (!_port.input()) { return; } bind_midi ((channel_t) (msg[0] & 0xf), eventType (msg[0] & 0xF0), msg[1]); - learning_stopped (); + controllable.LearningFinished (); } void -Controllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) +MIDIControllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) { char buf[64]; @@ -215,17 +212,17 @@ Controllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) control_channel = chn; control_additional = additional; - if (port == 0 || port->input() == 0) { + if (_port.input() == 0) { return; } - Parser& p = *port->input(); + Parser& p = *_port.input(); int chn_i = chn; switch (ev) { case MIDI::off: midi_sense_connection[0] = p.channel_note_off[chn_i].connect - (mem_fun (*this, &Controllable::midi_sense_note_off)); + (mem_fun (*this, &MIDIControllable::midi_sense_note_off)); /* if this is a bistate, connect to noteOn as well, and we'll toggle back and forth between the two. @@ -233,7 +230,7 @@ Controllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) if (bistate) { midi_sense_connection[1] = p.channel_note_on[chn_i].connect - (mem_fun (*this, &Controllable::midi_sense_note_on)); + (mem_fun (*this, &MIDIControllable::midi_sense_note_on)); connections = 2; } else { connections = 1; @@ -243,10 +240,10 @@ Controllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) case MIDI::on: midi_sense_connection[0] = p.channel_note_on[chn_i].connect - (mem_fun (*this, &Controllable::midi_sense_note_on)); + (mem_fun (*this, &MIDIControllable::midi_sense_note_on)); if (bistate) { midi_sense_connection[1] = p.channel_note_off[chn_i].connect - (mem_fun (*this, &Controllable::midi_sense_note_off)); + (mem_fun (*this, &MIDIControllable::midi_sense_note_off)); connections = 2; } else { connections = 1; @@ -256,7 +253,7 @@ Controllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) case MIDI::controller: midi_sense_connection[0] = p.channel_controller[chn_i].connect - (mem_fun (*this, &Controllable::midi_sense_controller)); + (mem_fun (*this, &MIDIControllable::midi_sense_controller)); connections = 1; snprintf (buf, sizeof (buf), "MIDI control: Controller %d", control_additional); _control_description = buf; @@ -266,7 +263,7 @@ Controllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) if (!bistate) { midi_sense_connection[0] = p.channel_program_change[chn_i].connect (mem_fun (*this, - &Controllable::midi_sense_program_change)); + &MIDIControllable::midi_sense_program_change)); connections = 1; _control_description = "MIDI control: ProgramChange"; } @@ -275,7 +272,7 @@ Controllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) case MIDI::pitchbend: if (!bistate) { midi_sense_connection[0] = p.channel_pitchbend[chn_i].connect - (mem_fun (*this, &Controllable::midi_sense_pitchbend)); + (mem_fun (*this, &MIDIControllable::midi_sense_pitchbend)); connections = 1; _control_description = "MIDI control: Pitchbend"; } @@ -287,40 +284,83 @@ Controllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) } void -Controllable::set_control_type (channel_t chn, eventType ev, MIDI::byte additional) +MIDIControllable::send_feedback () { - bind_midi (chn, ev, additional); -} + byte msg[3]; -bool -Controllable::get_control_info (channel_t& chn, eventType& ev, byte& additional) -{ - if (control_type == none) { - chn = -1; - return false; - } + if (setting || !_send_feedback || control_type == none) { + return; + } - ev = control_type; - chn = control_channel; - additional = control_additional; + msg[0] = (control_type & 0xF0) | (control_channel & 0xF); + msg[1] = control_additional; + msg[2] = (byte) (controllable.get_value() * 127.0f); - return true; + _port.write (msg, 3); } +MIDI::byte* +MIDIControllable::write_feedback (MIDI::byte* buf, int32_t& bufsize, bool force) +{ + if (control_type != none &&_send_feedback && bufsize > 2) { + + MIDI::byte gm = (MIDI::byte) (controllable.get_value() * 127.0); + + if (gm != last_written) { + *buf++ = (0xF0 & control_type) | (0xF & control_channel); + *buf++ = control_additional; /* controller number */ + *buf++ = gm; + last_written = gm; + bufsize -= 3; + } + } + + return buf; +} -void -Controllable::send_midi_feedback (float val) +int +MIDIControllable::set_state (const XMLNode& node) { - byte msg[3]; + const XMLProperty* prop; + int xx; - if (port == 0 || control_type == none) { - return; + if ((prop = node.property ("event")) != 0) { + sscanf (prop->value().c_str(), "0x%x", &xx); + control_type = (MIDI::eventType) xx; + } else { + return -1; } - - msg[0] = (control_type & 0xF0) | (control_channel & 0xF); - msg[1] = control_additional; - msg[2] = (byte) (val * 127.0f); - port->write (msg, 3); + if ((prop = node.property ("channel")) != 0) { + sscanf (prop->value().c_str(), "%d", &xx); + control_channel = (MIDI::channel_t) xx; + } else { + return -1; + } + + if ((prop = node.property ("additional")) != 0) { + sscanf (prop->value().c_str(), "0x%x", &xx); + control_additional = (MIDI::byte) xx; + } else { + return -1; + } + + return 0; +} + +XMLNode& +MIDIControllable::get_state () +{ + char buf[32]; + XMLNode& node (controllable.get_state ()); + + snprintf (buf, sizeof(buf), "0x%x", (int) control_type); + node.add_property ("event", buf); + snprintf (buf, sizeof(buf), "%d", (int) control_channel); + node.add_property ("channel", buf); + snprintf (buf, sizeof(buf), "0x%x", (int) control_additional); + node.add_property ("additional", buf); + + return node; } diff --git a/libs/surfaces/generic_midi/midicontrollable.h b/libs/surfaces/generic_midi/midicontrollable.h new file mode 100644 index 0000000000..ab15f9f4ab --- /dev/null +++ b/libs/surfaces/generic_midi/midicontrollable.h @@ -0,0 +1,97 @@ +/* + Copyright (C) 1998-2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: controllable.h 4 2005-05-13 20:47:18Z taybin $ +*/ + +#ifndef __gm_midicontrollable_h__ +#define __gm_midicontrollable_h__ + +#include <string> + +#include <sigc++/sigc++.h> + +#include <midi++/types.h> +#include <pbd/controllable.h> +#include <pbd/stateful.h> +#include <ardour/types.h> + +namespace MIDI { + +class Channel; +class Port; +class Parser; + +} + +class MIDIControllable : public Stateful +{ + public: + MIDIControllable (MIDI::Port&, PBD::Controllable&, bool bistate = false); + virtual ~MIDIControllable (); + + void send_feedback (); + MIDI::byte* write_feedback (MIDI::byte* buf, int32_t& bufsize, bool force = false); + + void midi_rebind (MIDI::channel_t channel=-1); + void midi_forget (); + void learn_about_external_control (); + void stop_learning (); + void drop_external_control (); + + bool get_midi_feedback () { return feedback; } + void set_midi_feedback (bool val) { feedback = val; } + + MIDI::Port& get_port() const { return _port; } + PBD::Controllable& get_controllable() const { return controllable; } + + std::string control_description() const { return _control_description; } + + XMLNode& get_state (void); + int set_state (const XMLNode&); + + private: + PBD::Controllable& controllable; + MIDI::Port& _port; + bool setting; + MIDI::byte last_written; + bool bistate; + int midi_msg_id; /* controller ID or note number */ + sigc::connection midi_sense_connection[2]; + sigc::connection midi_learn_connection; + size_t connections; + MIDI::eventType control_type; + MIDI::byte control_additional; + MIDI::channel_t control_channel; + std::string _control_description; + bool feedback; + + static bool _send_feedback; + + void midi_receiver (MIDI::Parser &p, MIDI::byte *, size_t); + void midi_sense_note (MIDI::Parser &, MIDI::EventTwoBytes *, bool is_on); + void midi_sense_note_on (MIDI::Parser &p, MIDI::EventTwoBytes *tb); + void midi_sense_note_off (MIDI::Parser &p, MIDI::EventTwoBytes *tb); + void midi_sense_controller (MIDI::Parser &, MIDI::EventTwoBytes *); + void midi_sense_program_change (MIDI::Parser &, MIDI::byte); + void midi_sense_pitchbend (MIDI::Parser &, MIDI::pitchbend_t); + + void bind_midi (MIDI::channel_t, MIDI::eventType, MIDI::byte); +}; + +#endif // __gm_midicontrollable_h__ + diff --git a/libs/surfaces/tranzport/SConscript b/libs/surfaces/tranzport/SConscript index 8f3568aa8f..3f9cc5cc15 100644 --- a/libs/surfaces/tranzport/SConscript +++ b/libs/surfaces/tranzport/SConscript @@ -34,7 +34,7 @@ tranzport.Merge ([ libraries['ardour'], libraries['ardour_cp'], libraries['sigc2'], - libraries['pbd3'], + libraries['pbd'], libraries['midi++2'], libraries['xml'], libraries['usb'], diff --git a/libs/surfaces/tranzport/tranzport_control_protocol.cc b/libs/surfaces/tranzport/tranzport_control_protocol.cc index ee8fa95bc2..426c837b2f 100644 --- a/libs/surfaces/tranzport/tranzport_control_protocol.cc +++ b/libs/surfaces/tranzport/tranzport_control_protocol.cc @@ -579,7 +579,7 @@ TranzportControlProtocol::monitor_work () if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) { // do we care? not particularly. - info << string_compose (_("%1: thread not running with realtime scheduling (%2)"), name(), strerror (errno)) << endmsg; + PBD::info << string_compose (_("%1: thread not running with realtime scheduling (%2)"), name(), strerror (errno)) << endmsg; } pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0); @@ -693,7 +693,7 @@ TranzportControlProtocol::update_state () /* per track */ if (route_table[0]) { - AudioTrack* at = dynamic_cast<AudioTrack*> (route_table[0]); + boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack> (route_table[0]); if (at && at->record_enabled()) { pending_lights[LightTrackrec] = true; } else { @@ -1574,3 +1574,15 @@ TranzportControlProtocol::print (int row, int col, const char *text) } } +XMLNode& +TranzportControlProtocol::get_state () +{ + XMLNode* node = new XMLNode (_name); /* node name must match protocol name */ + return *node; +} + +int +TranzportControlProtocol::set_state (const XMLNode& node) +{ + return 0; +} diff --git a/libs/surfaces/tranzport/tranzport_control_protocol.h b/libs/surfaces/tranzport/tranzport_control_protocol.h index 546cc2f2af..e6e1a83e46 100644 --- a/libs/surfaces/tranzport/tranzport_control_protocol.h +++ b/libs/surfaces/tranzport/tranzport_control_protocol.h @@ -23,6 +23,9 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol static bool probe (); + XMLNode& get_state (); + int set_state (const XMLNode&); + private: static const int VENDORID = 0x165b; static const int PRODUCTID = 0x8101; diff --git a/tools/.cvsignore b/tools/.cvsignore deleted file mode 100644 index 4149fafb53..0000000000 --- a/tools/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -ard_i18n -Makefile.in -Makefile diff --git a/tools/config.guess b/tools/config.guess index 78f6b92cd3..917bbc50f3 100755 --- a/tools/config.guess +++ b/tools/config.guess @@ -1,9 +1,9 @@ #! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003 Free Software Foundation, Inc. +# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. -timestamp='2003-01-10' +timestamp='2005-07-08' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -17,13 +17,15 @@ timestamp='2003-01-10' # # 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. + # Originally written by Per Bothner <per@bothner.com>. # Please send patches to <config-patches@gnu.org>. Submit a context # diff and a properly formatted ChangeLog entry. @@ -53,7 +55,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO @@ -66,11 +68,11 @@ Try \`$me --help' for more information." while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) - echo "$timestamp" ; exit 0 ;; + echo "$timestamp" ; exit ;; --version | -v ) - echo "$version" ; exit 0 ;; + echo "$version" ; exit ;; --help | --h* | -h ) - echo "$usage"; exit 0 ;; + echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. @@ -106,6 +108,7 @@ trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; @@ -122,7 +125,7 @@ case $CC_FOR_BUILD,$HOST_CC,$CC in ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; -esac ;' +esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) @@ -195,141 +198,109 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" - exit 0 ;; - amiga:OpenBSD:*:*) - echo m68k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - arc:OpenBSD:*:*) - echo mipsel-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - hp300:OpenBSD:*:*) - echo m68k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - mac68k:OpenBSD:*:*) - echo m68k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - macppc:OpenBSD:*:*) - echo powerpc-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - mvme68k:OpenBSD:*:*) - echo m68k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - mvme88k:OpenBSD:*:*) - echo m88k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - mvmeppc:OpenBSD:*:*) - echo powerpc-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - pmax:OpenBSD:*:*) - echo mipsel-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - sgi:OpenBSD:*:*) - echo mipseb-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - sun3:OpenBSD:*:*) - echo m68k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - wgrisc:OpenBSD:*:*) - echo mipsel-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; + exit ;; *:OpenBSD:*:*) - echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - *:MicroBSD:*:*) - echo ${UNAME_MACHINE}-unknown-microbsd${UNAME_RELEASE} - exit 0 ;; + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerppc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; alpha:OSF1:*:*) - if test $UNAME_RELEASE = "V4.0"; then + case $UNAME_RELEASE in + *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` - fi + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - eval $set_cc_for_build - cat <<EOF >$dummy.s - .data -\$Lformat: - .byte 37,100,45,37,120,10,0 # "%d-%x\n" - - .text - .globl main - .align 4 - .ent main -main: - .frame \$30,16,\$26,0 - ldgp \$29,0(\$27) - .prologue 1 - .long 0x47e03d80 # implver \$0 - lda \$2,-1 - .long 0x47e20c21 # amask \$2,\$1 - lda \$16,\$Lformat - mov \$0,\$17 - not \$1,\$18 - jsr \$26,printf - ldgp \$29,0(\$26) - mov 0,\$16 - jsr \$26,exit - .end main -EOF - $CC_FOR_BUILD -o $dummy $dummy.s 2>/dev/null - if test "$?" = 0 ; then - case `$dummy` in - 0-0) - UNAME_MACHINE="alpha" - ;; - 1-0) - UNAME_MACHINE="alphaev5" - ;; - 1-1) - UNAME_MACHINE="alphaev56" - ;; - 1-101) - UNAME_MACHINE="alphapca56" - ;; - 2-303) - UNAME_MACHINE="alphaev6" - ;; - 2-307) - UNAME_MACHINE="alphaev67" - ;; - 2-1307) - UNAME_MACHINE="alphaev68" - ;; - 3-1307) - UNAME_MACHINE="alphaev7" - ;; - esac - fi - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - exit 0 ;; + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix - exit 0 ;; + exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 - exit 0 ;; + exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 - exit 0;; + exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos - exit 0 ;; + exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos - exit 0 ;; + exit ;; *:OS/390:*:*) echo i370-ibm-openedition - exit 0 ;; + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} - exit 0;; + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp - exit 0;; + exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then @@ -337,29 +308,32 @@ EOF else echo pyramid-pyramid-bsd fi - exit 0 ;; + exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 - exit 0 ;; - DRS?6000:UNIX_SV:4.2*:7*) + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in - sparc) echo sparc-icl-nx7 && exit 0 ;; + sparc) echo sparc-icl-nx7; exit ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit 0 ;; + exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit 0 ;; + exit ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit 0 ;; + exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit 0 ;; + exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) @@ -368,10 +342,10 @@ EOF esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` - exit 0 ;; + exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} - exit 0 ;; + exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 @@ -383,10 +357,10 @@ EOF echo sparc-sun-sunos${UNAME_RELEASE} ;; esac - exit 0 ;; + exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} - exit 0 ;; + exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor @@ -397,37 +371,40 @@ EOF # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} - exit 0 ;; + exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} - exit 0 ;; + exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} - exit 0 ;; + exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} - exit 0 ;; + exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} - exit 0 ;; + exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} - exit 0 ;; + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} - exit 0 ;; + exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 - exit 0 ;; + exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} - exit 0 ;; + exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} - exit 0 ;; + exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} - exit 0 ;; + exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c @@ -451,32 +428,33 @@ EOF exit (-1); } EOF - $CC_FOR_BUILD -o $dummy $dummy.c \ - && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ - && exit 0 + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} - exit 0 ;; + exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax - exit 0 ;; + exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax - exit 0 ;; + exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax - exit 0 ;; + exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix - exit 0 ;; + exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 - exit 0 ;; + exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 - exit 0 ;; + exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 - exit 0 ;; + exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` @@ -492,29 +470,29 @@ EOF else echo i586-dg-dgux${UNAME_RELEASE} fi - exit 0 ;; + exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 - exit 0 ;; + exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 - exit 0 ;; + exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 - exit 0 ;; + exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd - exit 0 ;; + exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` - exit 0 ;; + exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. - echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id - exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix - exit 0 ;; + exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` @@ -522,7 +500,7 @@ EOF IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} - exit 0 ;; + exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build @@ -537,14 +515,18 @@ EOF exit(0); } EOF - $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 - echo rs6000-ibm-aix3.2.5 + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi - exit 0 ;; + exit ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then @@ -558,28 +540,28 @@ EOF IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} - exit 0 ;; + exit ;; *:AIX:*:*) echo rs6000-ibm-aix - exit 0 ;; + exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 - exit 0 ;; + exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to - exit 0 ;; # report: romp-ibm BSD 4.3 + exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx - exit 0 ;; + exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 - exit 0 ;; + exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd - exit 0 ;; + exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 - exit 0 ;; + exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in @@ -641,9 +623,19 @@ EOF esac if [ ${HP_ARCH} = "hppa2.0w" ] then - # avoid double evaluation of $set_cc_for_build - test -n "$CC_FOR_BUILD" || eval $set_cc_for_build - if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else @@ -651,11 +643,11 @@ EOF fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} - exit 0 ;; + exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} - exit 0 ;; + exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c @@ -683,147 +675,166 @@ EOF exit (0); } EOF - $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 - exit 0 ;; + exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd - exit 0 ;; + exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd - exit 0 ;; + exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix - exit 0 ;; + exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf - exit 0 ;; + exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf - exit 0 ;; + exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi - exit 0 ;; + exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites - exit 0 ;; + exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd - exit 0 ;; + exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi - exit 0 ;; + exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd - exit 0 ;; + exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd - exit 0 ;; + exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd - exit 0 ;; + exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit 0 ;; + exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' - exit 0 ;; + exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit 0 ;; + exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit 0 ;; + exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit 0 ;; + exit ;; *:UNICOS/mp:*:*) - echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit 0 ;; + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit 0 ;; + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} - exit 0 ;; + exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} - exit 0 ;; + exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} - exit 0 ;; + exit ;; *:FreeBSD:*:*) - # Determine whether the default compiler uses glibc. - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #include <features.h> - #if __GLIBC__ >= 2 - LIBC=gnu - #else - LIBC= - #endif -EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` - echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} - exit 0 ;; + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin - exit 0 ;; + exit ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 - exit 0 ;; + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 - exit 0 ;; - x86:Interix*:3*) - echo i586-pc-interix3 - exit 0 ;; + exit ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks - exit 0 ;; + exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix - exit 0 ;; + exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin - exit 0 ;; + exit ;; + amd64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin - exit 0 ;; + exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit 0 ;; + exit ;; *:GNU:*:*) + # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` - exit 0 ;; + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix - exit 0 ;; + exit ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu - exit 0 ;; + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu - exit 0 ;; + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu - exit 0 ;; + exit ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c @@ -841,7 +852,7 @@ EOF #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` - test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; mips64:Linux:*:*) eval $set_cc_for_build @@ -860,14 +871,14 @@ EOF #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` - test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu - exit 0 ;; + exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu - exit 0 ;; + exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; @@ -881,7 +892,7 @@ EOF objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} - exit 0 ;; + exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in @@ -889,22 +900,25 @@ EOF PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac - exit 0 ;; + exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu - exit 0 ;; + exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux - exit 0 ;; + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu - exit 0 ;; + exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu - exit 0 ;; + exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu - exit 0 ;; + exit ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent @@ -922,15 +936,15 @@ EOF ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" - exit 0 ;; + exit ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" - exit 0 ;; + exit ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" - exit 0 ;; + exit ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build @@ -953,17 +967,23 @@ EOF LIBC=gnuaout #endif #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` - test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 - test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 - exit 0 ;; + exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... @@ -971,24 +991,27 @@ EOF # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} - exit 0 ;; + exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx - exit 0 ;; + exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop - exit 0 ;; + exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos - exit 0 ;; + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} - exit 0 ;; + exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp - exit 0 ;; + exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then @@ -996,15 +1019,16 @@ EOF else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi - exit 0 ;; - i*86:*:5:[78]*) + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} - exit 0 ;; + exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` @@ -1022,73 +1046,73 @@ EOF else echo ${UNAME_MACHINE}-pc-sysv32 fi - exit 0 ;; + exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp - exit 0 ;; + exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 - exit 0 ;; + exit ;; paragon:*:*:*) echo i860-intel-osf1 - exit 0 ;; + exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi - exit 0 ;; + exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv - exit 0 ;; + exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv - exit 0 ;; + exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix - exit 0 ;; - M68*:*:R3V[567]*:*) - test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; - 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0) + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && echo i486-ncr-sysv4 && exit 0 ;; + && { echo i486-ncr-sysv4; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} - exit 0 ;; + exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 - exit 0 ;; + exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} - exit 0 ;; + exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} - exit 0 ;; + exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} - exit 0 ;; + exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} - exit 0 ;; + exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 - exit 0 ;; + exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 - exit 0 ;; + exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` @@ -1096,68 +1120,73 @@ EOF else echo ns32k-sni-sysv fi - exit 0 ;; + exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says <Richard.M.Bartel@ccMail.Census.GOV> echo i586-unisys-sysv4 - exit 0 ;; + exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes <hewes@openmarket.com>. # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 - exit 0 ;; + exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 - exit 0 ;; + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos - exit 0 ;; + exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} - exit 0 ;; + exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 - exit 0 ;; + exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi - exit 0 ;; + exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos - exit 0 ;; + exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos - exit 0 ;; + exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos - exit 0 ;; + exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} - exit 0 ;; + exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} - exit 0 ;; + exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} - exit 0 ;; + exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} - exit 0 ;; + exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} - exit 0 ;; + exit ;; *:Darwin:*:*) - case `uname -p` in + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in *86) UNAME_PROCESSOR=i686 ;; - powerpc) UNAME_PROCESSOR=powerpc ;; + unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} - exit 0 ;; + exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then @@ -1165,22 +1194,25 @@ EOF UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} - exit 0 ;; + exit ;; *:QNX:*:4*) echo i386-pc-qnx - exit 0 ;; - NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*) + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} - exit 0 ;; + exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux - exit 0 ;; + exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv - exit 0 ;; + exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} - exit 0 ;; + exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 @@ -1191,25 +1223,44 @@ EOF UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 - exit 0 ;; + exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 - exit 0 ;; + exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex - exit 0 ;; + exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 - exit 0 ;; + exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 - exit 0 ;; + exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 - exit 0 ;; + exit ;; *:ITS:*:*) echo pdp10-unknown-its - exit 0 ;; + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 @@ -1241,7 +1292,7 @@ main () #endif #if defined (__arm) && defined (__acorn) && defined (__unix) - printf ("arm-acorn-riscix"); exit (0); + printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) @@ -1330,11 +1381,12 @@ main () } EOF -$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0 +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. -test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) @@ -1343,22 +1395,22 @@ then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd - exit 0 ;; + exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi - exit 0 ;; + exit ;; c34*) echo c34-convex-bsd - exit 0 ;; + exit ;; c38*) echo c38-convex-bsd - exit 0 ;; + exit ;; c4*) echo c4-convex-bsd - exit 0 ;; + exit ;; esac fi @@ -1369,7 +1421,9 @@ This script, last modified $timestamp, has failed to recognize the operating system you are using. It is advised that you download the most up to date version of the config scripts from - ftp://ftp.gnu.org/pub/gnu/config/ + http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess +and + http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub If the version you run ($0) is already up to date, please send the following data and any information you think might be diff --git a/tools/osx_packaging/ardour2_mac_ui.rc b/tools/osx_packaging/ardour2_mac_ui.rc new file mode 100644 index 0000000000..fb739a94b7 --- /dev/null +++ b/tools/osx_packaging/ardour2_mac_ui.rc @@ -0,0 +1,1225 @@ +# +# This is the GTK style file for Ardour +# +# + +style "very_small_text" +{ + font_name = "sans 9" +} + +style "small_text" +{ + font_name = "sans 10" +} + +style "small_bold_text" +{ + font_name = "sans bold 10" +} + +style "medium_bold_text" +{ + font_name = "sans bold 11" +} + +style "medium_text" +{ + font_name = "sans 11" +} + +style "red_medium_text" = "medium_text" +{ + fg[NORMAL] = { 1.0, 0, 0 } + fg[ACTIVE] = { 1.0, 0, 0 } + fg[SELECTED] = { 1.0, 0, 0 } +} + + +style "large_text" +{ + font_name = "sans 18" +} + +style "larger_bold_text" +{ + font_name = "sans bold 14" +} + +style "plugin_name_text" +{ + font_name = "sans bold 25" + fg[NORMAL] = { 0.80, 0.80, 0.80 } +} + +style "plugin_maker_text" +{ + font_name = "sans bold 14" + fg[NORMAL] = { 0.80, 0.80, 0.80 } +} + +style "first_action_message" +{ + font_name = "sans medium 34" +} + +style "verbose_canvas_cursor" +{ + font_name = "sans bold 24" +} + +style "marker_text" +{ + font_name = "sans 9" +} + +style "time_axis_view_item_name" +{ + font_name = "sans medium 10" +} + +style "default_base" = "medium_text" +{ + GtkWidget::cursor_color = {1.0, 1.0, 1.0 } + GtkButton::default_border = { 0, 0, 0, 0 } + GtkButton::default_outside_border = { 0, 0, 0, 0 } + GtkTreeView::vertical-padding = 0 + GtkTreeView::horizontal-padding = 0 + + fg[NORMAL] = { 0.80, 0.80, 0.80 } + fg[ACTIVE] = { 0.80, 0.80, 0.80 } + fg[PRELIGHT] = { 1.0, 1.0, 1.0 } + fg[INSENSITIVE] = { 0.80, 0.80, 0.80 } + fg[SELECTED] = { 0.80, 0.80, 0.80 } + + bg[NORMAL] = { 0.40, 0.40, 0.40 } + bg[ACTIVE] = { 0.40, 0.40, 0.40 } + bg[PRELIGHT] = "#565690" + bg[INSENSITIVE] = { 0.10, 0.10, 0.10 } + bg[SELECTED] = { 0, 0.40, 0.60 } + + text[NORMAL] = { 0.80, 0.80, 0.80 } + text[ACTIVE] = { 0.80, 0.80, 0.80 } + text[PRELIGHT] = { 0.80, 0.80, 0.80 } + text[INSENSITIVE] = { 0.80, 0.80, 0.80} + text[SELECTED] = { 1.0, 1.0, 1.0 } + + base[ACTIVE] = "#2f272f" + base[NORMAL] = "#1c1e21" + base[PRELIGHT] = { 0.20, 0.20, 0.20 } + base[INSENSITIVE] = "#4c5159" + base[SELECTED] = { 0.25, 0.25, 0.25 } + + engine "clearlooks" { + menubarstyle = 2 # 0 = flat, 1 = sunken, 2 = flat gradient + menuitemstyle = 1 # 0 = flat, 1 = 3d-ish (gradient), 2 = 3d-ish (button) + listviewitemstyle = 1 # 0 = flat, 1 = 3d-ish (gradient) + progressbarstyle = 0 # 0 = candy bar, 1 = flat + } +} + +style "base_frame" +{ + fg[NORMAL] = { 0.80, 0.80, 0.80 } + bg[NORMAL] = { 0.40, 0.40, 0.40 } +} + +style "transport_base" = "medium_bold_text" +{ + bg[NORMAL] = { 0.10, 0.10, 0.10 } + bg[ACTIVE] = { 0, 0, 0 } + bg[PRELIGHT] = { 0, 0, 0 } + bg[INSENSITIVE] = { 0, 0, 0 } + bg[SELECTED] = { 0, 0, 0 } +} + +style "black_mackie_menu_bar" = "medium_bold_text" +{ + font_name = "sans bold 12" + fg[NORMAL] = { 1.0, 1.0, 1.0 } + bg[NORMAL] = { 0, 0, 0 } +} + +style "default_buttons_menus" +{ + font_name = "sans 11" + fg[ACTIVE] = { 1.0, 1.0, 1.0 } + + bg[NORMAL] = { 0.35, 0.35, 0.35 } + bg[ACTIVE] = "#565690" + bg[PRELIGHT] = { 0.20, 0.20, 0.20 } + bg[INSENSITIVE] = { 0.20, 0.20, 0.20 } + bg[SELECTED] = { 0.20, 0.20, 0.20 } +} + +style "very_small_button" = "default_buttons_menus" +{ + font_name = "sans 8" + ythickness = 0 + xthickness = 0 +} + +style "small_button" = "default_buttons_menus" +{ +} + +style "very_small_red_active_and_selected_button" = "very_small_button" +{ + bg[ACTIVE] = { 1.0, 0, 0} + bg[SELECTED] = { 1.0, 0, 0} +} + +style "small_red_active_and_selected_button" = "small_button" +{ + fg[ACTIVE] = { 0, 0, 0 } + bg[ACTIVE] = { 1.0, 0, 0} + bg[SELECTED] = { 1.0, 0, 0} +} + +style "track_rec_enable_button" = "small_button" +{ + fg[SELECTED] = { 0.0, 0.0, 0.0 } + fg[ACTIVE] = { 0.0, 0.0, 0.0 } + fg[PRELIGHT] = { 0.0, 0.0, 0.0 } + + bg[SELECTED] = { 1.0, 0.0, 0.0 } + bg[ACTIVE] = { 0.91, 0.68, 0.68} + bg[PRELIGHT] = { 1.0, 0.0, 0.0 } +} + +style "mixer_rec_enable_button" = "track_rec_enable_button" +{ + font_name = "sans 8" + xthickness = 0 + ythickness = 0 +} + +style "solo_button" = "small_button" +{ + bg[PRELIGHT] = { 0, 1.0, 0 } + bg[ACTIVE] = { 0.66, 0.97, 0.19 } + + fg[PRELIGHT] = { 0, 0, 0 } + fg[ACTIVE] = { 0, 0, 0 } +} + +style "mixer_solo_button" = "solo_button" +{ + font_name = "sans 8" + xthickness = 0 + ythickness = 0 + +} + + +style "mute_button" = "small_button" +{ + bg[PRELIGHT] = { 1.0, 0.65, 0.13 } + bg[ACTIVE] = { 1.0, 0.98, 0.53 } + + fg[PRELIGHT] = { 0, 0, 0 } +} + +style "mixer_mute_button" = "mute_button" +{ + font_name = "sans 8" + xthickness = 0 + ythickness = 0 +} + +style "track_loop_button" = "small_button" +{ + bg[ACTIVE] = { 1.0, 0.98, 0.53 } + bg[PRELIGHT] = { 1.0, 0.98, 0.53 } + +} + +style "mixer_red_active_button" = "very_small_button" +{ + fg[ACTIVE] = { 0, 1.0, 1.0 } + bg[ACTIVE] = { 0.7, 0, 0 } + + base[INSENSITIVE] = { 0.21, 0.21, 0.21 } + bg[INSENSITIVE] = { 0.21, 0.21, 0.21 } +} + +style "time_button" = "default_buttons_menus" +{ + font_name = "sans 10" +} + +style "default_menus" = "default_buttons_menus" +{ + font_name = "sans 11" +} + +style "transport_button" +{ + font_name = "sans 9" + bg[ACTIVE] = { 0.50, 1.0, 0.50 } + fg[ACTIVE] = { 0, 0, 0 } +} + +style "transport_rec_button" +{ + bg[ACTIVE] = { 1.0, 0, 0 } + bg[PRELIGHT] = { 0.91, 0.68, 0.68 } #blinking rec button color +} + +style "shuttle_control" = "very_small_text" +{ + fg[NORMAL] = { 0.85, 0.92, 0.98 } + fg[ACTIVE] = { 0.85, 0.92, 0.98 } + fg[PRELIGHT] = { 0.85, 0.92, 0.98 } + fg[SELECTED] = { 0.85, 0.92, 0.98 } + fg[INSENSITIVE] = { 0.85, 0.92, 0.98 } + + bg[NORMAL] = { 0.31, 0.31, 0.31 } + bg[PRELIGHT] = { 0.31, 0.31, 0.31 } + bg[INSENSITIVE] = { 0.31, 0.31, 0.31 } + bg[ACTIVE] = { 0.50, 1.0, 0.50 } + bg[SELECTED] = { 1.0, 0.04, 0.04 } +} + +style "ardour_adjusters" = "default_buttons_menus" +{ + bg[NORMAL] = { 0.60, 0.60, 0.60 } + bg[PRELIGHT] = { 0.80, 0.80, 0.80 } + bg[ACTIVE] = { 0.06, 0.06, 0.06 } +} + +style "ardour_progressbars" = "default_buttons_menus" +{ + bg[NORMAL] = { 0, 0, 0 } + bg[PRELIGHT] = { 0.00, 0.36, 0.40 } +} + +style "options_window" = "default_base" +{ + font_name = "sans 11" + fg[PRELIGHT] = { 0.80, 0.80, 0.80 } +} + +style "option_entry" = "default_base" +{ + fg[NORMAL] = { 0.50, 1.0, 1.0 } + fg[ACTIVE] = { 0.50, 1.0, 1.0 } + fg[INSENSITIVE] = { 0.80, 0.80, 0.80 } + + base[INSENSITIVE] = { 0.12, 0.12, 0.12 } + + bg[NORMAL] = { 0.40, 0.40, 0.40 } + bg[ACTIVE] = { 0.40, 0.40, 0.40 } +} + +style "red_when_active" = "medium_text" +{ + fg[NORMAL] = { 0.80, 0.80, 0.80 } + bg[NORMAL] = { 0.31, 0.31, 0.31 } + + fg[ACTIVE] = { 0.80, 0.80, 0.80 } + bg[ACTIVE] = { 1.0, 0, 0} +} + +style "xrun_warn" +{ + font_name = "sans bold 18" + + fg[NORMAL] = { 1.0, 1.0, 1.0 } + fg[ACTIVE] = { 1.0, 1.0, 1.0 } + text[NORMAL] = { 1.0, 1.0, 1.0 } + text[ACTIVE] = { 1.0, 1.0, 1.0 } + base[NORMAL] = { 0.09, 0.48, 0.46 } + base[ACTIVE] = { 0.09, 0.48, 0.46 } + bg[NORMAL] = { 1.0, 0.48, 0.46 } + bg[ACTIVE] = { 0.09, 1.0, 0.46 } +} + +style "menu_bar_base" +{ + bg[NORMAL] = { 0, 0, 0 } + bg[ACTIVE] = { 0, 0, 0 } + bg[PRELIGHT] = { 0, 0, 0 } + bg[INSENSITIVE] = { 0, 0, 0 } + bg[SELECTED] = { 0, 0, 0 } +} + +style "fatal_message" = "medium_text" +{ + fg[ACTIVE] = { 1.0, 0, 1.0 } + fg[NORMAL] = { 0.80, 0.80, 0.80 } + bg[ACTIVE] = { 0,0,0 } + bg[NORMAL] = { 0,0,0 } + base[ACTIVE] = { 0,0,0 } + base[NORMAL] = { 0,0,0 } +} + +style "error_message" = "medium_text" +{ + fg[ACTIVE] = { 1.0, 0, 0 } + fg[NORMAL] = { 0.80, 0.80, 0.80 } + bg[ACTIVE] = { 0,0,0 } + bg[NORMAL] = { 0,0,0 } + base[ACTIVE] = { 0,0,0 } + base[NORMAL] = { 0,0,0 } +} + +style "info_message" = "medium_text" +{ + fg[ACTIVE] = { 1.0, 0, 0 } + fg[NORMAL] = { 0.80, 0.80, 0.80 } + bg[ACTIVE] = { 0,0,0 } + bg[NORMAL] = { 0,0,0 } + base[ACTIVE] = { 0,0,0 } + base[NORMAL] = { 0,0,0 } +} + +style "warning_message" = "medium_text" +{ + fg[ACTIVE] = { 0.30,0.30, 1.0 } + fg[NORMAL] = { 0.80, 0.80, 0.80 } + bg[ACTIVE] = { 0, 0, 0 } + bg[NORMAL] = { 0, 0, 0 } + base[ACTIVE] = { 0, 0, 0 } + base[NORMAL] = { 0, 0, 0 } +} + +style "medium_entry" = "medium_text" +{ + fg[NORMAL] = { 0.50, 1.0, 1.0 } + fg[ACTIVE] = { 0.50, 1.0, 1.0 } + fg[SELECTED] = { 0.50, 1.0, 0.50 } + + bg[NORMAL] = { 0.40, 0.40, 0.40 } + + base[NORMAL] = { 0, 0, 0 } + base[ACTIVE] = { 0, 0, 0 } + base[SELECTED] = { 0.5, 0.5, 1.0 } +} + +style "medium_entry_noselection_fg" = "medium_entry" +{ + fg[SELECTED] = { 0.50, 1.0, 0.50 } +} + +style "medium_entry_noselection_bg" = "medium_entry" +{ + bg[SELECTED] = { 0.50, 1.0, 1.0 } +} + +style "medium_bold_entry" = "medium_bold_text" +{ + fg[NORMAL] = { 0.50, 1.0, 1.0 } + fg[ACTIVE] = { 0.50, 1.0, 1.0 } + + bg[NORMAL] = { 0.40, 0.40, 0.40 } + + base[NORMAL] = { 0, 0, 0 } + base[ACTIVE] = { 0, 0, 0 } + base[SELECTED] = { 0, 0, 0 } +} + + +style "small_entry" = "small_text" +{ + fg[NORMAL] = { 0.50, 1.0, 1.0 } + fg[ACTIVE] = { 0.50, 1.0, 1.0 } + bg[NORMAL] = { 0.0, 0.0, 0.0 } + base[NORMAL] = { 0, 0, 0 } + base[ACTIVE] = { 0, 0, 0 } + base[SELECTED] = { 0, 0, 0 } +} + +style "red_active_small_entry" = "small_entry" +{ + fg[ACTIVE] = { 1.0, 0.0, 0.0 } + fg[SELECTED] = { 1.0, 0, 0 } +} + +style "small_bold_entry" = "small_bold_text" +{ + fg[NORMAL] = { 0.50, 1.0, 1.0 } + fg[ACTIVE] = { 0.50, 1.0, 1.0 } + + bg[NORMAL] = { 0.40, 0.40, 0.40 } + + base[NORMAL] = { 0, 0, 0 } + base[ACTIVE] = { 0, 0, 0 } + base[SELECTED] = { 0, 0, 0 } +} + +style "small_red_on_black_entry" = "small_bold_text" +{ + fg[NORMAL] = { 1.0, 0, 0 } + fg[ACTIVE] = { 1.0, 0, 0 } + base[NORMAL] = { 0.0, 0.0, 0.0 } + base[ACTIVE] = { 0.0, 0.0, 0.0 } + bg[NORMAL] = { 0.0, 0.0, 0.0 } + bg[ACTIVE] = { 0.0, 0.0, 0.0 } +} + +style "big_clock_display" = "medium_entry" +{ + font_name = "courier bold 34" +} + +style "transport_clock_display" +{ + font_name = "sans bold 14" + + fg[NORMAL] = { 0.50, 1.0, 0.50 } + fg[ACTIVE] = { 1.0, 0, 0.0 } + fg[SELECTED] = { 1.0, 0, 0 } + fg[PRELIGHT] = { 1.0, 0, 0.0 } + fg[INSENSITIVE] = { 1.0, 0, 0.0 } + + base[NORMAL] = { 0.0, 0.0, 0.0 } + base[ACTIVE] = { 0.0, 0.0, 0.0 } + bg[NORMAL] = { 0.0, 0.0, 0.0 } + bg[ACTIVE] = { 0.0, 0.0, 0.0 } +} + +style "tempo_meter_clock_display" +{ + font_name = "sans 9" + fg[NORMAL] = { 1.0, 1.0, 1.0 } + fg[ACTIVE] = { 1.0, 1.0, 0.0 } + fg[SELECTED] = { 1.0, 0, 0 } + base[NORMAL] = { 0.0, 0.48, 1.0 } + base[ACTIVE] = { 0.09, 0.98, 0.46 } + bg[NORMAL] = { 0.0, 0.48, 1.0 } + bg[ACTIVE] = { 0.09, 0.98, 0.46 } +} + +style "default_clock_display" = "medium text" +{ + font_name = "sans 10" + fg[NORMAL] = { 0.50, 1.0, 0.50 } + fg[ACTIVE] = { 1.0, 0.0, 0.0 } + fg[SELECTED] = { 1.0, 0, 0 } + base[NORMAL] = { 0, 0, 0 } + base[ACTIVE] = { 0, 0, 0 } + bg[NORMAL] = { 0, 0, 0 } + bg[ACTIVE] = { 0, 0, 0 } +} + +style "editor_time_ruler" = "small_text" +{ + fg[NORMAL] = { 0.80, 0.80, 0.80 } + bg[NORMAL] = { 0.09, 0.09, 0.09 } +} + +style "audio_track_base" = "default_base" +{ + font_name = "sans 8" + fg[NORMAL] = { 0.77, 0.77, 0.72 } + bg[NORMAL] = { 0.18, 0.18, 0.22 } + bg[ACTIVE] = { 0.20, 0.20, 0.20 } + bg[PRELIGHT] = { 0.20, 0.20, 0.20 } + bg[INSENSITIVE] = { 0.20, 0.20, 0.20 } + bg[SELECTED] = { 0.20, 0.20, 0.20 } +} + +style "audio_bus_base" +{ + font_name = "sans 8" + fg[NORMAL] = { 0.77, 0.77, 0.72 } + fg[NORMAL] = { 0.7, 0.8, 0.2 } + #bg[NORMAL] = {0, 0.36, 0.40 } + bg[NORMAL] = "#464666" +} + +style "track_name_display" +{ + font_name = "sans medium 11" + fg[NORMAL] = { 0.80, 0.80, 0.80 } + fg[ACTIVE] = { 0.80, 0.80, 0.80 } + + base[NORMAL] = { 0.06, 0.06, 0.06 } + base[ACTIVE] = { 0.26, 0.26, 0.26 } + bg[NORMAL] = { 0.26, 0.26, 0.26 } + bg[ACTIVE] = { 0.26, 0.26, 0.26 } +} + +style "active_track_name_display" +{ + font_name = "sans medium 11" + text[NORMAL] = { 0.26, 0.26, 0.26 } + base[NORMAL] = { 0.89, 0.89, 0.89 } +} + +style "track_separator" +{ + bg[NORMAL] = { 0.40, 0.40, 0.40 } +} + +# +# Track edit groups. These styles define +# the colors that the "edit" button will +# use as a track is moved from +# track edit group to track edit group. +# There are 8 edit groups. Edit group 0 +# is used for tracks that are not editable, +# so we leave its style to the default. +# + +style "edit_group_0" + +{ + bg[ACTIVE] = { 1.0, 0.65, 0.13 } + bg[NORMAL] = { 0.31, 0.31, 0.31 } + fg[NORMAL] = { 0.82, 0.91, 0.99 } + fg[ACTIVE] = { 0, 0, 0 } +} + +style "edit_group_1" +{ + fg[NORMAL] = { 0, 0, 0 } + fg[PRELIGHT] = { 0, 0, 0 } + fg[SELECTED] = { 0, 0, 0 } + bg[NORMAL] = { 0.93, 0.34, 0.08 } + bg[PRELIGHT] = { 0.93, 0.34, 0.08 } + bg[SELECTED] = { 0.93, 0.34, 0.08 } +} + +style "edit_group_2" +{ + fg[NORMAL] = { 0, 0, 0 } + fg[PRELIGHT] = { 0, 0, 0 } + fg[SELECTED] = { 0, 0, 0 } + bg[NORMAL] = { 0.93, 0.34, 0.08 } + bg[PRELIGHT] = { 0.93, 0.34, 0.08 } + bg[SELECTED] = { 0.93, 0.34, 0.08 } +} + +style "edit_group_3" +{ + fg[NORMAL] = { 0, 0, 0 } + fg[PRELIGHT] = { 0, 0, 0 } + fg[SELECTED] = { 0, 0, 0 } + bg[NORMAL] = { 0.93, 0.34, 0.08 } + bg[PRELIGHT] = { 0.93, 0.34, 0.08 } + bg[SELECTED] = { 0.93, 0.34, 0.08 } +} + +style "region_list_display" = "small_bold_text" +{ + fg[NORMAL] = { 0.80, 0.80, 0.80 } + fg[ACTIVE] = { 0.80, 0.80, 0.80 } + fg[SELECTED] = { 0.50, 1.0, 1.0 } + bg[NORMAL] = { 0, 0, 0 } + bg[ACTIVE] = { 0, 0, 0 } + bg[SELECTED] = { 0, 0, 0 } + base[NORMAL] = { 0, 0, 0 } + base[ACTIVE] = { 0, 1, 0 } + base[INSENSITIVE] = { 0, 0, 0 } + base[SELECTED] = { 0.80, 0.80, 0.80 } +} + +style "main_canvas_area" +{ + bg[NORMAL] = { 0.38, 0.38, 0.38 } + bg[ACTIVE] = { 0.38, 0.38, 0.38 } + bg[INSENSITIVE] = { 0.38, 0.38, 0.38 } + bg[SELECTED] = { 0.38, 0.38, 0.38 } + bg[PRELIGHT] = { 0.38, 0.38, 0.38 } +} + +style "track_controls_inactive" +{ + bg[NORMAL] = { 0.60, 0.60, 0.66 } + bg[ACTIVE] = { 0.60, 0.60, 0.66 } + bg[INSENSITIVE] = { 0.60, 0.60, 0.66 } + bg[SELECTED] = { 0.60, 0.60, 0.66 } + bg[PRELIGHT] = { 0.60, 0.60, 0.66 } + + font_name = "sans medium 10" + fg[NORMAL] = { 0.7, 0.8, 0.2 } +} + +style "edit_controls_base_selected" +{ + bg[NORMAL] = { 0.56, 0.56, 0.56 } + bg[ACTIVE] = { 0.56, 0.56, 0.56 } + bg[INSENSITIVE] = { 0.56, 0.56, 0.56 } + bg[SELECTED] = { 0.56, 0.56, 0.56 } + bg[PRELIGHT] = { 0.56, 0.56, 0.56 } +} + +style "automation_track_controls_base" +{ + bg[NORMAL] = { 0.22, 0.22, 0.29 } + bg[ACTIVE] = { 0.22, 0.22, 0.29 } + bg[INSENSITIVE] = { 0.22, 0.22, 0.29 } + bg[SELECTED] = { 0.22, 0.22, 0.29 } + bg[PRELIGHT] = { 0.22, 0.22, 0.29 } +} + +# Plugin Editors +style "plugin_slider" +{ + font_name ="sans bold 10" + + # the slider itself. the inactive part is INSENSITIVE, + # the active part is something else. + + fg[NORMAL] = { 0.37, 0.43, 0.52 } + fg[ACTIVE] = { 0.37, 0.43, 0.52 } + fg[INSENSITIVE] = {0.40, 0.40, 0.40 } # matches default_base + fg[SELECTED] = { 0.37, 0.43, 0.52 } + fg[PRELIGHT] = { 0.37, 0.43, 0.52 } + + # draws the outer rectangle around the slider + + bg[NORMAL] = { 0.80, 0.80, 0.80 } + bg[ACTIVE] = { 0.80, 0.80, 0.80 } + bg[INSENSITIVE] = {0.80, 0.80, 0.80 } + bg[SELECTED] = { 0.80, 0.80, 0.80 } + bg[PRELIGHT] = { 0.80, 0.80, 0.80 } + + # the numeric display + + text[NORMAL] = { 0.80, 0.80, 0.80 } + text[ACTIVE] = { 0.80, 0.80, 0.80 } + text[INSENSITIVE] = { 0.80, 0.80, 0.80 } + text[SELECTED] = { 0.80, 0.80, 0.80 } + text[PRELIGHT] = { 0.80, 0.80, 0.80 } +} + +style "track_list_display" = "small_bold_text" +{ + text[NORMAL] = { 0.80, 0.80, 0.80 } + text[ACTIVE] = { 0.3, 0.3, 0.3 } + text[INSENSITIVE] = { 0, 0, 0 } + text[SELECTED] = { 0.8, 0.8, 0.8 } + + base[NORMAL] = { 0, 0, 0 } + base[ACTIVE] = { 0, 0, 0 } + base[INSENSITIVE] = { 0, 0, 0 } + base[SELECTED] = { 0, 0, 0 } +} + +style "inspector_track_list_display" = "track_list_display" +{ + text[ACTIVE] = { 0.8, 0.8, 0.8 } + + base[NORMAL] = { 0, 0, 0 } + base[ACTIVE] = { 0.2, 0.2, 0.2 } + base[INSENSITIVE] = { 0, 0, 0 } + base[SELECTED] = { 0.3, 0.3, 0.4 } +} + +style "redirect_list_display" +{ + GtkTreeView::horizontal-separator = 0 + GtkTreeView::vertical-separator = 0 + + font_name = "sans 10" + text[NORMAL] = { 0.80, 0.80, 0.80 } + text[ACTIVE] = { 0.5, 0.5, 0.9 } + text[INSENSITIVE] = { 0, 0, 0 } + text[SELECTED] = { 0.9, 0.3, 0.3 } + + base[NORMAL] = { 0, 0, 0 } + base[ACTIVE] = { 0, 0, 0 } + base[INSENSITIVE] = { 0, 0, 0 } + base[SELECTED] = { 0, 0, 0 } + + # these two are explicitly used by the cell renderer for the + # text + + fg[NORMAL] = { 0.5, 0.5, 0.5 } # used for inactive + fg[ACTIVE] = { 0.5, 1.0, 1.0 } # used for active +} + +style "inspector_redirect_list_display" = "redirect_list_display" +{ + base[SELECTED] = { 0.3, 0.3, 0.3 } +} + +# MixerPanZone: +# +# the NORMAL fg color is used for the pan puck +# the ACTIVE fg color is used for the speaker boxes + +style "pan_zone" = "default_base" +{ + fg[NORMAL] = { 0.34, 0.95, 0.92 } + fg[ACTIVE] = { 0.95, 0.48, 0.11 } +} + +style "wall_clock" = "medium_bold_text" +{ + fg[NORMAL] = { 1.0, 1.0, 1.0 } + bg[NORMAL] = { 0, 0, 0 } +} + +style "paler_red_when_active" = "medium_text" +{ + fg[NORMAL] = { 0.80, 0.80, 0.80 } + fg[PRELIGHT] = { 0.80, 0.80, 0.80 } + bg[NORMAL] = { 0.31, 0.31, 0.31 } + bg[PRELIGHT] = { 0.31, 0.31, 0.31 } + + fg[ACTIVE] = { 0.36, 0.46, 0.28 } + bg[ACTIVE] = { 1.00, 0.59, 0.59} +} + +style "peak_display_peaked_entry" = "small_text" +{ + fg[NORMAL] = { 1.0, 1.0, 1.0 } + fg[ACTIVE] = { 1.0, 1.0, 1.0 } + fg[SELECTED] = { 1.0, 1.0, 1.0 } + + bg[NORMAL] = {0.9, 0.0, 0.0 } + bg[ACTIVE] = { 0.9, 0.0, 0.0 } + bg[PRELIGHT] = { 0.9, 0.0, 0.0 } + bg[INSENSITIVE] = { 0.9, 0.0, 0.0 } + bg[SELECTED] = { 0.9, 0.0, 0.0 } + base[NORMAL] = { 0.9, 0.0, 0.0 } + base[ACTIVE] = { 0.9, 0.0, 0.0 } + base[PRELIGHT] = { 0.9, 0.0, 0.0 } + base[INSENSITIVE] = { 0.9, 0.0, 0.0 } + base[SELECTED] = { 0.9, 0.0, 0.0 } +} + +style "selected_strip_frame" +{ + fg[NORMAL] = { 0.74, 0.42, 0.47 } + bg[NORMAL] = { 0.79, 0.28, 0.18 } +} + +style "flashing_alert" = "very_small_text" +{ + fg[NORMAL] = { 0.80, 0.80, 0.80 } + bg[NORMAL] = { 0.31, 0.31, 0.31 } + + fg[ACTIVE] = { 0.80, 0.80, 0.80 } + bg[ACTIVE] = { 1.0, 0, 0} +} + +style "selected_io_selector_port_list" = "medium_text" +{ + fg[NORMAL] = { 0.50, 1.0, 1.0 } + fg[SELECTED] = { 0.50, 1.0, 1.0 } + base[NORMAL] = { 0, 0, 0 } + base[SELECTED] = { 0, 0, 0 } +} + +style "io_selector_port_list" = "medium_text" +{ + fg[NORMAL] = {0.80, 0.80, 0.70 } + fg[SELECTED] = {0.80, 0.80, 0.70 } + base[NORMAL] = { 0.26, 0.26, 0.26 } + base[SELECTED] = { 0.26, 0.26, 0.26 } +} + +style "io_selector_notebook" = "default_base" +{ + fg[NORMAL] = { 0.50, 1.0, 1.0 } + font_name ="sans bold 10" +} + +style "tearoff_arrow" = "medium_bold_entry" +{ + fg[NORMAL] = { 0.80, 0.80, 0.80 } + fg[PRELIGHT] = { 0.80, 0.80, 0.80 } + bg[NORMAL] = { 0.80, 0.80, 0.80 } + bg[PRELIGHT] = { 0.80, 0.80, 0.80 } +} + +style "meter_metrics_strip" = "default_base" +{ + font_name = "sans 5" + fg[NORMAL] = { 1.0, 0.8, 0.2 } +} + +style "location_row_button" = "default_buttons_menus" +{ + font_name = "sans 10" +} + +style "location_rows_clock" = "default_clock_display" +{ + font_name = "sans 12" +} + +style "pan_slider" +{ + font_name = "sans 8" + + fg[NORMAL] = { 0.67, 0.23, 0.22 } + fg[ACTIVE] = { 0.67, 0.23, 0.22 } + fg[INSENSITIVE] = {0.32, 0.39, 0.45 } # matches default_base + fg[SELECTED] = { 0.67, 0.23, 0.22 } + fg[PRELIGHT] = { 0.67, 0.23, 0.22 } + + bg[NORMAL] = { 0, 0, 0 } + bg[ACTIVE] = { 0, 0, 0 } + bg[INSENSITIVE] = {0.32, 0.39, 0.45 } # matches default_base + bg[SELECTED] = { 0, 0, 0 } + bg[PRELIGHT] = { 0, 0, 0 } + + text[NORMAL] = { 0.85, 0.92, 0.98 } + text[ACTIVE] = { 0.85, 0.92, 0.98 } + text[INSENSITIVE] = { 0.85, 0.92, 0.98 } + text[SELECTED] = { 0.85, 0.92, 0.98 } + text[PRELIGHT] = { 0.85, 0.92, 0.98 } +} + +style "region_list_whole_file" +{ + fg[NORMAL] = { 0.4, 0.4, 0.9 } +} + +style "ardour_button" ="default_buttons_menus" +{ + xthickness = 1 + ythickness = 1 +} + +#--------------------------------------------------------------- +widget "*FirstActionMessage" style "first_action_message" +widget "*VerboseCanvasCursor" style "verbose_canvas_cursor" +widget "*MarkerText" style "marker_text" +widget "*TimeAxisViewItemName" style "time_axis_view_item_name" +#widget "*ExportProgress" style "default_buttons_menus" +widget "*ExportFileLabel" style "small_bold_text" +widget "*ExportFormatLabel" style "medium_bold_text" +widget "*ExportHeader" style "small_bold_text" +widget "*ExportFileDisplay" style "medium_entry" +widget "*ExportFormatDisplay" style "medium_entry" +widget "*ExportCheckbox" style "small_entry" +widget "*ExportTrackSelector*" style "medium_entry_noselection_bg" +widget "*EditModeSelector" style "medium_bold_entry" +widget "*SnapTypeSelector" style "medium_bold_entry" +widget "*SnapModeSelector" style "medium_bold_entry" +widget "*ZoomFocusSelector" style "medium_bold_entry" +widget "*ArdourContextMenu*" style "default_menus" +widget "*EditGroupTitleButton*" style "default_buttons_menus" +widget "*MixerGroupTitleButton*" style "default_buttons_menus" +widget "*ErrorLogCloseButton" style "default_buttons_menus" +widget "*EditorGTKButton*" style "default_buttons_menus" +widget "*ToolbarButton" style "default_buttons_menus" +widget "*ToolbarButton*" style "default_buttons_menus" +widget "*CrossfadeEditButton" style "default_buttons_menus" +widget "*CrossfadeEditButton*" style "default_buttons_menus" +widget "*TrackHistoryButton*" style "default_buttons_menus" +widget "*TrackSizeButton*" style "default_buttons_menus" +widget "*TrackPlaylistButton*" style "default_buttons_menus" +widget "*TrackAutomationButton*" style "default_buttons_menus" +widget "*TrackGroupButton*" style "default_buttons_menus" +widget "*TrackMixButton*" style "default_buttons_menus" +widget "*TrackVisualButton*" style "default_buttons_menus" +widget "*TrackRemoveButton*" style "default_buttons_menus" +widget "*BaseButton" style "default_buttons_menus" +widget "*TakeButtonLabel" style "default_buttons_menus" +widget "*MixerWidthButton" style "default_buttons_menus" +widget "*MixerHideButton" style "default_buttons_menus" +widget "*MixerSendButton" style "default_buttons_menus" +widget "*MixerSendButtonLabel" style "default_buttons_menus" +widget "*MixerSendSwitch" style "default_buttons_menus" +widget "*MixerInsertButton" style "default_buttons_menus" +widget "*MixerInsertButtonLabel" style "default_buttons_menus" +widget "*MixerInsertSwitch" style "default_buttons_menus" +widget "*MixerMonitorInputButton*" style "very_small_button" +widget "*MixerMonitorInputButton.*" style "very_small_button" +widget "*MixerIOButton" style "very_small_button" +widget "*MixerIOButtonLabel" style "very_small_button" +widget "*AddRouteDialogSpinner" style "ardour_adjusters" +widget "*AddRouteDialogRadioButton*" style "options_window" +widget "*OptionsNotebook" style "options_window" +widget "*OptionEditorToggleButton*" style "options_window" +widget "*OptionsLabel" style "options_window" +widget "*OptionEditorAuditionerLabel" style "options_window" +widget "*OptionsEntry" style "option_entry" +widget "*InspectorNotebook" style "options_window" +widget "*NewSessionDialog" style "options_window" +widget "*NewSessionDialogButton*" style "options_window" +widget "*MixerSendSwitch*" style "very_small_red_active_and_selected_button" +widget "*OptionEditorToggleButton" style "small_red_active_and_selected_button" +widget "*NewSessionDialogButton" style "small_red_active_and_selected_button" +widget "*MixerRecordEnableButton" style "mixer_rec_enable_button" +widget "*MixerRecordEnableButton*" style "mixer_rec_enable_button" +widget "*TrackRecordEnableButton" style "track_rec_enable_button" +widget "*TrackRecordEnableButton*" style "track_rec_enable_button" +widget "*TrackMuteButton*" style "mute_button" +widget "*TrackLoopButton*" style "track_loop_button" +widget "*EditorTimeButton*" style "time_button" +widget "*EditorMixerButton*" style "default_buttons_menus" +widget "*SoloButton*" style "solo_button" +widget "*SoloButton.*" style "solo_button" +widget "*SafeSoloButton*" style "solo_button" +widget "*SafeSoloButton.*" style "solo_button" +widget "*MixerPhaseInvertButton*" style "very_small_button" +widget "*MixerPhaseInvertButton.*" style "very_small_button" +widget "*MixerAutomationRecordingButton*" style "very_small_button" +widget "*MixerAutomationRecordingButton.*" style "very_small_button" +widget "*MixerAutomationModeButton*" style "very_small_button" +widget "*MixerAutomationModeButton.*" style "very_small_button" +widget "*MixerAutomationPlaybackButton*" style "very_small_button" +widget "*MixerAutomationPlaybackButton.*" style "very_small_button" +widget "*MixerMuteButton*" style "mixer_mute_button" +widget "*MixerMuteButton.*" style "mixer_mute_button" +widget "*MixerSoloButton*" style "mixer_solo_button" +widget "*MixerSoloButton.*" style "mixer_solo_button" +widget "*MixerNameButton" style "very_small_button" +widget "*MixerNameButtonLabel" style "very_small_button" +widget "*MixerGroupButton" style "very_small_button" +widget "*MixerGroupButtonLabel" style "very_small_button" +widget "*MixerCommentButton" style "very_small_button" +widget "*MixerCommentButton*" style "very_small_button" +widget "*EditGroupButton" style "very_small_button" +widget "*EditGroupButtonLabel" style "very_small_button" +widget "*TransportButton" style "transport_button" +widget "*TransportButton*" style "transport_button" +widget "*ShuttleButton" style "transport_button" +widget "*ShuttleButton*" style "transport_button" +widget "*ShuttleDisplay" style "transport_button" +widget "*ShuttleDisplay*" style "transport_button" +widget "*ShuttleControl" style "shuttle_control" +widget "*TransportRecButton" style "transport_rec_button" +widget "*TransportRecButton*" style "transport_rec_button" +widget "*RecordingXrunWarningWindow" style "xrun_warn" +widget "*RecordingXrunWarningWindow*" style "xrun_warn" +widget "*MainMenuBar" style "menu_bar_base" +widget "*ErrorMessage" style "error_message" +widget "*FatalMessage" style "fatal_message" +widget "*InfoMessage" style "info_message" +widget "*WarningMessage" style "warning_message" +widget "*BigClockDisplay" style "big_clock_display" +widget "*TransportClockDisplay" style "transport_clock_display" +widget "*SecondaryClockDisplay" style "transport_clock_display" +widget "*BBTTempoLabel" style "tempo_meter_clock_display" +widget "*BBTMeterLabel" style "tempo_meter_clock_display" +widget "*SelectionStartClock" style "default_clock_display" +widget "*SelectionEndClock" style "default_clock_display" +widget "*EditCursorClock" style "default_clock_display" +widget "*PreRollClock" style "default_clock_display" +widget "*PostRollClock" style "default_clock_display" +widget "*NudgeClock" style "default_clock_display" +widget "*ZoomRangeClock" style "default_clock_display" +widget "*SMPTEOffsetClock" style "default_clock_display" +widget "*TransportLabel" style "small_bold_text" +widget "*TakeLabel" style "small_bold_text" +widget "*LocationLabel" style "small_bold_text" +widget "*WipeLabel" style "small_bold_text" +widget "*TakeTagLabel" style "small_bold_text" +widget "*ToolBarLabel" style "small_bold_text" +widget "*EditorDisplayLabel" style "small_bold_text" +widget "*NewSessionLabel" style "large_text" +widget "*GlobalButtonLabel" style "default_buttons_menus" +widget "*ClickButton" style "medium_entry" +widget "*RegionNameDisplay" style "medium_entry" +widget "*PluginDisplay" style "medium_entry" +widget "*SelectionDisplay" style "medium_entry" +widget "*HistorySelector" style "medium_entry" +widget "*LocationSelector" style "medium_entry" +widget "*TakeSelector" style "medium_entry" +widget "*RegionSelector" style "medium_entry" +widget "*SMPTERuler" style "editor_time_ruler" +widget "*BBTRuler" style "editor_time_ruler" +widget "*FramesRuler" style "editor_time_ruler" +widget "*MinSecRuler" style "editor_time_ruler" +widget "*BaseFrame" style "base_frame" +widget "*AudioTrackStripBase" style "audio_track_base" +widget "*TimeAxisViewControlsBaseUnselected" style "audio_track_base" +widget "*AudioTrackControlsBaseUnselected" style "audio_track_base" +widget "*AudioTrackFader" style "audio_track_base" +widget "*AudioBusStripBase" style "audio_bus_base" +widget "*BusControlsBaseUnselected" style "audio_bus_base" +widget "*AudioBusFader" style "audio_bus_base" +widget "*TrackSeparator" style "track_separator" +widget "*TrackEditIndicator0*" style "edit_group_0" +widget "*TrackEditIndicator1*" style "edit_group_1" +widget "*TrackEditIndicator2*" style "edit_group_2" +widget "*TrackEditIndicator3*" style "edit_group_3" +widget "*TrackEditIndicator4*" style "edit_group_3" +widget "*TrackEditIndicator5*" style "edit_group_3" +widget "*TrackEditIndicator6*" style "edit_group_3" +widget "*TrackEditIndicator7*" style "edit_group_3" +widget "*EditorTrackNameDisplay" style "track_name_display" +widget "*EditorTrackNameDisplay*" style "track_name_display" +widget "*EditorActiveTrackNameDisplay" style "active_track_name_display" +widget "*EditorActiveTrackNameDisplay*" style "active_track_name_display" +widget "*EditorRegionList" style "region_list_display" +widget "*CrossfadeEditAuditionButton" style "red_when_active" +widget "*CrossfadeEditAuditionButton*" style "red_when_active" +widget "*CrossfadeEditCurveButton" style "red_when_active" +widget "*CrossfadeEditCurveButton*" style "red_when_active" +widget "*CrossfadeEditLabel" style "medium_text" +widget "*CrossfadeEditFrame" style "base_frame" +widget "*MouseModeButton" style "default_buttons_menus" +widget "*MouseModeButton*" style "default_buttons_menus" +widget "*EditorMainCanvas" style "main_canvas_area" +widget "*AudioTrackControlsBaseInactiveUnselected" style "track_controls_inactive" +widget "*BusControlsBaseInactiveUnselected" style "track_controls_inactive" +widget "*AutomationTrackControlsBaseInactiveUnselected" style "track_controls_inactive" +widget "*AudioTrackControlsBaseInactiveSelected" style "track_controls_inactive" +widget "*BusControlsBaseInactiveSelected" style "track_controls_inactive" +widget "*AutomationTrackControlsBaseInactiveSelected" style "track_controls_inactive" +widget "*AudioTrackStripBaseInactive" style "track_controls_inactive" +widget "*AudioBusStripBaseInactive" style "track_controls_inactive" +widget "*AudioTrackControlsBaseSelected" style "edit_controls_base_selected" +widget "*BusControlsBaseSelected" style "edit_controls_base_selected" +widget "*AutomationTrackControlsBase" style "automation_track_controls_base" +widget "*AutomationTrackControlsBaseSelected" style "edit_controls_base_selected" +widget "*EditorMenuBar*" style "black_mackie_menu_bar" +widget "*MainMenuBar*" style "black_mackie_menu_bar" +widget "*ZoomClickBox" style "medium_bold_entry" +widget "*PluginParameterLabel" style "medium_text" +widget "*PluginNameInfo" style "plugin_name_text" +widget "*PluginMakerInfo" style "plugin_maker_text" +widget "*PluginParameterInfo" style "medium_text" +widget "*MotionControllerValue" style "medium_entry" +widget "*ParameterValueDisplay" style "medium_bold_entry" +widget "*PluginUIClickBox" style "medium_bold_entry" +widget "*PluginUIClickBox*" style "medium_bold_entry" +widget "*PluginSlider" style "plugin_slider" +widget "*TrackListDisplay" style "track_list_display" +widget "*TrackListDisplay.*" style "small_bold_text" +widget "*EditGroupList" style "track_list_display" +widget "*RegionListDisplay" style "small_bold_entry" +widget "*RegionListDisplay.*" style "small_bold_text" +widget "*RedirectSelector" style "redirect_list_display" +widget "*RedirectSelector.*" style "redirect_list_display" +widget "*MixerTrackCommentArea" style "option_entry" +widget "*MixerPanZone" style "pan_zone" +widget "*MixerTrackDisplayList" style "track_list_display" +widget "*MixerSnapshotDisplayList" style "track_list_display" +widget "*MixerAuxDisplayList" style "track_list_display" +widget "*MixerGroupList" style "track_list_display" +widget "*WallClock" style "wall_clock" +widget "*CPULoad" style "wall_clock" +widget "*RegionEditorLabel" style "medium_text" +widget "*RegionEditorSmallLabel" style "small_text" +widget "*RegionEditorEntry" style "medium_entry" +widget "*RegionEditorClock" style "default_clock_display" +widget "*RegionEditorToggleButton" style "paler_red_when_active" +widget "*RegionEditorToggleButton*" style "paler_red_when_active" +widget "*MixerStripSpeedBase" style "small_entry" +widget "*MixerStripSpeedBase*" style "small_entry" +widget "*MixerStripSpeedBaseNotOne" style "small_red_on_black_entry" +widget "*MixerStripSpeedBaseNotOne*" style "small_red_on_black_entry" +widget "*MixerStripGainDisplay" style "small_entry" +widget "*MixerStripGainUnitButton" style "very_small_button" +widget "*MixerStripGainUnitButton*" style "very_small_button" +widget "*MixerStripMeterPreButton" style "very_small_button" +widget "*MixerStripMeterPreButton*" style "very_small_button" +widget "*MixerStripPeakDisplay*" style "red_active_small_entry" +widget "*MixerStripPeakDisplayPeak*" style "peak_display_peaked_entry" +widget "*MixerStripSelectedFrame" style "selected_strip_frame" +widget "*MixerStripFrame" style "base_frame" +widget "*HWMonitorButton" style "red_when_active" +widget "*HWMonitorButton*" style "red_when_active" +widget "*BypassButton" style "red_when_active" +widget "*BypassButton*" style "red_when_active" +widget "*TransportSoloAlert" style "flashing_alert" +widget "*TransportSoloAlert.*" style "flashing_alert" +widget "*TransportAuditioningAlert" style "flashing_alert" +widget "*TransportAuditioningAlert.*" style "flashing_alert" +widget "*FadeCurve" style "medium_bold_entry" +widget "*FadeCurve*" style "medium_bold_entry" +widget "*IOSelectorButton" style "default_buttons_menus" +widget "*IOSelectorButton*" style "default_buttons_menus" +widget "*IOSelectorList" style "medium_entry_noselection_fg" +widget "*IOSelectorPortList" style "io_selector_port_list" +widget "*IOSelectorPortListSelected" style "selected_io_selector_port_list" +widget "*IOSelectorNotebook" style "io_selector_notebook" +widget "*IOSelectorNotebookTab" style "io_selector_notebook" +widget "*IOSelectorFrame" style "base_frame" +widget "*ConnectionEditorButton" style "default_buttons_menus" +widget "*ConnectionEditorButton*" style "default_buttons_menus" +widget "*ConnectionEditorList" style "medium_entry_noselection_fg" +widget "*ConnectionEditorConnectionList" style "medium_entry" +widget "*ConnectionEditorPortList" style "io_selector_port_list" +widget "*ConnectionEditorPortListSelected" style "selected_io_selector_port_list" +widget "*ConnectionEditorNotebook" style "io_selector_notebook" +widget "*ConnectionEditorNotebookTab" style "io_selector_notebook" +widget "*ConnectionEditorFrame" style "base_frame" +widget "*RouteParamsListDisplay" style "inspector_track_list_display" +widget "*RouteParamsPreListDisplay" style "inspector_redirect_list_display" +widget "*RouteParamsPostListDisplay" style "inspector_redirect_list_display" +widget "*TearOffArrow" style "tearoff_arrow" +widget "*RouteParamsTitleButton" style "medium_text" +widget "*RouteParamsTitleLabel" style "medium_text" +widget "*PluginAutomateRecordButton" style "small_red_active_and_selected_button" +widget "*PluginAutomateRecordButton*" style "small_red_active_and_selected_button" +widget "*PluginAutomatePlayButton" style "small_red_active_and_selected_button" +widget "*PluginAutomatePlayButton*" style "small_red_active_and_selected_button" +widget "*PluginAutomateButton" style "small_button" +widget "*PluginAutomateButton*" style "small_button" +widget "*PluginSaveButton" style "small_button" +widget "*PluginSaveButton*" style "small_button" +widget "*PluginLoadButton" style "small_button" +widget "*PluginLoadButton*" style "small_button" +widget "*FaderMetricsStrip" style "meter_metrics_strip" +widget "*MeterMetricsStrip" style "meter_metrics_strip" +widget "*MetricDialogFrame" style "base_frame" +widget "*MetricEntry" style "medium_bold_entry" +widget "*MetricButton" style "default_buttons_menus" +widget "*MetricButton.*" style "default_buttons_menus" +widget "*MetricLabel" style "medium_text" +widget "*TimeStretchButton" style "default_buttons_menus" +widget "*TimeStretchButton.*" style "default_buttons_menus" +widget "*TimeStretchProgress" style "default_buttons_menus" +widget "*ChoiceWindow" style "default_buttons_menus" +widget "*ChoicePrompt" style "default_buttons_menus" +widget "*ChoiceButton" style "default_buttons_menus" +widget "*ChoiceButton*" style "default_buttons_menus" +widget "*SelectionModeButton" style "default_buttons_menus" +widget "*SelectionModeButton*" style "default_buttons_menus" +widget "*TrackLabel" style "medium_text" +widget "*TrackPlugName" style "medium_text" +widget "*TrackParameterName" style "small_text" +widget "*AddRouteDialog*" style "medium_text" +widget "*AddRouteDialog.GtkLabel" style "medium_text" +widget "*AddRouteDialogChannelChoice" style "medium_bold_entry" +widget "*AddRouteDialogSpinner" style "medium_bold_entry" +widget "*AddRouteDialogSpinner*" style "medium_bold_entry" +widget "*AddRouteDialogRadioButton" style "red_when_active" +widget "*AddRouteDialogButton" style "default_buttons_menus" +widget "*AddRouteDialogNameTemplateEntry" style "medium_bold_entry" +widget "*NewSessionIOLabel" style "larger_bold_text" +widget "*NewSessionSR1Label" style "red_medium_text" +widget "*NewSessionSR2Label" style "medium_text" +widget "*NewSessionChannelChoice" style "medium_bold_entry" +widget "*NewSessionMainButton" style "larger_bold_text" +widget "*NewSessionMainButton*" style "larger_bold_text" +widget "*NewSessionMainLabel" style "larger_bold_text" +widget "*LocationEditRowClock" style "location_rows_clock" +widget "*LocationEditNameLabel" style "medium_text" +widget "*LocationEditSetButton" style "location_row_button" +widget "*LocationEditSetButton*" style "location_row_button" +widget "*LocationEditGoButton" style "location_row_button" +widget "*LocationEditGoButton*" style "location_row_button" +widget "*LocationEditCdButton" style "small_red_active_and_selected_button" +widget "*LocationEditCdButton*" style "small_red_active_and_selected_button" +widget "*LocationEditHideButton" style "small_red_active_and_selected_button" +widget "*LocationEditHideButton*" style "small_red_active_and_selected_button" +widget "*LocationEditNumberLabel" style "small_text" +widget "*LocationLocEditorFrame" style "base_frame" +widget "*LocationRangeEditorFrame" style "base_frame" +widget "*LocationEditNameEntry" style "option_entry" +widget "*LocationAddLocationButton" style "default_buttons_menus" +widget "*LocationAddLocationButton*" style "default_buttons_menus" +widget "*LocationAddRangeButton" style "default_buttons_menus" +widget "*LocationAddRangeButton*" style "default_buttons_menus" +widget "*LocationEditRemoveButton" style "location_row_button" +widget "*LocationEditRemoveButton*" style "location_row_button" +widget "*PanSlider" style "pan_slider" +widget "*PanningLinkButton" style "mixer_red_active_button" +widget "*PanningLinkButton.*" style "mixer_red_active_button" +widget "*PanningLinkDirectionButton" style "very_small_button" +widget "*PanningLinkDirectionButton.*" style "very_small_button" +widget "*ChannelCountSelector" style "medium_bold_entry" +widget "*ChannelCountSelector.GtkArrow" style "default_buttons_menus" +widget "*RegionListWholeFile" style "region_list_whole_file" + +class "GtkWidget" style "default_base" +class "GtkScrollbar" style "ardour_adjusters" +class "GtkLabel" style "default_buttons_menus" +class "GtkButton" style "ardour_button" +class "GtkArrow" style "tearoff_arrow" +class "GtkProgressBar" style "ardour_progressbars" + diff --git a/vst/SConscript b/vst/SConscript index fead9ba512..a711a1386d 100644 --- a/vst/SConscript +++ b/vst/SConscript @@ -17,8 +17,8 @@ winmain.c """ ) -ardour_vst.Append (CCFLAGS="-DVST_SUPPORT", CPPPATH="#libs/fst", LIBPATH='#gtk2_ardour') -ardour_vst.Append (LINKFLAGS='-L/usr/X11R6/lib -lasound -lardourgtk -lX11 -lpthread') +ardour_vst.Append (CCFLAGS="-DVST_SUPPORT", CPPPATH="#libs/fst", LIBPATH='#gtk2_ardour', LIBS="ardourgtk") +ardour_vst.Append (LINKFLAGS='-L/usr/X11R6/lib -lasound -lX11 -lpthread') ardour_vst["CC"] ="winegcc" ardour_vst["LINK"] ="wineg++ -mwindows" @@ -27,7 +27,7 @@ ardour_vst.Merge ([ libraries['ardour_cp'], libraries['gtkmm2ext'], libraries['midi++2'], - libraries['pbd3'], + libraries['pbd'], libraries['gtkmm2'], libraries['glib2'], libraries['libgnomecanvas2'], |